herm-tui 1.10.0-dev.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +1 -1
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -4211,7 +4211,7 @@ ${r.skipped.slice(0,8).join(", ")}${r.skipped.length>8?", \u2026":""}`:""}`,yes:
4211
4211
  ${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("eikon",void 0),x2.dispatch({kind:"system",text:`skin \u2192 ${name}`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return}case"resume":if(arg){x2.switchSession(arg);return}x2.goTo(TAB_SLASH.sessions.tab,TAB_SLASH.sessions.sub);return;case"branch":branch2(arg);return;case"compress":runCompress(arg);return;case"undo":destructive(arg,{title:"Undo last turn?",body:"Pops the last user + assistant pair from the transcript. /redo in this session to restore.",yes:"undo"},()=>{let msgs=x2.turnRef.current.messages,at=msgs.map((m2)=>m2.role).lastIndexOf("user");if(at>=0)x2.undone.current.push(msgs.slice(at));x2.session.undo().then(()=>gw.request("session.history").then((r)=>x2.dispatch({kind:"load",messages:transcriptToMessages(r.messages??[])})).catch(()=>{}))});return;case"redo":{let head=x2.undone.current.pop()?.find((m2)=>m2.role==="user");if(!head){toast.show({variant:"info",message:"nothing to redo"});return}x2.sendRef.current(text(head));return}case"retry":{let last4=[...x2.turnRef.current.messages].reverse().find((m2)=>m2.role==="user");if(!last4){toast.show({variant:"info",message:"nothing to retry"});return}x2.rewind(last4).then(()=>x2.sendRef.current(text(last4)));return}case"model":if(!arg){openModelPicker(dialog,gw);return}if(arg.trim()==="--refresh"){openModelPicker(dialog,gw,{refresh:!0});return}gw.request("config.set",{key:"model",value:arg}).then((r)=>{if(r.warning)toast.show({variant:"warning",message:r.warning});x2.dispatch({kind:"system",text:`model \u2192 ${r.value??arg}`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"yolo":gw.request("config.set",{key:"yolo"}).then((r)=>{if(r.info)x2.setInfo(r.info),x2.setUsage(r.info.usage);else x2.setInfo({...x2.info??{},yolo:!x2.info?.yolo});if(toast.show({variant:"success",message:`yolo ${r.value??"toggled"}`}),r.warning)toast.show({variant:"warning",message:r.warning})}).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"quit":quit(renderer,x2.sid,x2.title,gw);return;case"queue":if(!arg){x2.dispatch({kind:"system",text:`${x2.queueRef.current.length} queued`});return}x2.setQueue((q5)=>[...q5,arg]);return;case"stash":{let comp=x2.composer.current;if(arg==="pop"){let e=exports_stash.pop();if(!e)return toast.show({variant:"info",message:"stash empty"});comp?.set(e.text),x2.setFocusRegion("input");return}if(arg==="list"){let list3=exports_stash.all();if(list3.length===0)return toast.show({variant:"info",message:"stash empty"});dialog.replace($jsx(DialogSelect,{title:"Stashed prompts",filterable:list3.length>6,options:list3.map((e)=>({title:trunc5(e.text.replace(/\n/g," \u23CE "),50),value:String(e.at),hint:ago(e.at)})),onSelect:(o)=>{let e=list3.find((s)=>String(s.at)===o.value);if(e)exports_stash.drop(e.at),comp?.set(e.text),x2.setFocusRegion("input");dialog.clear()}}));return}let text4=arg||comp?.value().trim()||"";if(!text4)return toast.show({variant:"info",message:"nothing to stash \u2014 /stash list"});let n=exports_stash.push(text4);if(!arg)comp?.set("");toast.show({variant:"info",message:`stashed (${n}) \u2014 /stash pop to restore`});return}case"copy":{let all2=x2.turnRef.current.messages.filter((m3)=>m3.role==="assistant"),n=arg?Math.min(Math.max(1,parseInt(arg,10)||0),all2.length):all2.length,m2=all2[n-1];if(!m2){toast.show({variant:"info",message:"nothing to copy"});return}let body2=text(m2);copyText(body2,toast,`copied ${body2.length} chars`);return}case"paste":x2.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?x2.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){x2.dispatch({kind:"system",text:"/background <prompt>"});return}gw.request("prompt.background",x2.sid?{session_id:x2.sid,text:arg}:{text:arg}).then((r)=>{if(!r.task_id){toast.show({variant:"error",message:"background start failed"});return}bg2.register(r.task_id,arg),x2.dispatch({kind:"system",text:`bg ${r.task_id} started`})}).catch((e)=>toast.show({variant:"error",message:e.message}));return;case"voice":x2.voiceToggle((arg||"status").toLowerCase(),x2.sid).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"browser":{let parts2=arg.trim().split(/\s+/),sub2=parts2[0]?.toLowerCase()||"connect",url2=parts2[1];if(!["connect","disconnect","status"].includes(sub2)){toast.show({variant:"error",message:"usage: /browser [connect|disconnect|status] [url]"});return}let payload2={action:sub2};if(sub2==="connect"&&url2)payload2.url=url2;gw.request("browser.manage",payload2).then((r)=>{for(let m2 of r.messages??[])x2.dispatch({kind:"system",text:m2});if(r.connected)x2.dispatch({kind:"system",text:`Browser connected${r.url?` \u2192 ${r.url}`:""}`});else if(sub2==="disconnect")x2.dispatch({kind:"system",text:"Browser disconnected"});else if(sub2==="status")x2.dispatch({kind:"system",text:r.url??"No browser connected"})}).catch((e)=>toast.show({variant:"error",message:`browser: ${e.message}`}));return}case"setup":x2.dispatch({kind:"system",text:`/${c2.name} is an Ink-TUI command and has no effect in herm`});return;case"steer":{let fire=(text4)=>gw.request("session.steer",{text:text4}).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((text4)=>{if(text4)fire(text4)});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)=>{x2.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(c2.target!=="gateway"||!x2.capabilities.canDispatchGatewayCommand)return;let jump=TAB_SLASH[c2.name];if(jump!==void 0&&!arg){x2.goTo(jump.tab,jump.sub);return}let full=`/${c2.name}${arg?" "+arg:""}`;if(x2.turnRef.current.streaming){x2.setQueue((q5)=>[...q5,full]);return}x2.dispatch({kind:"user",text:full}),gw.request("slash.exec",{command:full}).then((res)=>{if(res?.warning)x2.dispatch({kind:"system",text:`\u26A0 ${res.warning}`});if(res?.output)x2.dispatch({kind:"system",text:res.output})}).catch(()=>{gw.request("command.dispatch",{name:c2.name,arg}).then((d2)=>{if(d2.notice)x2.dispatch({kind:"system",text:d2.notice});if(d2.type==="exec"||d2.type==="plugin")return x2.dispatch({kind:"system",text:d2.output||"(no output)"});if(d2.type==="alias"&&d2.target)return void x2.sendRef.current(`/${d2.target}${arg?" "+arg:""}`);if((d2.type==="skill"||d2.type==="send")&&d2.message){if(d2.type==="skill")x2.dispatch({kind:"system",text:`\u26A1 loading skill: ${d2.name??c2.name}`});return void x2.sendRef.current(d2.message)}x2.dispatch({kind:"system",text:`/${c2.name}: unknown`})}).catch((e)=>x2.dispatch({kind:"system",text:`error: ${e.message}`}))})},[gw,dialog,toast,themeCtx,renderer,destructive,applyTitle,runCompress,branch2]);return import_react131.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,ctx2.current.info,ctx2.current.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"},()=>{ctx2.current.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:()=>run({name:"undo",target:"local"})},{title:"Redo",value:"redo",action:"session.redo",category:"Session",onSelect:()=>run({name:"redo",target:"local"})},{title:"Branch Session",value:"branch",description:"Fork the current conversation",category:"Session",onSelect:()=>branch2()}]),[cmd,dialog,themeCtx,gw,toast,destructive,pickEikon,runCompress,branch2,run]),run}var import_react135=__toESM(require_react_production(),1);var import_react133=__toESM(require_react_production(),1);function openAlert(dialog,title,body2){dialog.replace($jsx(Alert,{title,body:body2,onClose:()=>dialog.clear()}))}var Alert=(props)=>{let theme=useTheme().theme,keys=useKeys(),[copied2,setCopied]=import_react133.useState(!1),doCopy=()=>{copy2(props.body),setCopied(!0),setTimeout(()=>setCopied(!1),900)};return useKeyboard((key5)=>{if(keys.match("dialog.cancel",key5)||keys.match("dialog.accept",key5))props.onClose();if(keys.match("dialog.copy",key5))doCopy()}),$jsxs("box",{flexDirection:"column",width:84,maxHeight:28,border:["left"],borderColor:theme.info,customBorderChars:LEFT_BAR,backgroundColor:theme.backgroundPanel,paddingLeft:2,paddingRight:2,paddingY:1,gap:1,children:[$jsx("box",{height:1,children:$jsxs("text",{children:[$jsx("span",{fg:theme.info,children:"\u25C8 "}),$jsx("span",{fg:theme.text,children:props.title})]})}),$jsx("scrollbox",{scrollY:!0,flexGrow:1,children:$jsx("text",{fg:theme.text,wrapMode:"word",children:props.body})}),$jsxs("box",{height:1,flexDirection:"row",children:[$jsx("box",{flexShrink:0,children:$jsx("text",{fg:theme.textMuted,children:`${keys.print("dialog.cancel")} close \xB7 ${keys.print("dialog.copy")} `})}),$jsx("box",{flexShrink:0,onMouseDown:(e)=>{e.stopPropagation(),doCopy()},children:$jsx("text",{fg:copied2?theme.success:theme.textMuted,children:$jsx("u",{children:copied2?"copied":"copy"})})})]})]})};init_perf();function variant(level2){switch(level2){case"error":return"error";case"warning":case"warn":return"warning";case"success":return"success";default:return"info"}}function duration2(p){if(p.kind==="sticky")return null;if(typeof p.ttl_ms==="number")return p.ttl_ms;if(typeof p.duration_ms==="number")return p.duration_ms;return}function showNotification(toast,p){let text4=String(p?.text??"").trim();if(!text4)return;toast.show({key:p?.key,variant:variant(p?.level),message:text4,duration:duration2(p??{text:text4})})}function clearNotification(toast,p){let key5=String(p?.key??"").trim();if(!key5)return;toast.clear(key5)}function count3(o){return o?Object.values(o).reduce((n,v2)=>n+v2.length,0):0}function reference(label3,text4,index3,count4){let head=index3&&count4?`\u25C7 Reference ${index3}/${count4} \u2014 ${label3}`:`\u25C7 Reference \u2014 ${label3}`,body2=text4.trim();return body2?`${head}
4212
4212
  ${body2}`:head}function formatProcessNotification(text4){let body2=text4.replace(/^\[IMPORTANT: /,"").replace(/\]$/,""),done2=body2.match(/^Background process (\S+) completed \(exit code (\S+)\)\.\nCommand: (.+?)(?:\n|$)/);if(done2)return`${done2[1]} exited ${done2[2]} \xB7 ${done2[3]}`;let hit2=body2.match(/^Background process (\S+) matched watch pattern "([^"]+)"\.\nCommand: (.+?)(?:\n|$)/);if(hit2)return`${hit2[1]} matched "${hit2[2]}" \xB7 ${hit2[3]}`;return body2.slice(0,100)}function mapEvent(ev,side){switch(ev.type){case"gateway.ready":if(side.onReady?.(),ev.payload?.skin)side.onSkin?.(ev.payload.skin);return null;case"session.info":{let si=ev.payload;side.onSessionInfo?.(si);let label3=si.model?`Connected \u2014 ${si.model} \xB7 ${count3(si.tools)} tools \xB7 ${count3(si.skills)} skills`:"Connected to Hermes";if(si.credential_warning)side.onStatus?.(si.credential_warning);return{kind:"system",text:label3}}case"session.title":return side.onSessionTitle?.(ev.payload.session_id,ev.payload.title),null;case"message.start":return count("stream:start"),mem("stream-start"),{kind:"message.start"};case"message.delta":{let chunk=ev.payload?.text??"";if(!chunk)return null;return count("stream:chunk"),{kind:"message.delta",chunk}}case"message.complete":{count("stream:done"),mem("stream-done");let p=ev.payload;if(p?.usage)side.onUsage?.(p.usage);if(side.onTurnComplete?.(),p?.status==="error")return{kind:"error",text:p.text||"request failed \u2014 see messages above"};if(p?.status==="interrupted")return{kind:"message.complete",text:(p.text||"")+`
4213
4213
 
4214
- *[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,args:ev.payload.args_text};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,duration:typeof ev.payload.duration_s==="number"?ev.payload.duration_s*1000:void 0,result:ev.payload.result_text};case"thinking.delta":return side.onStatus?.(ev.payload?.text??""),null;case"reasoning.delta":case"reasoning.available":{let text4=ev.payload?.text;if(!text4)return null;return{kind:"thinking",text:text4,final:ev.type==="reasoning.available",verbose:ev.payload?.verbose}}case"moa.reference":return{kind:"reference",text:reference(ev.payload?.label??"reference",ev.payload?.text??"",ev.payload?.index,ev.payload?.count)};case"moa.aggregating":{let agg=ev.payload?.aggregator;return side.onStatus?.(agg?`aggregating with ${agg}\u2026`:"aggregating\u2026"),null}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":if(shouldRemember({variant:"approval",...ev.payload}))return side.onApprovalRemembered?.(),null;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 text4=String(ev.payload?.text??"").trim();if(!text4)return null;return{kind:"system",text:text4}}case"btw.complete":return side.onBtw?.(ev.payload.text),null;case"gateway.stderr":{let line4=ev.payload.line;if(/error|fail|traceback|exception|\b[45]\d\d\b|refused|denied|unauthori/i.test(line4))return{kind:"error",text:line4,fatal:!1};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 text4=ev.payload?.message??"";if(!text4)return null;return ev.payload?.level==="error"?{kind:"error",text:text4}:{kind:"system",text:`\xB7 ${text4}`}}case"status.update":{let kind2=ev.payload?.kind,text4=ev.payload?.text??"";if(kind2==="process")return side.onStatus?.(formatProcessNotification(text4)),null;if(side.onStatus?.(text4),!kind2||kind2==="status")return null;return{kind:"system",text:text4}}case"notification.show":if(side.notices)showNotification(side.notices,ev.payload);return null;case"notification.clear":if(side.notices)clearNotification(side.notices,ev.payload);return null;case"voice.status":{let state2=String(ev.payload?.state??"");return side.onVoiceStatus?.(state2),null}case"voice.transcript":{if(ev.payload?.no_speech_limit===!0)return side.onVoiceTranscript?.("",!0),null;let text4=String(ev.payload?.text??"").trim();if(!text4)return null;return side.onVoiceTranscript?.(text4,!1),null}}return null}var STREAM_EVENTS=new Set(["message.start","message.delta","reasoning.delta","reasoning.available","thinking.delta","moa.reference","moa.aggregating","tool.start","tool.progress","tool.generating"]),TITLE_DELAYS=[1200,5000,15000,30000];function useStream(c){let gw=useGateway(),dialog=useDialog(),toast=useToast(),bg2=useBackground(),ctx2=import_react135.useRef(c);ctx2.current=c;let timers=import_react135.useRef([]);import_react135.useEffect(()=>()=>{timers.current.forEach(clearTimeout),timers.current=[]},[]);let interrupted=import_react135.useRef(!1),info3=import_react135.useRef(!1),deltas=import_react135.useRef({text:"",think:"",timer:null}),flush2=import_react135.useCallback(()=>{let d2=deltas.current;if(d2.timer)clearTimeout(d2.timer),d2.timer=null;if(d2.think)ctx2.current.dispatch({kind:"thinking",text:d2.think,final:!1}),d2.think="";if(d2.text)ctx2.current.dispatch({kind:"message.delta",chunk:d2.text}),d2.text=""},[]),sync=import_react135.useCallback((ms2=0)=>{let run=()=>gw.request("session.title").then((r)=>{if(ctx2.current.setTitle(r.title??""),r.session_key)set("lastSessionId",r.session_key)}).catch(()=>{});if(ms2<=0)return run();let id=setTimeout(()=>{timers.current=timers.current.filter((t2)=>t2!==id),run()},ms2);timers.current.push(id)},[gw]),retitle=import_react135.useCallback((sid2,title)=>{if(!sid2||title===void 0)return;if(sid2===ctx2.current.sidRef.current)ctx2.current.setTitle(title);home2.update("recentSessions",(rows3)=>rows3.map((r)=>r.id===sid2?{...r,title}:r))},[]),handle=import_react135.useCallback((ev)=>{let x2=ctx2.current;if(ev.type==="gateway.ready")info3.current=!1;if(ev.type==="message.start")x2.start();if(ev.type==="background.complete"&&ev.session_id&&x2.sidRef.current&&ev.session_id!==x2.sidRef.current){bg2.unregister(ev.payload.task_id);return}let shared=ev.type==="background.complete"&&!ev.session_id;if(ev.session_id&&x2.sidRef.current&&ev.session_id!==x2.sidRef.current&&!ev.type.startsWith("gateway.")&&!shared)return;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:()=>{x2.session.boot(x2.launchRef.current).then((r)=>{if(x2.setSid(r.id),r.info)x2.setInfo(r.info),x2.setUsage(r.info.usage);if(x2.sessionStart.current=Date.now(),r.messages.length)x2.dispatch({kind:"load",messages:r.messages});if(r.note)toast.show({variant:"info",message:r.note})})},onSessionInfo:(si)=>{if(x2.setInfo(si),si.usage)x2.setUsage(si.usage);if(x2.setReady(!0),si.running===!1)x2.start(),x2.setStarting(!1),x2.setStatus("");if(si.session_id)x2.setSid(si.session_id);x2.settle();let bad=(si.mcp_servers??[]).filter((s)=>!s.connected);if(bad.length)x2.dispatch({kind:"system",text:`MCP: ${bad.length} server(s) failed to connect \u2014 ${bad.map((s)=>s.name+(s.error?` (${s.error})`:"")).join(", ")}`});sync(),gw.request("config.get",{key:"busy"}).then((r)=>{let m2=r.value;if(m2==="queue"||m2==="steer"||m2==="interrupt")x2.setBusy(m2)}).catch(()=>{})},onUsage:(u3)=>x2.setUsage(u3),onTurnComplete:()=>{x2.setStarting(!1),x2.setStatus(""),flush(gw,x2.sidRef.current),x2.goalHook.check(x2.sidRef.current),TITLE_DELAYS.forEach(sync)},onBackground:(tid,text4)=>{let title=bg2.label(tid);bg2.unregister(tid),x2.dispatch({kind:"background",id:tid,title,text:text4})},onBtw:(text4)=>{let head=text4.split(`
4214
+ *[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,args:ev.payload.args_text};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,duration:typeof ev.payload.duration_s==="number"?ev.payload.duration_s*1000:void 0,result:ev.payload.result_text};case"thinking.delta":return side.onStatus?.(ev.payload?.text??""),null;case"reasoning.delta":case"reasoning.available":{let text4=ev.payload?.text;if(!text4)return null;return{kind:"thinking",text:text4,final:ev.type==="reasoning.available",verbose:ev.payload?.verbose}}case"moa.reference":return{kind:"reference",text:reference(ev.payload?.label??"reference",ev.payload?.text??"",ev.payload?.index,ev.payload?.count)};case"moa.aggregating":{let agg=ev.payload?.aggregator;return side.onStatus?.(agg?`aggregating with ${agg}\u2026`:"aggregating\u2026"),null}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":if(shouldRemember({variant:"approval",...ev.payload}))return side.onApprovalRemembered?.(),null;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 text4=String(ev.payload?.text??"").trim();if(!text4)return null;return{kind:"system",text:text4}}case"btw.complete":return side.onBtw?.(ev.payload.text),null;case"gateway.stderr":{let line4=ev.payload.line;if(/error|fail|traceback|exception|\b[45]\d\d\b|refused|denied|unauthori/i.test(line4))return{kind:"error",text:line4,fatal:!1};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 text4=ev.payload?.message??"";if(!text4)return null;return ev.payload?.level==="error"?{kind:"error",text:text4}:{kind:"system",text:`\xB7 ${text4}`}}case"status.update":{let kind2=ev.payload?.kind,text4=ev.payload?.text??"";if(kind2==="process")return side.onStatus?.(formatProcessNotification(text4)),null;if(side.onStatus?.(text4),!kind2||kind2==="status")return null;return{kind:"system",text:text4}}case"notification.show":if(side.notices)showNotification(side.notices,ev.payload);return null;case"notification.clear":if(side.notices)clearNotification(side.notices,ev.payload);return null;case"voice.status":{let state2=String(ev.payload?.state??"");return side.onVoiceStatus?.(state2),null}case"voice.transcript":{if(ev.payload?.no_speech_limit===!0)return side.onVoiceTranscript?.("",!0),null;let text4=String(ev.payload?.text??"").trim();if(!text4)return null;return side.onVoiceTranscript?.(text4,!1),null}}return null}var STREAM_EVENTS=new Set(["message.start","message.delta","reasoning.delta","reasoning.available","thinking.delta","moa.reference","moa.aggregating","tool.start","tool.progress","tool.generating"]),TITLE_DELAYS=[1200,5000,15000,30000];function useStream(c){let gw=useGateway(),dialog=useDialog(),toast=useToast(),bg2=useBackground(),ctx2=import_react135.useRef(c);ctx2.current=c;let timers=import_react135.useRef([]);import_react135.useEffect(()=>()=>{timers.current.forEach(clearTimeout),timers.current=[]},[]);let interrupted=import_react135.useRef(!1),info3=import_react135.useRef(!1),deltas=import_react135.useRef({text:"",think:"",timer:null}),flush2=import_react135.useCallback(()=>{let d2=deltas.current;if(d2.timer)clearTimeout(d2.timer),d2.timer=null;if(d2.think)ctx2.current.dispatch({kind:"thinking",text:d2.think,final:!1}),d2.think="";if(d2.text)ctx2.current.dispatch({kind:"message.delta",chunk:d2.text}),d2.text=""},[]),sync=import_react135.useCallback((ms2=0)=>{let run=()=>gw.request("session.title").then((r)=>{if(ctx2.current.setTitle(r.title??""),r.session_key)set("lastSessionId",r.session_key)}).catch(()=>{});if(ms2<=0)return run();let id=setTimeout(()=>{timers.current=timers.current.filter((t2)=>t2!==id),run()},ms2);timers.current.push(id)},[gw]),retitle=import_react135.useCallback((sid2,title)=>{if(!sid2||title===void 0)return;if(sid2===ctx2.current.sidRef.current)ctx2.current.setTitle(title);home2.update("recentSessions",(rows3)=>rows3.map((r)=>r.id===sid2?{...r,title}:r))},[]),handle=import_react135.useCallback((ev)=>{let x2=ctx2.current;if(ev.type==="gateway.ready")info3.current=!1;if(ev.type==="message.start")x2.start();if(ev.type==="background.complete"&&ev.session_id&&x2.sidRef.current&&ev.session_id!==x2.sidRef.current){bg2.unregister(ev.payload.task_id);return}let shared=ev.type==="background.complete"&&!ev.session_id;if(ev.session_id&&x2.sidRef.current&&ev.session_id!==x2.sidRef.current&&!ev.type.startsWith("gateway.")&&!shared)return;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:()=>{x2.session.boot(x2.launchRef.current).then((r)=>{if(x2.setSid(r.id),r.info)x2.setInfo(r.info),x2.setUsage(r.info.usage);if(x2.sessionStart.current=Date.now(),r.messages.length)x2.dispatch({kind:"load",messages:r.messages});if(r.note)toast.show({variant:"info",message:r.note})})},onSessionInfo:(si)=>{if(x2.setInfo(si),si.usage)x2.setUsage(si.usage);if(x2.setReady(!0),si.running===!1)x2.start(),x2.setStarting(!1),x2.setStatus("");if(si.session_id)x2.setSid(si.session_id);if(x2.settle(),si.title!==void 0)x2.setTitle(si.title);let bad=(si.mcp_servers??[]).filter((s)=>!s.connected);if(bad.length)x2.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("config.get",{key:"busy"}).then((r)=>{let m2=r.value;if(m2==="queue"||m2==="steer"||m2==="interrupt")x2.setBusy(m2)}).catch(()=>{})},onUsage:(u3)=>x2.setUsage(u3),onTurnComplete:()=>{x2.setStarting(!1),x2.setStatus(""),flush(gw,x2.sidRef.current),x2.goalHook.check(x2.sidRef.current),TITLE_DELAYS.forEach(sync)},onBackground:(tid,text4)=>{let title=bg2.label(tid);bg2.unregister(tid),x2.dispatch({kind:"background",id:tid,title,text:text4})},onBtw:(text4)=>{let head=text4.split(`
4215
4215
  `)[0].slice(0,80);x2.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",text4)}})},onStatus:(text4)=>x2.setStatus(text4),onSessionTitle:retitle,onApprovalRemembered:()=>{gw.request("approval.respond",{choice:"always"}).catch(()=>{})},onSkin:(s)=>x2.setSkin(deriveSkin(s)),notices:toast});if(!action)return;if(ev.type==="session.info"){if(info3.current)return;info3.current=!0}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==="message.start")x2.setStarting(!1),x2.setStatus("");if(action.kind==="error")x2.setStarting(!1);if(action.kind==="error")x2.setErrorPulse(!0);x2.dispatch(action)},[gw,dialog,toast,flush2,bg2,retitle]);useGatewayEvent(handle);let doInterrupt=import_react135.useCallback(()=>{interrupted.current=!0;let d2=deltas.current;if(d2.timer)clearTimeout(d2.timer),d2.timer=null;d2.text="",d2.think="",ctx2.current.session.interrupt()},[]);return{interrupted,doInterrupt}}var import_react141=__toESM(require_react_production(),1);init_perf();var PORT=Number(process.env.CONTROL_PORT)||7777,BIND=process.env.CONTROL_BIND||"127.0.0.1",enabled2=process.env.CONTROL==="1",LOOPBACK=new Set(["127.0.0.1","::1","localhost"]);function isLoopback(host){return LOOPBACK.has(host)}function warningFor(on,bind,port2){if(!on)return null;if(isLoopback(bind))return null;return{host:bind,port:port2,message:`CONTROL server bound to ${bind}:${port2} \u2014 reachable from the network. Set CONTROL_BIND=127.0.0.1 to restrict to loopback.`}}function warning(){return warningFor(enabled2,BIND,PORT)}var TAB_NAMES=TABS.map((t2)=>t2.name),bridge=null,pendingTab=null;function setBridge(b2){bridge=b2}function currentTab(){if(pendingTab!==null)return pendingTab;return bridge?.tab()??0}var json2=(data2,status=200)=>new Response(JSON.stringify(data2),{status,headers:{"Content-Type":"application/json"}}),idx=(name)=>{let n=TAB_NAMES.indexOf(name);if(n<0)throw Error(`control.ts DANGEROUS: tab '${name}' missing from TAB_NAMES`);return n},DANGEROUS={[idx("Chat")]:new Set(["return"]),[idx("Sessions")]:new Set(["d","delete","return"]),[idx("Profiles & Automation")]:new Set(["return","space","d","delete","k"]),[idx("Config")]:new Set(["space","return","h","l","]","[","ctrl+s","d","delete"]),[idx("Eikon")]:new Set(["return","n","d","delete","s","u","ctrl+s","ctrl+u"])};function isDangerous(tab,keyName2,ctrl){let set3=DANGEROUS[tab];if(!set3)return!1;let id=ctrl?`ctrl+${keyName2}`:keyName2;return set3.has(id)}function makeKey(opts){return{name:opts.name,ctrl:opts.ctrl??!1,meta:opts.meta??!1,shift:opts.shift??!1,option:!1,sequence:opts.raw??opts.name,number:!1,raw:opts.raw??opts.name,eventType:"press",source:"raw"}}function injectKey(renderer,key5){let r=renderer;if(!r?.keyInput?.processParsedKey)return!1;return r.keyInput.processParsedKey(key5)}function getNodeChildren(n){if(n.getChildren)return n.getChildren();if(n._childrenInLayoutOrder)return[...n._childrenInLayoutOrder];return[]}function getNodeType(n){return n._type||n.tagName||n.constructor?.name||"unknown"}function buildFocusTree(node,depth=0){if(!node||typeof node!=="object")return null;let n=node,type=getNodeType(n),focused=n.focused??!1,focusable=n.focusable??!1,children2=[];if(depth<20)for(let child of getNodeChildren(n)){let c=buildFocusTree(child,depth+1);if(c)children2.push(c)}if(!(focusable||children2.some((c)=>c.focusable||c.focused||c.children.length>0))&&!focused&&depth>0)return null;let text4=n.value||n.textContent||n.text||void 0;return{type,focused,focusable,children:children2,text:text4}}function findFocused(node){if(!node||typeof node!=="object")return null;let n=node;if(n.focused)return getNodeType(n);for(let child of getNodeChildren(n)){let found2=findFocused(child);if(found2)return found2}return null}function countNodes(node){let result={total:0,focusable:0,focused:0};function walk2(n){if(!n||typeof n!=="object")return;let nd=n;if(result.total++,nd.focusable)result.focusable++;if(nd.focused)result.focused++;for(let child of getNodeChildren(nd))walk2(child)}return walk2(node),result}async function handle(req){let url2=new URL(req.url),path7=url2.pathname;if(!bridge)return json2({error:"bridge not ready"},503);if(path7==="/status"){let m2=process.memoryUsage(),tab=currentTab();return pendingTab=null,json2({tab,tabName:TAB_NAMES[tab]??"unknown",ready:bridge.ready(),streaming:bridge.streaming(),messages:bridge.messages(),session:bridge.session(),input:bridge.input(),focusRegion:bridge.focusRegion(),rss:Math.round(m2.rss/1024/1024),heap:Math.round(m2.heapUsed/1024/1024)})}let tabMatch=path7.match(/^\/tab\/(\d+)$/);if(tabMatch){let n=Number(tabMatch[1]);if(n<0||n>TAB_MAX)return json2({error:`tab 0-${TAB_MAX}`},400);let renderer=bridge.renderer();if(renderer){let cur=bridge.tab(),diff=n-cur,key5=makeKey({name:diff>0?"right":"left",meta:!0});for(let i=Math.abs(diff);i>0;i--)injectKey(renderer,key5)}else bridge.setTab(n);return pendingTab=n,json2({tab:n,tabName:TAB_NAMES[n]})}if(path7==="/send"&&req.method==="POST"){let body2=await req.json();if(!body2.message)return json2({error:"message required"},400);if(!bridge.ready())return json2({error:"not connected"},503);if(bridge.streaming())return json2({error:"already streaming"},409);return bridge.send(body2.message),json2({sent:!0,message:body2.message})}if(path7==="/key"&&req.method==="POST"){let body2=await req.json();if(!body2.name)return json2({error:"name required"},400);let renderer=bridge.renderer();if(!renderer)return json2({error:"renderer not available"},503);let safe2=body2.safe!==!1,tab=currentTab();if(safe2&&isDangerous(tab,body2.name,!!body2.ctrl))return json2({error:"blocked",reason:`Key "${body2.ctrl?"ctrl+":""}${body2.name}" is dangerous on tab ${TAB_NAMES[tab]} (index ${tab}). Pass safe=false to override.`,tab,tabName:TAB_NAMES[tab]},403);let key5=makeKey({name:body2.name,ctrl:body2.ctrl,shift:body2.shift,meta:body2.meta,raw:body2.raw??(body2.name.length===1?body2.name:"")}),handled=injectKey(renderer,key5);return json2({injected:!0,handled,key:body2.name,tab,tabName:TAB_NAMES[tab]})}if(path7==="/keys"&&req.method==="POST"){let body2=await req.json();if(!body2.keys?.length)return json2({error:"keys array required"},400);let renderer=bridge.renderer();if(!renderer)return json2({error:"renderer not available"},503);let safe2=body2.safe!==!1,tab=currentTab(),delay=body2.delay??0,results=[];for(let k2 of body2.keys){if(safe2&&isDangerous(currentTab(),k2.name,!!k2.ctrl)){results.push({key:k2.name,injected:!1,handled:!1,blocked:!0});continue}let key5=makeKey({name:k2.name,ctrl:k2.ctrl,shift:k2.shift,meta:k2.meta,raw:k2.raw??(k2.name.length===1?k2.name:"")}),handled=injectKey(renderer,key5);if(results.push({key:k2.name,injected:!0,handled}),delay>0)await new Promise((r)=>setTimeout(r,delay))}return json2({results,tab,tabName:TAB_NAMES[tab]})}if(path7==="/type"&&req.method==="POST"){let body2=await req.json();if(!body2.text)return json2({error:"text required"},400);let renderer=bridge.renderer();if(!renderer)return json2({error:"renderer not available"},503);let safe2=body2.safe!==!1,tab=currentTab(),delay=body2.delay??0,count4=0;for(let ch of body2.text){if(safe2&&isDangerous(tab,ch,!1))continue;let key5=makeKey({name:ch,raw:ch});if(injectKey(renderer,key5),count4++,delay>0)await new Promise((r)=>setTimeout(r,delay))}return json2({typed:count4,total:body2.text.length,tab,tabName:TAB_NAMES[tab]})}if(path7==="/input"&&req.method==="POST"){let body2=await req.json();return bridge.setInput(body2.text??""),json2({ok:!0,text:body2.text??""})}if(path7==="/quit")return setTimeout(()=>process.exit(0),10),json2({ok:!0});if(path7==="/focus"){let r=bridge.renderer();if(!r?.root)return json2({error:"no renderer root"},503);let counts=countNodes(r.root),tree3=buildFocusTree(r.root),focused=findFocused(r.root),currentFocus=r.currentFocusedRenderable?getNodeType(r.currentFocusedRenderable):null;return json2({focused,currentFocus,counts,tree:tree3})}if(path7==="/frame"){let r=bridge.renderer();if(!r?.currentRenderBuffer)return json2({error:"no render buffer"},503);let frame2=new TextDecoder().decode(r.currentRenderBuffer.getRealCharBytes(!0)),grep=url2.searchParams.get("grep"),body2=grep?frame2.split(`
4216
4216
  `).filter((l)=>l.includes(grep)).join(`
4217
4217
  `):frame2;if(url2.searchParams.get("json")==="1")return json2({frame:body2,match:grep?frame2.includes(grep):void 0,lines:frame2.split(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "herm-tui",
3
- "version": "1.10.0-dev.1",
3
+ "version": "1.10.0",
4
4
  "description": "A modern TUI for Hermes Agent",
5
5
  "license": "MIT",
6
6
  "repository": {