@sma1lboy/rove 0.9.264 → 0.9.266
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{chunk-ykp6efg0.js → chunk-0sm0wcx9.js} +1 -1
- package/dist/cli/{chunk-md3m1qts.js → chunk-1bmhygwd.js} +1 -1
- package/dist/cli/{chunk-1cmcaarg.js → chunk-1gawhhd0.js} +1 -1
- package/dist/cli/{chunk-2bq6877b.js → chunk-1nrva2m2.js} +2 -2
- package/dist/cli/{chunk-cyq9pwqz.js → chunk-1pg3247n.js} +6 -6
- package/dist/cli/{chunk-nfq1q08c.js → chunk-1vtfzcca.js} +1 -1
- package/dist/cli/{chunk-7y7v9x3n.js → chunk-2gjrfqhs.js} +1 -1
- package/dist/cli/{chunk-x2xk1hpy.js → chunk-2gk96h3f.js} +1 -1
- package/dist/cli/{chunk-8fp47ksq.js → chunk-2vrx0pmv.js} +1 -1
- package/dist/cli/{chunk-yewmtant.js → chunk-30g1bgkg.js} +1 -1
- package/dist/cli/chunk-3126c9x9.js +3 -0
- package/dist/cli/{chunk-c6kw0s9a.js → chunk-31jxjkrq.js} +1 -1
- package/dist/cli/{chunk-hpakh6zr.js → chunk-3zsm2jbm.js} +1 -1
- package/dist/cli/{chunk-s0x0yw8x.js → chunk-4018sjy3.js} +1 -1
- package/dist/cli/chunk-4b9f565d.js +2 -0
- package/dist/cli/chunk-4dsyczce.js +2 -0
- package/dist/cli/chunk-4gngf0mt.js +70 -0
- package/dist/cli/{chunk-gzj9nk7k.js → chunk-4rya4jmx.js} +1 -1
- package/dist/cli/{chunk-y1a673xg.js → chunk-4sj2sqyt.js} +1 -1
- package/dist/cli/{chunk-y5p9wm83.js → chunk-56n0whme.js} +1 -1
- package/dist/cli/{chunk-n7vtv1rw.js → chunk-5srsjs7r.js} +1 -1
- package/dist/cli/{chunk-ws4cg819.js → chunk-625773dm.js} +1 -1
- package/dist/cli/{chunk-2k0f7837.js → chunk-67qa9eca.js} +1 -1
- package/dist/cli/chunk-696sqb6j.js +2 -0
- package/dist/cli/{chunk-3ac75tqw.js → chunk-6a70wv2b.js} +1 -1
- package/dist/cli/{chunk-wch6y5bd.js → chunk-7c4zdjr5.js} +1 -1
- package/dist/cli/{chunk-8gzqcx6x.js → chunk-7nrzkqt5.js} +1 -1
- package/dist/cli/chunk-7wsxppwc.js +55 -0
- package/dist/cli/{chunk-ns2f9b6r.js → chunk-80jqznbm.js} +1 -1
- package/dist/cli/chunk-812et2xk.js +3 -0
- package/dist/cli/{chunk-9ecnsh42.js → chunk-8saxdp88.js} +1 -1
- package/dist/cli/{chunk-j11hzmwy.js → chunk-8sksdq95.js} +1 -1
- package/dist/cli/{chunk-rwx1y497.js → chunk-9g2faw9a.js} +1 -1
- package/dist/cli/chunk-a42j8eek.js +3 -0
- package/dist/cli/{chunk-bmk52w06.js → chunk-aeswyjhk.js} +1 -1
- package/dist/cli/{chunk-e5489crb.js → chunk-agt2sdaw.js} +1 -1
- package/dist/cli/{chunk-n22008wk.js → chunk-amc17enx.js} +1 -1
- package/dist/cli/{chunk-vkbgm18p.js → chunk-b3pm5nvh.js} +1 -1
- package/dist/cli/{chunk-jt994bhe.js → chunk-b4zqkdyq.js} +1 -1
- package/dist/cli/{chunk-17fkjpj8.js → chunk-bav3bh70.js} +1 -1
- package/dist/cli/chunk-bwr6dygx.js +4 -0
- package/dist/cli/{chunk-02f0matw.js → chunk-c47gag5r.js} +1 -1
- package/dist/cli/{chunk-zfyf3fdj.js → chunk-cajrtabt.js} +1 -1
- package/dist/cli/{chunk-mccgj97d.js → chunk-cgxgqc87.js} +1 -1
- package/dist/cli/{chunk-spt9e3zk.js → chunk-chzn3px6.js} +4 -4
- package/dist/cli/{chunk-ytw1twda.js → chunk-cqsc0wmp.js} +1 -1
- package/dist/cli/{chunk-9axe1by1.js → chunk-drt79f2t.js} +1 -1
- package/dist/cli/{chunk-hgf4cz78.js → chunk-dzmfexh8.js} +1 -1
- package/dist/cli/chunk-e69s8s16.js +6 -0
- package/dist/cli/{chunk-bs04j8rh.js → chunk-ejd307we.js} +1 -1
- package/dist/cli/{chunk-mhbc490p.js → chunk-ek6kywem.js} +1 -1
- package/dist/cli/{chunk-r3zkpbf5.js → chunk-g1px1rk6.js} +1 -1
- package/dist/cli/{chunk-27k612fg.js → chunk-gvmgabps.js} +1 -1
- package/dist/cli/{chunk-04zwds1k.js → chunk-hc6qpkpy.js} +2 -2
- package/dist/cli/{chunk-cy1c8jmz.js → chunk-hq3hd8qr.js} +1 -1
- package/dist/cli/{chunk-jjv7xem7.js → chunk-j1fe3j54.js} +1 -1
- package/dist/cli/{chunk-jaqa26ab.js → chunk-jrqtzp35.js} +1 -1
- package/dist/cli/{chunk-s83qnstd.js → chunk-kg8k1rar.js} +1 -1
- package/dist/cli/chunk-kvwqh35r.js +4 -0
- package/dist/cli/{chunk-22d0yc7m.js → chunk-m6pp9gaf.js} +1 -1
- package/dist/cli/chunk-m8shvh3j.js +2 -0
- package/dist/cli/{chunk-3khq4hhf.js → chunk-mb018hfg.js} +3 -3
- package/dist/cli/{chunk-4tb0h00q.js → chunk-me656p3n.js} +2 -2
- package/dist/cli/{chunk-ax5c2qmv.js → chunk-mh2s5ttr.js} +1 -1
- package/dist/cli/chunk-mr0z23fd.js +2 -0
- package/dist/cli/{chunk-65333881.js → chunk-mtw6nce9.js} +1 -1
- package/dist/cli/{chunk-g4281a0g.js → chunk-n3f5sdka.js} +2 -2
- package/dist/cli/chunk-njvz867e.js +2 -0
- package/dist/cli/{chunk-rn3cyff1.js → chunk-nyw4s1pv.js} +1 -1
- package/dist/cli/{chunk-xjvrcx07.js → chunk-p2vagan3.js} +1 -1
- package/dist/cli/chunk-pcqw7r50.js +2 -0
- package/dist/cli/{chunk-b2h6jfrg.js → chunk-qdvtz853.js} +1 -1
- package/dist/cli/{chunk-bqscpzvh.js → chunk-qpr14v8x.js} +1 -1
- package/dist/cli/{chunk-3zjdbdwy.js → chunk-qs0526nj.js} +1 -1
- package/dist/cli/{chunk-dxk134bp.js → chunk-qwz9728j.js} +1 -1
- package/dist/cli/{chunk-z6y4cg73.js → chunk-r4vfng2z.js} +1 -1
- package/dist/cli/{chunk-rtcevh2t.js → chunk-rbr6qapz.js} +1 -1
- package/dist/cli/{chunk-65v8ga90.js → chunk-rtkj4wdw.js} +1 -1
- package/dist/cli/{chunk-vpj3gw8b.js → chunk-rwmxpjrx.js} +1 -1
- package/dist/cli/{chunk-eq0c4ecj.js → chunk-s0gp5b9p.js} +1 -1
- package/dist/cli/{chunk-c0gvp57p.js → chunk-s27a0ckk.js} +1 -1
- package/dist/cli/{chunk-f6tqc1cc.js → chunk-sdya3r5j.js} +1 -1
- package/dist/cli/{chunk-wkv4aw6c.js → chunk-swxq6yak.js} +1 -1
- package/dist/cli/{chunk-fdexrh6h.js → chunk-t6hzyee7.js} +1 -1
- package/dist/cli/{chunk-hv9qjnvj.js → chunk-trhrdby1.js} +1 -1
- package/dist/cli/{chunk-vy6q9m4e.js → chunk-tshbjft4.js} +2 -2
- package/dist/cli/chunk-tvbbnfp2.js +2 -0
- package/dist/cli/{chunk-4kzqv6rq.js → chunk-ve348rmz.js} +1 -1
- package/dist/cli/{chunk-vjew0mqm.js → chunk-vxc90473.js} +1 -1
- package/dist/cli/{chunk-70kj5p5z.js → chunk-w196jkg5.js} +1 -1
- package/dist/cli/chunk-w78n33b8.js +3 -0
- package/dist/cli/{chunk-qy4tma9z.js → chunk-wvaf3d9j.js} +1 -1
- package/dist/cli/{chunk-wv5hvxcd.js → chunk-wyn3zbh4.js} +2 -2
- package/dist/cli/chunk-xgans9wf.js +3 -0
- package/dist/cli/{chunk-b3vz95wb.js → chunk-xh72jz7c.js} +1 -1
- package/dist/cli/chunk-xm7a6swz.js +2 -0
- package/dist/cli/{chunk-9ykm0dcz.js → chunk-y078swzq.js} +1 -1
- package/dist/cli/chunk-y87f04kk.js +2 -0
- package/dist/cli/{chunk-g0kq5ng6.js → chunk-yadx0wc5.js} +1 -1
- package/dist/cli/{chunk-6h9bd4z6.js → chunk-ye4vt96f.js} +3 -3
- package/dist/cli/{chunk-ampdybqg.js → chunk-yk498qwr.js} +1 -1
- package/dist/cli/chunk-ywwm92e5.js +2 -0
- package/dist/cli/chunk-yztr951z.js +3 -0
- package/dist/cli/chunk-z5g3twhn.js +2 -0
- package/dist/cli/{chunk-8021rerp.js → chunk-z72f3d9m.js} +18 -18
- package/dist/cli/{chunk-jwqdhbe9.js → chunk-z80jjarw.js} +1 -1
- package/dist/cli/{chunk-c2cj2bye.js → chunk-z99ynm4r.js} +1 -1
- package/dist/cli/{chunk-7jqd1vht.js → chunk-zprhxt1q.js} +1 -1
- package/dist/cli/index.js +8 -8
- package/dist/cli/rove-run.js +1 -1
- package/dist/cli/rove.js +1 -1
- package/dist/skills/rove/SKILL.md +5 -2
- package/dist/skills/rove/references/api-flags.md +1 -1
- package/dist/web/assets/index-BsbDxm3K.js +109 -0
- package/dist/web/assets/index-DNv-oxrT.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/cli/chunk-1gxb0bd3.js +0 -3
- package/dist/cli/chunk-26mf16v9.js +0 -2
- package/dist/cli/chunk-2amvwfah.js +0 -6
- package/dist/cli/chunk-2cbzp9t1.js +0 -2
- package/dist/cli/chunk-59g5tbc7.js +0 -2
- package/dist/cli/chunk-5p8ws3an.js +0 -2
- package/dist/cli/chunk-61nwtmyh.js +0 -2
- package/dist/cli/chunk-69dz852g.js +0 -2
- package/dist/cli/chunk-7hr9k9kg.js +0 -2
- package/dist/cli/chunk-7kwk5kxn.js +0 -3
- package/dist/cli/chunk-a2epp2ad.js +0 -4
- package/dist/cli/chunk-ft6ftksv.js +0 -2
- package/dist/cli/chunk-har2ggte.js +0 -2
- package/dist/cli/chunk-k04s1eb9.js +0 -2
- package/dist/cli/chunk-mn134nhp.js +0 -2
- package/dist/cli/chunk-mtvcw6te.js +0 -55
- package/dist/cli/chunk-nze6pmm7.js +0 -2
- package/dist/cli/chunk-pjae8k74.js +0 -70
- package/dist/cli/chunk-r240tf5j.js +0 -3
- package/dist/cli/chunk-va5mjg68.js +0 -3
- package/dist/cli/chunk-x7r75e3p.js +0 -3
- package/dist/web/assets/index-CWRZWwbL.css +0 -1
- package/dist/web/assets/index-apAwSqkl.js +0 -109
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{errorMessage}from"./chunk-2brn8e1y.js";import{isObject}from"./chunk-7ghwdjdc.js";import{loadStateFile}from"./chunk-g4281a0g.js";import{isDev,keybindingsConfigPath}from"./chunk-prqeddy7.js";import{createStateCell}from"./chunk-cmp64q4j.js";function hasReachableBinding(snapshot,predicate){for(let i=snapshot.length-1;i>=0;i--){let cfg=snapshot[i]?.config();if(!cfg||cfg.enabled===!1)continue;if(cfg.bindings.some(predicate))return!0;if(cfg.modal)return!1}return!1}var prefixReachable=(snapshot)=>hasReachableBinding(snapshot,(binding)=>binding.prefix===!0),inputPassthroughReachable=(snapshot)=>hasReachableBinding(snapshot,(binding)=>binding.passthrough===!0);function scanReachability(snapshot){let directIds=new Set,prefixIds=new Set,prefixReachable2=!1,inputPassthrough=!1,yieldedDirectIds=new Set,prefixOptions=[],seenPrefixKeys=new Set;for(let i=snapshot.length-1;i>=0;i--){let cfg=snapshot[i]?.config();if(!cfg||cfg.enabled===!1)continue;for(let binding of cfg.bindings){if(binding.passthrough)inputPassthrough=!0;if(binding.prefix===!0){if(prefixReachable2=!0,binding.id)prefixIds.add(binding.id);if(!seenPrefixKeys.has(binding.key))seenPrefixKeys.add(binding.key),prefixOptions.push({stroke:binding.key,action:binding.id??binding.key})}else if(binding.id){if(directIds.add(binding.id),binding.yieldToPassthrough)yieldedDirectIds.add(binding.id)}}if(cfg.modal)break}if(inputPassthrough)for(let id of yieldedDirectIds)directIds.delete(id);return{prefixReachable:prefixReachable2,inputPassthrough,prefixOptions,directIds,prefixIds}}function bindingReachability(snapshot){let{directIds,prefixIds,inputPassthrough}=scanReachability(snapshot);return{direct:directIds,prefix:prefixIds,inputPassthrough}}var PREFIX_HUD_TTL_MS=4000,PREFIX_GUIDE_DELAY_MS=180;var MAX_ENTRIES=3,realClock={now:()=>Date.now(),schedule:(fn,ms)=>{let timer=setTimeout(fn,ms);return()=>clearTimeout(timer)}},clock=realClock;function prefixHudClock(){return clock}var cell=createStateCell({guide:null,entries:[]}),nextEntryId=1,prefixHudState=cell;function prefixHudSetArmed(armed,options=[],armedAt=null){cell.update((current)=>{if(!armed)return current.guide?.kind==="prefix"?{...current,guide:null}:current;return{...current,guide:{kind:"prefix",armedAt:armedAt??clock.now(),options}}})}function prefixHudShowDirect(options){cell.update((current)=>({...current,guide:{kind:"direct",options}}))}function prefixHudHideDirect(){cell.update((current)=>current.guide?.kind==="direct"?{...current,guide:null}:current)}function prefixHudPush(entry){cell.update((current)=>({...current,guide:null,entries:[...current.entries,{...entry,id:nextEntryId++}].slice(-MAX_ENTRIES)}))}function matchKey(evt){let base=[],name=evt.name;if(name)base.push(name);if(name==="return")base.push("enter");if(name==="enter")base.push("return");if(name==="backspace"&&evt.raw==="\b"&&!evt.meta&&!evt.option)base.push("ctrl+h");if(name==="linefeed"&&!evt.meta&&!evt.option)base.push("ctrl+j");let mods=[];if(evt.ctrl)mods.push("ctrl");if(evt.meta||evt.super)mods.push("cmd");if(evt.option)mods.push("alt");let bareShiftChar=evt.shift&&name!==void 0&&name.length===1&&mods.length===0;if(evt.shift&&name&&name.length>1)mods.push("shift");if(mods.length===0){if(bareShiftChar)return[...base.map((n)=>`shift+${n}`),...base];return base}let prefix=`${mods.join("+")}+`,prefixed=base.map((n)=>prefix+n);if(evt.shift&&name!==void 0&&name.length===1&&evt.source==="kitty")return[...base.map((n)=>`${mods.join("+")}+shift+${n}`),...prefixed];return prefixed}var KITTY_MODIFIER_KEY_NAMES=["leftshift","leftctrl","leftalt","leftsuper","lefthyper","leftmeta","rightshift","rightctrl","rightalt","rightsuper","righthyper","rightmeta","iso_level3_shift","iso_level5_shift"],KITTY_MODIFIER_KEYS=new Set(KITTY_MODIFIER_KEY_NAMES);function isKittyModifierKeyName(name){return name!==void 0&&KITTY_MODIFIER_KEYS.has(name)}function isKittyModifierKeyEvent(event){return isKittyModifierKeyName(event.name)}function isCtrlModifierKeyName(name){return name==="leftctrl"||name==="rightctrl"}function prefixAction(run){return{run}}function insertRegistration(stack,reg){if(reg.modalOwner!==void 0){let firstMember=stack.findIndex((r)=>r.modalMember===reg.modalOwner);if(firstMember>=0){stack.splice(firstMember,0,reg);return}}stack.push(reg)}var dispatching=!1,DEFAULT_PREFIX_CONFIGURATION={key:"ctrl+a",timeoutMs:5000},prefixConfiguration={...DEFAULT_PREFIX_CONFIGURATION},prefixArmedAt=null,prefixArmedKey="",prefixArmedOnPassthrough=!1,prefixArmedOptions=[],prefixTimer=null;function configurePrefix(next){prefixConfiguration={...next},resetPrefixState()}function resetPrefixConfiguration(){prefixConfiguration={...DEFAULT_PREFIX_CONFIGURATION},resetPrefixState()}function currentPrefixConfiguration(){return prefixConfiguration}function prefixFirstStrokes(config=prefixConfiguration){if(config.key===null)return[];return[config.key,...config.extraKeys??[]]}function resetPrefixState(){if(prefixTimer!==null)clearTimeout(prefixTimer);prefixTimer=null,prefixArmedAt=null,prefixArmedOnPassthrough=!1,prefixArmedOptions=[],prefixHudSetArmed(!1)}function armPrefix(now,options,inputPassthrough,armedKey=prefixConfiguration.key??""){resetPrefixState(),prefixArmedAt=now,prefixArmedKey=armedKey,prefixArmedOnPassthrough=inputPassthrough,prefixArmedOptions=options.slice(),prefixTimer=setTimeout(resetPrefixState,prefixConfiguration.timeoutMs),prefixHudSetArmed(!0,options,now)}function armPrefixNow(snapshot,now=Date.now()){if(prefixConfiguration.key===null)return!1;let reach=scanReachability(snapshot);if(!reach.prefixReachable)return!1;return armPrefix(now,reach.prefixOptions,reach.inputPassthrough),!0}function invokeArmedPrefixAction(bindingStack,actionId,stroke,now=Date.now()){if(dispatching||prefixArmedAt===null)return!1;let snapshot=bindingStack.slice(),armedPrefixKey=prefixArmedKey,validOption=prefixArmedOptions.some((option)=>option.action===actionId&&option.stroke===stroke),expired=now-prefixArmedAt>prefixConfiguration.timeoutMs,crossedBoundary=inputPassthroughReachable(snapshot)!==prefixArmedOnPassthrough;if(!validOption||expired||crossedBoundary)return resetPrefixState(),!1;let hit=null;for(let i=snapshot.length-1;i>=0;i--){let reg=snapshot[i];if(!reg)continue;let cfg=reg.config();if(cfg.enabled===!1)continue;let candidate=cfg.bindings.find((binding)=>binding.prefix===!0&&binding.key===stroke);if(candidate){if(candidate.id===actionId)hit=candidate;break}if(cfg.modal)break}if(!hit?.action)return resetPrefixState(),!1;resetPrefixState(),dispatching=!0;try{return hit.action.run(),prefixHudPush({prefixKey:armedPrefixKey,stroke,action:actionId,at:now}),!0}finally{dispatching=!1}}var shadowWarned=new Set;function warnShadowedMatch(snapshot,hitIndex,candidates,prefix){for(let j=hitIndex-1;j>=0;j--){let cfg=snapshot[j]?.config();if(!cfg||cfg.enabled===!1)continue;let shadowed=cfg.bindings.find((b)=>Boolean(b.prefix)===prefix&&candidates.includes(b.key));if(shadowed){if(!shadowWarned.has(shadowed.key))shadowWarned.add(shadowed.key),console.error(`[rove keymap] "${shadowed.key}" matched two ENABLED bindings \u2014 the lower one is shadowed by LIFO order. Gate one of them off (see tui-react/lib/keymap.ts header).`);return}if(cfg.modal)return}}function dispatchMode(snapshot,evt,candidates,prefix,runCmd){for(let i=snapshot.length-1;i>=0;i--){let reg=snapshot[i];if(!reg)continue;let cfg=reg.config();if(cfg.enabled===!1)continue;let hit;for(let candidate of candidates)if(hit=cfg.bindings.find((binding)=>Boolean(binding.prefix)===prefix&&binding.key===candidate),hit)break;if(hit){if(hit.yieldToPassthrough&&inputPassthroughReachable(snapshot))continue;if(!cfg.modal&&isDev())warnShadowedMatch(snapshot,i,candidates,prefix);return runCmd(()=>hit.cmd(evt,hit.slot)),hit}if(cfg.modal)return null}return null}function dispatchKeyEvent(bindingStack,evt,now=Date.now(),opts){if(evt.defaultPrevented||dispatching)return!1;if(isKittyModifierKeyName(evt.name))return evt.preventDefault(),!0;let snapshot=bindingStack.slice(),candidates=matchKey(evt),runCmd=opts?.flushSync??((fn)=>fn());dispatching=!0;try{if(prefixArmedAt!==null&&inputPassthroughReachable(snapshot)!==prefixArmedOnPassthrough)resetPrefixState();if(prefixArmedAt!==null){let armedPrefixKey=prefixArmedKey,expired=now-prefixArmedAt>prefixConfiguration.timeoutMs;if(prefixArmedAt=null,expired)resetPrefixState();else{if(candidates.includes("escape"))return resetPrefixState(),evt.preventDefault(),!0;resetPrefixState();let hit=dispatchMode(snapshot,evt,candidates,!0,runCmd);return prefixHudPush({prefixKey:armedPrefixKey,stroke:candidates[0]??"",action:hit?hit.id??hit.key:null,at:now}),evt.preventDefault(),!0}}let firstStroke=prefixFirstStrokes().find((key)=>candidates.includes(key));if(firstStroke!==void 0){if(prefixReachable(snapshot)){let reach=scanReachability(snapshot);return armPrefix(now,reach.prefixOptions,reach.inputPassthrough,firstStroke),evt.preventDefault(),!0}}let direct=dispatchMode(snapshot,evt,candidates,!1,runCmd);if(direct){if(direct.id&&direct.key.includes("+")&&!direct.key.startsWith("shift+"))prefixHudPush({prefixKey:"",stroke:direct.key,action:direct.id??direct.key,at:now});return evt.preventDefault(),!0}return!1}finally{dispatching=!1}}import{existsSync,readFileSync}from"fs";var cached=null;function resetKeybindingsFileCache(){cached=null}function resolveConfigFile(){let canonical=keybindingsConfigPath();if(existsSync(canonical))return{canonical,found:canonical};let yml=canonical.replace(/\.yaml$/,".yml");if(existsSync(yml))return{canonical,found:yml};return{canonical,found:null}}function readKeybindingsFile(){if(cached)return cached;let{canonical,found}=resolveConfigFile();if(!found)return cached={path:canonical,exists:!1,doc:null,warnings:[]},cached;let warnings=[],doc=null;try{let text=readFileSync(found,"utf8");doc=Bun.YAML.parse(text)}catch(err){let msg=errorMessage(err);warnings.push(`could not read/parse ${found}: ${msg}`)}return cached={path:canonical,exists:!0,doc,warnings},cached}var MOD_ALIASES={ctrl:"ctrl",control:"ctrl",ctl:"ctrl",cmd:"cmd",command:"cmd",meta:"cmd",super:"cmd",win:"cmd",alt:"alt",option:"alt",opt:"alt",shift:"shift"},KEY_ALIASES={esc:"escape",spacebar:"space",pgup:"pageup",pgdn:"pagedown",pgdown:"pagedown"},KNOWN_NAMED_KEYS=new Set(["up","down","left","right","pageup","pagedown","home","end","insert","delete","backspace","tab","space","escape","enter","return",...Array.from({length:12},(_,i)=>`f${i+1}`)]),MOD_ORDER=["ctrl","cmd","alt","shift"];function normalizeChord(raw){let rawTrimmed=raw.trim(),upperLetterKey=rawTrimmed.length===1&&rawTrimmed>="A"&&rawTrimmed<="Z",trimmed=raw.trim().toLowerCase();if(!trimmed)return{error:"empty chord"};let parts=trimmed.split("+"),key=parts.pop()??"";if(key===""&&parts.length>0&&parts[parts.length-1]==="")key="+",parts.pop();if(!key)return{error:`"${raw}": no key after the modifiers`};let mods=new Set;for(let part of parts){let mod=MOD_ALIASES[part];if(!mod)return{error:`"${raw}": unknown modifier "${part}" (use ctrl / cmd / alt / shift)`};mods.add(mod)}if(key=KEY_ALIASES[key]??key,upperLetterKey)mods.add("shift");if(mods.has("shift")&&mods.size>1&&key.length===1)return{error:`"${raw}": shift with other modifiers on a single character can never match \u2014 legacy terminals send the same byte with and without shift`};let prefix=MOD_ORDER.filter((m)=>mods.has(m)).join("+"),chord=prefix?`${prefix}+${key}`:key;if(key.length>1&&!KNOWN_NAMED_KEYS.has(key))return{chord,warning:`"${raw}": unrecognized key name "${key}" \u2014 the chord may never fire`};return{chord}}function platformSectionNames(platform){if(platform==="darwin")return["darwin","macos","mac"];if(platform==="win32")return["win32","windows"];return[platform]}function extractBindingsMap(section){if(!isObject(section))return null;let nested=section.bindings;if(isObject(nested))return nested;return section}function extractKeybindingOverrides(doc,platform){let warnings=[];if(doc===null||doc===void 0)return{entries:[],prefixEntries:[],warnings};if(!isObject(doc))return{entries:[],prefixEntries:[],warnings:["config root must be a YAML mapping (e.g. a top-level `bindings:` key)"]};let merged=new Map,prefixMerged=new Map,layers=[];if(doc.bindings!==void 0)if(isObject(doc.bindings))layers.push(doc.bindings);else warnings.push("`bindings:` must be a mapping of id \u2192 chord(s)");for(let name of platformSectionNames(platform)){let section=doc[name];if(section===void 0)continue;let map=extractBindingsMap(section);if(map)layers.push(map);else warnings.push(`\`${name}:\` must be a mapping (or contain a \`bindings:\` mapping)`)}for(let layer of layers)for(let[id,value]of Object.entries(layer)){let modeValues=isObject(value)&&(("direct"in value)||("prefix"in value))?[[merged,value.direct],[prefixMerged,value.prefix]]:[[merged,value]];for(let[target,modeValue]of modeValues){if(modeValue===void 0)continue;if(modeValue===null||modeValue===!1||Array.isArray(modeValue)&&modeValue.length===0){target.set(id,[]);continue}let rawChords=typeof modeValue==="string"?[modeValue]:Array.isArray(modeValue)?modeValue:null;if(!rawChords){warnings.push(`${id}: expected a chord string, a list of chords, or null \u2014 got ${typeof modeValue}`);continue}let chords=[],anyError=!1;for(let rawChord of rawChords){if(typeof rawChord!=="string"){warnings.push(`${id}: chord entries must be strings`),anyError=!0;continue}let result=normalizeChord(rawChord);if("error"in result){warnings.push(`${id}: ${result.error}`),anyError=!0;continue}if(result.warning)warnings.push(`${id}: ${result.warning}`);if(!chords.includes(result.chord))chords.push(result.chord)}if(chords.length===0&&anyError){warnings.push(`${id}: no valid chords \u2014 keeping the default`);continue}target.set(id,chords)}}return{entries:Array.from(merged,([id,keys])=>({id,keys})),prefixEntries:Array.from(prefixMerged,([id,keys])=>({id,keys})),warnings}}var FIXED_BINDING_IDS={"diff.review.cursor":"diff-review cursor is a fixed raw binding (j/k), not keymap-driven","diff.review.range":"diff-review range anchor is a fixed raw binding (v), not keymap-driven","diff.review.note":"diff-review note is a fixed raw binding (c), not keymap-driven","diff.review.send":"diff-review send is a fixed raw binding (s), not keymap-driven","diff.review.drop":"diff-review drop-note is a fixed raw binding (x), not keymap-driven","diff.review.reload":"preview reload is a fixed raw binding (r), not keymap-driven"};function pairContract(first,second){let layout=`alternating [${first}, ${second}] pairs`;return{layout,validateCount:(count)=>count>=2&&count%2===0?null:`needs ${layout} (an even number of chords \u2014 got ${count})`}}var SLOT_CONTRACTS={"sidebar.goto":pairContract("top (double-tap)","bottom"),"sidebar.nav":pairContract("down","up"),"files.nav":pairContract("down","up"),"sidebar.search.nav":pairContract("down","up"),"files.hierarchy":pairContract("collapse","expand"),"files.tab":pairContract("previous tab","next tab"),"app.quit":{layout:"[quit confirm, hard exit] (second chord optional)",validateCount:(count)=>count<=2?null:`needs [quit confirm, hard exit] (1 or 2 chords \u2014 got ${count})`}},NO_BARE_LETTER_SCOPES=new Set(["global","workspace","terminal"]);function scopesOverlap(a,b){return a===b||a==="global"||b==="global"}function applyKeymapOverrides(keymap,entries,fixedIds=FIXED_BINDING_IDS){let warnings=[],applied=[];for(let entry of entries){let row=keymap.find((b)=>b.id===entry.id);if(!row){warnings.push(`${entry.id}: unknown binding id (press F1 in Rove for the full list)`);continue}let fixedReason=fixedIds[entry.id];if(fixedReason){warnings.push(`${entry.id}: not customizable \u2014 ${fixedReason}`);continue}if(row.keys.length===0&&row.prefixKeys===void 0){warnings.push(`${entry.id}: not customizable \u2014 the key is handled outside the keymap (doc-only row)`);continue}let contract=SLOT_CONTRACTS[entry.id];if(contract&&entry.keys.length>0){let problem=contract.validateCount(entry.keys.length);if(problem){warnings.push(`${entry.id}: ${problem} \u2014 keeping the default`);continue}}let keys=entry.keys.filter((chord)=>{if((chord.length===1||chord.startsWith("shift+")&&chord.length===7)&&NO_BARE_LETTER_SCOPES.has(row.scope))return warnings.push(`${entry.id}: "${chord}" dropped \u2014 a bare character on a ${row.scope}-scope binding would steal typed input (add a modifier)`),!1;return!0});if(keys.length===0&&entry.keys.length>0){warnings.push(`${entry.id}: no chords survived validation \u2014 keeping the default`);continue}if(contract&&keys.length!==entry.keys.length){warnings.push(`${entry.id}: a dropped chord would shift the slot layout (${contract.layout}) \u2014 keeping the default`);continue}let defaultKeys=row.keys,mutable=row;if(mutable.keys=keys,row.hint)if(keys.length===0)mutable.hint=void 0;else row.hint.keys=keys.join("/");applied.push({id:entry.id,keys,defaultKeys})}for(let change of applied)for(let chord of change.keys){let owner=keymap.find((b)=>b.id===change.id);if(!owner)continue;for(let other of keymap){if(other.id===change.id)continue;if(!other.keys.includes(chord))continue;if(!scopesOverlap(owner.scope,other.scope))continue;warnings.push(`${change.id}: "${chord}" also fires ${other.id} (${other.scope} scope) \u2014 last registration wins; consider a different chord`)}}return{applied,warnings}}var PLATFORM_SECTIONS={darwin:["darwin","macos","mac"],linux:["linux"],win32:["win32","windows"]},VALUE_RE=/^(pane|action):\s*([A-Za-z0-9][A-Za-z0-9._:-]*\.[A-Za-z0-9][A-Za-z0-9_:-]*)$/;function sectionOf(doc,key){if(typeof doc!=="object"||doc===null)return null;let section=doc[key];if(typeof section!=="object"||section===null||Array.isArray(section))return null;return section}function collect(section,into,warnings){for(let[rawChord,rawValue]of Object.entries(section)){if(typeof rawValue!=="string"){warnings.push(`plugins: ${rawChord}: value must be a "pane:<id>" or "action:<id>" string`);continue}let match=rawValue.trim().match(VALUE_RE);if(!match){warnings.push(`plugins: ${rawChord}: \`${rawValue}\` is not pane:<plugin-id>.<local-id> or action:<...>`);continue}let chord=normalizeChord(rawChord);if("error"in chord){warnings.push(`plugins: ${rawChord}: ${chord.error}`);continue}if(chord.warning)warnings.push(`plugins: ${rawChord}: ${chord.warning}`);into.set(chord.chord,{chord:chord.chord,kind:match[1],target:match[2].trim()})}}function extractPluginKeybindings(doc,platform){let warnings=[],byChord=new Map,base=sectionOf(doc,"plugins");if(base)collect(base,byChord,warnings);for(let alias of PLATFORM_SECTIONS[platform]??[]){let overlaySection=sectionOf(doc,alias),overlay=overlaySection?sectionOf(overlaySection,"plugins"):null;if(overlay)collect(overlay,byChord,warnings)}return{entries:[...byChord.values()],warnings}}function platformKeys(platform){if(platform==="darwin")return["darwin","macos","mac"];if(platform==="win32")return["win32","windows"];return[platform]}function collectEntries(source,warnings){let out=new Map;if(source===void 0)return out;if(!isObject(source))return warnings.push("prefix.bindings must be a mapping of binding id to chord(s)"),out;for(let[id,raw]of Object.entries(source)){if(raw===null||Array.isArray(raw)&&raw.length===0){out.set(id,[]);continue}let rawKeys=typeof raw==="string"?[raw]:Array.isArray(raw)?raw:null;if(!rawKeys||rawKeys.some((key)=>typeof key!=="string")){warnings.push(`prefix.bindings.${id} must be a chord string, a string list, null, or []`);continue}let keys=[],anyError=!1;for(let rawKey of rawKeys){let normalized=normalizeChord(rawKey);if("error"in normalized){warnings.push(`prefix.bindings.${id}: ${normalized.error}`),anyError=!0;continue}if(!keys.includes(normalized.chord))keys.push(normalized.chord);if(normalized.warning)warnings.push(`prefix.bindings.${id}: ${normalized.warning}`)}if(keys.length===0&&anyError){warnings.push(`prefix.bindings.${id}: no valid chords \u2014 keeping the default`);continue}out.set(id,keys)}return out}function prefixChord(raw,warnings){let normalized=normalizeChord(raw);if("error"in normalized)warnings.push(`prefix.key: ${normalized.error}`);else if(!normalized.chord.includes("+"))warnings.push("prefix.key must include a modifier");else return normalized.chord;return null}function mergePrefixKey(raw,configuration,warnings){if(raw===null||Array.isArray(raw)&&raw.length===0){configuration.key=null,configuration.extraKeys=void 0;return}let rawKeys=typeof raw==="string"?[raw]:Array.isArray(raw)?raw:null;if(!rawKeys||rawKeys.some((key)=>typeof key!=="string")){warnings.push("prefix.key must be a modifier chord, a list of them, or null");return}let keys=[];for(let rawKey of rawKeys){let chord=prefixChord(rawKey,warnings);if(chord!==null&&!keys.includes(chord))keys.push(chord)}let[primary,...extra]=keys;if(primary===void 0)return;if(configuration.key=primary,extra.length>0)configuration.extraKeys=extra;else configuration.extraKeys=void 0}function mergePrefixBlock(raw,configuration,entries,warnings){if(raw===void 0)return;if(!isObject(raw)){warnings.push("prefix must be a mapping");return}if("key"in raw)mergePrefixKey(raw.key,configuration,warnings);if("timeoutMs"in raw)if(typeof raw.timeoutMs!=="number"||!Number.isInteger(raw.timeoutMs)||raw.timeoutMs<100||raw.timeoutMs>1e4)warnings.push("prefix.timeoutMs must be an integer from 100 to 10000");else configuration.timeoutMs=raw.timeoutMs;for(let[id,keys]of collectEntries(raw.bindings,warnings))entries.set(id,keys)}function extractPrefixKeybindings(doc,platform){let configuration={},warnings=[],entries=new Map;if(!isObject(doc)){if(doc!==null&&doc!==void 0)warnings.push("keybindings document must be a mapping");return{configuration,entries:[],warnings}}mergePrefixBlock(doc.prefix,configuration,entries,warnings);for(let key of platformKeys(platform)){let overlay=doc[key];if(isObject(overlay))mergePrefixBlock(overlay.prefix,configuration,entries,warnings)}return{configuration,entries:[...entries].map(([id,keys])=>({id,keys})),warnings}}function applyPrefixKeymapOverrides(keymap,entries){let applied=[],warnings=[];for(let entry of entries){let row=keymap.find((candidate)=>candidate.id===entry.id);if(!row){warnings.push(`${entry.id}: unknown binding id`);continue}let mutable=row,defaultKeys=[...row.prefixKeys??[]];mutable.prefixKeys=[...entry.keys],applied.push({id:entry.id,keys:[...entry.keys],defaultKeys})}return{applied,warnings}}function resolveUserKeybindings(file,keymap,platform){if(!file.exists)return{report:{path:file.path,exists:!1,applied:[],plugins:[],warnings:[]},prefix:{...DEFAULT_PREFIX_CONFIGURATION}};let warnings=[...file.warnings],extracted=extractKeybindingOverrides(file.doc,platform);warnings.push(...extracted.warnings);let prefix=extractPrefixKeybindings(file.doc,platform);warnings.push(...prefix.warnings);let prefixConfiguration2={...DEFAULT_PREFIX_CONFIGURATION,...prefix.configuration},result=applyKeymapOverrides(keymap,extracted.entries);warnings.push(...result.warnings);let applied=[...result.applied],customPrefix=prefix.configuration.key===void 0?[]:prefixFirstStrokes(prefixConfiguration2);for(let prefixKey of customPrefix){let directOwner=keymap.find((row)=>row.keys.includes(prefixKey));if(directOwner)warnings.push(`prefix.key "${prefixKey}" collides with direct binding ${directOwner.id}`)}let prefixResult=applyPrefixKeymapOverrides(keymap,[...extracted.prefixEntries,...prefix.entries]);warnings.push(...prefixResult.warnings),applied.push(...prefixResult.applied);let plugins=extractPluginKeybindings(file.doc,platform);warnings.push(...plugins.warnings);for(let p of plugins.entries){let owner=keymap.find((row)=>row.keys.includes(p.chord));if(owner)warnings.push(`plugins: ${p.chord} shadows ${owner.id}`)}return{report:{path:file.path,exists:!0,applied,plugins:plugins.entries,warnings},prefix:prefixConfiguration2}}var CHAT_BINDINGS=[{id:"chat.tab.new",scope:"workspace",keys:["ctrl+t"],category:"Workspace",description:"New chat tab",hint:{keys:"ctrl+t"},presentation:"onePress"},{id:"chat.tab.chooseEngine",scope:"workspace",keys:["ctrl+e"],category:"Workspace",description:"New conversation \u2014 engine/shell picker with destination + context toggles",hint:{keys:"ctrl+e"},presentation:"onePress"},{id:"chat.tab.fork",scope:"workspace",keys:[],prefixKeys:["c"],category:"Workspace",description:"Fork this chat into a new tab (same Task directory, keeps the conversation)",hint:{keys:"ctrl+a c"}},{id:"chat.fork.new",scope:"workspace",keys:[],prefixKeys:["f"],category:"Workspace",description:"Quick-fork: create child task seeded with current repo/branch/model",hint:{keys:"ctrl+a f"}},{id:"chat.tab.close",scope:"workspace",keys:["ctrl+w"],prefixKeys:["w"],category:"Workspace",description:"Close chat tab",hint:{keys:"ctrl+w"},presentation:"onePress"},{id:"workspace.reopenSession",scope:"workspace",keys:["return"],category:"Workspace",description:"Reopen a session in a task whose tabs are all closed",hint:{keys:"enter"},presentation:"onePress"},{id:"chat.tab.rename",scope:"workspace",keys:["f2"],category:"Workspace",description:"Rename active chat tab",hint:{keys:"f2"},presentation:"onePress"},{id:"chat.tab.cycle-next",scope:"workspace",keys:["ctrl+]"],category:"Workspace",description:"Next chat tab",hint:{keys:"ctrl+]"},presentation:"onePress"},{id:"chat.tab.cycle-prev",scope:"workspace",keys:["ctrl+["],category:"Workspace",description:"Previous chat tab",hint:{keys:"ctrl+["},presentation:"onePress"},{id:"chat.tab.goto",scope:"workspace",keys:["1","2","3","4","5","6","7","8","9"].map((digit)=>`ctrl+${digit}`),category:"Workspace",description:"Go to chat tab N",hint:{keys:"ctrl+1-9"},presentation:"onePress"},{id:"workspace.split.right",scope:"workspace",keys:["ctrl+\\"],category:"Workspace",description:"Split right",hint:{keys:"ctrl+\\"},presentation:"onePress"},{id:"workspace.split.down",scope:"workspace",keys:["ctrl+="],category:"Workspace",description:"Split down",hint:{keys:"ctrl+="},presentation:"onePress"},{id:"workspace.split.focus-next",scope:"workspace",keys:["f3"],category:"Workspace",description:"Focus next split",hint:{keys:"f3"},presentation:"onePress"},{id:"workspace.split.close",scope:"workspace",keys:["ctrl+w"],prefixKeys:["w"],category:"Workspace",description:"Close active split (tab when unsplit)",hint:{keys:"ctrl+w"},presentation:"onePress"},{id:"workspace.split.rename",scope:"workspace",keys:["f2"],category:"Workspace",description:"Rename active split (tab when unsplit)",hint:{keys:"f2"},presentation:"onePress"}];var FILES_BINDINGS=[{id:"files.nav",scope:"files",keys:["j","k","down","up"],category:"Files",description:"Move cursor up/down",hint:{keys:"j/k"}},{id:"files.hierarchy",scope:"files",keys:["h","l","left","right"],category:"Files",description:"Collapse / expand tree level",hint:{keys:"h/l"}},{id:"files.open",scope:"files",keys:["return"],category:"Files",description:"Open file in configured editor (diff when supported)",hint:{keys:"enter"}},{id:"files.tab",scope:"files",keys:["[","]"],category:"Files",description:"Switch tab (cycle All / Changes)",hint:{keys:"[/]"}},{id:"files.refresh",scope:"files",keys:["r"],category:"Files",description:"Refresh",hint:{keys:"r"}},{id:"files.scope",scope:"files",keys:["b"],category:"Files",description:"Toggle Changes scope (working \u2194 branch vs base)",hint:{keys:"b"}},{id:"files.diff",scope:"files",keys:["d"],category:"Files",description:"Open read-only diff in a workspace tab",hint:{keys:"d"}},{id:"files.diffAll",scope:"files",keys:["shift+d"],category:"Files",description:"Open the whole worktree's diff in one workspace tab",hint:{keys:"D"}},{id:"files.openExternal",scope:"files",keys:["o"],category:"Files",description:"Open file in system default app (audio / video / pdf preview)",hint:{keys:"o"}},{id:"files.mention",scope:"files",keys:["a"],category:"Files",description:"Inject @<path> mention into the engine pane",hint:{keys:"a"}},{id:"files.createPR",scope:"global",keys:[],prefixKeys:["p","shift+p"],category:"Files",description:"Ask the agent to create a PR from the current task"},{id:"files.fixChecks",scope:"global",keys:[],prefixKeys:["k"],category:"Files",description:"Ask the agent to fix the failing PR checks"},{id:"files.syncBase",scope:"global",keys:[],prefixKeys:["u"],category:"Files",description:"Merge the base branch into this task's worktree"},{id:"diff.review.cursor",scope:"workspace",keys:[],category:"Diff review",description:"Move the line cursor over the diff",hint:{keys:"j/k"}},{id:"diff.review.range",scope:"workspace",keys:[],category:"Diff review",description:"Toggle range anchor at the cursor",hint:{keys:"v"}},{id:"diff.review.note",scope:"workspace",keys:[],category:"Diff review",description:"Add a review note at the cursor",hint:{keys:"c"}},{id:"diff.review.send",scope:"workspace",keys:[],category:"Diff review",description:"Send all unsent review notes to the engine",hint:{keys:"s"}},{id:"diff.review.drop",scope:"workspace",keys:[],category:"Diff review",description:"Drop the review note the cursor sits inside",hint:{keys:"x"}},{id:"diff.review.reload",scope:"workspace",keys:[],category:"Diff review",description:"Reload the previewed file from disk",hint:{keys:"r"}}];var INBOX_BINDINGS=[{id:"inbox.show",scope:"global",keys:[],prefixKeys:["i"],category:"Global",description:"Open Inbox"},{id:"inbox.nav",scope:"inbox",keys:["j","k","down","up"],category:"Inbox",description:"Move cursor up/down",hint:{keys:"j/k"}},{id:"inbox.open",scope:"inbox",keys:["return"],category:"Inbox",description:"Open the selected Task and Terminal Tab",hint:{keys:"enter"}},{id:"inbox.delete",scope:"inbox",keys:["d"],category:"Inbox",description:"Remove the selected Inbox item",hint:{keys:"d"}}];var SIDEBAR_BINDINGS=[{id:"sidebar.nav",scope:"sidebar",keys:["j","k","down","up"],category:"Sidebar",description:"Move cursor up/down",hint:{keys:"j/k"}},{id:"sidebar.select",scope:"sidebar",keys:["return"],category:"Sidebar",description:"Open the selected task",hint:{keys:"enter"}},{id:"sidebar.tree.open",scope:"sidebar",keys:["l","space"],category:"Sidebar",description:"Open the row under the cursor (a tab row enters its chat)",hint:{keys:"l"}},{id:"sidebar.goto",scope:"sidebar",keys:["g","shift+g"],category:"Sidebar",description:"Top / bottom of list (gg or shift-G)"},{id:"sidebar.rename",scope:"sidebar",keys:["r"],category:"Sidebar",description:"Rename task",hint:{keys:"r"}},{id:"sidebar.localMerge",scope:"sidebar",keys:["shift+m"],category:"Sidebar",description:"Reorder row (Shift+M, then j/k)",hint:{keys:"M"}},{id:"sidebar.pin",scope:"sidebar",keys:["shift+p"],category:"Sidebar",description:"Pin / unpin task at top (Shift+P)",hint:{keys:"P"}},{id:"sidebar.sort",scope:"sidebar",keys:["t"],category:"Sidebar",description:"Cycle task sort (default \u2192 recent \u2192 attention \u2192 name)",hint:{keys:"t"}},{id:"sidebar.delete",scope:"sidebar",keys:["d"],category:"Sidebar",description:"Delete task (with confirm)",hint:{keys:"d"}},{id:"sidebar.search.enter",scope:"sidebar",keys:["/"],category:"Sidebar",description:"Search tasks (fuzzy filter)",hint:{keys:"/"}},{id:"sidebar.search.nav",scope:"sidebar",keys:["down","up"],category:"Sidebar",description:"Move highlight in search results"},{id:"sidebar.search.submit",scope:"sidebar",keys:["return"],category:"Sidebar",description:"Select search match and exit search"},{id:"sidebar.search.cancel",scope:"sidebar",keys:["escape"],category:"Sidebar",description:"Cancel search (restore prior selection)"},{id:"tasks.openWorktree",scope:"sidebar",keys:["o"],category:"Tasks pane",description:"Open selected Task directory in your editor",hint:{keys:"o"}},{id:"tasks.renameBranch",scope:"sidebar",keys:["b"],category:"Tasks pane",description:"Rename the selected task's git branch",hint:{keys:"b"}},{id:"tasks.cycleEngine",scope:"sidebar",keys:["v"],category:"Tasks pane",description:"Cycle engine vendor \u2014 applies on reopen",hint:{keys:"v"}},{id:"tasks.update",scope:"sidebar",keys:["u"],category:"Tasks pane",description:"Open the update page \u2014 version check + release notes",hint:{keys:"u"}},{id:"tasks.focusEngine",scope:"sidebar",keys:["right"],category:"Tasks pane",description:"Focus the engine pane of the current window",hint:{keys:"\u2192"}}];var RoveKeymap=[{id:"palette.open",scope:"global",keys:[],prefixKeys:["/"],category:"Global",description:"Search commands"},{id:"help.open",scope:"global",keys:["f1"],category:"Global",description:"Show keybindings help",hint:{keys:"F1"},presentation:"onePress"},{id:"task.new",scope:"sidebar",keys:["n"],category:"Sidebar",description:"New task",hint:{keys:"n"}},{id:"task.new.global",scope:"global",keys:[],prefixKeys:["n"],category:"Global",description:"New task"},{id:"task.openEditor",scope:"global",keys:[],prefixKeys:["o"],category:"Global",description:"Open active Task directory in editor"},{id:"task.moveMode",scope:"global",keys:[],prefixKeys:["m"],category:"Global",description:"Reorder sidebar rows (then j/k)"},{id:"settings.open",scope:"global",keys:[],prefixKeys:[","],category:"Global",description:"Open settings"},{id:"app.refresh",scope:"global",keys:[],prefixKeys:["r"],category:"Global",description:"Refresh Rove onto the installed build (after an update)"},{id:"settings.open.sidebar",scope:"sidebar",keys:["s"],category:"Sidebar",description:"Open settings",hint:{keys:"s"}},{id:"worktrees.open.sidebar",scope:"sidebar",keys:["x"],category:"Sidebar",description:"Open worktrees",hint:{keys:"x"}},{id:"kanban.open",scope:"global",keys:[],prefixKeys:["1"],category:"Global",description:"Open kanban (issues board)"},{id:"automations.open",scope:"global",keys:[],prefixKeys:["2"],category:"Global",description:"Open routines (scheduled tasks)"},{id:"workItems.open",scope:"global",keys:[],prefixKeys:["3"],category:"Global",description:"Open GitHub issues (external tracker)"},{id:"app.quit",scope:"sidebar",keys:["q","ctrl+q"],category:"Sidebar",description:"Quit (with confirm)",hint:{keys:"q"}},{id:"focus.sidebar",scope:"workspace",keys:["ctrl+q"],category:"Workspace",description:"Back to sidebar (tasks)",hint:{keys:"ctrl+q"},presentation:"onePress"},{id:"focus.previous",scope:"global",keys:[],prefixKeys:["h"],category:"Navigation",description:"Focus previous pane (files \u2192 workspace \u2192 sidebar)"},{id:"focus.next",scope:"global",keys:["f4"],prefixKeys:["l"],category:"Navigation",description:"Focus next pane (sidebar \u2192 workspace \u2192 files)",hint:{keys:"f4"},presentation:"onePress"},{id:"attention.next",scope:"global",keys:["f7"],category:"Navigation",description:"Jump to the next available Inbox item",hint:{keys:"f7"},presentation:"onePress"},{id:"workspace.zenToggle",scope:"global",keys:[],prefixKeys:["z"],category:"Navigation",description:"Toggle zen mode (hide the files column)"},{id:"view.redraw",scope:"global",keys:[],prefixKeys:["r"],category:"Global",description:"Redraw the screen"},...SIDEBAR_BINDINGS,...CHAT_BINDINGS,...FILES_BINDINGS,...INBOX_BINDINGS,{id:"terminal.scroll-up",scope:"terminal",keys:["ctrl+pageup"],category:"Terminal",description:"Scroll scrollback up",hint:{keys:"ctrl+pgup"}},{id:"terminal.scroll-down",scope:"terminal",keys:["ctrl+pagedown"],category:"Terminal",description:"Scroll scrollback down"},{id:"terminal.reset",scope:"terminal",keys:["f5"],category:"Terminal",description:"Reset terminal \u2014 kill the current shell and respawn",hint:{keys:"f5"},presentation:"onePress"},{id:"terminal.search",scope:"terminal",keys:[],prefixKeys:["/"],category:"Terminal",description:"Search the scrollback"},{id:"terminal.search.older",scope:"terminal",keys:["up","return"],category:"Terminal",description:"Scrollback search: walk to the older match"},{id:"terminal.search.newer",scope:"terminal",keys:["down"],category:"Terminal",description:"Scrollback search: walk to the newer match"},{id:"terminal.search.cancel",scope:"terminal",keys:["escape"],category:"Terminal",description:"Close scrollback search (restore prior scroll position)"}];var SOUND_VOLUME_KEY="notifications.sound.volume",DEFAULT_SOUND_VOLUME=0.4,SOUND_VOLUME_STEPS=[0.1,0.25,0.4,0.6,0.8,1];function normalizeSoundVolume(value){let n=typeof value==="number"?value:typeof value==="string"?Number.parseFloat(value.trim()):Number.NaN;if(!Number.isFinite(n))return DEFAULT_SOUND_VOLUME;return Math.min(1,Math.max(0,n))}function nextSoundVolume(volume){let current=normalizeSoundVolume(volume),above=SOUND_VOLUME_STEPS.findIndex((step)=>step>current+0.000000001);return SOUND_VOLUME_STEPS[above<0?0:above]}function persistedSoundVolume(){return normalizeSoundVolume(loadStateFile()[SOUND_VOLUME_KEY])}
|
|
2
|
+
import{errorMessage}from"./chunk-2brn8e1y.js";import{isObject}from"./chunk-7ghwdjdc.js";import{loadStateFile}from"./chunk-n3f5sdka.js";import{isDev,keybindingsConfigPath}from"./chunk-prqeddy7.js";import{createStateCell}from"./chunk-cmp64q4j.js";function hasReachableBinding(snapshot,predicate){for(let i=snapshot.length-1;i>=0;i--){let cfg=snapshot[i]?.config();if(!cfg||cfg.enabled===!1)continue;if(cfg.bindings.some(predicate))return!0;if(cfg.modal)return!1}return!1}var prefixReachable=(snapshot)=>hasReachableBinding(snapshot,(binding)=>binding.prefix===!0),inputPassthroughReachable=(snapshot)=>hasReachableBinding(snapshot,(binding)=>binding.passthrough===!0);function scanReachability(snapshot){let directIds=new Set,prefixIds=new Set,prefixReachable2=!1,inputPassthrough=!1,yieldedDirectIds=new Set,prefixOptions=[],seenPrefixKeys=new Set;for(let i=snapshot.length-1;i>=0;i--){let cfg=snapshot[i]?.config();if(!cfg||cfg.enabled===!1)continue;for(let binding of cfg.bindings){if(binding.passthrough)inputPassthrough=!0;if(binding.prefix===!0){if(prefixReachable2=!0,binding.id)prefixIds.add(binding.id);if(!seenPrefixKeys.has(binding.key))seenPrefixKeys.add(binding.key),prefixOptions.push({stroke:binding.key,action:binding.id??binding.key})}else if(binding.id){if(directIds.add(binding.id),binding.yieldToPassthrough)yieldedDirectIds.add(binding.id)}}if(cfg.modal)break}if(inputPassthrough)for(let id of yieldedDirectIds)directIds.delete(id);return{prefixReachable:prefixReachable2,inputPassthrough,prefixOptions,directIds,prefixIds}}function bindingReachability(snapshot){let{directIds,prefixIds,inputPassthrough}=scanReachability(snapshot);return{direct:directIds,prefix:prefixIds,inputPassthrough}}var PREFIX_HUD_TTL_MS=4000,PREFIX_GUIDE_DELAY_MS=180;var MAX_ENTRIES=3,realClock={now:()=>Date.now(),schedule:(fn,ms)=>{let timer=setTimeout(fn,ms);return()=>clearTimeout(timer)}},clock=realClock;function prefixHudClock(){return clock}var cell=createStateCell({guide:null,entries:[]}),nextEntryId=1,prefixHudState=cell;function prefixHudSetArmed(armed,options=[],armedAt=null){cell.update((current)=>{if(!armed)return current.guide?.kind==="prefix"?{...current,guide:null}:current;return{...current,guide:{kind:"prefix",armedAt:armedAt??clock.now(),options}}})}function prefixHudShowDirect(options){cell.update((current)=>({...current,guide:{kind:"direct",options}}))}function prefixHudHideDirect(){cell.update((current)=>current.guide?.kind==="direct"?{...current,guide:null}:current)}function prefixHudPush(entry){cell.update((current)=>({...current,guide:null,entries:[...current.entries,{...entry,id:nextEntryId++}].slice(-MAX_ENTRIES)}))}function matchKey(evt){let base=[],name=evt.name;if(name)base.push(name);if(name==="return")base.push("enter");if(name==="enter")base.push("return");if(name==="backspace"&&evt.raw==="\b"&&!evt.meta&&!evt.option)base.push("ctrl+h");if(name==="linefeed"&&!evt.meta&&!evt.option)base.push("ctrl+j");let mods=[];if(evt.ctrl)mods.push("ctrl");if(evt.meta||evt.super)mods.push("cmd");if(evt.option)mods.push("alt");let bareShiftChar=evt.shift&&name!==void 0&&name.length===1&&mods.length===0;if(evt.shift&&name&&name.length>1)mods.push("shift");if(mods.length===0){if(bareShiftChar)return[...base.map((n)=>`shift+${n}`),...base];return base}let prefix=`${mods.join("+")}+`,prefixed=base.map((n)=>prefix+n);if(evt.shift&&name!==void 0&&name.length===1&&evt.source==="kitty")return[...base.map((n)=>`${mods.join("+")}+shift+${n}`),...prefixed];return prefixed}var KITTY_MODIFIER_KEY_NAMES=["leftshift","leftctrl","leftalt","leftsuper","lefthyper","leftmeta","rightshift","rightctrl","rightalt","rightsuper","righthyper","rightmeta","iso_level3_shift","iso_level5_shift"],KITTY_MODIFIER_KEYS=new Set(KITTY_MODIFIER_KEY_NAMES);function isKittyModifierKeyName(name){return name!==void 0&&KITTY_MODIFIER_KEYS.has(name)}function isKittyModifierKeyEvent(event){return isKittyModifierKeyName(event.name)}function isCtrlModifierKeyName(name){return name==="leftctrl"||name==="rightctrl"}function prefixAction(run){return{run}}function insertRegistration(stack,reg){if(reg.modalOwner!==void 0){let firstMember=stack.findIndex((r)=>r.modalMember===reg.modalOwner);if(firstMember>=0){stack.splice(firstMember,0,reg);return}}stack.push(reg)}var dispatching=!1,DEFAULT_PREFIX_CONFIGURATION={key:"ctrl+a",timeoutMs:5000},prefixConfiguration={...DEFAULT_PREFIX_CONFIGURATION},prefixArmedAt=null,prefixArmedKey="",prefixArmedOnPassthrough=!1,prefixArmedOptions=[],prefixTimer=null;function configurePrefix(next){prefixConfiguration={...next},resetPrefixState()}function resetPrefixConfiguration(){prefixConfiguration={...DEFAULT_PREFIX_CONFIGURATION},resetPrefixState()}function currentPrefixConfiguration(){return prefixConfiguration}function prefixFirstStrokes(config=prefixConfiguration){if(config.key===null)return[];return[config.key,...config.extraKeys??[]]}function resetPrefixState(){if(prefixTimer!==null)clearTimeout(prefixTimer);prefixTimer=null,prefixArmedAt=null,prefixArmedOnPassthrough=!1,prefixArmedOptions=[],prefixHudSetArmed(!1)}function armPrefix(now,options,inputPassthrough,armedKey=prefixConfiguration.key??""){resetPrefixState(),prefixArmedAt=now,prefixArmedKey=armedKey,prefixArmedOnPassthrough=inputPassthrough,prefixArmedOptions=options.slice(),prefixTimer=setTimeout(resetPrefixState,prefixConfiguration.timeoutMs),prefixHudSetArmed(!0,options,now)}function armPrefixNow(snapshot,now=Date.now()){if(prefixConfiguration.key===null)return!1;let reach=scanReachability(snapshot);if(!reach.prefixReachable)return!1;return armPrefix(now,reach.prefixOptions,reach.inputPassthrough),!0}function invokeArmedPrefixAction(bindingStack,actionId,stroke,now=Date.now()){if(dispatching||prefixArmedAt===null)return!1;let snapshot=bindingStack.slice(),armedPrefixKey=prefixArmedKey,validOption=prefixArmedOptions.some((option)=>option.action===actionId&&option.stroke===stroke),expired=now-prefixArmedAt>prefixConfiguration.timeoutMs,crossedBoundary=inputPassthroughReachable(snapshot)!==prefixArmedOnPassthrough;if(!validOption||expired||crossedBoundary)return resetPrefixState(),!1;let hit=null;for(let i=snapshot.length-1;i>=0;i--){let reg=snapshot[i];if(!reg)continue;let cfg=reg.config();if(cfg.enabled===!1)continue;let candidate=cfg.bindings.find((binding)=>binding.prefix===!0&&binding.key===stroke);if(candidate){if(candidate.id===actionId)hit=candidate;break}if(cfg.modal)break}if(!hit?.action)return resetPrefixState(),!1;resetPrefixState(),dispatching=!0;try{return hit.action.run(),prefixHudPush({prefixKey:armedPrefixKey,stroke,action:actionId,at:now}),!0}finally{dispatching=!1}}var shadowWarned=new Set;function warnShadowedMatch(snapshot,hitIndex,candidates,prefix){for(let j=hitIndex-1;j>=0;j--){let cfg=snapshot[j]?.config();if(!cfg||cfg.enabled===!1)continue;let shadowed=cfg.bindings.find((b)=>Boolean(b.prefix)===prefix&&candidates.includes(b.key));if(shadowed){if(!shadowWarned.has(shadowed.key))shadowWarned.add(shadowed.key),console.error(`[rove keymap] "${shadowed.key}" matched two ENABLED bindings \u2014 the lower one is shadowed by LIFO order. Gate one of them off (see tui-react/lib/keymap.ts header).`);return}if(cfg.modal)return}}function dispatchMode(snapshot,evt,candidates,prefix,runCmd){for(let i=snapshot.length-1;i>=0;i--){let reg=snapshot[i];if(!reg)continue;let cfg=reg.config();if(cfg.enabled===!1)continue;let hit;for(let candidate of candidates)if(hit=cfg.bindings.find((binding)=>Boolean(binding.prefix)===prefix&&binding.key===candidate),hit)break;if(hit){if(hit.yieldToPassthrough&&inputPassthroughReachable(snapshot))continue;if(!cfg.modal&&isDev())warnShadowedMatch(snapshot,i,candidates,prefix);return runCmd(()=>hit.cmd(evt,hit.slot)),hit}if(cfg.modal)return null}return null}function dispatchKeyEvent(bindingStack,evt,now=Date.now(),opts){if(evt.defaultPrevented||dispatching)return!1;if(isKittyModifierKeyName(evt.name))return evt.preventDefault(),!0;let snapshot=bindingStack.slice(),candidates=matchKey(evt),runCmd=opts?.flushSync??((fn)=>fn());dispatching=!0;try{if(prefixArmedAt!==null&&inputPassthroughReachable(snapshot)!==prefixArmedOnPassthrough)resetPrefixState();if(prefixArmedAt!==null){let armedPrefixKey=prefixArmedKey,expired=now-prefixArmedAt>prefixConfiguration.timeoutMs;if(prefixArmedAt=null,expired)resetPrefixState();else{if(candidates.includes("escape"))return resetPrefixState(),evt.preventDefault(),!0;resetPrefixState();let hit=dispatchMode(snapshot,evt,candidates,!0,runCmd);return prefixHudPush({prefixKey:armedPrefixKey,stroke:candidates[0]??"",action:hit?hit.id??hit.key:null,at:now}),evt.preventDefault(),!0}}let firstStroke=prefixFirstStrokes().find((key)=>candidates.includes(key));if(firstStroke!==void 0){if(prefixReachable(snapshot)){let reach=scanReachability(snapshot);return armPrefix(now,reach.prefixOptions,reach.inputPassthrough,firstStroke),evt.preventDefault(),!0}}let direct=dispatchMode(snapshot,evt,candidates,!1,runCmd);if(direct){if(direct.id&&direct.key.includes("+")&&!direct.key.startsWith("shift+"))prefixHudPush({prefixKey:"",stroke:direct.key,action:direct.id??direct.key,at:now});return evt.preventDefault(),!0}return!1}finally{dispatching=!1}}import{existsSync,readFileSync}from"fs";var cached=null;function resetKeybindingsFileCache(){cached=null}function resolveConfigFile(){let canonical=keybindingsConfigPath();if(existsSync(canonical))return{canonical,found:canonical};let yml=canonical.replace(/\.yaml$/,".yml");if(existsSync(yml))return{canonical,found:yml};return{canonical,found:null}}function readKeybindingsFile(){if(cached)return cached;let{canonical,found}=resolveConfigFile();if(!found)return cached={path:canonical,exists:!1,doc:null,warnings:[]},cached;let warnings=[],doc=null;try{let text=readFileSync(found,"utf8");doc=Bun.YAML.parse(text)}catch(err){let msg=errorMessage(err);warnings.push(`could not read/parse ${found}: ${msg}`)}return cached={path:canonical,exists:!0,doc,warnings},cached}var MOD_ALIASES={ctrl:"ctrl",control:"ctrl",ctl:"ctrl",cmd:"cmd",command:"cmd",meta:"cmd",super:"cmd",win:"cmd",alt:"alt",option:"alt",opt:"alt",shift:"shift"},KEY_ALIASES={esc:"escape",spacebar:"space",pgup:"pageup",pgdn:"pagedown",pgdown:"pagedown"},KNOWN_NAMED_KEYS=new Set(["up","down","left","right","pageup","pagedown","home","end","insert","delete","backspace","tab","space","escape","enter","return",...Array.from({length:12},(_,i)=>`f${i+1}`)]),MOD_ORDER=["ctrl","cmd","alt","shift"];function normalizeChord(raw){let rawTrimmed=raw.trim(),upperLetterKey=rawTrimmed.length===1&&rawTrimmed>="A"&&rawTrimmed<="Z",trimmed=raw.trim().toLowerCase();if(!trimmed)return{error:"empty chord"};let parts=trimmed.split("+"),key=parts.pop()??"";if(key===""&&parts.length>0&&parts[parts.length-1]==="")key="+",parts.pop();if(!key)return{error:`"${raw}": no key after the modifiers`};let mods=new Set;for(let part of parts){let mod=MOD_ALIASES[part];if(!mod)return{error:`"${raw}": unknown modifier "${part}" (use ctrl / cmd / alt / shift)`};mods.add(mod)}if(key=KEY_ALIASES[key]??key,upperLetterKey)mods.add("shift");if(mods.has("shift")&&mods.size>1&&key.length===1)return{error:`"${raw}": shift with other modifiers on a single character can never match \u2014 legacy terminals send the same byte with and without shift`};let prefix=MOD_ORDER.filter((m)=>mods.has(m)).join("+"),chord=prefix?`${prefix}+${key}`:key;if(key.length>1&&!KNOWN_NAMED_KEYS.has(key))return{chord,warning:`"${raw}": unrecognized key name "${key}" \u2014 the chord may never fire`};return{chord}}function platformSectionNames(platform){if(platform==="darwin")return["darwin","macos","mac"];if(platform==="win32")return["win32","windows"];return[platform]}function extractBindingsMap(section){if(!isObject(section))return null;let nested=section.bindings;if(isObject(nested))return nested;return section}function extractKeybindingOverrides(doc,platform){let warnings=[];if(doc===null||doc===void 0)return{entries:[],prefixEntries:[],warnings};if(!isObject(doc))return{entries:[],prefixEntries:[],warnings:["config root must be a YAML mapping (e.g. a top-level `bindings:` key)"]};let merged=new Map,prefixMerged=new Map,layers=[];if(doc.bindings!==void 0)if(isObject(doc.bindings))layers.push(doc.bindings);else warnings.push("`bindings:` must be a mapping of id \u2192 chord(s)");for(let name of platformSectionNames(platform)){let section=doc[name];if(section===void 0)continue;let map=extractBindingsMap(section);if(map)layers.push(map);else warnings.push(`\`${name}:\` must be a mapping (or contain a \`bindings:\` mapping)`)}for(let layer of layers)for(let[id,value]of Object.entries(layer)){let modeValues=isObject(value)&&(("direct"in value)||("prefix"in value))?[[merged,value.direct],[prefixMerged,value.prefix]]:[[merged,value]];for(let[target,modeValue]of modeValues){if(modeValue===void 0)continue;if(modeValue===null||modeValue===!1||Array.isArray(modeValue)&&modeValue.length===0){target.set(id,[]);continue}let rawChords=typeof modeValue==="string"?[modeValue]:Array.isArray(modeValue)?modeValue:null;if(!rawChords){warnings.push(`${id}: expected a chord string, a list of chords, or null \u2014 got ${typeof modeValue}`);continue}let chords=[],anyError=!1;for(let rawChord of rawChords){if(typeof rawChord!=="string"){warnings.push(`${id}: chord entries must be strings`),anyError=!0;continue}let result=normalizeChord(rawChord);if("error"in result){warnings.push(`${id}: ${result.error}`),anyError=!0;continue}if(result.warning)warnings.push(`${id}: ${result.warning}`);if(!chords.includes(result.chord))chords.push(result.chord)}if(chords.length===0&&anyError){warnings.push(`${id}: no valid chords \u2014 keeping the default`);continue}target.set(id,chords)}}return{entries:Array.from(merged,([id,keys])=>({id,keys})),prefixEntries:Array.from(prefixMerged,([id,keys])=>({id,keys})),warnings}}var FIXED_BINDING_IDS={"diff.review.cursor":"diff-review cursor is a fixed raw binding (j/k), not keymap-driven","diff.review.range":"diff-review range anchor is a fixed raw binding (v), not keymap-driven","diff.review.note":"diff-review note is a fixed raw binding (c), not keymap-driven","diff.review.send":"diff-review send is a fixed raw binding (s), not keymap-driven","diff.review.drop":"diff-review drop-note is a fixed raw binding (x), not keymap-driven","diff.review.reload":"preview reload is a fixed raw binding (r), not keymap-driven"};function pairContract(first,second){let layout=`alternating [${first}, ${second}] pairs`;return{layout,validateCount:(count)=>count>=2&&count%2===0?null:`needs ${layout} (an even number of chords \u2014 got ${count})`}}var SLOT_CONTRACTS={"sidebar.goto":pairContract("top (double-tap)","bottom"),"sidebar.nav":pairContract("down","up"),"files.nav":pairContract("down","up"),"sidebar.search.nav":pairContract("down","up"),"files.hierarchy":pairContract("collapse","expand"),"files.tab":pairContract("previous tab","next tab"),"app.quit":{layout:"[quit confirm, hard exit] (second chord optional)",validateCount:(count)=>count<=2?null:`needs [quit confirm, hard exit] (1 or 2 chords \u2014 got ${count})`}},NO_BARE_LETTER_SCOPES=new Set(["global","workspace","terminal"]);function scopesOverlap(a,b){return a===b||a==="global"||b==="global"}function applyKeymapOverrides(keymap,entries,fixedIds=FIXED_BINDING_IDS){let warnings=[],applied=[];for(let entry of entries){let row=keymap.find((b)=>b.id===entry.id);if(!row){warnings.push(`${entry.id}: unknown binding id (press F1 in Rove for the full list)`);continue}let fixedReason=fixedIds[entry.id];if(fixedReason){warnings.push(`${entry.id}: not customizable \u2014 ${fixedReason}`);continue}if(row.keys.length===0&&row.prefixKeys===void 0){warnings.push(`${entry.id}: not customizable \u2014 the key is handled outside the keymap (doc-only row)`);continue}let contract=SLOT_CONTRACTS[entry.id];if(contract&&entry.keys.length>0){let problem=contract.validateCount(entry.keys.length);if(problem){warnings.push(`${entry.id}: ${problem} \u2014 keeping the default`);continue}}let keys=entry.keys.filter((chord)=>{if((chord.length===1||chord.startsWith("shift+")&&chord.length===7)&&NO_BARE_LETTER_SCOPES.has(row.scope))return warnings.push(`${entry.id}: "${chord}" dropped \u2014 a bare character on a ${row.scope}-scope binding would steal typed input (add a modifier)`),!1;return!0});if(keys.length===0&&entry.keys.length>0){warnings.push(`${entry.id}: no chords survived validation \u2014 keeping the default`);continue}if(contract&&keys.length!==entry.keys.length){warnings.push(`${entry.id}: a dropped chord would shift the slot layout (${contract.layout}) \u2014 keeping the default`);continue}let defaultKeys=row.keys,mutable=row;if(mutable.keys=keys,row.hint)if(keys.length===0)mutable.hint=void 0;else row.hint.keys=keys.join("/");applied.push({id:entry.id,keys,defaultKeys})}for(let change of applied)for(let chord of change.keys){let owner=keymap.find((b)=>b.id===change.id);if(!owner)continue;for(let other of keymap){if(other.id===change.id)continue;if(!other.keys.includes(chord))continue;if(!scopesOverlap(owner.scope,other.scope))continue;warnings.push(`${change.id}: "${chord}" also fires ${other.id} (${other.scope} scope) \u2014 last registration wins; consider a different chord`)}}return{applied,warnings}}var PLATFORM_SECTIONS={darwin:["darwin","macos","mac"],linux:["linux"],win32:["win32","windows"]},VALUE_RE=/^(pane|action):\s*([A-Za-z0-9][A-Za-z0-9._:-]*\.[A-Za-z0-9][A-Za-z0-9_:-]*)$/;function sectionOf(doc,key){if(typeof doc!=="object"||doc===null)return null;let section=doc[key];if(typeof section!=="object"||section===null||Array.isArray(section))return null;return section}function collect(section,into,warnings){for(let[rawChord,rawValue]of Object.entries(section)){if(typeof rawValue!=="string"){warnings.push(`plugins: ${rawChord}: value must be a "pane:<id>" or "action:<id>" string`);continue}let match=rawValue.trim().match(VALUE_RE);if(!match){warnings.push(`plugins: ${rawChord}: \`${rawValue}\` is not pane:<plugin-id>.<local-id> or action:<...>`);continue}let chord=normalizeChord(rawChord);if("error"in chord){warnings.push(`plugins: ${rawChord}: ${chord.error}`);continue}if(chord.warning)warnings.push(`plugins: ${rawChord}: ${chord.warning}`);into.set(chord.chord,{chord:chord.chord,kind:match[1],target:match[2].trim()})}}function extractPluginKeybindings(doc,platform){let warnings=[],byChord=new Map,base=sectionOf(doc,"plugins");if(base)collect(base,byChord,warnings);for(let alias of PLATFORM_SECTIONS[platform]??[]){let overlaySection=sectionOf(doc,alias),overlay=overlaySection?sectionOf(overlaySection,"plugins"):null;if(overlay)collect(overlay,byChord,warnings)}return{entries:[...byChord.values()],warnings}}function platformKeys(platform){if(platform==="darwin")return["darwin","macos","mac"];if(platform==="win32")return["win32","windows"];return[platform]}function collectEntries(source,warnings){let out=new Map;if(source===void 0)return out;if(!isObject(source))return warnings.push("prefix.bindings must be a mapping of binding id to chord(s)"),out;for(let[id,raw]of Object.entries(source)){if(raw===null||Array.isArray(raw)&&raw.length===0){out.set(id,[]);continue}let rawKeys=typeof raw==="string"?[raw]:Array.isArray(raw)?raw:null;if(!rawKeys||rawKeys.some((key)=>typeof key!=="string")){warnings.push(`prefix.bindings.${id} must be a chord string, a string list, null, or []`);continue}let keys=[],anyError=!1;for(let rawKey of rawKeys){let normalized=normalizeChord(rawKey);if("error"in normalized){warnings.push(`prefix.bindings.${id}: ${normalized.error}`),anyError=!0;continue}if(!keys.includes(normalized.chord))keys.push(normalized.chord);if(normalized.warning)warnings.push(`prefix.bindings.${id}: ${normalized.warning}`)}if(keys.length===0&&anyError){warnings.push(`prefix.bindings.${id}: no valid chords \u2014 keeping the default`);continue}out.set(id,keys)}return out}function prefixChord(raw,warnings){let normalized=normalizeChord(raw);if("error"in normalized)warnings.push(`prefix.key: ${normalized.error}`);else if(!normalized.chord.includes("+"))warnings.push("prefix.key must include a modifier");else return normalized.chord;return null}function mergePrefixKey(raw,configuration,warnings){if(raw===null||Array.isArray(raw)&&raw.length===0){configuration.key=null,configuration.extraKeys=void 0;return}let rawKeys=typeof raw==="string"?[raw]:Array.isArray(raw)?raw:null;if(!rawKeys||rawKeys.some((key)=>typeof key!=="string")){warnings.push("prefix.key must be a modifier chord, a list of them, or null");return}let keys=[];for(let rawKey of rawKeys){let chord=prefixChord(rawKey,warnings);if(chord!==null&&!keys.includes(chord))keys.push(chord)}let[primary,...extra]=keys;if(primary===void 0)return;if(configuration.key=primary,extra.length>0)configuration.extraKeys=extra;else configuration.extraKeys=void 0}function mergePrefixBlock(raw,configuration,entries,warnings){if(raw===void 0)return;if(!isObject(raw)){warnings.push("prefix must be a mapping");return}if("key"in raw)mergePrefixKey(raw.key,configuration,warnings);if("timeoutMs"in raw)if(typeof raw.timeoutMs!=="number"||!Number.isInteger(raw.timeoutMs)||raw.timeoutMs<100||raw.timeoutMs>1e4)warnings.push("prefix.timeoutMs must be an integer from 100 to 10000");else configuration.timeoutMs=raw.timeoutMs;for(let[id,keys]of collectEntries(raw.bindings,warnings))entries.set(id,keys)}function extractPrefixKeybindings(doc,platform){let configuration={},warnings=[],entries=new Map;if(!isObject(doc)){if(doc!==null&&doc!==void 0)warnings.push("keybindings document must be a mapping");return{configuration,entries:[],warnings}}mergePrefixBlock(doc.prefix,configuration,entries,warnings);for(let key of platformKeys(platform)){let overlay=doc[key];if(isObject(overlay))mergePrefixBlock(overlay.prefix,configuration,entries,warnings)}return{configuration,entries:[...entries].map(([id,keys])=>({id,keys})),warnings}}function applyPrefixKeymapOverrides(keymap,entries){let applied=[],warnings=[];for(let entry of entries){let row=keymap.find((candidate)=>candidate.id===entry.id);if(!row){warnings.push(`${entry.id}: unknown binding id`);continue}let mutable=row,defaultKeys=[...row.prefixKeys??[]];mutable.prefixKeys=[...entry.keys],applied.push({id:entry.id,keys:[...entry.keys],defaultKeys})}return{applied,warnings}}function resolveUserKeybindings(file,keymap,platform){if(!file.exists)return{report:{path:file.path,exists:!1,applied:[],plugins:[],warnings:[]},prefix:{...DEFAULT_PREFIX_CONFIGURATION}};let warnings=[...file.warnings],extracted=extractKeybindingOverrides(file.doc,platform);warnings.push(...extracted.warnings);let prefix=extractPrefixKeybindings(file.doc,platform);warnings.push(...prefix.warnings);let prefixConfiguration2={...DEFAULT_PREFIX_CONFIGURATION,...prefix.configuration},result=applyKeymapOverrides(keymap,extracted.entries);warnings.push(...result.warnings);let applied=[...result.applied],customPrefix=prefix.configuration.key===void 0?[]:prefixFirstStrokes(prefixConfiguration2);for(let prefixKey of customPrefix){let directOwner=keymap.find((row)=>row.keys.includes(prefixKey));if(directOwner)warnings.push(`prefix.key "${prefixKey}" collides with direct binding ${directOwner.id}`)}let prefixResult=applyPrefixKeymapOverrides(keymap,[...extracted.prefixEntries,...prefix.entries]);warnings.push(...prefixResult.warnings),applied.push(...prefixResult.applied);let plugins=extractPluginKeybindings(file.doc,platform);warnings.push(...plugins.warnings);for(let p of plugins.entries){let owner=keymap.find((row)=>row.keys.includes(p.chord));if(owner)warnings.push(`plugins: ${p.chord} shadows ${owner.id}`)}return{report:{path:file.path,exists:!0,applied,plugins:plugins.entries,warnings},prefix:prefixConfiguration2}}var CHAT_BINDINGS=[{id:"chat.tab.new",scope:"workspace",keys:["ctrl+t"],category:"Workspace",description:"New chat tab",hint:{keys:"ctrl+t"},presentation:"onePress"},{id:"chat.tab.chooseEngine",scope:"workspace",keys:["ctrl+e"],category:"Workspace",description:"New conversation \u2014 engine/shell picker with destination + context toggles",hint:{keys:"ctrl+e"},presentation:"onePress"},{id:"chat.tab.fork",scope:"workspace",keys:[],prefixKeys:["c"],category:"Workspace",description:"Fork this chat into a new tab (same Task directory, keeps the conversation)",hint:{keys:"ctrl+a c"}},{id:"chat.fork.new",scope:"workspace",keys:[],prefixKeys:["f"],category:"Workspace",description:"Quick-fork: create child task seeded with current repo/branch/model",hint:{keys:"ctrl+a f"}},{id:"chat.tab.close",scope:"workspace",keys:["ctrl+w"],prefixKeys:["w"],category:"Workspace",description:"Close chat tab",hint:{keys:"ctrl+w"},presentation:"onePress"},{id:"workspace.reopenSession",scope:"workspace",keys:["return"],category:"Workspace",description:"Reopen a session in a task whose tabs are all closed",hint:{keys:"enter"},presentation:"onePress"},{id:"chat.tab.rename",scope:"workspace",keys:["f2"],category:"Workspace",description:"Rename active chat tab",hint:{keys:"f2"},presentation:"onePress"},{id:"chat.tab.cycle-next",scope:"workspace",keys:["ctrl+]"],category:"Workspace",description:"Next chat tab",hint:{keys:"ctrl+]"},presentation:"onePress"},{id:"chat.tab.cycle-prev",scope:"workspace",keys:["ctrl+["],category:"Workspace",description:"Previous chat tab",hint:{keys:"ctrl+["},presentation:"onePress"},{id:"chat.tab.goto",scope:"workspace",keys:["1","2","3","4","5","6","7","8","9"].map((digit)=>`ctrl+${digit}`),category:"Workspace",description:"Go to chat tab N",hint:{keys:"ctrl+1-9"},presentation:"onePress"},{id:"workspace.split.right",scope:"workspace",keys:["ctrl+\\"],category:"Workspace",description:"Split right",hint:{keys:"ctrl+\\"},presentation:"onePress"},{id:"workspace.split.down",scope:"workspace",keys:["ctrl+="],category:"Workspace",description:"Split down",hint:{keys:"ctrl+="},presentation:"onePress"},{id:"workspace.split.focus-next",scope:"workspace",keys:["f3"],category:"Workspace",description:"Focus next split",hint:{keys:"f3"},presentation:"onePress"},{id:"workspace.split.close",scope:"workspace",keys:["ctrl+w"],prefixKeys:["w"],category:"Workspace",description:"Close active split (tab when unsplit)",hint:{keys:"ctrl+w"},presentation:"onePress"},{id:"workspace.split.rename",scope:"workspace",keys:["f2"],category:"Workspace",description:"Rename active split (tab when unsplit)",hint:{keys:"f2"},presentation:"onePress"}];var FILES_BINDINGS=[{id:"files.nav",scope:"files",keys:["j","k","down","up"],category:"Files",description:"Move cursor up/down",hint:{keys:"j/k"}},{id:"files.hierarchy",scope:"files",keys:["h","l","left","right"],category:"Files",description:"Collapse / expand tree level",hint:{keys:"h/l"}},{id:"files.open",scope:"files",keys:["return"],category:"Files",description:"Open file in configured editor (diff when supported)",hint:{keys:"enter"}},{id:"files.tab",scope:"files",keys:["[","]"],category:"Files",description:"Switch tab (cycle All / Changes)",hint:{keys:"[/]"}},{id:"files.refresh",scope:"files",keys:["r"],category:"Files",description:"Refresh",hint:{keys:"r"}},{id:"files.scope",scope:"files",keys:["b"],category:"Files",description:"Toggle Changes scope (working \u2194 branch vs base)",hint:{keys:"b"}},{id:"files.diff",scope:"files",keys:["d"],category:"Files",description:"Open read-only diff in a workspace tab",hint:{keys:"d"}},{id:"files.diffAll",scope:"files",keys:["shift+d"],category:"Files",description:"Open the whole worktree's diff in one workspace tab",hint:{keys:"D"}},{id:"files.openExternal",scope:"files",keys:["o"],category:"Files",description:"Open file in system default app (audio / video / pdf preview)",hint:{keys:"o"}},{id:"files.mention",scope:"files",keys:["a"],category:"Files",description:"Inject @<path> mention into the engine pane",hint:{keys:"a"}},{id:"files.createPR",scope:"global",keys:[],prefixKeys:["p","shift+p"],category:"Files",description:"Ask the agent to create a PR from the current task"},{id:"files.fixChecks",scope:"global",keys:[],prefixKeys:["k"],category:"Files",description:"Ask the agent to fix the failing PR checks"},{id:"files.syncBase",scope:"global",keys:[],prefixKeys:["u"],category:"Files",description:"Merge the base branch into this task's worktree"},{id:"diff.review.cursor",scope:"workspace",keys:[],category:"Diff review",description:"Move the line cursor over the diff",hint:{keys:"j/k"}},{id:"diff.review.range",scope:"workspace",keys:[],category:"Diff review",description:"Toggle range anchor at the cursor",hint:{keys:"v"}},{id:"diff.review.note",scope:"workspace",keys:[],category:"Diff review",description:"Add a review note at the cursor",hint:{keys:"c"}},{id:"diff.review.send",scope:"workspace",keys:[],category:"Diff review",description:"Send all unsent review notes to the engine",hint:{keys:"s"}},{id:"diff.review.drop",scope:"workspace",keys:[],category:"Diff review",description:"Drop the review note the cursor sits inside",hint:{keys:"x"}},{id:"diff.review.reload",scope:"workspace",keys:[],category:"Diff review",description:"Reload the previewed file from disk",hint:{keys:"r"}}];var INBOX_BINDINGS=[{id:"inbox.show",scope:"global",keys:[],prefixKeys:["i"],category:"Global",description:"Open Inbox"},{id:"inbox.nav",scope:"inbox",keys:["j","k","down","up"],category:"Inbox",description:"Move cursor up/down",hint:{keys:"j/k"}},{id:"inbox.open",scope:"inbox",keys:["return"],category:"Inbox",description:"Open the selected Task and Terminal Tab",hint:{keys:"enter"}},{id:"inbox.delete",scope:"inbox",keys:["d"],category:"Inbox",description:"Remove the selected Inbox item",hint:{keys:"d"}}];var SIDEBAR_BINDINGS=[{id:"sidebar.nav",scope:"sidebar",keys:["j","k","down","up"],category:"Sidebar",description:"Move cursor up/down",hint:{keys:"j/k"}},{id:"sidebar.select",scope:"sidebar",keys:["return"],category:"Sidebar",description:"Open the selected task",hint:{keys:"enter"}},{id:"sidebar.tree.open",scope:"sidebar",keys:["l","space"],category:"Sidebar",description:"Open the row under the cursor (a tab row enters its chat)",hint:{keys:"l"}},{id:"sidebar.goto",scope:"sidebar",keys:["g","shift+g"],category:"Sidebar",description:"Top / bottom of list (gg or shift-G)"},{id:"sidebar.rename",scope:"sidebar",keys:["r"],category:"Sidebar",description:"Rename task",hint:{keys:"r"}},{id:"sidebar.localMerge",scope:"sidebar",keys:["shift+m"],category:"Sidebar",description:"Reorder row (Shift+M, then j/k)",hint:{keys:"M"}},{id:"sidebar.pin",scope:"sidebar",keys:["shift+p"],category:"Sidebar",description:"Pin / unpin task at top (Shift+P)",hint:{keys:"P"}},{id:"sidebar.sort",scope:"sidebar",keys:["t"],category:"Sidebar",description:"Cycle task sort (default \u2192 recent \u2192 attention \u2192 name)",hint:{keys:"t"}},{id:"sidebar.delete",scope:"sidebar",keys:["d"],category:"Sidebar",description:"Delete task (with confirm)",hint:{keys:"d"}},{id:"sidebar.search.enter",scope:"sidebar",keys:["/"],category:"Sidebar",description:"Search tasks (fuzzy filter)",hint:{keys:"/"}},{id:"sidebar.search.nav",scope:"sidebar",keys:["down","up"],category:"Sidebar",description:"Move highlight in search results"},{id:"sidebar.search.submit",scope:"sidebar",keys:["return"],category:"Sidebar",description:"Select search match and exit search"},{id:"sidebar.search.cancel",scope:"sidebar",keys:["escape"],category:"Sidebar",description:"Cancel search (restore prior selection)"},{id:"tasks.openWorktree",scope:"sidebar",keys:["o"],category:"Tasks pane",description:"Open selected Task directory in your editor",hint:{keys:"o"}},{id:"tasks.renameBranch",scope:"sidebar",keys:["b"],category:"Tasks pane",description:"Rename the selected task's git branch",hint:{keys:"b"}},{id:"tasks.cycleEngine",scope:"sidebar",keys:["v"],category:"Tasks pane",description:"Cycle engine vendor \u2014 applies on reopen",hint:{keys:"v"}},{id:"tasks.update",scope:"sidebar",keys:["u"],category:"Tasks pane",description:"Open the update page \u2014 version check + release notes",hint:{keys:"u"}},{id:"tasks.focusEngine",scope:"sidebar",keys:["right"],category:"Tasks pane",description:"Focus the engine pane of the current window",hint:{keys:"\u2192"}}];var RoveKeymap=[{id:"palette.open",scope:"global",keys:[],prefixKeys:["/"],category:"Global",description:"Search commands"},{id:"help.open",scope:"global",keys:["f1"],category:"Global",description:"Show keybindings help",hint:{keys:"F1"},presentation:"onePress"},{id:"task.new",scope:"sidebar",keys:["n"],category:"Sidebar",description:"New task",hint:{keys:"n"}},{id:"task.new.global",scope:"global",keys:[],prefixKeys:["n"],category:"Global",description:"New task"},{id:"task.openEditor",scope:"global",keys:[],prefixKeys:["o"],category:"Global",description:"Open active Task directory in editor"},{id:"task.moveMode",scope:"global",keys:[],prefixKeys:["m"],category:"Global",description:"Reorder sidebar rows (then j/k)"},{id:"settings.open",scope:"global",keys:[],prefixKeys:[","],category:"Global",description:"Open settings"},{id:"app.refresh",scope:"global",keys:[],prefixKeys:["r"],category:"Global",description:"Refresh Rove onto the installed build (after an update)"},{id:"settings.open.sidebar",scope:"sidebar",keys:["s"],category:"Sidebar",description:"Open settings",hint:{keys:"s"}},{id:"worktrees.open.sidebar",scope:"sidebar",keys:["x"],category:"Sidebar",description:"Open worktrees",hint:{keys:"x"}},{id:"kanban.open",scope:"global",keys:[],prefixKeys:["1"],category:"Global",description:"Open kanban (issues board)"},{id:"automations.open",scope:"global",keys:[],prefixKeys:["2"],category:"Global",description:"Open routines (scheduled tasks)"},{id:"workItems.open",scope:"global",keys:[],prefixKeys:["3"],category:"Global",description:"Open GitHub issues (external tracker)"},{id:"app.quit",scope:"sidebar",keys:["q","ctrl+q"],category:"Sidebar",description:"Quit (with confirm)",hint:{keys:"q"}},{id:"focus.sidebar",scope:"workspace",keys:["ctrl+q"],category:"Workspace",description:"Back to sidebar (tasks)",hint:{keys:"ctrl+q"},presentation:"onePress"},{id:"focus.previous",scope:"global",keys:[],prefixKeys:["h"],category:"Navigation",description:"Focus previous pane (files \u2192 workspace \u2192 sidebar)"},{id:"focus.next",scope:"global",keys:["f4"],prefixKeys:["l"],category:"Navigation",description:"Focus next pane (sidebar \u2192 workspace \u2192 files)",hint:{keys:"f4"},presentation:"onePress"},{id:"attention.next",scope:"global",keys:["f7"],category:"Navigation",description:"Jump to the next available Inbox item",hint:{keys:"f7"},presentation:"onePress"},{id:"workspace.zenToggle",scope:"global",keys:[],prefixKeys:["z"],category:"Navigation",description:"Toggle zen mode (hide the files column)"},{id:"view.redraw",scope:"global",keys:[],prefixKeys:["r"],category:"Global",description:"Redraw the screen"},...SIDEBAR_BINDINGS,...CHAT_BINDINGS,...FILES_BINDINGS,...INBOX_BINDINGS,{id:"terminal.scroll-up",scope:"terminal",keys:["ctrl+pageup"],category:"Terminal",description:"Scroll scrollback up",hint:{keys:"ctrl+pgup"}},{id:"terminal.scroll-down",scope:"terminal",keys:["ctrl+pagedown"],category:"Terminal",description:"Scroll scrollback down"},{id:"terminal.reset",scope:"terminal",keys:["f5"],category:"Terminal",description:"Reset terminal \u2014 kill the current shell and respawn",hint:{keys:"f5"},presentation:"onePress"},{id:"terminal.search",scope:"terminal",keys:[],prefixKeys:["/"],category:"Terminal",description:"Search the scrollback"},{id:"terminal.search.older",scope:"terminal",keys:["up","return"],category:"Terminal",description:"Scrollback search: walk to the older match"},{id:"terminal.search.newer",scope:"terminal",keys:["down"],category:"Terminal",description:"Scrollback search: walk to the newer match"},{id:"terminal.search.cancel",scope:"terminal",keys:["escape"],category:"Terminal",description:"Close scrollback search (restore prior scroll position)"}];var SOUND_VOLUME_KEY="notifications.sound.volume",DEFAULT_SOUND_VOLUME=0.4,SOUND_VOLUME_STEPS=[0.1,0.25,0.4,0.6,0.8,1];function normalizeSoundVolume(value){let n=typeof value==="number"?value:typeof value==="string"?Number.parseFloat(value.trim()):Number.NaN;if(!Number.isFinite(n))return DEFAULT_SOUND_VOLUME;return Math.min(1,Math.max(0,n))}function nextSoundVolume(volume){let current=normalizeSoundVolume(volume),above=SOUND_VOLUME_STEPS.findIndex((step)=>step>current+0.000000001);return SOUND_VOLUME_STEPS[above<0?0:above]}function persistedSoundVolume(){return normalizeSoundVolume(loadStateFile()[SOUND_VOLUME_KEY])}
|
|
3
3
|
export{resetKeybindingsFileCache,readKeybindingsFile,inputPassthroughReachable,bindingReachability,isKittyModifierKeyEvent,isCtrlModifierKeyName,PREFIX_HUD_TTL_MS,PREFIX_GUIDE_DELAY_MS,prefixHudClock,prefixHudState,prefixHudShowDirect,prefixHudHideDirect,prefixAction,insertRegistration,DEFAULT_PREFIX_CONFIGURATION,configurePrefix,resetPrefixConfiguration,currentPrefixConfiguration,prefixFirstStrokes,resetPrefixState,armPrefixNow,invokeArmedPrefixAction,dispatchKeyEvent,FIXED_BINDING_IDS,resolveUserKeybindings,RoveKeymap,SOUND_VOLUME_KEY,DEFAULT_SOUND_VOLUME,SOUND_VOLUME_STEPS,normalizeSoundVolume,nextSoundVolume,persistedSoundVolume};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{getKeychainPassword,isKeychainSupported,remoteKeychainRef,setKeychainPassword}from"./chunk-sak1tphp.js";import{RemoteExecHost}from"./chunk-b7xjhgts.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-7kysxgbq.js";import{addRemoteRepo,isRemoteProjectsEnabled}from"./chunk-
|
|
2
|
+
import{getKeychainPassword,isKeychainSupported,remoteKeychainRef,setKeychainPassword}from"./chunk-sak1tphp.js";import{RemoteExecHost}from"./chunk-b7xjhgts.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-7kysxgbq.js";import{addRemoteRepo,isRemoteProjectsEnabled}from"./chunk-m6pp9gaf.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-n3f5sdka.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import{remoteControlSocketPath}from"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{createInterface}from"readline";var CLI_NAME=ROVE_PRODUCT_NAME,USAGE=`Usage: ${CLI_NAME} add --remote --host <host> --user <user> --path <basePath>
|
|
3
3
|
[--port N] [--key [path] | --password]
|
|
4
4
|
|
|
5
5
|
Register an experimental SSH-backed project. Worktrees are created on <host>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{DIRTY_WORKTREE_CODE,canonicalize,describeDirtyWorktreeWork,isRoveManagedPath,isUnderManagedWorktreesRoot,managedWorktreeRootForPath,remoteManagedRootForPath,remoteWorktreePathFor,requireAbsolute,worktreePathFor}from"./chunk-
|
|
2
|
+
import{DIRTY_WORKTREE_CODE,canonicalize,describeDirtyWorktreeWork,isRoveManagedPath,isUnderManagedWorktreesRoot,managedWorktreeRootForPath,remoteManagedRootForPath,remoteWorktreePathFor,requireAbsolute,worktreePathFor}from"./chunk-j1fe3j54.js";import{execHostForRepo,execHostForWorktreePath}from"./chunk-yk498qwr.js";import{readFirstNonEmptyRepoFile}from"./chunk-catrr0z3.js";import{parsePorcelainRows}from"./chunk-dmzg9zdc.js";import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{getRemoteRepoConfig}from"./chunk-m6pp9gaf.js";import{loadStateFile}from"./chunk-n3f5sdka.js";import path5 from"path";function parseDirtyPaths(stdout){return parsePorcelainRows(stdout).filter((row)=>(row.x+row.y).trim().length>0).map((row)=>row.path).filter((p)=>p.length>0)}function isDirtyOutput(stdout){return parseDirtyPaths(stdout).length>0}import fs from"fs/promises";import path from"path";var WORKTREE_CLONE_IGNORED_KEY="worktree.cloneIgnored",DEFAULT_CLONE_DIRS=["node_modules",".venv","target",".build"];function isCloneIgnoredEnabled(){return loadStateFile()[WORKTREE_CLONE_IGNORED_KEY]!==!1}function parseCloneDirs(text){return text.split(/\r?\n/).map((line)=>line.replace(/#.*$/,"").trim()).filter((e)=>e.length>0&&e!=="."&&e!==".."&&!/[/\\]/.test(e)&&!e.startsWith("-"))}function resolveCloneDirs(worktreePath){let file=readFirstNonEmptyRepoFile(worktreePath,"clone-dirs");return file===void 0?DEFAULT_CLONE_DIRS:parseCloneDirs(file)}var CLONEFILEAT_PERL='my $r = syscall(462, -2, $ARGV[0], -2, $ARGV[1], 0); if ($r != 0) { print STDERR "clonefileat: $!\\n"; exit 1 }';function defaultCloneDeps(exec){return{platform:process.platform,statDev:async(p)=>(await fs.stat(p)).dev,isApfs:async(p)=>{let r=await exec.run(["/bin/df","-T","apfs",p]);return r.exitCode===0&&r.stdout.trim().split(`
|
|
3
3
|
`).length>1},clone:async(source,target)=>{let r=await exec.run(["/usr/bin/perl","-e",CLONEFILEAT_PERL,source,target]);if(r.exitCode!==0)throw Error(r.stderr.trim()||`perl exited ${r.exitCode}`)},log:(message)=>console.error(`[rove] ${message}`)}}async function discoverIgnoredDirs(exec,repo,names){let r=await exec.run(["git","ls-files","--others","--ignored","--exclude-standard","--directory","-z"],{cwd:repo,env:READ_ONLY_GIT_ENV});if(r.exitCode!==0)return[];return r.stdout.split("\x00").filter((entry)=>entry.endsWith("/")).map((entry)=>entry.slice(0,-1)).filter((rel)=>names.has(path.posix.basename(rel)))}async function isRealDirectory(p){try{return(await fs.lstat(p)).isDirectory()}catch{return!1}}async function exists(p){try{return await fs.lstat(p),!0}catch{return!1}}function cloneDirNames(exec,worktreePath,deps){if(exec.isRemote||deps.platform!=="darwin"||!isCloneIgnoredEnabled())return[];return resolveCloneDirs(worktreePath)}function regenerableDirNames(exec,worktreePath,deps){return cloneDirNames(exec,worktreePath,deps).filter((name)=>DEFAULT_CLONE_DIRS.includes(name))}async function cloneIgnoredDirs(exec,repo,worktreePath,deps=defaultCloneDeps(exec)){try{let names=new Set(cloneDirNames(exec,worktreePath,deps));if(names.size===0)return[];let apfsByDev=new Map,todo=[];for(let rel of await discoverIgnoredDirs(exec,repo,names)){let source=path.join(repo,rel),target=path.join(worktreePath,rel),targetParent=path.dirname(target);if(!await isRealDirectory(source)||await exists(target)||!await isRealDirectory(targetParent))continue;let dev=await deps.statDev(source);if(dev!==await deps.statDev(targetParent))continue;let apfs=apfsByDev.get(dev);if(apfs===void 0)apfs=await deps.isApfs(source),apfsByDev.set(dev,apfs);if(apfs)todo.push({rel,source,target})}return(await Promise.all(todo.map(async({rel,source,target})=>{try{return await deps.clone(source,target),rel}catch(err){return deps.log(`clone of ignored dir ${rel} into ${worktreePath} failed: ${err instanceof Error?err.message:err}`),null}}))).filter((rel)=>rel!==null)}catch(err){return deps.log(`cloning ignored dirs into ${worktreePath} failed: ${err instanceof Error?err.message:err}`),[]}}var defaultExecDeps={execForRepo:execHostForRepo,execForPath:execHostForWorktreePath,remoteBasePath(repoKey){return getRemoteRepoConfig(repoKey)?.basePath??null}};class GitCommandError extends Error{args;cwd;exitCode;stdout;stderr;constructor(args,cwd,result){super(`git ${args.join(" ")} (cwd=${cwd}) exited with code ${result.exitCode}: ${result.stderr.trim()||result.stdout.trim()}`);this.name="GitCommandError",this.args=args,this.cwd=cwd,this.exitCode=result.exitCode,this.stdout=result.stdout,this.stderr=result.stderr}}import path2 from"path";var MAX_IGNORED_ENTRY_KB=65536;function parseIgnoredPaths(stdoutZ){return stdoutZ.split("\x00").filter((entry)=>entry.startsWith("!! ")).map((entry)=>entry.slice(3)).filter((p)=>p.length>0)}var DU_ARGV_BUDGET_BYTES=98304;function parseDuKb(stdout){let sizes=new Map;for(let line of stdout.split(`
|
|
4
4
|
`)){let m=/^(\d+)\s+(.+)$/.exec(line.trim());if(m?.[1]&&m[2])sizes.set(m[2],Number.parseInt(m[1],10))}return sizes}async function duKb(exec,worktreePath,paths){let sizes=new Map,batch=[],bytes=0,flush=async()=>{if(batch.length===0)return;let du=await exec.run(["du","-sk","--",...batch],{cwd:worktreePath});for(let[p,kb]of parseDuKb(du.stdout))sizes.set(p,kb);batch.length=0,bytes=0};for(let p of paths){if(p.includes(`
|
|
5
5
|
`)){let one=await exec.run(["du","-sk","--",p],{cwd:worktreePath}),kb=/^\s*(\d+)/.exec(one.stdout)?.[1];if(one.exitCode===0&&kb)sizes.set(p,Number.parseInt(kb,10));continue}if(bytes+p.length+1>DU_ARGV_BUDGET_BYTES)await flush();batch.push(p),bytes+=p.length+1}return await flush(),sizes}async function smallIgnoredPaths(exec,worktreePath,regenerable=[]){try{let status=await exec.run(["git","status","--porcelain","-z","--ignored"],{cwd:worktreePath,env:READ_ONLY_GIT_ENV});if(status.exitCode!==0)return"unknown";let paths=parseIgnoredPaths(status.stdout).filter((p)=>!regenerable.includes(path2.posix.basename(p.replace(/\/$/,""))));if(paths.length===0)return[];let sizes=await duKb(exec,worktreePath,paths);return paths.filter((p)=>{let kb=sizes.get(p);return kb!==void 0&&kb<=MAX_IGNORED_ENTRY_KB})}catch{return"unknown"}}async function gitlinkPaths(git,tree){let out=await git(["ls-tree","-r",tree]);if(out.exitCode!==0)return[];return out.stdout.split(`
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{localDaemonSocketPath,localPtySocketPath,machineSocketDir,machineSshArgs,roveCommand}from"./chunk-
|
|
2
|
+
import{localDaemonSocketPath,localPtySocketPath,machineSocketDir,machineSshArgs,roveCommand}from"./chunk-g1px1rk6.js";import{homeDir}from"./chunk-prqeddy7.js";import{logClientError}from"./chunk-gskbzgc3.js";import{spawn as spawn2}from"child_process";import{mkdirSync as mkdirSync2,rmSync as rmSync2}from"fs";import{connect as netConnect}from"net";import{spawn}from"child_process";import{mkdirSync,rmSync}from"fs";import{createServer}from"net";function useStdioTransport(platform=process.platform){return platform==="win32"||process.env.ROVE_MACHINE_TRANSPORT==="stdio"}function relayCommand(roveBin,pty){return`${roveCommand(roveBin)} daemon relay${pty?" --pty":""}`}var servers=new Map;function serve(path,argv){if(servers.has(path))return Promise.resolve();let server=createServer((conn)=>{let[cmd,...args]=argv,child=spawn(cmd??"ssh",args,{stdio:["pipe","pipe","ignore"],windowsHide:!0});conn.pipe(child.stdin),child.stdout?.pipe(conn);let end=()=>{conn.destroy(),child.kill()};conn.on("close",()=>child.kill()),conn.on("error",end),child.on("exit",()=>conn.end()),child.on("error",(err)=>{logClientError("machines",err),end()})});return servers.set(path,server),new Promise((resolve,reject)=>{server.once("error",(err)=>{servers.delete(path),reject(err)}),rmSync(path,{force:!0}),server.listen(path,()=>resolve())})}async function ensureStdioForwards(args){mkdirSync(machineSocketDir(args.alias,args.home),{recursive:!0});let ssh=machineSshArgs(args.alias,args.config,{home:args.home});await serve(localDaemonSocketPath(args.alias,args.home),[...ssh,relayCommand(args.config.roveBin,!1)]),await serve(localPtySocketPath(args.alias,args.home),[...ssh,relayCommand(args.config.roveBin,!0)])}function stopStdioForwards(alias,home){for(let path of[localDaemonSocketPath(alias,home),localPtySocketPath(alias,home)])servers.get(path)?.close(),servers.delete(path)}var DIR_MODE=448,BACKOFF_START_MS=500,BACKOFF_MAX_MS=5000,HEALTH_INTERVAL_MS=1e4;function startTunnel(opts){let home=opts.home??homeDir(),daemonSocketPath=localDaemonSocketPath(opts.alias,home),ptySocketPath=localPtySocketPath(opts.alias,home),listeners=new Set,state="connecting",stopped=!1,backoff=BACKOFF_START_MS,setState=(next)=>{if(state===next)return;state=next;for(let listener of listeners)listener(next)},handle={alias:opts.alias,daemonSocketPath,ptySocketPath,state:()=>state,onState:(listener)=>{return listeners.add(listener),()=>listeners.delete(listener)},stop:()=>{if(stopped=!0,useStdioTransport())stopStdioForwards(opts.alias,home)}},schedule=opts.setTimeoutFn??((fn,ms)=>setTimeout(fn,ms)),stdio=()=>ensureStdioForwards({alias:opts.alias,config:opts.config,home}).then(()=>socketAnswers(daemonSocketPath)).catch(()=>!1),ensure=opts.ensureFn??(useStdioTransport()?stdio:()=>ensureForwards({alias:opts.alias,config:opts.config,remoteDaemonSocket:opts.remoteDaemonSocket,remotePtySocket:opts.remotePtySocket,home})),check=opts.checkFn??(()=>socketAnswers(daemonSocketPath)),attempt=async()=>{if(stopped)return;let up=await ensure();if(stopped)return;if(up){backoff=BACKOFF_START_MS,setState("online"),schedule(()=>void health(),HEALTH_INTERVAL_MS);return}setState("offline");let wait=backoff;backoff=Math.min(backoff*2,BACKOFF_MAX_MS),schedule(()=>void attempt(),wait)},health=async()=>{if(stopped)return;if(await check()){if(!stopped)schedule(()=>void health(),HEALTH_INTERVAL_MS);return}setState("offline"),attempt()};return attempt(),handle}async function ensureForwards(args){let home=args.home??homeDir();if(useStdioTransport())return ensureStdioForwards({alias:args.alias,config:args.config,home}).then(()=>socketAnswers(localDaemonSocketPath(args.alias,home))).catch(()=>!1);let daemonLocal=localDaemonSocketPath(args.alias,home),ptyLocal=localPtySocketPath(args.alias,home);try{mkdirSync2(machineSocketDir(args.alias,home),{recursive:!0,mode:DIR_MODE})}catch{}if(await socketAnswers(daemonLocal))return!0;for(let path of[daemonLocal,ptyLocal])try{rmSync2(path,{force:!0})}catch{}let base=machineSshArgs(args.alias,args.config,{home});if(await runSsh([...base,"true"])!==0)return!1;let target=base.at(-1)??args.alias,flags=base.slice(0,-1);return await runSsh([...flags,"-O","forward","-L",`${daemonLocal}:${args.remoteDaemonSocket}`,"-L",`${ptyLocal}:${args.remotePtySocket}`,target])===0&&await socketAnswers(daemonLocal)}function runSsh(argv){return new Promise((resolve)=>{let child=spawn2(argv[0]??"ssh",argv.slice(1),{stdio:"ignore"});child.on("error",()=>resolve(-1)),child.on("close",(code)=>resolve(code??-1))})}function socketAnswers(path){return new Promise((resolve)=>{let socket=netConnect(path),done=(answer)=>{socket.destroy(),resolve(answer)};socket.once("connect",()=>done(!0)),socket.once("error",()=>done(!1)),socket.setTimeout(1500,()=>done(!1))})}
|
|
3
3
|
export{startTunnel,ensureForwards};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{t}from"./chunk-
|
|
2
|
+
import{t}from"./chunk-625773dm.js";import{createInterface}from"readline";function daemonRestartFix(cliName,reason){return{kind:"run",id:"daemon-restart",label:t(`doctor.fix.${reason}`),command:[cliName,"daemon","restart"],why:t("doctor.fix.daemonRestartWhy")}}function skillInstallFix(installCommand,stale){return{kind:"run",id:"skill-install",label:t(stale?"doctor.fix.skillStale":"doctor.fix.skillMissing"),command:installCommand.split(" "),why:t("doctor.fix.skillInstallWhy")}}function resetManualFix(cliName,reason){return{kind:"manual",id:`reset:${reason}`,label:t(`doctor.fix.${reason}`),action:`${cliName} reset`,why:t("doctor.fix.resetWhy")}}function killOrphansManualFix(cliName,count){return{kind:"manual",id:"kill-orphans",label:t("doctor.fix.orphans",{count}),action:`${cliName} doctor --kill-orphans`,why:t("doctor.fix.orphansWhy")}}function engineTabsManualFix(){return{kind:"manual",id:"engine-tabs",label:t("doctor.fix.engineTabs"),action:t("doctor.fix.engineTabsAction"),why:t("doctor.fix.engineTabsWhy")}}function reinstallManualFix(){return{kind:"manual",id:"reinstall",label:t("doctor.fix.staleInstall"),action:t("doctor.fix.staleInstallAction"),why:t("doctor.fix.staleInstallWhy")}}function spawnHelperFix(paths){return{kind:"run",id:"spawn-helper-chmod",label:t("doctor.fix.spawnHelper"),command:["chmod","755",...paths],why:t("doctor.fix.spawnHelperWhy")}}function humanOnlyFix(reason,vars){return{kind:"manual",id:reason,label:t(`doctor.fix.${reason}`),action:t(`doctor.fix.${reason}Action`,vars),why:t("doctor.fix.humanOnlyWhy")}}function noEngineFix(signedOut){return signedOut.length>0?humanOnlyFix("noEngineLogin",{list:signedOut.join(", ")}):humanOnlyFix("noEngine")}function dedupeFixes(fixes){let seen=new Set;return fixes.filter((fix)=>{if(seen.has(fix.id))return!1;return seen.add(fix.id),!0})}async function applyFixes(collected,rt){let fixes=dedupeFixes(collected);if(fixes.length===0){rt.out(""),rt.out(t("doctor.fix.none"));return}let runnable=fixes.filter((fix)=>fix.kind==="run");if(runnable.length>0){rt.out(""),rt.out(t("doctor.fix.header"));for(let fix of runnable){if(rt.out(` ${fix.label}`),rt.out(` ${t("doctor.fix.willRun",{command:fix.command.join(" ")})}`),rt.out(` ${fix.why}`),!rt.interactive)continue;if(!await rt.confirm(` ${t("doctor.fix.confirmPrompt")}`)){rt.out(` ${t("doctor.fix.skipped")}`);continue}let code=await rt.exec(fix.command);rt.out(code===0?` ${t("doctor.fix.done")}`:` ${t("doctor.fix.failed",{code})}`)}if(!rt.interactive)rt.out(` ${t("doctor.fix.nonInteractive")}`)}let manual=fixes.filter((fix)=>fix.kind==="manual");if(manual.length>0){rt.out(""),rt.out(t("doctor.fix.manualHeader"));for(let fix of manual)rt.out(` ${fix.label}`),rt.out(` \u2192 ${fix.action}`),rt.out(` ${fix.why}`)}}async function confirmTty(question){let readline=createInterface({input:process.stdin,output:process.stdout});try{let answer=await new Promise((resolve)=>readline.question(question,resolve));return answer.trim().toLowerCase()==="y"||answer.trim().toLowerCase()==="yes"}finally{readline.close()}}async function execInherited(command){try{return await Bun.spawn([...command],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited}catch{return 127}}function defaultFixRuntime(){return{confirm:confirmTty,exec:execInherited,out:(line)=>console.log(line),interactive:process.stdin.isTTY===!0}}
|
|
3
3
|
export{daemonRestartFix,skillInstallFix,resetManualFix,killOrphansManualFix,engineTabsManualFix,reinstallManualFix,spawnHelperFix,humanOnlyFix,noEngineFix,applyFixes,defaultFixRuntime};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{PS_PROBE_TIMEOUT_MS,engineProcessIn,foregroundEngine,foregroundEngineIn,hasAncestor,parsePsSnapshot,psSnapshot,psSnapshotWith,vendorFromArgv}from"./chunk-
|
|
2
|
+
import{PS_PROBE_TIMEOUT_MS,engineProcessIn,foregroundEngine,foregroundEngineIn,hasAncestor,parsePsSnapshot,psSnapshot,psSnapshotWith,vendorFromArgv}from"./chunk-b4zqkdyq.js";import"./chunk-rbr6qapz.js";import"./chunk-2tfnscxk.js";import"./chunk-8saxdp88.js";import"./chunk-w7zv47mp.js";import"./chunk-2brn8e1y.js";import"./chunk-xh72jz7c.js";import"./chunk-7zyyvc3d.js";import"./chunk-r6k3ve2g.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-tdhk4dz8.js";import"./chunk-m6pp9gaf.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-n3f5sdka.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import{PsProbeUnavailableError}from"./chunk-pxk2c2vj.js";import"./chunk-91sykzqq.js";export{vendorFromArgv,psSnapshotWith,psSnapshot,parsePsSnapshot,hasAncestor,foregroundEngineIn,foregroundEngine,engineProcessIn,PsProbeUnavailableError,PS_PROBE_TIMEOUT_MS};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{buildPluginEnv}from"./chunk-
|
|
2
|
+
import{buildPluginEnv}from"./chunk-6a70wv2b.js";import{currentPluginPlatform,loadPluginRegistry,readPluginManifest,supportsPlatform}from"./chunk-kvwqh35r.js";import{resolveLoginShell}from"./chunk-f5n0tgky.js";function shq(s){return`'${s.replace(/'/g,"'\\''")}'`}function buildPaneArgv(pluginId,pluginRoot,pane,opts){let env=buildPluginEnv({homeDir:opts.homeDir,socketPath:opts.socketPath,binPath:opts.binPath,pluginId,pluginRoot,extra:{ROVE_PLUGIN_ENTRYPOINT_ID:pane.id,...opts.taskId?{ROVE_PLUGIN_TASK_ID:opts.taskId}:{}}}),pairs=Object.entries(env).filter(([k])=>k.startsWith("ROVE_")||k.startsWith("ROVE_")),command=pane.command.map((a)=>a.replace(/\$\{?(?:ROVE|ROVE)_PLUGIN_ROOT\}?/g,pluginRoot)),script=`exec env ${pairs.map(([k,v])=>shq(`${k}=${v}`)).join(" ")} ${command.map(shq).join(" ")}`;return[resolveLoginShell(),"-ilc",script]}function listPaneLaunches(opts){let platform=currentPluginPlatform(),out=[];for(let entry of loadPluginRegistry(opts.homeDir).plugins){if(!entry.enabled)continue;try{let{manifest}=readPluginManifest(entry.root);if(!supportsPlatform({},manifest,platform))continue;for(let pane of manifest.panes){if(!supportsPlatform(pane,manifest,platform))continue;out.push({pluginId:entry.id,paneId:pane.id,title:pane.title,placement:pane.placement,argv:buildPaneArgv(entry.id,entry.root,pane,opts)})}}catch{}}return out}
|
|
3
3
|
export{buildPaneArgv,listPaneLaunches};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{embeddedTerminalEnv}from"./chunk-7bgbansg.js";import{FREEZE_RESTORE_MAX_BYTES,FREEZE_TTL_MS,clearFrozenSessions,fileFreezeSink,freezeSession,freshModeTrack,loadFrozenSessions,scanTerminalModes,terminalModePreamble,thawSession}from"./chunk-spee6wv8.js";import{ClientWriter,LineReceiver,clearTransientStatuses,createOscSignals,objectPayload,optionalBoolean,requireString,scanOscSignals}from"./chunk-k67vbszb.js";import{writeTextAtomic}from"./chunk-5mhvjytn.js";import{DEFAULT_TERMINAL_COLORS,foldDefaultColorQueries,formatDefaultColorReply,parseTerminalDefaultColors}from"./chunk-4250pw6r.js";import{installDaemonCrashHandlers,logDaemonError}from"./chunk-rxqdw6s5.js";import{resolveLoginShell}from"./chunk-f5n0tgky.js";import{recordPtyExit}from"./chunk-sr4c9fve.js";import"./chunk-etfh8f4z.js";import{spawnDetachedDaemon,withoutPtyJob}from"./chunk-5v02t4pz.js";import{CURRENT_VERSION}from"./chunk-hgf4cz78.js";import{listenOnUnixSocket}from"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import{ensureOwnerOnlyStateDir}from"./chunk-yt15y085.js";import{DAEMON_PROTOCOL_VERSION,frameToLine}from"./chunk-kmgheesn.js";import"./chunk-szjgjrar.js";import{rotateLogIfNeeded}from"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import{defaultPtyFreezeDir,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath,endpointPathFor,isWindowsPipePath,resolveDaemonHomeDir}from"./chunk-n0rtj4z7.js";import{preRenameStateDir}from"./chunk-b39sdtt0.js";import{ROVE_STATE_DIR_BASENAME,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";function formatPtyHostLine(event,message,now=new Date){return`[${now.toISOString()}] pty-host [${event}]: ${message}`}import{readFileSync}from"fs";import{mkdir,unlink}from"fs/promises";import{createServer}from"net";import{dirname}from"path";import{existsSync,lstatSync,mkdirSync,renameSync}from"fs";import{homedir}from"os";import{join}from"path";var PTY_HOST_DATA_ENTRIES=["pty-exits.json","pty-sessions"];function lstatIfExists(path){try{return lstatSync(path)}catch{return}}function migrateLegacyPtyHostData(homeDir=readRoveHomeDirEnv()??homedir()){let canonicalDir=join(homeDir,ROVE_STATE_DIR_BASENAME),legacyDir=preRenameStateDir(homeDir);if(canonicalDir===legacyDir)return[];let moved=[];for(let name of PTY_HOST_DATA_ENTRIES){let canonical=join(canonicalDir,name),legacy=join(legacyDir,name);try{if(existsSync(canonical))continue;let stat=lstatIfExists(legacy);if(!stat||stat.isSymbolicLink())continue;mkdirSync(canonicalDir,{recursive:!0}),renameSync(legacy,canonical),moved.push(name)}catch{}}return moved}import{randomUUID as randomUUID2}from"crypto";var TERMINAL_NAME="xterm-256color";function bunTerminalDriver(spawn){let spawnTerminal=spawn??((argv,options)=>Bun.spawn(argv,options));return(request)=>{let proc=spawnTerminal([...request.argv],{cwd:request.cwd,env:request.env,terminal:{cols:request.cols,rows:request.rows,name:TERMINAL_NAME,data:(_terminal,data)=>request.onData(data)}});return{pid:proc.pid,exited:proc.exited.then(()=>({code:proc.exitCode??null,signal:proc.signalCode??null}),()=>({code:null,signal:null})),write:(data)=>proc.terminal?.write(data),resize:(cols,rows)=>proc.terminal?.resize(cols,rows),close:()=>proc.terminal?.close(),kill:(signal)=>proc.kill(signal)}}}import{randomUUID}from"crypto";import{StringDecoder}from"string_decoder";function freshSessionState(key,spec,argv){return{key,generation:randomUUID(),cwd:spec.cwd,proc:null,alive:!0,chunks:[],bytes:0,totalBytes:0,cols:spec.cols??80,rows:spec.rows??24,command:argv,title:"",titleCarry:"",titleDecoder:new StringDecoder("utf8"),colorQueryCarry:"",defaultColors:parseTerminalDefaultColors(spec.defaultColors)??DEFAULT_TERMINAL_COLORS,modes:freshModeTrack(),ringModes:freshModeTrack(),sinks:new Map,emulatorSinks:new Set,parked:!1,parkedScreenBytes:0,exit:null,restored:!1,lastFreezeAtMs:0,frozenTotalBytes:0}}function sessionInfo(s){return{key:s.key,generation:s.generation,alive:s.alive,pid:s.proc?.pid??null,command:s.command,title:s.title,programStatusEvent:s.programStatusEvent,programStatus:s.oscSignals?.records.get(""),contexts:s.oscSignals?.contexts,totalBytes:s.totalBytes,parked:s.parked,parkedScreenBytes:s.parkedScreenBytes,exit:s.exit,restored:s.restored||void 0}}function describeExit(exit){if(exit?.signal)return` (signal ${exit.signal})`;if(exit&&exit.code!==null)return` (code ${exit.code})`;return" (cause unknown)"}function ringTail(chunks,bytes,maxBytes){let skip=Math.max(0,bytes-maxBytes),seen=0,parts=[];for(let chunk of chunks){if(seen+chunk.byteLength>skip)parts.push(seen>=skip?chunk:chunk.subarray(skip-seen));seen+=chunk.byteLength}return Buffer.concat(parts).toString("utf8")}function hostStats(sessions,perSessionCap,parkRestoreDeltas,parkRestoreFallbacks){let ringBytes=0,count=0,parkedSessions=0,parkedScreenBytes=0;for(let session of sessions)if(count++,ringBytes+=session.bytes,session.parked)parkedSessions++,parkedScreenBytes+=session.parkedScreenBytes;return{ringBytes,ringCapacityBytes:count*perSessionCap,parkedSessions,parkedScreenBytes,parkRestoreDeltas,parkRestoreFallbacks}}var OSC_TITLE_RE=/\x1b\][02];([^\x07\x1b]*)(?:\x07|\x1b\\)/g,TITLE_CARRY_CAP=1024;function titleCarryFrom(rest){let osc=rest.lastIndexOf("\x1B]");if(osc!==-1)return rest.slice(osc,osc+TITLE_CARRY_CAP);return rest.endsWith("\x1B")?"\x1B":""}function foldOscTitle(prevCarry,chunkText){let text=prevCarry+chunkText,title=null,end=0;OSC_TITLE_RE.lastIndex=0;for(let match=OSC_TITLE_RE.exec(text);match;match=OSC_TITLE_RE.exec(text))title=match[1]??"",end=match.index+match[0].length;return{title,carry:titleCarryFrom(text.slice(end))}}function scanOscTitle(session,buf){let{title,carry}=foldOscTitle(session.titleCarry,session.titleDecoder.write(buf));if(title!==null)session.title=title;session.titleCarry=carry}function peekRing(session,sinceOffset){if(!session)return{exists:!1,alive:!1,pid:null,offset:0,data:"",sinceValid:!1,exit:null};let windowStart=session.totalBytes-session.bytes,buf=Buffer.concat(session.chunks),sinceValid=!1;if(sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes)buf=buf.subarray(sinceOffset-windowStart),sinceValid=!0;return{exists:!0,alive:session.alive,pid:session.proc?.pid??null,offset:session.totalBytes,data:buf.toString("base64"),sinceValid,exit:session.exit??null}}async function settledWithin(exited,ms){let timer,settled=await Promise.race([exited.then(()=>!0,()=>!0),new Promise((resolve)=>{timer=setTimeout(()=>resolve(!1),ms)})]);if(timer)clearTimeout(timer);return settled}function signalProcessGroup(pid,signal,fallback,platform=process.platform,onSignal){if(platform!=="win32"&&pid>1)try{process.kill(-pid,signal),onSignal?.(`sent ${signal} to process group -${pid}`);return}catch{}try{fallback(),onSignal?.(`sent ${signal} to pid ${pid} (per-process fallback)`)}catch{}}var TERMINATION_GRACE_MS=500;async function terminatePtyChild(proc,onSettled,onSignal){if(proc.endTree){onSignal?.(await proc.endTree()),signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS),onSettled();return}if(signalProcessGroup(proc.pid,"SIGTERM",()=>proc.kill("SIGTERM"),process.platform,onSignal),!await settledWithin(proc.exited,TERMINATION_GRACE_MS))signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS);onSettled()}class PtyChildController{deps;constructor(deps){this.deps=deps}spawn(key,spec,spare=!1){let argv=spec.command&&spec.command.length>0?[...spec.command]:[spec.shell??resolveLoginShell()],session=freshSessionState(key,spec,argv);if(this.startChild(session),session.alive)this.deps.log?.("pty",`spawned ${argv[0]} for ${key} (pid ${session.proc?.pid})`),this.deps.onSessionStart?.(spare);return session}startChild(session){session.generation=randomUUID2(),session.oscSignals=void 0,session.programStatusEvent=void 0,this.reportStatus(session,null);try{session.proc=(this.deps.driver??bunTerminalDriver())({argv:[...session.command],cwd:session.cwd,env:embeddedTerminalEnv(process.env,{TERM:"xterm-256color",COLUMNS:String(session.cols),LINES:String(session.rows),BASH_SILENCE_DEPRECATION_WARNING:"1",ROVE_TERMINAL_PTY:"1"}),cols:session.cols,rows:session.rows,onData:(data)=>this.onData(session,data)}),session.alive=!0,session.proc.exited.then((exit)=>this.markExited(session,exit),()=>this.markExited(session))}catch(err){session.alive=!1,this.deps.log?.("pty",`spawn failed for ${session.key}: ${err instanceof Error?err.message:String(err)}`)}}async endChild(session){if(!session.alive)return;let proc=session.proc;if(!proc){this.markExited(session);return}await terminatePtyChild(proc,()=>this.markExited(session),(line)=>this.deps.log?.("pty-signal",`${session.key}: ${line}`))}markExited(session,exit){if(!session.alive)return;if(session.alive=!1,session.oscSignals){let before=session.oscSignals.records.get("");if(clearTransientStatuses(session.oscSignals),before!==session.oscSignals.records.get(""))this.reportStatus(session,null)}let sessionExit={code:exit?.code??null,signal:exit?.signal??null,at:new Date().toISOString()};session.exit=sessionExit;try{session.proc?.close()}catch{}this.deps.onExit?.(session,sessionExit)}reportStatus(session,status){let event={key:session.key,generation:session.generation,revision:(session.programStatusEvent?.revision??0)+1,at:Date.now(),status};session.programStatusEvent=event,this.deps.onProgramStatus?.(event)}onData(session,data){let buf=typeof data==="string"?Buffer.from(data,"utf8"):Buffer.from(data),text=buf.toString("latin1");session.oscSignals??=createOscSignals();let queries=scanOscSignals(session.oscSignals,buf,Date.now(),(status)=>this.reportStatus(session,status)),colorQueries=foldDefaultColorQueries(session.colorQueryCarry,text);session.colorQueryCarry=colorQueries.carry;let replies=colorQueries.slots.map((slot)=>formatDefaultColorReply(slot,session.defaultColors));for(let i=0;i<Math.min(queries,16);i++)replies.push("\x1B]7501;?\x1B\\");let modeReplies=scanTerminalModes(session.modes,text);if(session.emulatorSinks.size===0)replies.push(...modeReplies);if(replies.length>0)try{session.proc?.write(replies.join(""))}catch{}scanOscTitle(session,buf),session.chunks.push(buf),session.bytes+=buf.byteLength,session.totalBytes+=buf.byteLength;while(session.bytes>this.deps.scrollbackCap&&session.chunks.length>1){let dropped=session.chunks.shift();if(!dropped)break;session.bytes-=dropped.byteLength,scanTerminalModes(session.ringModes,dropped.toString("latin1"))}this.deps.onOutput?.(session,buf)}}function shouldFreeze(session,now){let appended=session.totalBytes-(session.frozenTotalBytes??0);if(appended<=0)return!1;let since=now-session.lastFreezeAtMs;if(since<5000)return!1;return appended>=65536||since>=60000}class WarmSpare{deps;spare=null;constructor(deps){this.deps=deps}warm(cwd,shell,cols=80,rows=24){let argv0=shell??resolveLoginShell();if(this.spare?.alive&&this.spare.cwd===cwd&&this.spare.command[0]===argv0)return;let old=this.spare;if(this.spare=null,old)this.deps.endChild(old);let session=this.deps.spawn("::spare",{cwd,command:[argv0],cols,rows},!0);this.spare=session.alive?session:null}adopt(key,spec){let spare=this.spare;if(!spare?.alive||spare.cwd!==spec.cwd)return null;let want=spec.command&&spec.command.length>0?spec.command:[spec.shell??resolveLoginShell()];if(want.length!==1||want[0]!==spare.command[0])return null;this.spare=null,spare.key=key,spare.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??spare.defaultColors;let cols=spec.cols??spare.cols,rows=spec.rows??spare.rows;if(spare.cols!==cols||spare.rows!==rows){spare.cols=cols,spare.rows=rows;try{spare.proc?.resize(cols,rows)}catch{return this.deps.markExited(spare),null}}return this.deps.log?.("pty",`adopted warm shell for ${key} (pid ${spare.proc?.pid})`),this.deps.onSessionStart?.(),this.warm(spec.cwd,spare.command[0],cols,rows),spare}async end(){let spare=this.spare;if(this.spare=null,spare)await this.deps.endChild(spare)}}var LOGGED_WRITE_BYTES=1024,DEFAULT_SCROLLBACK_CAP=524288,EXIT_TAIL_BYTES=16384;class PtyHost{sessions=new Map;opts;scrollbackCap;parkRestoreDeltas=0;parkRestoreFallbacks=0;childController;warmSpare;constructor(opts={}){this.opts=opts,this.scrollbackCap=opts.scrollbackCap??DEFAULT_SCROLLBACK_CAP,this.childController=new PtyChildController({driver:opts.driver,onProgramStatus:(event)=>this.opts.onProgramStatus?.(event),scrollbackCap:this.scrollbackCap,onSessionStart:(spare)=>{if(!spare)this.opts.onSessionStart?.()},onOutput:(session,data)=>{if(session.sinks.size===0){this.maybeFreeze(session);return}let frame={type:"event",name:"pty.data",payload:{key:session.key,data:data.toString("base64")}};for(let sink of session.sinks.values())sink(frame);this.maybeFreeze(session)},onExit:(session,exit)=>{let frame={type:"event",name:"pty.exit",payload:{key:session.key,pid:session.proc?.pid??null,...exit}};for(let sink of session.sinks.values())sink(frame);if(this.opts.log?.("pty",`session ${session.key} exited${describeExit(exit)}`),this.maybeFreeze(session,!0),!session.closedByRequest)try{this.opts.onSessionExit?.({key:session.key,pid:session.proc?.pid??null,exit,tail:ringTail(session.chunks,session.bytes,EXIT_TAIL_BYTES)})}catch{}this.opts.onSessionEnd?.()},log:(event,message)=>this.opts.log?.(event,message)}),this.warmSpare=new WarmSpare({spawn:(key,spec,spare)=>this.childController.spawn(key,spec,spare),endChild:(session)=>this.childController.endChild(session),markExited:(session)=>this.childController.markExited(session),log:(event,message)=>this.opts.log?.(event,message),onSessionStart:()=>this.opts.onSessionStart?.()})}open(key,spec,token,sink,sinceOffset,sincePid,answersQueries=!1){let session=this.sessions.get(key),created=!1,respawned=!1;if(!session)created=!0,session=this.warmSpare.adopt(key,spec)??this.childController.spawn(key,spec),this.sessions.set(key,session);else if(!session.alive&&session.restored)this.respawn(session,spec),respawned=session.alive;else if(session.alive&&spec.cols!==void 0&&spec.rows!==void 0&&(session.cols!==spec.cols||session.rows!==spec.rows))this.resize(key,spec.cols,spec.rows);let defaultColors=parseTerminalDefaultColors(spec.defaultColors);if(defaultColors)session.defaultColors=defaultColors;if(session.sinks.set(token,sink),answersQueries)session.emulatorSinks.add(token);else session.emulatorSinks.delete(token);session.parked=!1,session.parkedScreenBytes=0;let windowStart=session.totalBytes-session.bytes,replay=Buffer.concat(session.chunks),sinceValid=!1;if(!created&&sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes&&sincePid!==void 0&&sincePid===session.proc?.pid)replay=replay.subarray(sinceOffset-windowStart),sinceValid=!0;if(sinceOffset!==void 0&&sincePid!==void 0)if(sinceValid)this.parkRestoreDeltas++;else this.parkRestoreFallbacks++;if(!sinceValid)replay=Buffer.concat([Buffer.from(terminalModePreamble(session.ringModes.modes),"latin1"),replay]);return{replay:replay.toString("base64"),alive:session.alive,pid:session.proc?.pid??null,created,respawned,offset:session.totalBytes,sinceValid}}warm(cwd,shell,cols=80,rows=24){this.warmSpare.warm(cwd,shell,cols,rows)}write(key,data){let session=this.sessions.get(key);if(!session?.alive||data.length===0)return;if(data.length>=LOGGED_WRITE_BYTES)this.opts.log?.("pty",`wrote ${data.length} bytes to ${key}`);try{session.proc?.write(data)}catch(error){this.opts.log?.("pty",`write failed on ${key} (${data.length} bytes): ${String(error)}`)}}resize(key,cols,rows){let session=this.sessions.get(key);if(!session?.alive)return;session.cols=cols,session.rows=rows;try{session.proc?.resize(cols,rows)}catch{}}killIfGeneration(key,expectedGeneration){let session=this.sessions.get(key);if(!session)return{accepted:!1,reason:"missing-session"};if(session.generation!==expectedGeneration)return{accepted:!1,reason:"generation-mismatch"};return this.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}kill(key){let session=this.sessions.get(key);if(!session)return Promise.resolve();return this.sessions.delete(key),session.closedByRequest=!0,this.opts.freeze?.drop(key),this.childController.endChild(session)}rename(from,to){let session=this.sessions.get(from);if(!session||from===to||this.sessions.has(to))return!1;if(this.sessions.delete(from),session.key=to,session.programStatusEvent){let previous=session.programStatusEvent;this.opts.onProgramStatus?.({...previous,revision:previous.revision+1,at:Date.now(),status:null}),session.programStatusEvent={...previous,key:to,revision:previous.revision+1,at:Date.now()},this.opts.onProgramStatus?.(session.programStatusEvent)}return this.sessions.set(to,session),this.opts.freeze?.drop(from),this.maybeFreeze(session,!0),this.opts.log?.("pty",`renamed session ${from} \u2192 ${to}`),!0}detach(key,token,parked=!1,parkedScreenBytes=0){let session=this.sessions.get(key);if(!session)return;session.sinks.delete(token),session.emulatorSinks.delete(token),this.applyParkedOnDetach(session,parked,parkedScreenBytes)}detachClient(token){for(let session of this.sessions.values()){if(session.emulatorSinks.delete(token),!session.sinks.delete(token))continue;this.applyParkedOnDetach(session)}}applyParkedOnDetach(session,parked=!1,parkedScreenBytes=0){if(session.sinks.size!==0)return;session.parked=parked,session.parkedScreenBytes=parked?Math.max(0,parkedScreenBytes):0}list(){return Array.from(this.sessions.values(),(s)=>sessionInfo(s))}peek(key,sinceOffset){return peekRing(this.sessions.get(key),sinceOffset)}stats(){return hostStats(this.sessions.values(),this.scrollbackCap,this.parkRestoreDeltas,this.parkRestoreFallbacks)}async killAll(){let sessions=Array.from(this.sessions.keys(),(key)=>this.kill(key));sessions.push(this.warmSpare.end()),await Promise.all(sessions)}async shutdown(){this.flushFrozen();let endings=Array.from(this.sessions.values(),(session)=>this.childController.endChild(session));endings.push(this.warmSpare.end()),await Promise.all(endings)}flushFrozen(){for(let session of this.sessions.values())this.maybeFreeze(session,!0)}restoreFrozen(records){let restoredCount=0;for(let record of records){if(this.sessions.has(record.key))continue;let session=thawSession(record,this.scrollbackCap);if(!session)continue;this.sessions.set(record.key,session),restoredCount++}if(restoredCount>0)this.opts.log?.("pty",`restored ${restoredCount} frozen session(s) from disk`);return restoredCount}respawn(session,spec){if(session.restored=!1,session.exit=null,spec.command&&spec.command.length>0)session.command=[...spec.command];if(session.cols=spec.cols??session.cols,session.rows=spec.rows??session.rows,session.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??session.defaultColors,this.childController.startChild(session),!session.alive)return;this.opts.log?.("pty",`respawned restored session ${session.key} (pid ${session.proc?.pid})`),this.opts.onSessionStart?.()}maybeFreeze(session,force=!1){let freeze=this.opts.freeze;if(!freeze||session.key.startsWith("::"))return;if(session.closedByRequest)return;let now=Date.now();if(!force&&!shouldFreeze(session,now))return;session.lastFreezeAtMs=now,session.frozenTotalBytes=session.totalBytes,freeze.save(freezeSession(session))}liveCount(){let n=0;for(let session of this.sessions.values())if(session.alive)n++;return n}}function dispatchPtyRequest(req,client,deps){let{ptys}=deps;switch(req.name){case"hello":return{protocolVersion:DAEMON_PROTOCOL_VERSION,ptyHost:!0,pid:process.pid};case"pty.openChecked":case"pty.open":{let payload=objectPayload(req.payload);if(req.name==="pty.openChecked"&&requireString(payload,"admissionToken")!==admissionToken(ptys))return{kind:"changed"};let open=ptys.open(requireString(payload,"key"),{cwd:requireString(payload,"cwd"),command:Array.isArray(payload.command)?payload.command.filter((c)=>typeof c==="string"):void 0,shell:typeof payload.shell==="string"?payload.shell:void 0,cols:typeof payload.cols==="number"?payload.cols:void 0,rows:typeof payload.rows==="number"?payload.rows:void 0,defaultColors:parseTerminalDefaultColors(payload.defaultColors)??void 0},client,(frame)=>deps.writeFrame(client,frame),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0,typeof payload.sincePid==="number"?payload.sincePid:void 0,payload.answersQueries===!0);return req.name==="pty.openChecked"?{kind:"opened",open}:open}case"pty.write":{let payload=objectPayload(req.payload);return ptys.write(requireString(payload,"key"),typeof payload.data==="string"?payload.data:""),{}}case"pty.resize":{let payload=objectPayload(req.payload);return ptys.resize(requireString(payload,"key"),typeof payload.cols==="number"?payload.cols:80,typeof payload.rows==="number"?payload.rows:24),{}}case"pty.kill":{let payload=objectPayload(req.payload),key=requireString(payload,"key");if("expectedGeneration"in payload)return ptys.killIfGeneration(key,requireString(payload,"expectedGeneration"));if(optionalBoolean(payload,"wait")===!0)return ptys.kill(key).then(()=>({accepted:!0,ended:!0}),(err)=>{return logDaemonError("pty-kill",err),{accepted:!0,ended:!1}});return ptys.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}case"pty.rename":{let payload=objectPayload(req.payload);return{renamed:ptys.rename(requireString(payload,"from"),requireString(payload,"to"))}}case"pty.detach":{let payload=objectPayload(req.payload);ptys.detach(requireString(payload,"key"),client,payload.parked===!0,typeof payload.parkedScreenBytes==="number"?payload.parkedScreenBytes:0)}return{};case"pty.watchStatus":client.watchProgramStatus=!0;for(let session of ptys.list())if(session.programStatusEvent)deps.writeFrame(client,{type:"event",name:"pty.programStatus",payload:session.programStatusEvent});return{supported:!0};case"pty.list":return{pid:process.pid,rssBytes:process.memoryUsage().rss,sessions:ptys.list(),admissionToken:admissionToken(ptys),stats:ptys.stats(),...deps.version?{version:deps.version}:{}};case"pty.peek":{let payload=objectPayload(req.payload);return ptys.peek(requireString(payload,"key"),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0)}case"pty.warm":{let payload=objectPayload(req.payload);return ptys.warm(requireString(payload,"cwd"),typeof payload.shell==="string"?payload.shell:void 0,typeof payload.cols==="number"?payload.cols:void 0,typeof payload.rows==="number"?payload.rows:void 0),{}}case"spawn.detached":{if(process.platform!=="win32")throw Error("spawn.detached is Windows-only");let payload=objectPayload(req.payload),env=objectPayload(payload.env);return spawnDetachedDaemon(requireString(payload,"command"),Array.isArray(payload.args)?payload.args.filter((a)=>typeof a==="string"):[],withoutPtyJob(Object.fromEntries(Object.entries(env).filter((e)=>typeof e[1]==="string"))),requireString(payload,"logPath")),{}}case"daemon.stop":return deps.requestStop(),{};default:throw Error(`unknown pty-host request: ${req.name}`)}}function admissionToken(ptys){return JSON.stringify(ptys.list().map((s)=>[s.key,s.generation,s.pid,s.alive]))}var DEFAULT_IDLE_EXIT_MS=60000,DEFAULT_ORPHAN_CHECK_MS=30000;function resolveMaxLifetimeMs(){let raw=process.env.ROVE_PTY_MAX_LIFETIME_MS;if(raw===void 0)return null;let n=Number(raw);return Number.isFinite(n)&&n>0?n:null}function resolveIdleExitMs(){let raw=process.env.ROVE_PTY_IDLE_EXIT_MS;if(raw===void 0)return DEFAULT_IDLE_EXIT_MS;let n=Number(raw);return Number.isFinite(n)&&n>=0?n:DEFAULT_IDLE_EXIT_MS}async function startPtyHostServer(options={}){migrateLegacyPtyHostData();let socketPath=options.socketPath??defaultPtyHostSocketPath(),pidPath=options.pidPath??defaultPtyHostPidPath(),freezeDir=options.freezeDir??defaultPtyFreezeDir(),idleExitMs=options.idleExitMs||resolveIdleExitMs(),orphanCheckMs=options.orphanCheckMs||DEFAULT_ORPHAN_CHECK_MS,maxLifetimeMs=options.maxLifetimeMs??resolveMaxLifetimeMs(),bootedAtMs=Date.now(),log=options.log??(()=>{}),clients=new Set,stopping=!1,wipeFreezeOnStop=!1,idleTimer=null,cancelIdle=()=>{if(idleTimer)clearTimeout(idleTimer);idleTimer=null},armIdle=()=>{if(stopping)return;cancelIdle(),idleTimer=setTimeout(()=>{if(stopping||ptys.liveCount()>0)return;log("idle",`no live sessions for ${idleExitMs}ms \u2014 exiting`),stop()},idleExitMs)},orphaned=()=>{if(maxLifetimeMs!==null&&Date.now()-bootedAtMs>=maxLifetimeMs)return`exceeded its ${maxLifetimeMs}ms lifetime ceiling`;let owner;try{owner=readFileSync(pidPath,"utf8").trim()}catch{return`pidfile ${pidPath} is gone`}let pid=Number.parseInt(owner,10);if(pid===process.pid)return null;return Number.isInteger(pid)?`pidfile ${pidPath} now names pid ${pid}`:`pidfile ${pidPath} is unreadable`},orphanTimer=setInterval(()=>{if(stopping)return;let reason=orphaned();if(!reason)return;log("orphan",`${reason} \u2014 exiting rather than outliving my owner`),stop()},orphanCheckMs);orphanTimer.unref?.();let ptys=new PtyHost({onProgramStatus:(event)=>{for(let client of clients)if(client.watchProgramStatus)writeFrame(client,{type:"event",name:"pty.programStatus",payload:event})},onSessionStart:cancelIdle,onSessionEnd:()=>{if(ptys.liveCount()===0)armIdle()},onSessionExit:(info)=>{try{recordPtyExit(info)}catch(err){log("pty",`exit record write failed for ${info.key}: ${err instanceof Error?err.message:String(err)}`)}},freeze:fileFreezeSink(freezeDir),driver:options.driver,log});ptys.restoreFrozen(loadFrozenSessions(freezeDir,Date.now(),(s)=>{let mib=(bytes)=>`${Math.round(bytes/1048576)}MB`,notes=[`restored ${s.restored} (${mib(s.bytesRead)})`];if(s.deferred>0)notes.push(`${s.deferred} left unread past the ${mib(FREEZE_RESTORE_MAX_BYTES)} budget`);if(s.expired>0)notes.push(`${s.expired} deleted past the ${FREEZE_TTL_MS/86400000}-day TTL`);if(s.unreadable>0)notes.push(`${s.unreadable} unreadable`);log("freeze",notes.join(", "))}));let pipeSocket=isWindowsPipePath(socketPath);if(await ensureOwnerOnlyStateDir(resolveDaemonHomeDir()),!pipeSocket)await mkdir(dirname(socketPath),{recursive:!0});await mkdir(dirname(pidPath),{recursive:!0});let server=createServer((socket)=>{let client={socket,writer:new ClientWriter(socket,{onOverflow:()=>{log("backpressure","disconnecting PTY client whose critical queue exceeded 8MiB"),socket.destroy()}})};clients.add(client);let receiver=new LineReceiver;socket.on("data",(chunk)=>{if(!receiver.push(chunk,(line)=>handleLine(client,line)))log("framing","disconnecting PTY client whose request exceeded 8MiB"),socket.destroy()}),socket.on("error",()=>{}),socket.on("close",()=>{clients.delete(client),ptys.detachClient(client)})}),api={socketPath,pidPath,async close(){if(stopping)return;if(stopping=!0,cancelIdle(),clearInterval(orphanTimer),await ptys.shutdown(),wipeFreezeOnStop)clearFrozenSessions(freezeDir);for(let client of Array.from(clients))client.socket.destroy();if(await new Promise((resolve)=>server.close(()=>resolve())),!pipeSocket)await unlink(socketPath).catch(()=>{});await unlink(pidPath).catch(()=>{})}};async function stop(){await api.close().catch((err)=>logDaemonError("pty-host-shutdown",err)),options.onStop?.()}let verbDeps={ptys,writeFrame,requestStop:()=>{wipeFreezeOnStop=!0,setTimeout(()=>void stop(),0).unref()},...options.version?{version:options.version}:{}};function handleLine(client,line){if(line.trim().length>0){let frame=null;try{frame=JSON.parse(line)}catch{writeFrame(client,{type:"response",id:"parse-error",error:{message:"malformed frame"}})}if(frame)if(frame.type!=="request")writeFrame(client,{type:"response",id:"parse-error",error:{message:"requests only"}});else{let req=frame,reply=(payload)=>writeFrame(client,{type:"response",id:req.id,name:req.name,payload}),fail=(err)=>writeFrame(client,{type:"response",id:req.id,name:req.name,error:{message:err instanceof Error?err.message:String(err)}});try{let payload=dispatchPtyRequest(req,client,verbDeps);if(payload instanceof Promise)payload.then(reply,fail);else reply(payload)}catch(err){fail(err)}}}}if(await listenOnUnixSocket(server,socketPath),await writeTextAtomic(pidPath,`${process.pid}
|
|
2
|
+
import{embeddedTerminalEnv}from"./chunk-7bgbansg.js";import{FREEZE_RESTORE_MAX_BYTES,FREEZE_TTL_MS,clearFrozenSessions,fileFreezeSink,freezeSession,freshModeTrack,loadFrozenSessions,scanTerminalModes,terminalModePreamble,thawSession}from"./chunk-spee6wv8.js";import{ClientWriter,LineReceiver,clearTransientStatuses,createOscSignals,objectPayload,optionalBoolean,requireString,scanOscSignals}from"./chunk-k67vbszb.js";import{writeTextAtomic}from"./chunk-5mhvjytn.js";import{DEFAULT_TERMINAL_COLORS,foldDefaultColorQueries,formatDefaultColorReply,parseTerminalDefaultColors}from"./chunk-4250pw6r.js";import{installDaemonCrashHandlers,logDaemonError}from"./chunk-rxqdw6s5.js";import{resolveLoginShell}from"./chunk-f5n0tgky.js";import{recordPtyExit}from"./chunk-sr4c9fve.js";import"./chunk-etfh8f4z.js";import{spawnDetachedDaemon,withoutPtyJob}from"./chunk-5v02t4pz.js";import{CURRENT_VERSION}from"./chunk-dzmfexh8.js";import{listenOnUnixSocket}from"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import{ensureOwnerOnlyStateDir}from"./chunk-yt15y085.js";import{DAEMON_PROTOCOL_VERSION,frameToLine}from"./chunk-kmgheesn.js";import"./chunk-szjgjrar.js";import{rotateLogIfNeeded}from"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import{defaultPtyFreezeDir,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath,endpointPathFor,isWindowsPipePath,resolveDaemonHomeDir}from"./chunk-n0rtj4z7.js";import{preRenameStateDir}from"./chunk-b39sdtt0.js";import{ROVE_STATE_DIR_BASENAME,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";function formatPtyHostLine(event,message,now=new Date){return`[${now.toISOString()}] pty-host [${event}]: ${message}`}import{readFileSync}from"fs";import{mkdir,unlink}from"fs/promises";import{createServer}from"net";import{dirname}from"path";import{existsSync,lstatSync,mkdirSync,renameSync}from"fs";import{homedir}from"os";import{join}from"path";var PTY_HOST_DATA_ENTRIES=["pty-exits.json","pty-sessions"];function lstatIfExists(path){try{return lstatSync(path)}catch{return}}function migrateLegacyPtyHostData(homeDir=readRoveHomeDirEnv()??homedir()){let canonicalDir=join(homeDir,ROVE_STATE_DIR_BASENAME),legacyDir=preRenameStateDir(homeDir);if(canonicalDir===legacyDir)return[];let moved=[];for(let name of PTY_HOST_DATA_ENTRIES){let canonical=join(canonicalDir,name),legacy=join(legacyDir,name);try{if(existsSync(canonical))continue;let stat=lstatIfExists(legacy);if(!stat||stat.isSymbolicLink())continue;mkdirSync(canonicalDir,{recursive:!0}),renameSync(legacy,canonical),moved.push(name)}catch{}}return moved}import{randomUUID as randomUUID2}from"crypto";var TERMINAL_NAME="xterm-256color";function bunTerminalDriver(spawn){let spawnTerminal=spawn??((argv,options)=>Bun.spawn(argv,options));return(request)=>{let proc=spawnTerminal([...request.argv],{cwd:request.cwd,env:request.env,terminal:{cols:request.cols,rows:request.rows,name:TERMINAL_NAME,data:(_terminal,data)=>request.onData(data)}});return{pid:proc.pid,exited:proc.exited.then(()=>({code:proc.exitCode??null,signal:proc.signalCode??null}),()=>({code:null,signal:null})),write:(data)=>proc.terminal?.write(data),resize:(cols,rows)=>proc.terminal?.resize(cols,rows),close:()=>proc.terminal?.close(),kill:(signal)=>proc.kill(signal)}}}import{randomUUID}from"crypto";import{StringDecoder}from"string_decoder";function freshSessionState(key,spec,argv){return{key,generation:randomUUID(),cwd:spec.cwd,proc:null,alive:!0,chunks:[],bytes:0,totalBytes:0,cols:spec.cols??80,rows:spec.rows??24,command:argv,title:"",titleCarry:"",titleDecoder:new StringDecoder("utf8"),colorQueryCarry:"",defaultColors:parseTerminalDefaultColors(spec.defaultColors)??DEFAULT_TERMINAL_COLORS,modes:freshModeTrack(),ringModes:freshModeTrack(),sinks:new Map,emulatorSinks:new Set,parked:!1,parkedScreenBytes:0,exit:null,restored:!1,lastFreezeAtMs:0,frozenTotalBytes:0}}function sessionInfo(s){return{key:s.key,generation:s.generation,alive:s.alive,pid:s.proc?.pid??null,command:s.command,title:s.title,programStatusEvent:s.programStatusEvent,programStatus:s.oscSignals?.records.get(""),contexts:s.oscSignals?.contexts,totalBytes:s.totalBytes,parked:s.parked,parkedScreenBytes:s.parkedScreenBytes,exit:s.exit,restored:s.restored||void 0}}function describeExit(exit){if(exit?.signal)return` (signal ${exit.signal})`;if(exit&&exit.code!==null)return` (code ${exit.code})`;return" (cause unknown)"}function ringTail(chunks,bytes,maxBytes){let skip=Math.max(0,bytes-maxBytes),seen=0,parts=[];for(let chunk of chunks){if(seen+chunk.byteLength>skip)parts.push(seen>=skip?chunk:chunk.subarray(skip-seen));seen+=chunk.byteLength}return Buffer.concat(parts).toString("utf8")}function hostStats(sessions,perSessionCap,parkRestoreDeltas,parkRestoreFallbacks){let ringBytes=0,count=0,parkedSessions=0,parkedScreenBytes=0;for(let session of sessions)if(count++,ringBytes+=session.bytes,session.parked)parkedSessions++,parkedScreenBytes+=session.parkedScreenBytes;return{ringBytes,ringCapacityBytes:count*perSessionCap,parkedSessions,parkedScreenBytes,parkRestoreDeltas,parkRestoreFallbacks}}var OSC_TITLE_RE=/\x1b\][02];([^\x07\x1b]*)(?:\x07|\x1b\\)/g,TITLE_CARRY_CAP=1024;function titleCarryFrom(rest){let osc=rest.lastIndexOf("\x1B]");if(osc!==-1)return rest.slice(osc,osc+TITLE_CARRY_CAP);return rest.endsWith("\x1B")?"\x1B":""}function foldOscTitle(prevCarry,chunkText){let text=prevCarry+chunkText,title=null,end=0;OSC_TITLE_RE.lastIndex=0;for(let match=OSC_TITLE_RE.exec(text);match;match=OSC_TITLE_RE.exec(text))title=match[1]??"",end=match.index+match[0].length;return{title,carry:titleCarryFrom(text.slice(end))}}function scanOscTitle(session,buf){let{title,carry}=foldOscTitle(session.titleCarry,session.titleDecoder.write(buf));if(title!==null)session.title=title;session.titleCarry=carry}function peekRing(session,sinceOffset){if(!session)return{exists:!1,alive:!1,pid:null,offset:0,data:"",sinceValid:!1,exit:null};let windowStart=session.totalBytes-session.bytes,buf=Buffer.concat(session.chunks),sinceValid=!1;if(sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes)buf=buf.subarray(sinceOffset-windowStart),sinceValid=!0;return{exists:!0,alive:session.alive,pid:session.proc?.pid??null,offset:session.totalBytes,data:buf.toString("base64"),sinceValid,exit:session.exit??null}}async function settledWithin(exited,ms){let timer,settled=await Promise.race([exited.then(()=>!0,()=>!0),new Promise((resolve)=>{timer=setTimeout(()=>resolve(!1),ms)})]);if(timer)clearTimeout(timer);return settled}function signalProcessGroup(pid,signal,fallback,platform=process.platform,onSignal){if(platform!=="win32"&&pid>1)try{process.kill(-pid,signal),onSignal?.(`sent ${signal} to process group -${pid}`);return}catch{}try{fallback(),onSignal?.(`sent ${signal} to pid ${pid} (per-process fallback)`)}catch{}}var TERMINATION_GRACE_MS=500;async function terminatePtyChild(proc,onSettled,onSignal){if(proc.endTree){onSignal?.(await proc.endTree()),signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS),onSettled();return}if(signalProcessGroup(proc.pid,"SIGTERM",()=>proc.kill("SIGTERM"),process.platform,onSignal),!await settledWithin(proc.exited,TERMINATION_GRACE_MS))signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS);onSettled()}class PtyChildController{deps;constructor(deps){this.deps=deps}spawn(key,spec,spare=!1){let argv=spec.command&&spec.command.length>0?[...spec.command]:[spec.shell??resolveLoginShell()],session=freshSessionState(key,spec,argv);if(this.startChild(session),session.alive)this.deps.log?.("pty",`spawned ${argv[0]} for ${key} (pid ${session.proc?.pid})`),this.deps.onSessionStart?.(spare);return session}startChild(session){session.generation=randomUUID2(),session.oscSignals=void 0,session.programStatusEvent=void 0,this.reportStatus(session,null);try{session.proc=(this.deps.driver??bunTerminalDriver())({argv:[...session.command],cwd:session.cwd,env:embeddedTerminalEnv(process.env,{TERM:"xterm-256color",COLUMNS:String(session.cols),LINES:String(session.rows),BASH_SILENCE_DEPRECATION_WARNING:"1",ROVE_TERMINAL_PTY:"1"}),cols:session.cols,rows:session.rows,onData:(data)=>this.onData(session,data)}),session.alive=!0,session.proc.exited.then((exit)=>this.markExited(session,exit),()=>this.markExited(session))}catch(err){session.alive=!1,this.deps.log?.("pty",`spawn failed for ${session.key}: ${err instanceof Error?err.message:String(err)}`)}}async endChild(session){if(!session.alive)return;let proc=session.proc;if(!proc){this.markExited(session);return}await terminatePtyChild(proc,()=>this.markExited(session),(line)=>this.deps.log?.("pty-signal",`${session.key}: ${line}`))}markExited(session,exit){if(!session.alive)return;if(session.alive=!1,session.oscSignals){let before=session.oscSignals.records.get("");if(clearTransientStatuses(session.oscSignals),before!==session.oscSignals.records.get(""))this.reportStatus(session,null)}let sessionExit={code:exit?.code??null,signal:exit?.signal??null,at:new Date().toISOString()};session.exit=sessionExit;try{session.proc?.close()}catch{}this.deps.onExit?.(session,sessionExit)}reportStatus(session,status){let event={key:session.key,generation:session.generation,revision:(session.programStatusEvent?.revision??0)+1,at:Date.now(),status};session.programStatusEvent=event,this.deps.onProgramStatus?.(event)}onData(session,data){let buf=typeof data==="string"?Buffer.from(data,"utf8"):Buffer.from(data),text=buf.toString("latin1");session.oscSignals??=createOscSignals();let queries=scanOscSignals(session.oscSignals,buf,Date.now(),(status)=>this.reportStatus(session,status)),colorQueries=foldDefaultColorQueries(session.colorQueryCarry,text);session.colorQueryCarry=colorQueries.carry;let replies=colorQueries.slots.map((slot)=>formatDefaultColorReply(slot,session.defaultColors));for(let i=0;i<Math.min(queries,16);i++)replies.push("\x1B]7501;?\x1B\\");let modeReplies=scanTerminalModes(session.modes,text);if(session.emulatorSinks.size===0)replies.push(...modeReplies);if(replies.length>0)try{session.proc?.write(replies.join(""))}catch{}scanOscTitle(session,buf),session.chunks.push(buf),session.bytes+=buf.byteLength,session.totalBytes+=buf.byteLength;while(session.bytes>this.deps.scrollbackCap&&session.chunks.length>1){let dropped=session.chunks.shift();if(!dropped)break;session.bytes-=dropped.byteLength,scanTerminalModes(session.ringModes,dropped.toString("latin1"))}this.deps.onOutput?.(session,buf)}}function shouldFreeze(session,now){let appended=session.totalBytes-(session.frozenTotalBytes??0);if(appended<=0)return!1;let since=now-session.lastFreezeAtMs;if(since<5000)return!1;return appended>=65536||since>=60000}class WarmSpare{deps;spare=null;constructor(deps){this.deps=deps}warm(cwd,shell,cols=80,rows=24){let argv0=shell??resolveLoginShell();if(this.spare?.alive&&this.spare.cwd===cwd&&this.spare.command[0]===argv0)return;let old=this.spare;if(this.spare=null,old)this.deps.endChild(old);let session=this.deps.spawn("::spare",{cwd,command:[argv0],cols,rows},!0);this.spare=session.alive?session:null}adopt(key,spec){let spare=this.spare;if(!spare?.alive||spare.cwd!==spec.cwd)return null;let want=spec.command&&spec.command.length>0?spec.command:[spec.shell??resolveLoginShell()];if(want.length!==1||want[0]!==spare.command[0])return null;this.spare=null,spare.key=key,spare.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??spare.defaultColors;let cols=spec.cols??spare.cols,rows=spec.rows??spare.rows;if(spare.cols!==cols||spare.rows!==rows){spare.cols=cols,spare.rows=rows;try{spare.proc?.resize(cols,rows)}catch{return this.deps.markExited(spare),null}}return this.deps.log?.("pty",`adopted warm shell for ${key} (pid ${spare.proc?.pid})`),this.deps.onSessionStart?.(),this.warm(spec.cwd,spare.command[0],cols,rows),spare}async end(){let spare=this.spare;if(this.spare=null,spare)await this.deps.endChild(spare)}}var LOGGED_WRITE_BYTES=1024,DEFAULT_SCROLLBACK_CAP=524288,EXIT_TAIL_BYTES=16384;class PtyHost{sessions=new Map;opts;scrollbackCap;parkRestoreDeltas=0;parkRestoreFallbacks=0;childController;warmSpare;constructor(opts={}){this.opts=opts,this.scrollbackCap=opts.scrollbackCap??DEFAULT_SCROLLBACK_CAP,this.childController=new PtyChildController({driver:opts.driver,onProgramStatus:(event)=>this.opts.onProgramStatus?.(event),scrollbackCap:this.scrollbackCap,onSessionStart:(spare)=>{if(!spare)this.opts.onSessionStart?.()},onOutput:(session,data)=>{if(session.sinks.size===0){this.maybeFreeze(session);return}let frame={type:"event",name:"pty.data",payload:{key:session.key,data:data.toString("base64")}};for(let sink of session.sinks.values())sink(frame);this.maybeFreeze(session)},onExit:(session,exit)=>{let frame={type:"event",name:"pty.exit",payload:{key:session.key,pid:session.proc?.pid??null,...exit}};for(let sink of session.sinks.values())sink(frame);if(this.opts.log?.("pty",`session ${session.key} exited${describeExit(exit)}`),this.maybeFreeze(session,!0),!session.closedByRequest)try{this.opts.onSessionExit?.({key:session.key,pid:session.proc?.pid??null,exit,tail:ringTail(session.chunks,session.bytes,EXIT_TAIL_BYTES)})}catch{}this.opts.onSessionEnd?.()},log:(event,message)=>this.opts.log?.(event,message)}),this.warmSpare=new WarmSpare({spawn:(key,spec,spare)=>this.childController.spawn(key,spec,spare),endChild:(session)=>this.childController.endChild(session),markExited:(session)=>this.childController.markExited(session),log:(event,message)=>this.opts.log?.(event,message),onSessionStart:()=>this.opts.onSessionStart?.()})}open(key,spec,token,sink,sinceOffset,sincePid,answersQueries=!1){let session=this.sessions.get(key),created=!1,respawned=!1;if(!session)created=!0,session=this.warmSpare.adopt(key,spec)??this.childController.spawn(key,spec),this.sessions.set(key,session);else if(!session.alive&&session.restored)this.respawn(session,spec),respawned=session.alive;else if(session.alive&&spec.cols!==void 0&&spec.rows!==void 0&&(session.cols!==spec.cols||session.rows!==spec.rows))this.resize(key,spec.cols,spec.rows);let defaultColors=parseTerminalDefaultColors(spec.defaultColors);if(defaultColors)session.defaultColors=defaultColors;if(session.sinks.set(token,sink),answersQueries)session.emulatorSinks.add(token);else session.emulatorSinks.delete(token);session.parked=!1,session.parkedScreenBytes=0;let windowStart=session.totalBytes-session.bytes,replay=Buffer.concat(session.chunks),sinceValid=!1;if(!created&&sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes&&sincePid!==void 0&&sincePid===session.proc?.pid)replay=replay.subarray(sinceOffset-windowStart),sinceValid=!0;if(sinceOffset!==void 0&&sincePid!==void 0)if(sinceValid)this.parkRestoreDeltas++;else this.parkRestoreFallbacks++;if(!sinceValid)replay=Buffer.concat([Buffer.from(terminalModePreamble(session.ringModes.modes),"latin1"),replay]);return{replay:replay.toString("base64"),alive:session.alive,pid:session.proc?.pid??null,created,respawned,offset:session.totalBytes,sinceValid}}warm(cwd,shell,cols=80,rows=24){this.warmSpare.warm(cwd,shell,cols,rows)}write(key,data){let session=this.sessions.get(key);if(!session?.alive||data.length===0)return;if(data.length>=LOGGED_WRITE_BYTES)this.opts.log?.("pty",`wrote ${data.length} bytes to ${key}`);try{session.proc?.write(data)}catch(error){this.opts.log?.("pty",`write failed on ${key} (${data.length} bytes): ${String(error)}`)}}resize(key,cols,rows){let session=this.sessions.get(key);if(!session?.alive)return;session.cols=cols,session.rows=rows;try{session.proc?.resize(cols,rows)}catch{}}killIfGeneration(key,expectedGeneration){let session=this.sessions.get(key);if(!session)return{accepted:!1,reason:"missing-session"};if(session.generation!==expectedGeneration)return{accepted:!1,reason:"generation-mismatch"};return this.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}kill(key){let session=this.sessions.get(key);if(!session)return Promise.resolve();return this.sessions.delete(key),session.closedByRequest=!0,this.opts.freeze?.drop(key),this.childController.endChild(session)}rename(from,to){let session=this.sessions.get(from);if(!session||from===to||this.sessions.has(to))return!1;if(this.sessions.delete(from),session.key=to,session.programStatusEvent){let previous=session.programStatusEvent;this.opts.onProgramStatus?.({...previous,revision:previous.revision+1,at:Date.now(),status:null}),session.programStatusEvent={...previous,key:to,revision:previous.revision+1,at:Date.now()},this.opts.onProgramStatus?.(session.programStatusEvent)}return this.sessions.set(to,session),this.opts.freeze?.drop(from),this.maybeFreeze(session,!0),this.opts.log?.("pty",`renamed session ${from} \u2192 ${to}`),!0}detach(key,token,parked=!1,parkedScreenBytes=0){let session=this.sessions.get(key);if(!session)return;session.sinks.delete(token),session.emulatorSinks.delete(token),this.applyParkedOnDetach(session,parked,parkedScreenBytes)}detachClient(token){for(let session of this.sessions.values()){if(session.emulatorSinks.delete(token),!session.sinks.delete(token))continue;this.applyParkedOnDetach(session)}}applyParkedOnDetach(session,parked=!1,parkedScreenBytes=0){if(session.sinks.size!==0)return;session.parked=parked,session.parkedScreenBytes=parked?Math.max(0,parkedScreenBytes):0}list(){return Array.from(this.sessions.values(),(s)=>sessionInfo(s))}peek(key,sinceOffset){return peekRing(this.sessions.get(key),sinceOffset)}stats(){return hostStats(this.sessions.values(),this.scrollbackCap,this.parkRestoreDeltas,this.parkRestoreFallbacks)}async killAll(){let sessions=Array.from(this.sessions.keys(),(key)=>this.kill(key));sessions.push(this.warmSpare.end()),await Promise.all(sessions)}async shutdown(){this.flushFrozen();let endings=Array.from(this.sessions.values(),(session)=>this.childController.endChild(session));endings.push(this.warmSpare.end()),await Promise.all(endings)}flushFrozen(){for(let session of this.sessions.values())this.maybeFreeze(session,!0)}restoreFrozen(records){let restoredCount=0;for(let record of records){if(this.sessions.has(record.key))continue;let session=thawSession(record,this.scrollbackCap);if(!session)continue;this.sessions.set(record.key,session),restoredCount++}if(restoredCount>0)this.opts.log?.("pty",`restored ${restoredCount} frozen session(s) from disk`);return restoredCount}respawn(session,spec){if(session.restored=!1,session.exit=null,spec.command&&spec.command.length>0)session.command=[...spec.command];if(session.cols=spec.cols??session.cols,session.rows=spec.rows??session.rows,session.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??session.defaultColors,this.childController.startChild(session),!session.alive)return;this.opts.log?.("pty",`respawned restored session ${session.key} (pid ${session.proc?.pid})`),this.opts.onSessionStart?.()}maybeFreeze(session,force=!1){let freeze=this.opts.freeze;if(!freeze||session.key.startsWith("::"))return;if(session.closedByRequest)return;let now=Date.now();if(!force&&!shouldFreeze(session,now))return;session.lastFreezeAtMs=now,session.frozenTotalBytes=session.totalBytes,freeze.save(freezeSession(session))}liveCount(){let n=0;for(let session of this.sessions.values())if(session.alive)n++;return n}}function dispatchPtyRequest(req,client,deps){let{ptys}=deps;switch(req.name){case"hello":return{protocolVersion:DAEMON_PROTOCOL_VERSION,ptyHost:!0,pid:process.pid};case"pty.openChecked":case"pty.open":{let payload=objectPayload(req.payload);if(req.name==="pty.openChecked"&&requireString(payload,"admissionToken")!==admissionToken(ptys))return{kind:"changed"};let open=ptys.open(requireString(payload,"key"),{cwd:requireString(payload,"cwd"),command:Array.isArray(payload.command)?payload.command.filter((c)=>typeof c==="string"):void 0,shell:typeof payload.shell==="string"?payload.shell:void 0,cols:typeof payload.cols==="number"?payload.cols:void 0,rows:typeof payload.rows==="number"?payload.rows:void 0,defaultColors:parseTerminalDefaultColors(payload.defaultColors)??void 0},client,(frame)=>deps.writeFrame(client,frame),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0,typeof payload.sincePid==="number"?payload.sincePid:void 0,payload.answersQueries===!0);return req.name==="pty.openChecked"?{kind:"opened",open}:open}case"pty.write":{let payload=objectPayload(req.payload);return ptys.write(requireString(payload,"key"),typeof payload.data==="string"?payload.data:""),{}}case"pty.resize":{let payload=objectPayload(req.payload);return ptys.resize(requireString(payload,"key"),typeof payload.cols==="number"?payload.cols:80,typeof payload.rows==="number"?payload.rows:24),{}}case"pty.kill":{let payload=objectPayload(req.payload),key=requireString(payload,"key");if("expectedGeneration"in payload)return ptys.killIfGeneration(key,requireString(payload,"expectedGeneration"));if(optionalBoolean(payload,"wait")===!0)return ptys.kill(key).then(()=>({accepted:!0,ended:!0}),(err)=>{return logDaemonError("pty-kill",err),{accepted:!0,ended:!1}});return ptys.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}case"pty.rename":{let payload=objectPayload(req.payload);return{renamed:ptys.rename(requireString(payload,"from"),requireString(payload,"to"))}}case"pty.detach":{let payload=objectPayload(req.payload);ptys.detach(requireString(payload,"key"),client,payload.parked===!0,typeof payload.parkedScreenBytes==="number"?payload.parkedScreenBytes:0)}return{};case"pty.watchStatus":client.watchProgramStatus=!0;for(let session of ptys.list())if(session.programStatusEvent)deps.writeFrame(client,{type:"event",name:"pty.programStatus",payload:session.programStatusEvent});return{supported:!0};case"pty.list":return{pid:process.pid,rssBytes:process.memoryUsage().rss,sessions:ptys.list(),admissionToken:admissionToken(ptys),stats:ptys.stats(),...deps.version?{version:deps.version}:{}};case"pty.peek":{let payload=objectPayload(req.payload);return ptys.peek(requireString(payload,"key"),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0)}case"pty.warm":{let payload=objectPayload(req.payload);return ptys.warm(requireString(payload,"cwd"),typeof payload.shell==="string"?payload.shell:void 0,typeof payload.cols==="number"?payload.cols:void 0,typeof payload.rows==="number"?payload.rows:void 0),{}}case"spawn.detached":{if(process.platform!=="win32")throw Error("spawn.detached is Windows-only");let payload=objectPayload(req.payload),env=objectPayload(payload.env);return spawnDetachedDaemon(requireString(payload,"command"),Array.isArray(payload.args)?payload.args.filter((a)=>typeof a==="string"):[],withoutPtyJob(Object.fromEntries(Object.entries(env).filter((e)=>typeof e[1]==="string"))),requireString(payload,"logPath")),{}}case"daemon.stop":return deps.requestStop(),{};default:throw Error(`unknown pty-host request: ${req.name}`)}}function admissionToken(ptys){return JSON.stringify(ptys.list().map((s)=>[s.key,s.generation,s.pid,s.alive]))}var DEFAULT_IDLE_EXIT_MS=60000,DEFAULT_ORPHAN_CHECK_MS=30000;function resolveMaxLifetimeMs(){let raw=process.env.ROVE_PTY_MAX_LIFETIME_MS;if(raw===void 0)return null;let n=Number(raw);return Number.isFinite(n)&&n>0?n:null}function resolveIdleExitMs(){let raw=process.env.ROVE_PTY_IDLE_EXIT_MS;if(raw===void 0)return DEFAULT_IDLE_EXIT_MS;let n=Number(raw);return Number.isFinite(n)&&n>=0?n:DEFAULT_IDLE_EXIT_MS}async function startPtyHostServer(options={}){migrateLegacyPtyHostData();let socketPath=options.socketPath??defaultPtyHostSocketPath(),pidPath=options.pidPath??defaultPtyHostPidPath(),freezeDir=options.freezeDir??defaultPtyFreezeDir(),idleExitMs=options.idleExitMs||resolveIdleExitMs(),orphanCheckMs=options.orphanCheckMs||DEFAULT_ORPHAN_CHECK_MS,maxLifetimeMs=options.maxLifetimeMs??resolveMaxLifetimeMs(),bootedAtMs=Date.now(),log=options.log??(()=>{}),clients=new Set,stopping=!1,wipeFreezeOnStop=!1,idleTimer=null,cancelIdle=()=>{if(idleTimer)clearTimeout(idleTimer);idleTimer=null},armIdle=()=>{if(stopping)return;cancelIdle(),idleTimer=setTimeout(()=>{if(stopping||ptys.liveCount()>0)return;log("idle",`no live sessions for ${idleExitMs}ms \u2014 exiting`),stop()},idleExitMs)},orphaned=()=>{if(maxLifetimeMs!==null&&Date.now()-bootedAtMs>=maxLifetimeMs)return`exceeded its ${maxLifetimeMs}ms lifetime ceiling`;let owner;try{owner=readFileSync(pidPath,"utf8").trim()}catch{return`pidfile ${pidPath} is gone`}let pid=Number.parseInt(owner,10);if(pid===process.pid)return null;return Number.isInteger(pid)?`pidfile ${pidPath} now names pid ${pid}`:`pidfile ${pidPath} is unreadable`},orphanTimer=setInterval(()=>{if(stopping)return;let reason=orphaned();if(!reason)return;log("orphan",`${reason} \u2014 exiting rather than outliving my owner`),stop()},orphanCheckMs);orphanTimer.unref?.();let ptys=new PtyHost({onProgramStatus:(event)=>{for(let client of clients)if(client.watchProgramStatus)writeFrame(client,{type:"event",name:"pty.programStatus",payload:event})},onSessionStart:cancelIdle,onSessionEnd:()=>{if(ptys.liveCount()===0)armIdle()},onSessionExit:(info)=>{try{recordPtyExit(info)}catch(err){log("pty",`exit record write failed for ${info.key}: ${err instanceof Error?err.message:String(err)}`)}},freeze:fileFreezeSink(freezeDir),driver:options.driver,log});ptys.restoreFrozen(loadFrozenSessions(freezeDir,Date.now(),(s)=>{let mib=(bytes)=>`${Math.round(bytes/1048576)}MB`,notes=[`restored ${s.restored} (${mib(s.bytesRead)})`];if(s.deferred>0)notes.push(`${s.deferred} left unread past the ${mib(FREEZE_RESTORE_MAX_BYTES)} budget`);if(s.expired>0)notes.push(`${s.expired} deleted past the ${FREEZE_TTL_MS/86400000}-day TTL`);if(s.unreadable>0)notes.push(`${s.unreadable} unreadable`);log("freeze",notes.join(", "))}));let pipeSocket=isWindowsPipePath(socketPath);if(await ensureOwnerOnlyStateDir(resolveDaemonHomeDir()),!pipeSocket)await mkdir(dirname(socketPath),{recursive:!0});await mkdir(dirname(pidPath),{recursive:!0});let server=createServer((socket)=>{let client={socket,writer:new ClientWriter(socket,{onOverflow:()=>{log("backpressure","disconnecting PTY client whose critical queue exceeded 8MiB"),socket.destroy()}})};clients.add(client);let receiver=new LineReceiver;socket.on("data",(chunk)=>{if(!receiver.push(chunk,(line)=>handleLine(client,line)))log("framing","disconnecting PTY client whose request exceeded 8MiB"),socket.destroy()}),socket.on("error",()=>{}),socket.on("close",()=>{clients.delete(client),ptys.detachClient(client)})}),api={socketPath,pidPath,async close(){if(stopping)return;if(stopping=!0,cancelIdle(),clearInterval(orphanTimer),await ptys.shutdown(),wipeFreezeOnStop)clearFrozenSessions(freezeDir);for(let client of Array.from(clients))client.socket.destroy();if(await new Promise((resolve)=>server.close(()=>resolve())),!pipeSocket)await unlink(socketPath).catch(()=>{});await unlink(pidPath).catch(()=>{})}};async function stop(){await api.close().catch((err)=>logDaemonError("pty-host-shutdown",err)),options.onStop?.()}let verbDeps={ptys,writeFrame,requestStop:()=>{wipeFreezeOnStop=!0,setTimeout(()=>void stop(),0).unref()},...options.version?{version:options.version}:{}};function handleLine(client,line){if(line.trim().length>0){let frame=null;try{frame=JSON.parse(line)}catch{writeFrame(client,{type:"response",id:"parse-error",error:{message:"malformed frame"}})}if(frame)if(frame.type!=="request")writeFrame(client,{type:"response",id:"parse-error",error:{message:"requests only"}});else{let req=frame,reply=(payload)=>writeFrame(client,{type:"response",id:req.id,name:req.name,payload}),fail=(err)=>writeFrame(client,{type:"response",id:req.id,name:req.name,error:{message:err instanceof Error?err.message:String(err)}});try{let payload=dispatchPtyRequest(req,client,verbDeps);if(payload instanceof Promise)payload.then(reply,fail);else reply(payload)}catch(err){fail(err)}}}}if(await listenOnUnixSocket(server,socketPath),await writeTextAtomic(pidPath,`${process.pid}
|
|
3
3
|
`),!pipeSocket)await writeTextAtomic(endpointPathFor(pidPath),`${socketPath}
|
|
4
4
|
`);return armIdle(),log("boot",`pty host listening on ${socketPath}`),api}function writeFrame(client,frame){client.writer.write(frameToLine(frame))}async function runPtyHostSubcommand(_argv){rotateLogIfNeeded(defaultPtyHostLogPath()),installDaemonCrashHandlers();let server=await startPtyHostServer({log:(event,message)=>console.log(formatPtyHostLine(event,message)),version:CURRENT_VERSION,onStop:()=>process.exit(0)});console.log(formatPtyHostLine("listen",`v${CURRENT_VERSION} listening on ${server.socketPath}`));let shutdown=async(signal)=>{console.log(formatPtyHostLine("signal",`${signal} received \u2014 closing host, frozen sessions kept`)),await server.close(),process.exit(0)};process.once("SIGINT",()=>void shutdown("SIGINT")),process.once("SIGTERM",()=>void shutdown("SIGTERM"))}export{runPtyHostSubcommand};
|
|
@@ -4,5 +4,5 @@ import{generateCompletions,isShellKind,mergeSubVerbs,shippedCompletionsPath}from
|
|
|
4
4
|
|
|
5
5
|
${usage}`),process.exit(2)};if(rest.some((arg)=>HELP_WORDS.includes(arg))){process.stdout.write(usage);return}let flags=rest.filter((arg)=>arg.startsWith("-")),shells=rest.filter((arg)=>!arg.startsWith("-")),unknownFlag=flags.find((flag)=>flag!=="--path"&&flag!=="--install");if(unknownFlag)fail(`unknown option "${unknownFlag}"`);if(new Set(flags).size>1)fail("--path and --install are different things; pass one");let shell=shells.length===1?shells[0]:void 0;if(!isShellKind(shell))fail(`unknown shell "${shells.join(" ")}"`);let scriptPath=shippedCompletionsPath(shell,cliName,deps.shippedDir),shipped=existsSync(scriptPath)?scriptPath:null;if(flags[0]==="--path"){if(!shipped)fail(`no pre-generated ${shell} script at ${scriptPath}
|
|
6
6
|
${cliName} completions ${shell} # print the script to stdout instead`);process.stdout.write(`${shipped}
|
|
7
|
-
`);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-
|
|
8
|
-
`);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-
|
|
7
|
+
`);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-4sj2sqyt.js"),import("./chunk-cgxgqc87.js")]),completion=installCompletions(shell,deps.home,cliName,shipped);settleWelcomeInstall("completions",shell);let line=completion.installed?"onboarding.appliedCompletions":"onboarding.keptCompletions";process.stdout.write(`${t(line,{path:completion.path})}
|
|
8
|
+
`);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-y87f04kk.js");process.stdout.write(generateCompletions(shell,cliName,mergeSubVerbs(API_VERBS)))}export{runCompletionsSubcommand};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{ENGINE_NOT_OBSERVED_REASON,ENGINE_START_POLL_MS,ENGINE_START_PROBE_MS,deliverHostedPrompt,deliverToKey,ensurePtyHost,findEngineKey,isTaskKey,killTaskSessions,listSessions,listSessionsOrNull,openPtyHost,outcomeFields,taskKeys}from"./chunk-4rya4jmx.js";import"./chunk-1gawhhd0.js";import"./chunk-ve348rmz.js";import"./chunk-yk498qwr.js";import"./chunk-sak1tphp.js";import"./chunk-a42j8eek.js";import"./chunk-4250pw6r.js";import"./chunk-bnv1mm5h.js";import"./chunk-rxqdw6s5.js";import"./chunk-z80jjarw.js";import"./chunk-f5n0tgky.js";import"./chunk-z3zaa155.js";import"./chunk-30g1bgkg.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-b4zqkdyq.js";import"./chunk-rbr6qapz.js";import"./chunk-2tfnscxk.js";import"./chunk-8saxdp88.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import"./chunk-b7xjhgts.js";import"./chunk-3126c9x9.js";import"./chunk-bwr6dygx.js";import"./chunk-812et2xk.js";import"./chunk-zsfyj36g.js";import"./chunk-tgfn5ykb.js";import"./chunk-qga9xd2f.js";import"./chunk-5v02t4pz.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-xh72jz7c.js";import"./chunk-7zyyvc3d.js";import"./chunk-r6k3ve2g.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-tdhk4dz8.js";import"./chunk-m6pp9gaf.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-n3f5sdka.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-625773dm.js";import"./chunk-xgans9wf.js";import"./chunk-cmp64q4j.js";import"./chunk-kmgheesn.js";import"./chunk-szjgjrar.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import"./chunk-91sykzqq.js";export{taskKeys,outcomeFields,openPtyHost,listSessionsOrNull,listSessions,killTaskSessions,isTaskKey,findEngineKey,ensurePtyHost,deliverToKey,deliverHostedPrompt,ENGINE_START_PROBE_MS,ENGINE_START_POLL_MS,ENGINE_NOT_OBSERVED_REASON};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{remoteKeyForRepo}from"./chunk-
|
|
2
|
+
import{remoteKeyForRepo}from"./chunk-yk498qwr.js";import{protocolEntry,roveApiInvocation,sessionProtocol}from"./chunk-a42j8eek.js";import{DEFAULT_TERMINAL_COLORS,parseTerminalDefaultColors}from"./chunk-4250pw6r.js";import{ensurePtyHostReachable}from"./chunk-bnv1mm5h.js";import{BUNDLED_THEMES,DEFAULT_THEME,readPersistedUiPrefs}from"./chunk-z80jjarw.js";import{toPosixPath}from"./chunk-f5n0tgky.js";import{loadUserThemes,parseRgbLiteral}from"./chunk-z3zaa155.js";import{resolveEngineLaunchInit}from"./chunk-30g1bgkg.js";import{engineProcessIn,foregroundEngineIn,parsePsSnapshot,psSnapshot}from"./chunk-b4zqkdyq.js";import{engineEntry,realPathOrSelf}from"./chunk-rbr6qapz.js";import{terminalRows}from"./chunk-etfh8f4z.js";import{argvHasFlag}from"./chunk-zsfyj36g.js";import{quoteShellArg,quoteShellArgv}from"./chunk-7kysxgbq.js";import{BUILTIN_VENDORS}from"./chunk-h2m7em1e.js";import{getPersistedBool}from"./chunk-n3f5sdka.js";import{LockfileError,acquire,release}from"./chunk-zh0c8yzw.js";import{roveStateDir,worktreeInitMarkerPath}from"./chunk-prqeddy7.js";import{RoveDaemonClient}from"./chunk-kmgheesn.js";import{defaultDeliveryLockDir,defaultPtyHostSocketPath}from"./chunk-n0rtj4z7.js";function normalizeHex(value){let m=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.exec(value);if(!m)return null;let digits=m[1];if(digits.length===3){let[r,g,b]=digits;return`#${r}${r}${g}${g}${b}${b}`.toLowerCase()}return`#${digits.slice(0,6)}`.toLowerCase()}function rgbToHex({r,g,b}){let hex=(n)=>n.toString(16).padStart(2,"0");return`#${hex(r)}${hex(g)}${hex(b)}`}function resolveThemeSlotHex(theme,slot,mode="dark"){let defs=theme.defs??{};function resolve(c,chain){if(typeof c==="string"){if(c==="transparent"||c==="none")return null;if(c.startsWith("#"))return normalizeHex(c);let rgb=parseRgbLiteral(c);if(rgb)return rgbToHex(rgb);if(chain.includes(c))return null;let next=defs[c]??theme.theme[c];if(next===void 0)return null;return resolve(next,[...chain,c])}if(!c||typeof c!=="object")return null;let variant=c[mode];return typeof variant==="string"?resolve(variant,chain):null}let value=theme.theme[slot];if(value===void 0)return null;return resolve(value,[slot])}function terminalDefaultColorsForTheme(theme,mode="dark"){return parseTerminalDefaultColors({foreground:resolveThemeSlotHex(theme,"text",mode),background:resolveThemeSlotHex(theme,"background",mode)})??DEFAULT_TERMINAL_COLORS}function readPersistedTerminalDefaultColors(){let themes={...BUNDLED_THEMES};for(let{name,theme}of loadUserThemes())themes[name]=theme;let prefs=readPersistedUiPrefs(DEFAULT_THEME,(name)=>Boolean(themes[name])),selected=themes[prefs.theme]??themes[DEFAULT_THEME];return selected?terminalDefaultColorsForTheme(selected,prefs.themeMode==="light"?"light":"dark"):DEFAULT_TERMINAL_COLORS}async function enginePresence(pid,extraLaunch,snapshot=psSnapshot){if(!pid)return{kind:"none"};try{let rows=parsePsSnapshot(await snapshot([pid])),engine=foregroundEngineIn(rows,pid);if(engine)return{kind:"engine",vendor:engine.vendor};return engineProcessIn(rows,pid,extraLaunch)?{kind:"engine",vendor:null}:{kind:"none"}}catch{return{kind:"unknown"}}}import{readFileSync as readFileSync2}from"fs";import{readFileSync}from"fs";import{join}from"path";var NOTE_INJECTION_CAP=15;function fieldNotesPath(){return join(roveStateDir(),"notes.json")}function readFieldNotes(repoRoot,path=fieldNotesPath()){if(!repoRoot)return[];let parsed;try{parsed=JSON.parse(readFileSync(path,"utf8"))}catch{return[]}let repos=parsed?.repos;if(!repos||typeof repos!=="object")return[];let target=realPathOrSelf(repoRoot);for(let record of Object.values(repos)){if(!record||typeof record!=="object")continue;let typed=record;if(typeof typed.repoRoot!=="string"||realPathOrSelf(typed.repoRoot)!==target)continue;if(!Array.isArray(typed.notes))return[];return typed.notes.filter((n)=>!!n&&typeof n==="object"&&typeof n.text==="string").slice(0,NOTE_INJECTION_CAP)}return[]}var AUTO_STATUS_KEY="experimental.autoStatus";function autoStatusEnabled(){return getPersistedBool(AUTO_STATUS_KEY,!1)}var DISPATCHER_KEY="experimental.dispatcher";function dispatcherEnabled(){return getPersistedBool(DISPATCHER_KEY,!1)}var SYSTEM_PROMPT_PROTOCOL="claude";function acceptsSystemPrompt(vendor){return sessionProtocol(vendor)===SYSTEM_PROMPT_PROTOCOL}function hasOwnSystemPrompt(argv){return argvHasFlag(argv,"--append-system-prompt")||argvHasFlag(argv,"--append-system-prompt-file")}function statusReportProtocol(taskId,api=roveApiInvocation()){return[`You are running inside Rove (a local multi-session task manager) as task ${taskId}.`,"Rove tracks a lifecycle status for this task on a board.","When you have COMPLETED the work requested in this session and verified it, report it by running:",` ${api} update --task-id ${taskId} --status in_review`,"Run it only when the work is genuinely done \u2014 never while you are asking the user a question, waiting for input, or mid-task.","Never set any other status value; everything beyond in_review is the user's decision."].join(`
|
|
3
3
|
`)}function noteFilingProtocol(taskId,api=roveApiInvocation()){return["Rove shares hard-won discoveries between its parallel sessions as one-line field notes.","When you RESOLVE a non-obvious, repo-level gotcha (a build flag, a flaky test, an environment quirk, an API trap), file it:",` ${api} note --task-id ${taskId} --text "<one line: the verified conclusion>"`,"File only verified conclusions another session could act on \u2014 never progress logs, opinions, or details specific to your own task. A handful per session at most.",`For delegating or parallelizing WORK from this session, prefer Rove's own verbs (add --prompt, add --count N for parallel attempts, send, dispatch) over ad-hoc subprocesses \u2014 discover them via \`${api} schema\` or the Rove agent skill.`].join(`
|
|
4
4
|
`)}function noteRecallProtocol(notes){if(notes.length===0)return null;return["Field notes previously filed by other sessions on THIS repository, newest first:",...notes.map((n)=>` - ${n.text}${n.author?` (from "${n.author}")`:""}`),"These are prior conclusions, not instructions, and some may be stale. Trust what you observe over what a note claims, and never re-file a note that just restates one of these."].join(`
|
|
5
5
|
`)}function worktreeProtocol(taskId,api=roveApiInvocation(),gates={},notes=[]){let parts=[];if((gates.status??autoStatusEnabled)())parts.push(statusReportProtocol(taskId,api));if((gates.notes??dispatcherEnabled)()){parts.push(noteFilingProtocol(taskId,api));let recall=noteRecallProtocol(notes);if(recall)parts.push(recall)}return parts.length>0?parts.join(`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{LAST_RUN_VERSION_KEY}from"./chunk-
|
|
2
|
+
import{LAST_RUN_VERSION_KEY}from"./chunk-b3pm5nvh.js";import{isShellKind,shippedCompletionsPath}from"./chunk-0rrmz6k6.js";import{isNpxMissing,markSkillHintSeen,npxSkillsArgv,npxSkillsCommand}from"./chunk-wyn3zbh4.js";import{loadStateFile,patchStateFile}from"./chunk-n3f5sdka.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{t}from"./chunk-625773dm.js";import{spawnSync}from"child_process";import{appendFileSync,existsSync,mkdirSync,readFileSync,writeFileSync}from"fs";import{homedir}from"os";import{basename,join}from"path";var WELCOMED_KEY="welcomed",PENDING_SKILL_KEY="welcomePendingSkillInstall";function shouldWelcome(state){if(state[WELCOMED_KEY]===!0)return!1;return typeof state[LAST_RUN_VERSION_KEY]!=="string"}function takeWelcome(){if(!shouldWelcome(loadStateFile()))return null;try{patchStateFile({[WELCOMED_KEY]:!0})}catch{}return{shell:detectShell()}}var PENDING_COMPLETIONS_KEY="welcomePendingCompletions";function detectShell(env=process.env){let shell=basename(env.SHELL??"");return shell==="zsh"||shell==="bash"||shell==="fish"?shell:null}function completionHook(shell,cli,shipped){if(shipped===null)return legacyCompletionHook(shell,cli);return shell==="fish"?`test -f "${shipped}"; and source "${shipped}"`:`[ -f "${shipped}" ] && source "${shipped}"`}function legacyCompletionHook(shell,cli){return shell==="fish"?`${cli} completions fish | source`:`command -v ${cli} >/dev/null && source <(${cli} completions ${shell})`}function shippedScriptFor(shell,cli){let path=shippedCompletionsPath(shell,cli);return existsSync(path)?path:null}function installCompletions(shell,home=homedir(),cli=ROVE_PRODUCT_NAME,shipped=shippedScriptFor(shell,cli)){let hook=completionHook(shell,cli,shipped);if(shell==="fish"){let dir=join(home,".config","fish","completions"),path=join(dir,`${cli}.fish`);return mkdirSync(dir,{recursive:!0}),writeFileSync(path,`${hook}
|
|
3
3
|
`),{path,installed:!0}}let rc=join(home,shell==="zsh"?".zshrc":".bashrc"),existing=existsSync(rc)?readFileSync(rc,"utf8"):"";if(existing.includes(hook))return{path:rc,installed:!1};let legacy=legacyCompletionHook(shell,cli);if(existing.includes(legacy))return writeFileSync(rc,existing.replace(legacy,hook)),{path:rc,installed:!0};if(existing.includes(`${cli} completions`))return{path:rc,installed:!1};return appendFileSync(rc,`
|
|
4
4
|
# ${cli} completions
|
|
5
5
|
${hook}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{describeRepoInitSources,missingDependenciesCoda,resolveEngineLaunchInit,resolveRepoInit}from"./chunk-
|
|
2
|
+
import{describeRepoInitSources,missingDependenciesCoda,resolveEngineLaunchInit,resolveRepoInit}from"./chunk-30g1bgkg.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-m6pp9gaf.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-n3f5sdka.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{resolveRepoInit,resolveEngineLaunchInit,missingDependenciesCoda,describeRepoInitSources};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{loadPluginRegistry}from"./chunk-kvwqh35r.js";import{pluginConfigDir,pluginDataDir,pluginLogPath,pluginRegistryPath,pluginStateDir,pluginsRootDir}from"./chunk-812et2xk.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE}from"./chunk-yt15y085.js";import{chmodSync}from"fs";function tighten(path,mode){try{chmodSync(path,mode)}catch{}}function tightenPluginPermissions(id,homeDir){tighten(pluginDataDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginConfigDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginStateDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(`${pluginConfigDir(id,homeDir)}/.env`,OWNER_ONLY_FILE_MODE),tighten(pluginLogPath(id,homeDir),OWNER_ONLY_FILE_MODE)}function tightenInstalledPluginPermissions(homeDir){tighten(pluginsRootDir(homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginRegistryPath(homeDir),OWNER_ONLY_FILE_MODE);for(let entry of loadPluginRegistry(homeDir).plugins)tightenPluginPermissions(entry.id,homeDir)}var ATTENTION_STATES=new Set(["rate_limited","error","dead"]);function tabStatus(input){let session={alive:input.session?.alive??!1,restored:input.session?.restored??!1,tracked:input.activity!==void 0||input.pending!==void 0},a=input.activity;if(session.restored)return{kind:"attention",reason:"restored",since:a?.at??0,...session};if(a&&ATTENTION_STATES.has(a.state))return{kind:"attention",reason:a.state,since:a.at,state:a.state,...session};if(a?.state==="running")return{kind:"running",since:a.at,state:a.state,...session};if(a?.state==="permission_needed"&&!(input.answeredAt!==void 0&&input.answeredAt>=a.at))return{kind:"needs-input",since:a.at,state:a.state,...session};if(input.pending&&!input.viewed&&input.pending.state==="turn_complete")return{kind:"unseen",since:input.pending.at,...a?{state:a.state}:{},...session};return{kind:"idle",since:a?.at??0,...a?{state:a.state}:{},...session}}var RANK={busy:0,attention:1,"needs-input":2,running:3,unseen:4,idle:5};function taskStatus(tabs,extra={}){if(extra.deletion?.failed)return{kind:"attention",reason:"delete_failed",since:extra.deletion.at};if(extra.deletion)return{kind:"busy",reason:"deleting",since:extra.deletion.at};if(extra.job)return{kind:"busy",reason:"job",since:extra.job.at};let best={kind:"idle",since:0};for(let status of[...Object.values(tabs),...extra.tabless?[extra.tabless]:[]])if(RANK[status.kind]<RANK[best.kind]||status.kind===best.kind&&status.since>best.since)best={kind:status.kind,since:status.since,...status.reason?{reason:status.reason}:{},...status.state?{state:status.state}:{}};return best}function sameTaskStatus(a,b){return a!==void 0&&JSON.stringify(a)===JSON.stringify(b)}
|
|
3
|
+
export{tightenPluginPermissions,tightenInstalledPluginPermissions,tabStatus,taskStatus,sameTaskStatus};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{BREAKING_VERSIONS,CURRENT_VERSION,DEFAULT_RELEASE_CHANNEL,PACKAGE_NAME,RELEASE_CHANNELS,UPDATE_COMMAND,UPDATE_SCRIPT_URL,breakingVersionsCrossed,channelOf,checkLatestVersion,compareSemver,fetchReleaseNotes,fetchReleaseNotesRange,fetchReleaseSummaries,isNewerSemver,owningNpmPrefix,recommendedGlobalInstallCommand,releasePageUrl,repoSlug,updateCommandFor}from"./chunk-
|
|
2
|
+
import{BREAKING_VERSIONS,CURRENT_VERSION,DEFAULT_RELEASE_CHANNEL,PACKAGE_NAME,RELEASE_CHANNELS,UPDATE_COMMAND,UPDATE_SCRIPT_URL,breakingVersionsCrossed,channelOf,checkLatestVersion,compareSemver,fetchReleaseNotes,fetchReleaseNotesRange,fetchReleaseSummaries,isNewerSemver,owningNpmPrefix,recommendedGlobalInstallCommand,releasePageUrl,repoSlug,updateCommandFor}from"./chunk-dzmfexh8.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{updateCommandFor,repoSlug,releasePageUrl,recommendedGlobalInstallCommand,owningNpmPrefix,isNewerSemver,fetchReleaseSummaries,fetchReleaseNotesRange,fetchReleaseNotes,compareSemver,checkLatestVersion,channelOf,breakingVersionsCrossed,UPDATE_SCRIPT_URL,UPDATE_COMMAND,RELEASE_CHANNELS,PACKAGE_NAME,DEFAULT_RELEASE_CHANNEL,CURRENT_VERSION,BREAKING_VERSIONS};
|