herm-tui 1.3.0-dev.8 → 1.3.0-dev.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +5 -5
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -4157,10 +4157,10 @@ Usage:
|
|
|
4157
4157
|
*[interrupted]*`,usage:p?.usage};return{kind:"message.complete",text:p?.text??void 0,usage:p?.usage}}case"tool.start":return{kind:"tool.start",id:ev.payload.tool_id,name:ev.payload.name??"unknown",preview:ev.payload.context};case"tool.progress":return{kind:"tool.progress",name:ev.payload.name,preview:ev.payload.preview};case"tool.generating":return{kind:"tool.generating",name:ev.payload.name};case"tool.complete":return{kind:"tool.complete",id:ev.payload.tool_id,summary:ev.payload.summary,error:ev.payload.error,inline_diff:ev.payload.inline_diff};case"thinking.delta":return side.onStatus?.(ev.payload?.text??""),null;case"reasoning.delta":case"reasoning.available":{let text2=ev.payload?.text;if(!text2)return null;return{kind:"thinking",text:text2,final:ev.type==="reasoning.available"}}case"subagent.start":case"subagent.thinking":case"subagent.tool":case"subagent.progress":case"subagent.complete":{let sub2=ev.type.slice(9);return record(sub2,ev.payload),{kind:"subagent",event:sub2,payload:ev.payload}}case"error":return{kind:"error",text:ev.payload?.message??"Unknown error"};case"clarify.request":return{kind:"prompt",id:ev.payload.request_id,req:{variant:"clarify",...ev.payload}};case"approval.request":return{kind:"prompt",id:`approval-${pid()}`,req:{variant:"approval",...ev.payload}};case"sudo.request":return{kind:"prompt",id:ev.payload.request_id,req:{variant:"sudo",...ev.payload}};case"secret.request":return{kind:"prompt",id:ev.payload.request_id,req:{variant:"secret",...ev.payload}};case"background.complete":return side.onBackground?.(ev.payload.task_id,ev.payload.text),null;case"review.summary":{let text2=String(ev.payload?.text??"").trim();if(!text2)return null;return{kind:"system",text:text2}}case"btw.complete":return side.onBtw?.(ev.payload.text),null;case"gateway.stderr":{let line3=ev.payload.line;if(/error|fail|traceback|exception|\b[45]\d\d\b|refused|denied|unauthori/i.test(line3))return{kind:"system",text:line3.slice(0,200)};return null}case"skin.changed":return side.onSkin?.(ev.payload),null;case"gateway.start_timeout":return{kind:"error",text:`gateway startup timed out (${ev.payload?.python??"python"} @ ${ev.payload?.cwd??"?"})`};case"gateway.protocol_error":return{kind:"system",text:`protocol error: ${ev.payload?.preview??"?"}`};case"browser.progress":{let text2=ev.payload?.message??"";if(!text2)return null;return ev.payload?.level==="error"?{kind:"error",text:text2}:{kind:"system",text:`\xB7 ${text2}`}}case"status.update":{let kind=ev.payload?.kind,text2=ev.payload?.text??"";if(side.onStatus?.(text2),!kind||kind==="status")return null;return{kind:"system",text:text2}}}return null}var import_react114=__toESM(require_react_production(),1);init_sessions_db();var normalize2=(sid)=>sid.trim().replace(/\.json$/i,"").replace(/^session_(?=\d{8}_)/,"");function useSession(){let gw=useGateway(),resume=import_react114.useCallback(async(sid)=>{let target=normalize2(sid),res=await gw.request("session.resume",{session_id:target}),id=res.session_id;gw.setSession(id),set("lastSessionId",res.resumed??target);let messages=res.messages?.length?transcriptToMessages(res.messages):[];return{id,messages}},[gw]),create=import_react114.useCallback(async()=>{let res=await gw.request("session.create",{});return gw.setSession(res.session_id),res.session_id},[gw]),close=import_react114.useCallback(async(sid)=>{if(!sid)return;try{await gw.request("session.close",{session_id:sid})}catch{}},[gw]),boot2=import_react114.useCallback(async(launch)=>{let fresh=async(note)=>({id:await create(),messages:[],note});if(launch.mode==="resume"){let target=launch.sid??lastReal()?.id;if(!target)return fresh("no prior session to resume \u2014 starting fresh");try{return await resume(target)}catch(e){let msg=e instanceof Error?e.message:String(e);return fresh(`resume ${target} failed: ${msg} \u2014 starting fresh`)}}let last3=get("lastSessionId"),tip2=last3?chainTip(last3):null;if(tip2&&byId(tip2)?.message_count===0)try{return await resume(tip2)}catch{}return fresh()},[create,resume]),interrupt=import_react114.useCallback(async()=>{try{await gw.request("session.interrupt")}catch{}},[gw]),branch2=import_react114.useCallback(async(name)=>{try{return(await gw.request("session.branch",name?{name}:{})).session_id??null}catch{return null}},[gw]),compress=import_react114.useCallback(async()=>{try{return await gw.request("session.compress")}catch{return null}},[gw]),undo=import_react114.useCallback(async()=>{try{await gw.request("session.undo")}catch{}},[gw]);return import_react114.useMemo(()=>({boot:boot2,create,resume,close,interrupt,branch:branch2,compress,undo}),[boot2,create,resume,close,interrupt,branch2,compress,undo])}var import_react116=__toESM(require_react_production(),1);import{tmpdir as tmpdir2}from"os";import{join as join16}from"path";import{rm}from"fs/promises";async function editInEditor(renderer,seed){let cmd=process.env.VISUAL||process.env.EDITOR;if(!cmd)return;let path7=join16(tmpdir2(),`herm-${Date.now()}.md`);await Bun.write(path7,seed),renderer.suspend(),renderer.currentRenderBuffer.clear();let parts2=cmd.split(" ");await Bun.spawn([...parts2,path7],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited;let text2=await Bun.file(path7).text().catch(()=>"");if(rm(path7,{force:!0}).catch(()=>{}),renderer.isDestroyed)return text2.trim()||void 0;return renderer.currentRenderBuffer.clear(),renderer.resume(),renderer.requestRender(),text2.trim()||void 0}function redraw(renderer){resolveRenderLib().clearTerminal(renderer.rendererPtr),renderer.currentRenderBuffer.clear(RGBA.fromValues(0,0,0,0)),renderer.requestRender()}var INTERRUPT_MS=5000,DOUBLE_TAB_MS=400;function useAppKeys(o){let renderer=useRenderer(),keys=useKeys(),lastEsc=import_react116.useRef(0),lastTab=import_react116.useRef(0),regionFor=(t2)=>t2===o.chatTab?"input":"content";import_react116.useEffect(()=>{let found=conflicts(keys.table).filter((c)=>!(c.a==="session.interrupt"&&c.b==="dialog.cancel")).filter((c)=>!(c.a==="app.exit"&&c.b==="input.clear"));if(found.length===0)return;let first=found[0];o.onNotice(`Keybinding conflict: ${print([first.chord])} \u2192 ${first.a} and ${first.b}`+(found.length>1?` (+${found.length-1} more)`:""))},[keys.table]),useKeyboard((key2)=>{let c=o.composer.current;if(keys.match("input.clear",key2)&&c&&!c.isEmpty()){c.set(""),key2.stopPropagation();return}if(keys.match("app.exit",key2))return o.onQuit();if(keys.match("app.suspend",key2)){renderer.suspend(),process.kill(process.pid,"SIGTSTP"),process.once("SIGCONT",()=>renderer.resume());return}if(keys.match("app.redraw",key2)){redraw(renderer),key2.stopPropagation();return}if(keys.match("app.sidebar",key2)){o.onToggleSidebar();return}if(o.dialogOpen())return;if(keys.match("queue.flush",key2)&&o.streaming&&o.queued>0){o.onFlushQueue(),key2.stopPropagation();return}if(o.onPromptKey&&!keys.leader&&!key2.ctrl&&!key2.meta&&key2.eventType!=="release"){if(o.onPromptKey(key2)){key2.stopPropagation();return}}if(keys.match("editor.open",key2)&&!o.streaming){let seed=c?.value()??"";editInEditor(renderer,seed).then((out)=>{if(out===void 0){if(!process.env.VISUAL&&!process.env.EDITOR)o.onNotice("Set $EDITOR or $VISUAL to use the external editor");return}c?.set(out),o.setFocusRegion("input")});return}if(keys.match("tab.prev",key2)){o.setTab((t2)=>{let n=Math.max(0,t2-1);return o.setFocusRegion(regionFor(n)),n});return}if(keys.match("tab.next",key2)){o.setTab((t2)=>{let n=Math.min(o.tabMax,t2+1);return o.setFocusRegion(regionFor(n)),n});return}if(o.subCount>0&&key2.shift&&!key2.ctrl&&!key2.meta&&key2.eventType!=="release"){if(key2.name==="left"){o.cycleSub(-1),key2.stopPropagation();return}if(key2.name==="right"){o.cycleSub(1),key2.stopPropagation();return}}if(keys.leader&&!key2.ctrl&&!key2.meta&&!key2.shift&&key2.eventType!=="release"){let n={"1":0,"2":1,"3":2,"4":3,"5":4,"6":5,"7":6,"8":7,"9":8,"0":9,"-":10}[key2.name];if(n!==void 0&&n<=o.tabMax){o.setTab(()=>{return o.setFocusRegion(regionFor(n)),n}),key2.stopPropagation();return}}if(key2.meta&&!key2.ctrl&&!key2.shift&&key2.eventType!=="release"){let n={"1":0,"2":1,"3":2,"4":3,"5":4,"6":5,"7":6,"8":7,"9":8,"0":9,"-":10}[key2.name];if(n!==void 0&&n<=o.tabMax){o.setTab(()=>{return o.setFocusRegion(regionFor(n)),n}),key2.stopPropagation();return}}if(c?.popOpen()){if(key2.name==="escape")return c.popCancel();if(key2.name==="up"){c.popNav(-1),key2.stopPropagation();return}if(key2.name==="down"){c.popNav(1),key2.stopPropagation();return}if(key2.name==="tab")return c.popAccept();return}if(keys.match("focus.cycle",key2)&&!o.streaming){if(o.tab===o.chatTab){o.setFocusRegion((r)=>r==="input"?"content":"input");return}if(o.focusRegion==="input"){o.setFocusRegion("content");return}let now2=Date.now();if(now2-lastTab.current<DOUBLE_TAB_MS)o.setFocusRegion("input"),lastTab.current=0,key2.stopPropagation();else lastTab.current=now2;return}if(keys.match("session.interrupt",key2)){if(!o.streaming&&o.onEscape?.())return;if(o.streaming){let now2=Date.now();if(now2-lastEsc.current<INTERRUPT_MS){o.onInterrupt(),lastEsc.current=0;return}lastEsc.current=now2,o.onInterruptNotice();return}if(o.tab===o.chatTab&&o.focusRegion==="content")o.setFocusRegion("input");return}if(keys.match("reply.copy",key2))return o.onCopyLast();if(keys.match("clipboard.attach",key2)){o.onAttachClipboard(),key2.stopPropagation();return}if(o.focusRegion==="input"&&!o.streaming){if(key2.name==="up")return void c?.historyUp();if(key2.name==="down")return void c?.historyDown();if(key2.name==="backspace"&&!key2.ctrl&&!key2.meta&&c?.isEmpty()&&o.onDetachLast()){key2.stopPropagation();return}}if(o.tab===o.chatTab&&o.focusRegion==="content"&&!o.streaming&&!key2.ctrl&&!key2.meta&&key2.eventType!=="release"){if(key2.name.length===1&&key2.name!==" "){let ch=key2.shift&&/[a-z]/.test(key2.name)?key2.name.toUpperCase():key2.name;o.setFocusRegion("input"),c?.insert(ch),key2.stopPropagation()}}})}import{writeSync}from"fs";var done=!1;function quit(renderer,sid,title,gw){if(done)process.exit(0);done=!0;try{gw?.kill()}catch{}if(renderer.destroy(),process.stdout.isTTY&&sid){let t2=title?` \u2014 ${title.slice(0,60)}`:"";writeSync(1,`
|
|
4158
4158
|
continue herm --resume ${sid}${t2}
|
|
4159
4159
|
|
|
4160
|
-
`)}process.exit(0)}init_sessions_db();init_hermes_analytics();function rehome(newHome){process.env.HERMES_HOME=newHome,setHome2(newHome),setHome(newHome),cache2.clear(),resetKanban(),reload(),home2.reset()}var import_react117=__toESM(require_react_production(),1);var Countdown=(p)=>{let theme=useTheme().theme,[n,setN]=import_react117.useState(p.seconds);import_react117.useEffect(()=>{if(n<=0){p.onFire();return}let t2=setTimeout(()=>setN((v2)=>v2-1),1000);return()=>clearTimeout(t2)},[n,p.onFire]),useKeyboard(()=>p.onCancel());let bar3="\u2588".repeat(n)+"\u2591".repeat(Math.max(0,p.seconds-n));return $jsxs("box",{flexDirection:"column",width:58,children:[$jsx("box",{height:1,children:$jsx("text",{fg:theme.warning,children:$jsx("strong",{children:p.title})})}),$jsx("box",{height:1}),$jsx("box",{minHeight:1,children:$jsx("text",{wrapMode:"word",children:p.body})}),$jsx("box",{height:1}),$jsx("box",{height:1,children:$jsxs("text",{fg:theme.warning,children:[bar3," ",n,"s"]})}),$jsx("box",{height:1,children:$jsx("text",{fg:theme.textMuted,children:p.action})}),$jsx("box",{height:1}),$jsx("box",{height:1,children:$jsx("text",{fg:theme.textMuted,children:"press any key to cancel"})})]})};function openCountdown(dialog,opts){return new Promise((resolve4)=>{dialog.replace($jsx(Countdown,{...opts,onFire:()=>{dialog.clear(),resolve4(!0)},onCancel:()=>{dialog.clear(),resolve4(!1)}}),()=>resolve4(!1))})}var SECONDS=10,SUSPEND=process.platform==="darwin"?"pmset sleepnow":"systemctl suspend",run=(cmd)=>Bun.spawn(["sh","-c",cmd],{stdout:"ignore",stderr:"ignore"}),fired=new Map;function makeGoalHook(dialog,toast){let act=(goal)=>{let pref=(get("onGoalDone")??"toast").trim(),head=goal.length>60?goal.slice(0,57)+"\u2026":goal;if(toast.show({variant:"success",title:"Goal complete",message:head,duration:8000}),pref==="toast")return;let cmd=pref==="suspend"?SUSPEND:pref;openCountdown(dialog,{title:"Goal complete \u2014 "+(pref==="suspend"?"suspending":"running hook"),body:head,action:`\u2192 ${cmd}`,seconds:SECONDS}).then((ok)=>{if(ok)run(cmd)})};return{check:(sid)=>{if(!sid)return;io.goalState(sid).then((s)=>{if(!s||s.status!=="done")return;if(fired.get(sid)===s.goal)return;fired.set(sid,s.goal),act(s.goal)}).catch(()=>{})}}}var App=(props)=>$jsx(ThemeProvider,{initial:props.initialTheme,children:$jsx(GatewayProvider,{client:props.gateway,children:$jsx(ToastProvider,{children:$jsx(KeysProvider,{children:$jsx(DialogProvider,{children:$jsx(CommandProvider,{children:$jsx(AppInner,{launch:props.launch??{mode:"new"}})})})})})})}),AppInner=({launch:launch0})=>{let gw=useGateway(),gwRestart=useGatewayRestart(),dialog=useDialog(),themeCtx=useTheme(),cmd=useCommand(),toast=useToast(),renderer=useRenderer(),session=useSession(),dims=useTerminalDimensions(),goalHook=import_react120.useMemo(()=>makeGoalHook(dialog,toast),[dialog,toast]),[turn,dispatch]=import_react120.useReducer(turnReducer,initialTurn),[ready,setReady]=import_react120.useState(!1),[sid,setSid]=import_react120.useState(""),sidRef=import_react120.useRef(sid);sidRef.current=sid;let[tab,setTab]=import_react120.useState(CHAT_TAB),[subTabs,setSubTabs]=import_react120.useState(()=>({[SESSIONS_TAB]:0,[AUTOMATION_TAB]:0,[CONFIG_TAB]:0})),setSub=import_react120.useCallback((tabIdx,sub2)=>setSubTabs((prev)=>prev[tabIdx]===sub2?prev:{...prev,[tabIdx]:sub2}),[]),[hideSidebar,setHideSidebar]=import_react120.useState(!1),[usage,setUsage]=import_react120.useState(void 0),[info2,setInfo]=import_react120.useState(null),[title,setTitle]=import_react120.useState(""),[focusRegion,setFocusRegion]=import_react120.useState("input"),goToTab=import_react120.useCallback((t2)=>{setTab(t2),setFocusRegion(t2===CHAT_TAB?"input":"content")},[]),goTo=import_react120.useCallback((t2,sub2)=>{setTab(t2),setSubTabs((prev)=>prev[t2]===sub2?prev:{...prev,[t2]:sub2}),setFocusRegion(t2===CHAT_TAB?"input":"content")},[]),[status,setStatus]=import_react120.useState(""),[eikon,setEikon]=import_react120.useState(void 0),[queue,setQueue]=import_react120.useState([]),[busy,setBusy]=import_react120.useState("queue"),launchRef=import_react120.useRef(launch0),launch=launchRef.current,[splash,setSplash]=import_react120.useState(launch.splash!==!1),[switching,setSwitching]=import_react120.useState(!1),summoned=import_react120.useRef(!1),[composing,setComposing]=import_react120.useState(!1),splashLast=import_react120.useMemo(()=>launch.mode==="new"?lastReal():void 0,[launch.mode]),news=import_react120.useMemo(()=>readChangelog()?.headline,[]),[attachments,setAttachments]=import_react120.useState([]),[cloudH,setCloudH]=import_react120.useState(CLOUD_MIN),[pick,setPick]=import_react120.useState(void 0),[skin,setSkin]=import_react120.useState(()=>deriveSkin(void 0)),inflight=import_react120.useRef(!1),interrupted=import_react120.useRef(!1),sessionStart=import_react120.useRef(Date.now()),composer2=import_react120.useRef(null),promptRef=import_react120.useRef(null),{cmds}=useSlashCommands(),cmdsRef=import_react120.useRef(cmds);cmdsRef.current=cmds;let[errorPulse,setErrorPulse]=import_react120.useState(!1),agentState=errorPulse?"error":turn.toolActive?"working":turn.streaming&&turn.hasContent?"speaking":turn.streaming?"thinking":composing?"listening":"idle",onAvatarHold=import_react120.useCallback((s)=>{if(s==="error")setErrorPulse(!1)},[]),prompt=pending(turn.messages),cloudAuto=turn.streaming&&!turn.hasContent&&!prompt,[force,setForce]=import_react120.useState(void 0),cloud=!prompt&&(force??cloudAuto),prevStream=import_react120.useRef(turn.streaming);import_react120.useEffect(()=>{if(!prevStream.current&&turn.streaming)setForce(void 0),setPick(void 0);prevStream.current=turn.streaming},[turn.streaming]);let onPick=import_react120.useCallback((m2)=>{setPick((p)=>{if(m2&&p&&m2.id===p.id){setForce(!1);return}return setForce(!!m2),m2})},[]),onAvatar=import_react120.useCallback(()=>{let next2=!cloud;if(!next2)setPick(void 0);setForce(next2)},[cloud]),closeCloud=import_react120.useCallback(()=>{setForce(!1),setPick(void 0)},[]),intr=import_react120.useRef(()=>{}),onEnqueue=import_react120.useCallback((t2)=>{if(busy==="steer"){gw.request("session.steer",{text:t2}).then((r)=>{if(r.status==="queued")return toast.show({variant:"success",message:"steered \u2014 lands on next tool result"});setQueue((q4)=>[...q4,t2]),toast.show({variant:"info",message:"steer rejected \u2014 queued for next turn"})}).catch(()=>setQueue((q4)=>[...q4,t2]));return}if(busy==="interrupt")return intr.current(),setQueue((q4)=>[t2,...q4]);setQueue((q4)=>[...q4,t2])},[busy,gw,toast]),onAttach=import_react120.useCallback((r)=>setAttachments((a)=>[...a,r]),[]),reset=import_react120.useCallback(()=>{interrupted.current=!1,dispatch({kind:"reset"}),setUsage(void 0),setReady(!1),setStatus(""),setTitle(""),setAttachments([])},[]),newSession=import_react120.useCallback(async()=>{let prev=sidRef.current;if(reset(),summoned.current=!0,setSplash(!0),prev)session.close(prev);try{setSid(await session.create()),sessionStart.current=Date.now()}catch{}},[reset,session]),switchSession=import_react120.useCallback(async(target)=>{let prev=sidRef.current;reset(),summoned.current=!0,setSplash(!0),setSwitching(!0),goToTab(CHAT_TAB);try{let res=await session.resume(target);if(setSid(res.id),sessionStart.current=Date.now(),res.messages.length)dispatch({kind:"load",messages:res.messages});if(prev&&prev!==res.id)session.close(prev);setSplash(!1),summoned.current=!1}catch(err){dispatch({kind:"system",text:`Failed to resume: ${err instanceof Error?err.message:String(err)}`}),setSplash(!1),summoned.current=!1}finally{setSwitching(!1)}},[reset,session,goToTab]),switchProfile=import_react120.useCallback((newHome,name)=>{rehome(newHome),reset(),gw.setSession(""),setSid(""),setInfo(null),setSkin(deriveSkin(void 0)),summoned.current=!0,setSplash(!0),launchRef.current={mode:"new",splash:!0},toast.show({variant:"info",message:`Switching to '${name}'\u2026`}),goToTab(CHAT_TAB),gwRestart()},[reset,goToTab,gwRestart,toast,gw]),runCompress=import_react120.useCallback(async()=>{toast.show({variant:"info",message:"Compressing session\u2026"});let r=await session.compress();if(!r)return;if(r.info)setInfo(r.info);if(r.usage)setUsage(r.usage);if(Array.isArray(r.messages))dispatch({kind:"load",messages:transcriptToMessages(r.messages)});if(!r.summary)return;let s=r.summary;if(s.noop){toast.show({variant:"info",message:s.headline??`No changes \xB7 ~${r.before_tokens??0} tokens`});return}let lines2=[s.headline,s.token_line,s.note].filter(Boolean).join(`
|
|
4161
|
-
`);if(lines2)dispatch({kind:"system",text:lines2});toast.show({variant:"success",message:s.headline??`Compressed ${r.before_messages??0}\u2192${r.after_messages??0} messages`})},[session,toast,dispatch]),loadEikon=import_react120.useCallback((path7)=>{Bun.file(path7).text().then((t2)=>setEikon(parseEikon(t2))).catch(()=>{})},[]),eikonPath=usePref("eikonPath");import_react120.useEffect(()=>{let p=eikonPath||bundledEikonPath(skin.skin?.name);if(p)loadEikon(p);else setEikon(void 0)},[eikonPath,skin.skin?.name,loadEikon]);let pickEikon=import_react120.useCallback(()=>{openEikonPicker(dialog,(path7)=>set("eikonPath",path7))},[dialog]),applyTitle=import_react120.useCallback((t2)=>{gw.request("session.title",{title:t2}).then((r)=>{setTitle(r.title),dispatch({kind:"system",text:`Title: ${r.title}`})}).catch((e)=>toast.show({variant:"error",message:e.message}))},[gw,toast]),editTitle=import_react120.useCallback(()=>{openTextPrompt(dialog,{title:"Session Title",initial:title}).then((v2)=>{if(v2)applyTitle(v2)})},[dialog,title,applyTitle]),turnsFrom=(m2)=>{let
|
|
4162
|
-
${SKINS.join(" ")}`});return}if(!SKINS.includes(name)){toast.show({variant:"error",message:`unknown skin: ${name}`});return}gw.request("config.set",{key:"skin",value:name}).then((r)=>{if(r.warning)toast.show({variant:"warning",message:r.warning});if(themeCtx.has(name))themeCtx.set(name);set("eikonPath",void 0),dispatch({kind:"system",text:`skin \u2192 ${name}`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return}case"resume":if(arg){switchSession(arg);return}goTo(TAB_SLASH.sessions.tab,TAB_SLASH.sessions.sub);return;case"branch":session.branch(arg||void 0).then((id)=>id?void switchSession(id):toast.show({variant:"error",message:"branch failed"}));return;case"compress":runCompress();return;case"undo":destructive(arg,{title:"Undo last turn?",body:"Pops the last user + assistant pair from the transcript. Cannot be undone.",yes:"undo"},()=>{session.undo().then(()=>gw.request("session.history").then((r)=>dispatch({kind:"load",messages:transcriptToMessages(r.messages??[])})).catch(()=>{}))});return;case"retry":{let last3=[...
|
|
4163
|
-
`):text2;dispatch({kind:"user",text:withMedia}),setAttachments([]),gw.request("prompt.submit",{text:text2}).catch(()=>{inflight.current=!1}),setTab(CHAT_TAB)},[gw,slash,attachments]);sendRef.current=send;let onSend=import_react120.useCallback((raw)=>{return setSplash(!1),send(raw)},[send]),onEmptyEnter=import_react120.useCallback(()=>{if(!splash||summoned.current||!splashLast||composing)return!1;return setSplash(!1),switchSession(splashLast.id),!0},[splash,splashLast,composing,switchSession]);import_react120.useEffect(()=>{if(turn.streaming)inflight.current=!1},[turn.streaming]),import_react120.useEffect(()=>{if(turn.streaming||inflight.current||!ready||queue.length===0)return;let[head,...rest]=queue;inflight.current=!0,setQueue(rest),send(head)},[turn.streaming,ready,queue,send]);let dequeue=import_react120.useCallback((i)=>{let item=
|
|
4160
|
+
`)}process.exit(0)}init_sessions_db();init_hermes_analytics();function rehome(newHome){process.env.HERMES_HOME=newHome,setHome2(newHome),setHome(newHome),cache2.clear(),resetKanban(),reload(),home2.reset()}var import_react117=__toESM(require_react_production(),1);var Countdown=(p)=>{let theme=useTheme().theme,[n,setN]=import_react117.useState(p.seconds);import_react117.useEffect(()=>{if(n<=0){p.onFire();return}let t2=setTimeout(()=>setN((v2)=>v2-1),1000);return()=>clearTimeout(t2)},[n,p.onFire]),useKeyboard(()=>p.onCancel());let bar3="\u2588".repeat(n)+"\u2591".repeat(Math.max(0,p.seconds-n));return $jsxs("box",{flexDirection:"column",width:58,children:[$jsx("box",{height:1,children:$jsx("text",{fg:theme.warning,children:$jsx("strong",{children:p.title})})}),$jsx("box",{height:1}),$jsx("box",{minHeight:1,children:$jsx("text",{wrapMode:"word",children:p.body})}),$jsx("box",{height:1}),$jsx("box",{height:1,children:$jsxs("text",{fg:theme.warning,children:[bar3," ",n,"s"]})}),$jsx("box",{height:1,children:$jsx("text",{fg:theme.textMuted,children:p.action})}),$jsx("box",{height:1}),$jsx("box",{height:1,children:$jsx("text",{fg:theme.textMuted,children:"press any key to cancel"})})]})};function openCountdown(dialog,opts){return new Promise((resolve4)=>{dialog.replace($jsx(Countdown,{...opts,onFire:()=>{dialog.clear(),resolve4(!0)},onCancel:()=>{dialog.clear(),resolve4(!1)}}),()=>resolve4(!1))})}var SECONDS=10,SUSPEND=process.platform==="darwin"?"pmset sleepnow":"systemctl suspend",run=(cmd)=>Bun.spawn(["sh","-c",cmd],{stdout:"ignore",stderr:"ignore"}),fired=new Map;function makeGoalHook(dialog,toast){let act=(goal)=>{let pref=(get("onGoalDone")??"toast").trim(),head=goal.length>60?goal.slice(0,57)+"\u2026":goal;if(toast.show({variant:"success",title:"Goal complete",message:head,duration:8000}),pref==="toast")return;let cmd=pref==="suspend"?SUSPEND:pref;openCountdown(dialog,{title:"Goal complete \u2014 "+(pref==="suspend"?"suspending":"running hook"),body:head,action:`\u2192 ${cmd}`,seconds:SECONDS}).then((ok)=>{if(ok)run(cmd)})};return{check:(sid)=>{if(!sid)return;io.goalState(sid).then((s)=>{if(!s||s.status!=="done")return;if(fired.get(sid)===s.goal)return;fired.set(sid,s.goal),act(s.goal)}).catch(()=>{})}}}var App=(props)=>$jsx(ThemeProvider,{initial:props.initialTheme,children:$jsx(GatewayProvider,{client:props.gateway,children:$jsx(ToastProvider,{children:$jsx(KeysProvider,{children:$jsx(DialogProvider,{children:$jsx(CommandProvider,{children:$jsx(AppInner,{launch:props.launch??{mode:"new"}})})})})})})}),AppInner=({launch:launch0})=>{let gw=useGateway(),gwRestart=useGatewayRestart(),dialog=useDialog(),themeCtx=useTheme(),cmd=useCommand(),toast=useToast(),renderer=useRenderer(),session=useSession(),dims=useTerminalDimensions(),goalHook=import_react120.useMemo(()=>makeGoalHook(dialog,toast),[dialog,toast]),[turn,dispatch]=import_react120.useReducer(turnReducer,initialTurn),[ready,setReady]=import_react120.useState(!1),[sid,setSid]=import_react120.useState(""),sidRef=import_react120.useRef(sid);sidRef.current=sid;let[tab,setTab]=import_react120.useState(CHAT_TAB),[subTabs,setSubTabs]=import_react120.useState(()=>({[SESSIONS_TAB]:0,[AUTOMATION_TAB]:0,[CONFIG_TAB]:0})),setSub=import_react120.useCallback((tabIdx,sub2)=>setSubTabs((prev)=>prev[tabIdx]===sub2?prev:{...prev,[tabIdx]:sub2}),[]),sessSub=import_react120.useCallback((i)=>setSub(SESSIONS_TAB,i),[setSub]),autoSub=import_react120.useCallback((i)=>setSub(AUTOMATION_TAB,i),[setSub]),cfgSub=import_react120.useCallback((i)=>setSub(CONFIG_TAB,i),[setSub]),[hideSidebar,setHideSidebar]=import_react120.useState(!1),[usage,setUsage]=import_react120.useState(void 0),[info2,setInfo]=import_react120.useState(null),[title,setTitle]=import_react120.useState(""),[focusRegion,setFocusRegion]=import_react120.useState("input"),goToTab=import_react120.useCallback((t2)=>{setTab(t2),setFocusRegion(t2===CHAT_TAB?"input":"content")},[]),goTo=import_react120.useCallback((t2,sub2)=>{setTab(t2),setSubTabs((prev)=>prev[t2]===sub2?prev:{...prev,[t2]:sub2}),setFocusRegion(t2===CHAT_TAB?"input":"content")},[]),[status,setStatus]=import_react120.useState(""),[eikon,setEikon]=import_react120.useState(void 0),[queue,setQueue]=import_react120.useState([]),[busy,setBusy]=import_react120.useState("queue"),turnRef=import_react120.useRef(turn);turnRef.current=turn;let queueRef=import_react120.useRef(queue);queueRef.current=queue;let launchRef=import_react120.useRef(launch0),launch=launchRef.current,[splash,setSplash]=import_react120.useState(launch.splash!==!1),[switching,setSwitching]=import_react120.useState(!1),summoned=import_react120.useRef(!1),[composing,setComposing]=import_react120.useState(!1),splashLast=import_react120.useMemo(()=>launch.mode==="new"?lastReal():void 0,[launch.mode]),splashInfo=import_react120.useMemo(()=>info2?{agentVersion:info2.version,behind:info2.update_behind,model:info2.model}:void 0,[info2?.version,info2?.update_behind,info2?.model]),splashLastProp=import_react120.useMemo(()=>splashLast?{id:splashLast.id,title:splashLast.title}:void 0,[splashLast]),news=import_react120.useMemo(()=>readChangelog()?.headline,[]),[attachments,setAttachments]=import_react120.useState([]),[cloudH,setCloudH]=import_react120.useState(CLOUD_MIN),[pick,setPick]=import_react120.useState(void 0),[skin,setSkin]=import_react120.useState(()=>deriveSkin(void 0)),inflight=import_react120.useRef(!1),interrupted=import_react120.useRef(!1),sessionStart=import_react120.useRef(Date.now()),composer2=import_react120.useRef(null),promptRef=import_react120.useRef(null),{cmds}=useSlashCommands(),cmdsRef=import_react120.useRef(cmds);cmdsRef.current=cmds;let[errorPulse,setErrorPulse]=import_react120.useState(!1),agentState=errorPulse?"error":turn.toolActive?"working":turn.streaming&&turn.hasContent?"speaking":turn.streaming?"thinking":composing?"listening":"idle",onAvatarHold=import_react120.useCallback((s)=>{if(s==="error")setErrorPulse(!1)},[]),prompt=import_react120.useMemo(()=>pending(turn.messages),[turn.messages]),cloudAuto=turn.streaming&&!turn.hasContent&&!prompt,[force,setForce]=import_react120.useState(void 0),cloud=!prompt&&(force??cloudAuto),prevStream=import_react120.useRef(turn.streaming);import_react120.useEffect(()=>{if(!prevStream.current&&turn.streaming)setForce(void 0),setPick(void 0);prevStream.current=turn.streaming},[turn.streaming]);let onPick=import_react120.useCallback((m2)=>{setPick((p)=>{if(m2&&p&&m2.id===p.id){setForce(!1);return}return setForce(!!m2),m2})},[]),onAvatar=import_react120.useCallback(()=>{let next2=!cloud;if(!next2)setPick(void 0);setForce(next2)},[cloud]),closeCloud=import_react120.useCallback(()=>{setForce(!1),setPick(void 0)},[]),intr=import_react120.useRef(()=>{}),onEnqueue=import_react120.useCallback((t2)=>{if(busy==="steer"){gw.request("session.steer",{text:t2}).then((r)=>{if(r.status==="queued")return toast.show({variant:"success",message:"steered \u2014 lands on next tool result"});setQueue((q4)=>[...q4,t2]),toast.show({variant:"info",message:"steer rejected \u2014 queued for next turn"})}).catch(()=>setQueue((q4)=>[...q4,t2]));return}if(busy==="interrupt")return intr.current(),setQueue((q4)=>[t2,...q4]);setQueue((q4)=>[...q4,t2])},[busy,gw,toast]),onAttach=import_react120.useCallback((r)=>setAttachments((a)=>[...a,r]),[]),reset=import_react120.useCallback(()=>{interrupted.current=!1,dispatch({kind:"reset"}),setUsage(void 0),setReady(!1),setStatus(""),setTitle(""),setAttachments([])},[]),newSession=import_react120.useCallback(async()=>{let prev=sidRef.current;if(reset(),summoned.current=!0,setSplash(!0),prev)session.close(prev);try{setSid(await session.create()),sessionStart.current=Date.now()}catch{}},[reset,session]),switchSession=import_react120.useCallback(async(target)=>{let prev=sidRef.current;reset(),summoned.current=!0,setSplash(!0),setSwitching(!0),goToTab(CHAT_TAB);try{let res=await session.resume(target);if(setSid(res.id),sessionStart.current=Date.now(),res.messages.length)dispatch({kind:"load",messages:res.messages});if(prev&&prev!==res.id)session.close(prev);setSplash(!1),summoned.current=!1}catch(err){dispatch({kind:"system",text:`Failed to resume: ${err instanceof Error?err.message:String(err)}`}),setSplash(!1),summoned.current=!1}finally{setSwitching(!1)}},[reset,session,goToTab]),switchProfile=import_react120.useCallback((newHome,name)=>{rehome(newHome),reset(),gw.setSession(""),setSid(""),setInfo(null),setSkin(deriveSkin(void 0)),summoned.current=!0,setSplash(!0),launchRef.current={mode:"new",splash:!0},toast.show({variant:"info",message:`Switching to '${name}'\u2026`}),goToTab(CHAT_TAB),gwRestart()},[reset,goToTab,gwRestart,toast,gw]),runCompress=import_react120.useCallback(async()=>{toast.show({variant:"info",message:"Compressing session\u2026"});let r=await session.compress();if(!r)return;if(r.info)setInfo(r.info);if(r.usage)setUsage(r.usage);if(Array.isArray(r.messages))dispatch({kind:"load",messages:transcriptToMessages(r.messages)});if(!r.summary)return;let s=r.summary;if(s.noop){toast.show({variant:"info",message:s.headline??`No changes \xB7 ~${r.before_tokens??0} tokens`});return}let lines2=[s.headline,s.token_line,s.note].filter(Boolean).join(`
|
|
4161
|
+
`);if(lines2)dispatch({kind:"system",text:lines2});toast.show({variant:"success",message:s.headline??`Compressed ${r.before_messages??0}\u2192${r.after_messages??0} messages`})},[session,toast,dispatch]),loadEikon=import_react120.useCallback((path7)=>{Bun.file(path7).text().then((t2)=>setEikon(parseEikon(t2))).catch(()=>{})},[]),eikonPath=usePref("eikonPath");import_react120.useEffect(()=>{let p=eikonPath||bundledEikonPath(skin.skin?.name);if(p)loadEikon(p);else setEikon(void 0)},[eikonPath,skin.skin?.name,loadEikon]);let pickEikon=import_react120.useCallback(()=>{openEikonPicker(dialog,(path7)=>set("eikonPath",path7))},[dialog]),applyTitle=import_react120.useCallback((t2)=>{gw.request("session.title",{title:t2}).then((r)=>{setTitle(r.title),dispatch({kind:"system",text:`Title: ${r.title}`})}).catch((e)=>toast.show({variant:"error",message:e.message}))},[gw,toast]),editTitle=import_react120.useCallback(()=>{openTextPrompt(dialog,{title:"Session Title",initial:title}).then((v2)=>{if(v2)applyTitle(v2)})},[dialog,title,applyTitle]),turnsFrom=(m2)=>{let msgs=turnRef.current.messages,at=msgs.findIndex((x2)=>x2.id===m2.id);return at<0?0:msgs.slice(at).filter((x2)=>x2.role==="user").length},rewind=import_react120.useCallback(async(m2)=>{if(turnRef.current.streaming)return;let n=turnsFrom(m2);if(n===0)return;let text2=m2.parts.filter((p)=>p.type==="text").map((p)=>p.content).join("");for(let i=0;i<n;i++)await gw.request("session.undo").catch(()=>{});let r=await gw.request("session.history").catch(()=>null),msgs=turnRef.current.messages,at=msgs.findIndex((x2)=>x2.id===m2.id);dispatch({kind:"load",messages:r?transcriptToMessages(r.messages??[]):msgs.slice(0,at)}),composer2.current?.set(text2),setFocusRegion("input")},[gw]),fork=import_react120.useCallback(async(m2)=>{if(turnRef.current.streaming)return;let n=turnsFrom(m2),text2=m2.parts.filter((p)=>p.type==="text").map((p)=>p.content).join(""),res=await gw.request("session.branch",{}).catch((e)=>{return toast.show({variant:"error",message:`branch failed: ${e.message}`}),null});if(!res?.session_id)return;for(let i=0;i<n;i++)await gw.request("session.undo",{session_id:res.session_id}).catch(()=>{});await switchSession(res.session_id),composer2.current?.set(text2),setFocusRegion("input"),toast.show({variant:"success",message:`forked \u2192 ${res.title??res.session_id}`})},[gw,toast,switchSession]),msgMenu=import_react120.useCallback((m2)=>{if(turnRef.current.streaming)return;openMessage(dialog,m2,{rewind,fork})},[dialog,rewind,fork]),attachClipboard=import_react120.useCallback(()=>{gw.request("clipboard.paste").then((r)=>r.attached?setAttachments((a)=>[...a,r]):toast.show({variant:"info",message:r.message??"No image in clipboard"})).catch((e)=>toast.show({variant:"error",message:e.message}))},[gw,toast]),cfg=useHome("config"),destructive=import_react120.useCallback((arg,opts,action)=>{let a=arg.trim().toLowerCase(),skip=a==="now"||a==="once"||a==="approve"||a==="yes"||a==="always",bypass=!(cfg?.approvals?.destructive_slash_confirm??!0)||process.env.HERMES_TUI_NO_CONFIRM==="1",persist2=a==="always",fire=()=>{if(persist2)Promise.resolve().then(() => (init_lane(),exports_lane)).then(({writeConfig:writeConfig2})=>writeConfig2(gw,[{key:"approvals.destructive_slash_confirm",to:!1}]).then((r)=>{if(r.failed.length){toast.show({variant:"warning",message:`couldn't persist: ${r.failed[0].err}`});return}home2.invalidate("config"),toast.show({variant:"success",message:`${opts.yes} \xB7 future runs silent`})}).catch((e)=>toast.show({variant:"error",message:e.message})));action()};if(skip||bypass)return fire();openConfirm(dialog,{title:opts.title,body:opts.body,yes:opts.yes,danger:!0}).then((ok)=>{if(ok)fire()})},[cfg,dialog,gw,toast]),sendRef=import_react120.useRef(()=>{}),slash=import_react120.useCallback((c,arg="")=>{if(c.target==="local")switch(c.name){case"clear":destructive(arg,{title:"Clear session?",body:"Discards the in-memory transcript. Your session on disk is unchanged; reload to restore.",yes:"clear"},()=>dispatch({kind:"reset"}));return;case"new":destructive(arg,{title:"Start a new session?",body:"Ends the current session and starts a fresh one. The existing session remains saved and resumable.",yes:"new session"},()=>{newSession()});return;case"theme":openThemePicker(dialog,themeCtx);return;case"help":dialog.replace($jsx(HelpDialog,{}));return;case"keys":openKeys(dialog);return;case"logs":openLogs(dialog);return;case"eikon":pickEikon();return;case"title":arg?applyTitle(arg):editTitle();return;case"rollback":openRollback(dialog,gw,toast);return;case"history":openHistory(dialog,gw);return;case"status":openStatus(dialog,info2,sid);return;case"usage":openUsage(dialog,gw);return;case"profile":openProfile(dialog);return;case"chafa":if(!arg.trim()){toast.show({variant:"info",message:"usage: /chafa <path>"});return}openChafa(dialog,arg.trim());return;case"splash":summoned.current=!0,setSplash(!0);return;case"skin":{let name=arg.trim();if(!name){dispatch({kind:"system",text:`skin: ${skin.skin?.name??"\u2014"}
|
|
4162
|
+
${SKINS.join(" ")}`});return}if(!SKINS.includes(name)){toast.show({variant:"error",message:`unknown skin: ${name}`});return}gw.request("config.set",{key:"skin",value:name}).then((r)=>{if(r.warning)toast.show({variant:"warning",message:r.warning});if(themeCtx.has(name))themeCtx.set(name);set("eikonPath",void 0),dispatch({kind:"system",text:`skin \u2192 ${name}`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return}case"resume":if(arg){switchSession(arg);return}goTo(TAB_SLASH.sessions.tab,TAB_SLASH.sessions.sub);return;case"branch":session.branch(arg||void 0).then((id)=>id?void switchSession(id):toast.show({variant:"error",message:"branch failed"}));return;case"compress":runCompress();return;case"undo":destructive(arg,{title:"Undo last turn?",body:"Pops the last user + assistant pair from the transcript. Cannot be undone.",yes:"undo"},()=>{session.undo().then(()=>gw.request("session.history").then((r)=>dispatch({kind:"load",messages:transcriptToMessages(r.messages??[])})).catch(()=>{}))});return;case"retry":{let last3=[...turnRef.current.messages].reverse().find((m2)=>m2.role==="user");if(!last3){toast.show({variant:"info",message:"nothing to retry"});return}rewind(last3).then(()=>sendRef.current(text(last3)));return}case"model":if(!arg){openModelPicker(dialog,gw);return}gw.request("config.set",{key:"model",value:arg}).then((r)=>{if(r.warning)toast.show({variant:"warning",message:r.warning});dispatch({kind:"system",text:`model \u2192 ${r.value??arg}`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"quit":quit(renderer,sid,title,gw);return;case"queue":if(!arg){dispatch({kind:"system",text:`${queueRef.current.length} queued`});return}setQueue((q4)=>[...q4,arg]);return;case"copy":{let all=turnRef.current.messages.filter((m3)=>m3.role==="assistant"),n=arg?Math.min(Math.max(1,parseInt(arg,10)||0),all.length):all.length,m2=all[n-1];if(!m2){toast.show({variant:"info",message:"nothing to copy"});return}let body2=text(m2);copy(body2),toast.show({variant:"success",message:`copied ${body2.length} chars`});return}case"paste":attachClipboard();return;case"image":if(!arg){toast.show({variant:"info",message:"usage: /image <path>"});return}gw.request("image.attach",{path:arg}).then((r)=>r.attached?setAttachments((a)=>[...a,r]):toast.show({variant:"warning",message:r.message??"attach failed"})).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"background":if(!arg){toast.show({variant:"info",message:"usage: /background <prompt>"});return}gw.request("prompt.background",{text:arg}).then((r)=>toast.show(r.task_id?{variant:"success",message:`background ${r.task_id} started`}:{variant:"error",message:"background start failed"})).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"voice":gw.request("voice.toggle",{action:(arg||"status").toLowerCase()}).then((r)=>dispatch({kind:"system",text:`voice ${r.enabled?"on":"off"}${r.tts?" \xB7 tts on":""}`})).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"mouse":{let want=arg==="on"?!0:arg==="off"?!1:!renderer.useMouse;renderer.useMouse=want,set("mouse",want),toast.show({variant:"info",message:`mouse ${want?"on":"off"}`});return}case"redraw":redraw(renderer);return;case"compact":case"setup":dispatch({kind:"system",text:`/${c.name} is an Ink-TUI command and has no effect in herm`});return;case"steer":{let fire=(text2)=>gw.request("session.steer",{text:text2}).then((r)=>toast.show(r.status==="queued"?{variant:"success",message:"Queued \u2014 lands on next tool result"}:{variant:"info",message:"No turn running; send as a normal message"})).catch((e)=>toast.show({variant:"error",message:e.message}));if(arg){fire(arg);return}openTextPrompt(dialog,{title:"Steer",label:"Note to inject on next tool result"}).then((text2)=>{if(text2)fire(text2)});return}case"reload-mcp":{let a=arg.trim().toLowerCase(),skip=a==="now"||a==="once"||a==="approve"||a==="yes"||a==="always",fire=(always)=>gw.request("reload.mcp",{confirm:!0,always}).then((r)=>r.status==="confirm_required"?toast.show({variant:"warning",message:r.message??"reload requires confirmation"}):toast.show({variant:"success",message:always?"MCP servers reloaded \xB7 future /reload-mcp runs silently":"MCP servers reloaded"})).catch((e)=>toast.show({variant:"error",message:e.message}));if(skip){fire(a==="always");return}openConfirm(dialog,{title:"Reload MCP servers?",body:"Rebuilds the MCP tool set. Invalidates the prompt cache, so the next message re-sends full input tokens.",yes:"reload",danger:!0}).then((ok)=>{if(ok)fire(!1)});return}case"reload":gw.request("reload.env",{}).then((r)=>{let n=Number(r.updated??0);toast.show({variant:"success",message:`Reloaded .env (${n} var${n===1?"":"s"} updated) \xB7 /new to apply`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"reload-skills":gw.request("skills.reload",{}).then((r)=>{dispatch({kind:"system",text:r.output});let n=Number(r.result?.total??0);toast.show({variant:"success",message:`Skills reloaded (${n} available)`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"save":gw.request("session.save").then((r)=>toast.show({variant:"success",message:`Saved \u2192 ${r.file}`})).catch((e)=>toast.show({variant:"error",message:e.message}));return}if(c.target!=="gateway"||!ready)return;let jump=TAB_SLASH[c.name];if(jump!==void 0&&!arg){goTo(jump.tab,jump.sub);return}let full=`/${c.name}${arg?" "+arg:""}`;if(turnRef.current.streaming){setQueue((q4)=>[...q4,full]);return}dispatch({kind:"user",text:full}),gw.request("slash.exec",{command:full}).then((res)=>{if(res?.warning)dispatch({kind:"system",text:`\u26A0 ${res.warning}`});if(res?.output)dispatch({kind:"system",text:res.output})}).catch(()=>{gw.request("command.dispatch",{name:c.name,arg}).then((d2)=>{if(d2.notice)dispatch({kind:"system",text:d2.notice});if(d2.type==="exec"||d2.type==="plugin")return dispatch({kind:"system",text:d2.output||"(no output)"});if(d2.type==="alias"&&d2.target)return void sendRef.current(`/${d2.target}${arg?" "+arg:""}`);if((d2.type==="skill"||d2.type==="send")&&d2.message){if(d2.type==="skill")dispatch({kind:"system",text:`\u26A1 loading skill: ${d2.name??c.name}`});return void sendRef.current(d2.message)}dispatch({kind:"system",text:`/${c.name}: unknown`})}).catch((e)=>dispatch({kind:"system",text:`error: ${e.message}`}))})},[ready,dialog,themeCtx,newSession,gw,pickEikon,editTitle,applyTitle,toast,info2,sid,title,switchSession,session,runCompress,rewind,renderer,attachClipboard,goTo,skin,destructive]),send=import_react120.useCallback(async(raw)=>{let m2=raw.match(/^\/(\S+)(?:\s+([\s\S]*))?$/);if(m2){let[,name,arg=""]=m2,r=resolve7(cmdsRef.current,name);if("hit"in r)return slash(r.hit,arg.trim());if("ambiguous"in r){let head=r.ambiguous.slice(0,6).join(", ");return dispatch({kind:"system",text:`ambiguous: /${name} \u2192 ${head}${r.ambiguous.length>6?", \u2026":""}`})}}let text2=raw;if(hasInterp(raw))setStatus("interpolating\u2026"),text2=await interpolate(gw,raw),setStatus("");interrupted.current=!1;let withMedia=attachments.length?[...attachments.flatMap((a)=>a.path?[`MEDIA:${a.path}`]:[]),text2].filter(Boolean).join(`
|
|
4163
|
+
`):text2;dispatch({kind:"user",text:withMedia}),setAttachments([]),gw.request("prompt.submit",{text:text2}).catch(()=>{inflight.current=!1}),setTab(CHAT_TAB)},[gw,slash,attachments]);sendRef.current=send;let onSend=import_react120.useCallback((raw)=>{return setSplash(!1),send(raw)},[send]),onEmptyEnter=import_react120.useCallback(()=>{if(!splash||summoned.current||!splashLast||composing)return!1;return setSplash(!1),switchSession(splashLast.id),!0},[splash,splashLast,composing,switchSession]);import_react120.useEffect(()=>{if(turn.streaming)inflight.current=!1},[turn.streaming]),import_react120.useEffect(()=>{if(turn.streaming||inflight.current||!ready||queue.length===0)return;let[head,...rest]=queue;inflight.current=!0,setQueue(rest),send(head)},[turn.streaming,ready,queue,send]);let dequeue=import_react120.useCallback((i)=>{let item=queueRef.current[i];if(item===void 0)return;setQueue((q4)=>q4.filter((_2,j2)=>j2!==i)),composer2.current?.set(item),setFocusRegion("input")},[]),copyLast=import_react120.useCallback(()=>{let msgs=turnRef.current.messages;for(let i=msgs.length-1;i>=0;i--){let m2=msgs[i];if(m2.role!=="assistant")continue;let text2=m2.parts.filter((p)=>p.type==="text").map((p)=>p.content).join("");if(!text2)continue;return process.stdout.write(`\x1B]52;c;${Buffer.from(text2).toString("base64")}\x07`),!0}return!1},[]),deltas=import_react120.useRef({text:"",think:"",timer:null}),flush2=import_react120.useCallback(()=>{let d2=deltas.current;if(d2.timer)clearTimeout(d2.timer),d2.timer=null;if(d2.think)dispatch({kind:"thinking",text:d2.think,final:!1}),d2.think="";if(d2.text)dispatch({kind:"message.delta",chunk:d2.text}),d2.text=""},[]),STREAM_EVENTS=import_react120.useRef(new Set(["message.start","message.delta","reasoning.delta","reasoning.available","thinking.delta","tool.start","tool.progress","tool.generating"])).current,handle2=import_react120.useCallback((ev)=>{if(interrupted.current){if(STREAM_EVENTS.has(ev.type))return;if(ev.type==="status.update"&&ev.payload?.kind==="lifecycle")return}let action=mapEvent(ev,{onReady:()=>{session.boot(launchRef.current).then((r)=>{if(setSid(r.id),sessionStart.current=Date.now(),r.messages.length)dispatch({kind:"load",messages:r.messages});if(r.note)toast.show({variant:"info",message:r.note})})},onSessionInfo:(si)=>{if(setInfo(si),setReady(!0),si.session_id)setSid(si.session_id);let bad=(si.mcp_servers??[]).filter((s)=>!s.connected);if(bad.length)dispatch({kind:"system",text:`MCP: ${bad.length} server(s) failed to connect \u2014 ${bad.map((s)=>s.name+(s.error?` (${s.error})`:"")).join(", ")}`});gw.request("session.title").then((r)=>{if(setTitle(r.title??""),r.session_key)set("lastSessionId",r.session_key)}).catch(()=>{}),gw.request("config.get",{key:"busy"}).then((r)=>{let m2=r.value;if(m2==="queue"||m2==="steer"||m2==="interrupt")setBusy(m2)}).catch(()=>{})},onUsage:(u3)=>setUsage(u3),onTurnComplete:()=>{setStatus(""),flush(gw,sidRef.current),goalHook.check(sidRef.current)},onBackground:(tid,text2)=>{let head=text2.split(`
|
|
4164
4164
|
`)[0].slice(0,80);dispatch({kind:"system",text:`\u25F7 background task ${tid} complete \u2014 ${head}`}),toast.show({variant:"info",title:"Background task complete",message:head,duration:8000,action:{label:"view",run:()=>openAlert(dialog,`Background task ${tid}`,text2)}})},onBtw:(text2)=>{let head=text2.split(`
|
|
4165
|
-
`)[0].slice(0,80);dispatch({kind:"system",text:`\u25C8 btw \u2014 ${head}`}),toast.show({variant:"info",title:"btw",message:head,duration:8000,action:{label:"view",run:()=>openAlert(dialog,"btw",text2)}})},onStatus:(text2)=>setStatus(text2),onSkin:(s)=>setSkin(deriveSkin(s))});if(!action)return;let d2=deltas.current;if(action.kind==="message.delta"){if(d2.think)flush2();d2.text+=action.chunk,d2.timer??=setTimeout(flush2,16);return}if(action.kind==="thinking"&&!action.final){if(d2.text)flush2();d2.think+=action.text,d2.timer??=setTimeout(flush2,16);return}if(flush2(),action.kind==="error")setErrorPulse(!0);dispatch(action)},[session,dialog,toast,gw,flush2,goalHook]);useGatewayEvent(handle2),import_react120.useEffect(()=>cmd.register([{title:"Help",value:"help",action:"help.open",category:"General",onSelect:()=>dialog.replace($jsx(HelpDialog,{}))},{title:"Keybindings",value:"keys",description:"View & rebind shortcuts",category:"General",onSelect:()=>openKeys(dialog)},{title:"Gateway Logs",value:"logs",description:"Show gateway stderr",category:"General",onSelect:()=>openLogs(dialog)},{title:"Switch Theme",value:"theme",action:"theme.pick",category:"General",onSelect:()=>openThemePicker(dialog,themeCtx)},{title:"Switch Model",value:"model",action:"model.pick",category:"General",onSelect:()=>openModelPicker(dialog,gw)},{title:"Pick Avatar",value:"eikon",description:"Choose sidebar .eikon avatar",category:"General",onSelect:()=>pickEikon()},{title:"Rollback",value:"rollback",description:"Browse & restore checkpoints",category:"Session",onSelect:()=>openRollback(dialog,gw,toast)},{title:"History",value:"history",action:"session.timeline",category:"Session",onSelect:()=>openHistory(dialog,gw)},{title:"Status",value:"status",action:"status.open",category:"Info",onSelect:()=>openStatus(dialog,info2,sid)},{title:"Usage",value:"usage",description:"Tokens \xB7 context \xB7 cost",category:"Info",onSelect:()=>openUsage(dialog,gw)},{title:"Profile",value:"profile",description:"Active profile details",category:"Info",onSelect:()=>openProfile(dialog)},{title:"New Session",value:"new-session",action:"session.new",category:"Session",onSelect:()=>destructive("",{title:"Start a new session?",body:"Ends the current session and starts a fresh one. The existing session remains saved and resumable.",yes:"new session"},()=>{newSession()})},{title:"Compress Session",value:"compress",action:"session.compress",category:"Session",onSelect:()=>runCompress()},{title:"Undo Last Turn",value:"undo",description:"Pop last user+assistant pair",category:"Session",onSelect:()=>destructive("",{title:"Undo last turn?",body:"Pops the last user + assistant pair from the transcript. Cannot be undone.",yes:"undo"},()=>{session.undo()})},{title:"Branch Session",value:"branch",description:"Fork the current conversation",category:"Session",onSelect:()=>session.branch()}]),[cmd,dialog,themeCtx,session,gw,toast,newSession,pickEikon,info2,sid,runCompress,destructive]);let doInterrupt=import_react120.useCallback(()=>{interrupted.current=!0;let d2=deltas.current;if(d2.timer)clearTimeout(d2.timer),d2.timer=null;d2.text="",d2.think="",session.interrupt()},[session]);intr.current=doInterrupt;let subCount=SUB_TABS[tab]?.length??0,cycleSub=import_react120.useCallback((dir)=>{let labels=SUB_TABS[tab];if(!labels||labels.length===0)return;setSubTabs((prev)=>{let cur=prev[tab]??0,next2=(cur+dir+labels.length)%labels.length;return next2===cur?prev:{...prev,[tab]:next2}})},[tab]);useAppKeys({tab,tabMax:TAB_MAX,chatTab:CHAT_TAB,setTab,subCount,cycleSub,focusRegion,setFocusRegion,streaming:turn.streaming,dialogOpen:dialog.open,composer:composer2,onPromptKey:(k2)=>promptRef.current?.feed(k2)??!1,onEscape:()=>{if(!splash||!summoned.current)return!1;return setSplash(!1),summoned.current=!1,!0},onInterrupt:doInterrupt,queued:queue.length,onFlushQueue:doInterrupt,onQuit:()=>quit(renderer,sid,title,gw),onInterruptNotice:()=>dispatch({kind:"interrupt.notice",text:"Press Escape again to interrupt"}),onCopyLast:()=>{copyLast()},onAttachClipboard:attachClipboard,onDetachLast:()=>{if(attachments.length===0)return!1;return setAttachments((a)=>a.slice(0,-1)),!0},onNotice:(text2)=>dispatch({kind:"system",text:text2}),onToggleSidebar:()=>setHideSidebar((v2)=>!v2)});let state2=import_react120.useRef({tab,ready,streaming:turn.streaming,messages:turn.messages,sid,focusRegion});state2.current={tab,ready,streaming:turn.streaming,messages:turn.messages,sid,focusRegion},import_react120.useEffect(()=>{if(!enabled2)return;setBridge({tab:()=>state2.current.tab,setTab,send:(msg)=>{if(!state2.current.ready||state2.current.streaming)return;dispatch({kind:"user",text:msg}),gw.request("prompt.submit",{text:msg}).catch(()=>{}),setTab(CHAT_TAB)},ready:()=>state2.current.ready,streaming:()=>state2.current.streaming,messages:()=>state2.current.messages.length,session:()=>state2.current.sid,input:()=>composer2.current?.value()??"",setInput:(v2)=>composer2.current?.set(v2),focusRegion:()=>state2.current.focusRegion,setFocusRegion,renderer:()=>renderer,logs:(n)=>gw.tail(n)})},[gw,renderer]);let contentFocused=focusRegion==="content"&&!turn.streaming,promptAnswer=import_react120.useCallback((id,label,ok)=>dispatch({kind:"prompt.answered",id,label,ok}),[]),promptWire=import_react120.useMemo(()=>({ref:promptRef,onAnswer:promptAnswer}),[promptAnswer]);import_react120.useEffect(()=>{if(prompt&&tab!==CHAT_TAB)setTab(CHAT_TAB)},[prompt?.id]);let content=()=>{let inner=(()=>{switch(tab){case CHAT_TAB:return $jsx(Chat,{messages:turn.messages,streaming:turn.streaming,prompt:promptWire,cloud,cloudH,pick,onResize:setCloudH,onPick,onClose:closeCloud,onRewind:msgMenu});case SESSIONS_TAB:return $jsx(SessionsGroup,{focused:contentFocused,sub:subTabs[SESSIONS_TAB]??0,setSub:
|
|
4165
|
+
`)[0].slice(0,80);dispatch({kind:"system",text:`\u25C8 btw \u2014 ${head}`}),toast.show({variant:"info",title:"btw",message:head,duration:8000,action:{label:"view",run:()=>openAlert(dialog,"btw",text2)}})},onStatus:(text2)=>setStatus(text2),onSkin:(s)=>setSkin(deriveSkin(s))});if(!action)return;let d2=deltas.current;if(action.kind==="message.delta"){if(d2.think)flush2();d2.text+=action.chunk,d2.timer??=setTimeout(flush2,16);return}if(action.kind==="thinking"&&!action.final){if(d2.text)flush2();d2.think+=action.text,d2.timer??=setTimeout(flush2,16);return}if(flush2(),action.kind==="error")setErrorPulse(!0);dispatch(action)},[session,dialog,toast,gw,flush2,goalHook]);useGatewayEvent(handle2),import_react120.useEffect(()=>cmd.register([{title:"Help",value:"help",action:"help.open",category:"General",onSelect:()=>dialog.replace($jsx(HelpDialog,{}))},{title:"Keybindings",value:"keys",description:"View & rebind shortcuts",category:"General",onSelect:()=>openKeys(dialog)},{title:"Gateway Logs",value:"logs",description:"Show gateway stderr",category:"General",onSelect:()=>openLogs(dialog)},{title:"Switch Theme",value:"theme",action:"theme.pick",category:"General",onSelect:()=>openThemePicker(dialog,themeCtx)},{title:"Switch Model",value:"model",action:"model.pick",category:"General",onSelect:()=>openModelPicker(dialog,gw)},{title:"Pick Avatar",value:"eikon",description:"Choose sidebar .eikon avatar",category:"General",onSelect:()=>pickEikon()},{title:"Rollback",value:"rollback",description:"Browse & restore checkpoints",category:"Session",onSelect:()=>openRollback(dialog,gw,toast)},{title:"History",value:"history",action:"session.timeline",category:"Session",onSelect:()=>openHistory(dialog,gw)},{title:"Status",value:"status",action:"status.open",category:"Info",onSelect:()=>openStatus(dialog,info2,sid)},{title:"Usage",value:"usage",description:"Tokens \xB7 context \xB7 cost",category:"Info",onSelect:()=>openUsage(dialog,gw)},{title:"Profile",value:"profile",description:"Active profile details",category:"Info",onSelect:()=>openProfile(dialog)},{title:"New Session",value:"new-session",action:"session.new",category:"Session",onSelect:()=>destructive("",{title:"Start a new session?",body:"Ends the current session and starts a fresh one. The existing session remains saved and resumable.",yes:"new session"},()=>{newSession()})},{title:"Compress Session",value:"compress",action:"session.compress",category:"Session",onSelect:()=>runCompress()},{title:"Undo Last Turn",value:"undo",description:"Pop last user+assistant pair",category:"Session",onSelect:()=>destructive("",{title:"Undo last turn?",body:"Pops the last user + assistant pair from the transcript. Cannot be undone.",yes:"undo"},()=>{session.undo()})},{title:"Branch Session",value:"branch",description:"Fork the current conversation",category:"Session",onSelect:()=>session.branch()}]),[cmd,dialog,themeCtx,session,gw,toast,newSession,pickEikon,info2,sid,runCompress,destructive]);let doInterrupt=import_react120.useCallback(()=>{interrupted.current=!0;let d2=deltas.current;if(d2.timer)clearTimeout(d2.timer),d2.timer=null;d2.text="",d2.think="",session.interrupt()},[session]);intr.current=doInterrupt;let subCount=SUB_TABS[tab]?.length??0,cycleSub=import_react120.useCallback((dir)=>{let labels=SUB_TABS[tab];if(!labels||labels.length===0)return;setSubTabs((prev)=>{let cur=prev[tab]??0,next2=(cur+dir+labels.length)%labels.length;return next2===cur?prev:{...prev,[tab]:next2}})},[tab]);useAppKeys({tab,tabMax:TAB_MAX,chatTab:CHAT_TAB,setTab,subCount,cycleSub,focusRegion,setFocusRegion,streaming:turn.streaming,dialogOpen:dialog.open,composer:composer2,onPromptKey:(k2)=>promptRef.current?.feed(k2)??!1,onEscape:()=>{if(!splash||!summoned.current)return!1;return setSplash(!1),summoned.current=!1,!0},onInterrupt:doInterrupt,queued:queue.length,onFlushQueue:doInterrupt,onQuit:()=>quit(renderer,sid,title,gw),onInterruptNotice:()=>dispatch({kind:"interrupt.notice",text:"Press Escape again to interrupt"}),onCopyLast:()=>{copyLast()},onAttachClipboard:attachClipboard,onDetachLast:()=>{if(attachments.length===0)return!1;return setAttachments((a)=>a.slice(0,-1)),!0},onNotice:(text2)=>dispatch({kind:"system",text:text2}),onToggleSidebar:()=>setHideSidebar((v2)=>!v2)});let state2=import_react120.useRef({tab,ready,streaming:turn.streaming,messages:turn.messages,sid,focusRegion});state2.current={tab,ready,streaming:turn.streaming,messages:turn.messages,sid,focusRegion},import_react120.useEffect(()=>{if(!enabled2)return;setBridge({tab:()=>state2.current.tab,setTab,send:(msg)=>{if(!state2.current.ready||state2.current.streaming)return;dispatch({kind:"user",text:msg}),gw.request("prompt.submit",{text:msg}).catch(()=>{}),setTab(CHAT_TAB)},ready:()=>state2.current.ready,streaming:()=>state2.current.streaming,messages:()=>state2.current.messages.length,session:()=>state2.current.sid,input:()=>composer2.current?.value()??"",setInput:(v2)=>composer2.current?.set(v2),focusRegion:()=>state2.current.focusRegion,setFocusRegion,renderer:()=>renderer,logs:(n)=>gw.tail(n)})},[gw,renderer]);let contentFocused=focusRegion==="content"&&!turn.streaming,promptAnswer=import_react120.useCallback((id,label,ok)=>dispatch({kind:"prompt.answered",id,label,ok}),[]),promptWire=import_react120.useMemo(()=>({ref:promptRef,onAnswer:promptAnswer}),[promptAnswer]);import_react120.useEffect(()=>{if(prompt&&tab!==CHAT_TAB)setTab(CHAT_TAB)},[prompt?.id]);let content=()=>{let inner=(()=>{switch(tab){case CHAT_TAB:return $jsx(Chat,{messages:turn.messages,streaming:turn.streaming,prompt:promptWire,cloud,cloudH,pick,onResize:setCloudH,onPick,onClose:closeCloud,onRewind:msgMenu});case SESSIONS_TAB:return $jsx(SessionsGroup,{focused:contentFocused,sub:subTabs[SESSIONS_TAB]??0,setSub:sessSub,onSwitch:switchSession,currentId:sid,messages:turn.messages,sessionStart:sessionStart.current,info:info2??void 0});case AUTOMATION_TAB:return $jsx(Automation,{focused:contentFocused,sub:subTabs[AUTOMATION_TAB]??0,setSub:autoSub,sessionId:sid,onSwitchProfile:switchProfile});case CONFIG_TAB:return $jsx(ConfigGroup,{focused:contentFocused,sub:subTabs[CONFIG_TAB]??0,setSub:cfgSub});default:return null}})(),name=TABS[tab]?.name??"unknown";return $jsx(import_react120.Profiler,{id:`tab:${name}`,onRender,children:inner})},theme=themeCtx.theme,onMouseUp=import_react120.useCallback(()=>copySelection(renderer),[renderer]),inputFocused=focusRegion==="input"&&!prompt;return $jsx(import_react120.Profiler,{id:"shell",onRender,children:$jsx(SkinProvider,{value:skin,children:$jsxs("box",{width:"100%",height:"100%",flexDirection:"column",backgroundColor:theme.background,onMouseUp,children:[$jsx(TabBar,{tabs:TABS,activeTab:tab,onTabChange:goToTab}),$jsxs("box",{flexGrow:1,flexDirection:"row",children:[$jsxs("box",{flexGrow:1,flexDirection:"column",children:[$jsxs("box",{flexGrow:1,position:"relative",children:[content(),splash&&tab===CHAT_TAB?$jsx(Splash,{info:splashInfo,last:summoned.current?void 0:splashLastProp,composing,news,loading:switching||!info2}):null]}),$jsx("box",{flexShrink:0,zIndex:1,children:$jsx(Composer,{ref:composer2,focused:inputFocused,ready,streaming:turn.streaming,status,queue,attachments,cmds,onSend,onSlash:slash,onAttach,onEnqueue,onDequeue:dequeue,onDirty:setComposing,onEmptyEnter})})]}),dims.width>=(tab===CHAT_TAB?120:140)&&!hideSidebar?$jsx(import_react120.Profiler,{id:"sidebar",onRender,children:$jsx(Sidebar,{agentState,info:info2,usage,eikon,profile:activeProfileName(),title,cloud:tab===0&&cloud,pulse:turn.streaming,onAvatar,onAvatarHold})}):null]})]})})})};init_perf();import{writeSync as writeSync2}from"fs";var TERMINAL_MODE_RESET="\x1B[0'z\x1B[0'{\x1B[?2029l\x1B[?1016l\x1B[?1015l\x1B[?1006l\x1B[?1005l\x1B[?1003l\x1B[?1002l\x1B[?1001l\x1B[?1000l\x1B[?9l\x1B[?1004l\x1B[?2004l\x1B[?1049l\x1B[<u\x1B[>4;0m\x1B[0m\x1B[?25h";function resetTerminalModes(stream=process.stdout){if(!stream.isTTY)return!1;let fd=typeof stream.fd==="number"?stream.fd:stream===process.stdout?1:void 0;if(fd!==void 0)try{return writeSync2(fd,TERMINAL_MODE_RESET),!0}catch{}try{return stream.write(TERMINAL_MODE_RESET),!0}catch{return!1}}var wired=!1;function installExitResetHooks(){if(wired)return;wired=!0,process.on("exit",()=>{resetTerminalModes()});let codes={SIGHUP:129,SIGINT:130,SIGTERM:143};for(let sig of["SIGINT","SIGTERM","SIGHUP"])process.on(sig,()=>{resetTerminalModes(),process.exit(codes[sig])});process.on("uncaughtException",(err)=>{resetTerminalModes(),console.error(err),process.exit(1)}),process.on("unhandledRejection",(reason)=>{resetTerminalModes(),console.error(reason),process.exit(1)})}boot("import-graph",Bun.nanoseconds()/1e6);var argv=Bun.argv.slice(2);if(argv.includes("--help")||argv.includes("-h"))process.stdout.write(HELP),process.exit(0);if(argv.includes("--version")||argv.includes("-v"))process.stdout.write(VERSION+`
|
|
4166
4166
|
`),process.exit(0);var launch=parseLaunch(argv),main2=async()=>{resetTerminalModes(),installExitResetHooks(),mem("pre-renderer");let prefs=load(),end=mark("renderer-init"),renderer=await createCliRenderer({exitOnCtrlC:!1,useMouse:prefs.mouse??!0,targetFps:prefs.targetFps??30,gatherStats:!1});end();let bump=()=>renderer.capabilities?.kitty_keyboard||process.stdout.isTTY&&process.stdout.write("\x1B[>4;2m");bump(),renderer.on("focus",bump),mem("post-renderer");let root2=createRoot(renderer),endRender=mark("first-render");root2.render($jsx(App,{initialTheme:prefs.theme,launch})),endRender(),boot("first-render",Bun.nanoseconds()/1e6),warmup(),warm(),mem("post-first-render"),monitor(15000),start()};main2().catch(console.error);
|