@sma1lboy/rove 0.9.252 → 0.9.254
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-r0etyq15.js → chunk-08ycv55d.js} +1 -1
- package/dist/cli/chunk-0g1me47p.js +2 -0
- package/dist/cli/{chunk-cvrtapqt.js → chunk-13msr643.js} +1 -1
- package/dist/cli/chunk-18dpws0y.js +2 -0
- package/dist/cli/{chunk-gaf6n1ea.js → chunk-1e6jbj70.js} +1 -1
- package/dist/cli/{chunk-07jq0271.js → chunk-1mpheecn.js} +1 -1
- package/dist/cli/{chunk-57wm48dh.js → chunk-1yzg4hzy.js} +1 -1
- package/dist/cli/{chunk-md094j05.js → chunk-278sc87n.js} +1 -1
- package/dist/cli/{chunk-q854fweb.js → chunk-3jnw3ftt.js} +1 -1
- package/dist/cli/chunk-3r8v2gza.js +2 -0
- package/dist/cli/{chunk-34468esa.js → chunk-4mxn5jg6.js} +1 -1
- package/dist/cli/{chunk-2ks86x2d.js → chunk-4myck788.js} +1 -1
- package/dist/cli/{chunk-sgegp9x9.js → chunk-4zhmbqt3.js} +1 -1
- package/dist/cli/chunk-5a6b4kv9.js +4 -0
- package/dist/cli/{chunk-5hhr44fc.js → chunk-5b7pd8j5.js} +1 -1
- package/dist/cli/chunk-5d0vb6v9.js +2 -0
- package/dist/cli/{chunk-9e21z4gn.js → chunk-5fhrns31.js} +1 -1
- package/dist/cli/{chunk-m3bz62v4.js → chunk-5j6z32fh.js} +1 -1
- package/dist/cli/chunk-5s4g1bkx.js +2 -0
- package/dist/cli/{chunk-q2fnt7gm.js → chunk-68gxqtse.js} +1 -1
- package/dist/cli/chunk-68pcd00x.js +2 -0
- package/dist/cli/chunk-6d5csfp4.js +2 -0
- package/dist/cli/{chunk-pgmv2hwf.js → chunk-6g5wvt5m.js} +2 -2
- package/dist/cli/{chunk-36pkmg07.js → chunk-6wxnkz3c.js} +10 -10
- package/dist/cli/{chunk-jn7vr075.js → chunk-6zvh002j.js} +1 -1
- package/dist/cli/{chunk-axmpjma9.js → chunk-7cd1epfw.js} +1 -1
- package/dist/cli/chunk-7ghwdjdc.js +3 -0
- package/dist/cli/chunk-7wga6bet.js +8 -0
- package/dist/cli/{chunk-jwnhthx9.js → chunk-7zpkyrxy.js} +1 -1
- package/dist/cli/{chunk-npb9xz3y.js → chunk-80zzjcvp.js} +1 -1
- package/dist/cli/{chunk-namxa4wy.js → chunk-8bd054vx.js} +1 -1
- package/dist/cli/{chunk-s5k3g5ra.js → chunk-9dendh71.js} +1 -1
- package/dist/cli/chunk-9g0vz9dk.js +209 -0
- package/dist/cli/chunk-9vd6fv1k.js +3 -0
- package/dist/cli/{chunk-tntdcyra.js → chunk-afwh7as3.js} +1 -1
- package/dist/cli/{chunk-9sta3ak4.js → chunk-ant4k6dm.js} +1 -1
- package/dist/cli/chunk-avz72132.js +3 -0
- package/dist/cli/chunk-ax7wzcam.js +2 -0
- package/dist/cli/{chunk-zk5qkkb1.js → chunk-axxf5dkq.js} +1 -1
- package/dist/cli/{chunk-a7kq09ke.js → chunk-b31cte10.js} +1 -1
- package/dist/cli/{chunk-fktvtdkb.js → chunk-bphs6am4.js} +1 -1
- package/dist/cli/chunk-cjxvb9vg.js +2 -0
- package/dist/cli/chunk-cm923k09.js +52 -0
- package/dist/cli/{chunk-6a4xqzqf.js → chunk-d48g9zzm.js} +3 -3
- package/dist/cli/{chunk-zzzm2cfx.js → chunk-d4mvprvq.js} +2 -2
- package/dist/cli/{chunk-952aedqm.js → chunk-ddc4t38t.js} +1 -1
- package/dist/cli/{chunk-resmnaxq.js → chunk-dehnv06q.js} +1 -1
- package/dist/cli/{chunk-y1cb8pj5.js → chunk-dqprpnd6.js} +1 -1
- package/dist/cli/chunk-dx72asyw.js +2 -0
- package/dist/cli/{chunk-e8pv3b92.js → chunk-e5vnptx5.js} +1 -1
- package/dist/cli/chunk-edsm15ht.js +4 -0
- package/dist/cli/{chunk-2rfyjb3y.js → chunk-ef7ckm5b.js} +1 -1
- package/dist/cli/{chunk-s2t9acrv.js → chunk-f6836h0n.js} +1 -1
- package/dist/cli/{chunk-s5a5dyab.js → chunk-fnsch8kr.js} +2 -2
- package/dist/cli/chunk-ft6ftksv.js +2 -0
- package/dist/cli/{chunk-trjve2xz.js → chunk-fwt0t2h7.js} +1 -1
- package/dist/cli/{chunk-ra40m849.js → chunk-gb3qb83h.js} +1 -1
- package/dist/cli/chunk-ghyz3fd7.js +4 -0
- package/dist/cli/chunk-gqpka00s.js +30 -0
- package/dist/cli/{chunk-4ays3krf.js → chunk-hqp8b49k.js} +2 -2
- package/dist/cli/{chunk-h3q3r1py.js → chunk-hzzq6pdb.js} +1 -1
- package/dist/cli/{chunk-x8pk5cyf.js → chunk-j19gkhzh.js} +1 -1
- package/dist/cli/{chunk-b67pjyyg.js → chunk-j26zqrnq.js} +1 -1
- package/dist/cli/{chunk-24dryfqb.js → chunk-j7831wcj.js} +1 -1
- package/dist/cli/{chunk-t3v57v42.js → chunk-j84zbw79.js} +2 -2
- package/dist/cli/chunk-j9c9tdfg.js +2 -0
- package/dist/cli/{chunk-zcadc92x.js → chunk-jetsx9zr.js} +1 -1
- package/dist/cli/{chunk-5q08srg6.js → chunk-jtpjdmb6.js} +1 -1
- package/dist/cli/chunk-jwtqe209.js +2 -0
- package/dist/cli/{chunk-w2sp489k.js → chunk-k3wzznqw.js} +1 -1
- package/dist/cli/chunk-k7ke95vy.js +5 -0
- package/dist/cli/chunk-k9ahks28.js +41 -0
- package/dist/cli/{chunk-nz9nmp4v.js → chunk-kwd59v51.js} +1 -1
- package/dist/cli/{chunk-j6t7xvm3.js → chunk-m0cbndc2.js} +1 -1
- package/dist/cli/{chunk-a7m7w6d1.js → chunk-m6qv5rsv.js} +1 -1
- package/dist/cli/{chunk-4e1wcgw7.js → chunk-mpdfhvgs.js} +3 -3
- package/dist/cli/chunk-mxkm0snt.js +2 -0
- package/dist/cli/chunk-n3wdy4z4.js +2 -0
- package/dist/cli/{chunk-tfqrc2v1.js → chunk-n5xj11ps.js} +3 -3
- package/dist/cli/{chunk-kda565xs.js → chunk-p5902z3e.js} +1 -1
- package/dist/cli/chunk-pahcf9td.js +3 -0
- package/dist/cli/{chunk-rc8baevh.js → chunk-pkq8n3gs.js} +2 -2
- package/dist/cli/{chunk-2bxts9pp.js → chunk-pvah9q79.js} +1 -1
- package/dist/cli/chunk-pyv2ywxr.js +3 -0
- package/dist/cli/chunk-qb6ktr8a.js +2 -0
- package/dist/cli/{chunk-mw0ysrpd.js → chunk-qk5f6p3e.js} +1 -1
- package/dist/cli/{chunk-rxge7bh5.js → chunk-qkd4eweb.js} +1 -1
- package/dist/cli/{chunk-h7y9v8k1.js → chunk-r4bn0mtb.js} +1 -1
- package/dist/cli/{chunk-ayhkcv0w.js → chunk-r7q7s63y.js} +2 -2
- package/dist/cli/{chunk-cbd6y9at.js → chunk-rf4z7b6g.js} +1 -1
- package/dist/cli/{chunk-25867jnk.js → chunk-rn97jntv.js} +1 -1
- package/dist/cli/{chunk-1tebqkdv.js → chunk-rnxk3587.js} +1 -1
- package/dist/cli/chunk-s96qnht3.js +2 -0
- package/dist/cli/chunk-sma961wh.js +3 -0
- package/dist/cli/{chunk-p2jeq98m.js → chunk-stcvcsfm.js} +1 -1
- package/dist/cli/{chunk-qh4y4e27.js → chunk-sxhjvr0w.js} +1 -1
- package/dist/cli/{chunk-0gxa04rx.js → chunk-sxt12set.js} +1 -1
- package/dist/cli/chunk-tbq3t259.js +2 -0
- package/dist/cli/{chunk-jp31bpgp.js → chunk-tewt7vre.js} +1 -1
- package/dist/cli/{chunk-1v8y9xtk.js → chunk-tmz0wzq8.js} +1 -1
- package/dist/cli/{chunk-zb5d61xa.js → chunk-tnft1xw4.js} +1 -1
- package/dist/cli/{chunk-032g0ahy.js → chunk-tq6pq1ws.js} +1 -1
- package/dist/cli/{chunk-x0rvg54z.js → chunk-v0jvt60f.js} +1 -1
- package/dist/cli/{chunk-qyfmfpjg.js → chunk-v7prawj1.js} +1 -1
- package/dist/cli/chunk-v8s0s21v.js +2 -0
- package/dist/cli/{chunk-t5qayy7m.js → chunk-v9dcyjmj.js} +1 -1
- package/dist/cli/chunk-v9fgdd90.js +3 -0
- package/dist/cli/chunk-vfwbgx85.js +2 -0
- package/dist/cli/{chunk-a1wjg2cv.js → chunk-vvw1njx5.js} +1 -1
- package/dist/cli/chunk-vzn94t0z.js +6 -0
- package/dist/cli/{chunk-vgknea9y.js → chunk-wbtebbrv.js} +1 -1
- package/dist/cli/{chunk-meyfwc50.js → chunk-wkk63qck.js} +1 -1
- package/dist/cli/chunk-wn2w5ar9.js +2 -0
- package/dist/cli/{chunk-2s762g8n.js → chunk-wsv6tw1b.js} +1 -1
- package/dist/cli/{chunk-2n1n70f2.js → chunk-x40h0f1w.js} +1 -1
- package/dist/cli/{chunk-0y4qgnby.js → chunk-x5ymh8ev.js} +1 -1
- package/dist/cli/{chunk-568q390y.js → chunk-x7r75e3p.js} +2 -2
- package/dist/cli/{chunk-7h7270rz.js → chunk-x7ryv67y.js} +2 -2
- package/dist/cli/{chunk-phpt1d3e.js → chunk-x951qvk5.js} +1 -1
- package/dist/cli/{chunk-ebhbtvhd.js → chunk-xdhs40fx.js} +1 -1
- package/dist/cli/chunk-xg6zg6kz.js +2 -0
- package/dist/cli/{chunk-21ek142k.js → chunk-xkr7fwvb.js} +1 -1
- package/dist/cli/{chunk-nqtvthqg.js → chunk-xpxxgzw9.js} +1 -1
- package/dist/cli/{chunk-7j00hbq5.js → chunk-y330t2bt.js} +2 -2
- package/dist/cli/{chunk-hq9tbzqa.js → chunk-y55zpren.js} +1 -1
- package/dist/cli/chunk-yebn33mf.js +2 -0
- package/dist/cli/chunk-ykdpg0zd.js +15 -0
- package/dist/cli/{chunk-qstjfseh.js → chunk-yshp8cmx.js} +1 -1
- package/dist/cli/chunk-z3zaa155.js +3 -0
- package/dist/cli/{chunk-npwzmmv9.js → chunk-z7zm8h1q.js} +2 -2
- package/dist/cli/index.js +8 -8
- package/dist/cli/pty-host-node.mjs +3 -0
- package/dist/cli/rove-run.js +1 -1
- package/dist/cli/rove.js +1 -1
- package/dist/completions/rove.bash +1 -1
- package/dist/completions/rove.fish +1 -1
- package/dist/completions/rove.zsh +1 -1
- package/dist/skills/rove/SKILL.md +61 -2
- package/dist/skills/rove/references/api-flags.md +75 -29
- package/dist/web/assets/{index-DHlgMx7L.js → index-BydepNFM.js} +3 -3
- package/dist/web/index.html +1 -1
- package/dist/web-ui/assets/{harness-BHiciz5A.js → harness-dYkQBfYz.js} +3 -3
- package/dist/web-ui/assets/{index-BkxJISAI.js → index-ByMdqeTv.js} +2 -2
- package/dist/web-ui/index.html +1 -1
- package/package.json +3 -3
- package/dist/cli/chunk-17pg88dq.js +0 -22
- package/dist/cli/chunk-1zwp3ase.js +0 -2
- package/dist/cli/chunk-2bp01vf2.js +0 -2
- package/dist/cli/chunk-2g2w5vvn.js +0 -2
- package/dist/cli/chunk-564jgrb3.js +0 -2
- package/dist/cli/chunk-5qxp7xx3.js +0 -2
- package/dist/cli/chunk-6f01fsje.js +0 -2
- package/dist/cli/chunk-7zxf47xb.js +0 -2
- package/dist/cli/chunk-8e0nmegv.js +0 -2
- package/dist/cli/chunk-9dregrj6.js +0 -5
- package/dist/cli/chunk-9h940gnr.js +0 -2
- package/dist/cli/chunk-9mcpqrx8.js +0 -2
- package/dist/cli/chunk-bhm24ne6.js +0 -9
- package/dist/cli/chunk-c0ksxg3z.js +0 -3
- package/dist/cli/chunk-cb1dg7nz.js +0 -2
- package/dist/cli/chunk-ccn7pq03.js +0 -5
- package/dist/cli/chunk-cpv1rpc7.js +0 -2
- package/dist/cli/chunk-csdttpme.js +0 -52
- package/dist/cli/chunk-fz0xfw86.js +0 -2
- package/dist/cli/chunk-h89ghyex.js +0 -2
- package/dist/cli/chunk-jnj2kk2h.js +0 -3
- package/dist/cli/chunk-kqv7t8jk.js +0 -8
- package/dist/cli/chunk-kx0wzjj4.js +0 -2
- package/dist/cli/chunk-m2t2n474.js +0 -6
- package/dist/cli/chunk-n2xemv4a.js +0 -2
- package/dist/cli/chunk-n92fz0hn.js +0 -2
- package/dist/cli/chunk-nj53wrzz.js +0 -2
- package/dist/cli/chunk-pdvyfz3n.js +0 -3
- package/dist/cli/chunk-pj3gnkfr.js +0 -3
- package/dist/cli/chunk-q3xt0mqt.js +0 -3
- package/dist/cli/chunk-qzsahxd9.js +0 -3
- package/dist/cli/chunk-r2c5nbcq.js +0 -4
- package/dist/cli/chunk-rf0jrh3q.js +0 -2
- package/dist/cli/chunk-rj7fwa30.js +0 -2
- package/dist/cli/chunk-sbn5pbz9.js +0 -2
- package/dist/cli/chunk-va0n5rwm.js +0 -39
- package/dist/cli/chunk-va5am5n6.js +0 -2
- package/dist/cli/chunk-vd8qqev9.js +0 -4
- package/dist/cli/chunk-vwpcv7j1.js +0 -4
- package/dist/cli/chunk-yknavm97.js +0 -3
- package/dist/cli/chunk-yt24rrvx.js +0 -2
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{errorMessage}from"./chunk-2brn8e1y.js";import{JsonHookAdapter,bobAuthSecretsPath,claudeGlobalConfigPath,codexAuthPath,copilotConfigPath,editJsonSettings,hookCommandQuoting,isObject,isRoveHook,kimiCredentialsPath,readTextFileSyncBounded,roveHookArgs,roveHookInvocation}from"./chunk-9dregrj6.js";import{quoteShellArgv}from"./chunk-7kysxgbq.js";import{getCustomEngineIds,getDisabledEngineIds}from"./chunk-21ek142k.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync}from"fs";import{homedir}from"os";import{dirname,join}from"path";function parseFlatHooks(raw){if(raw===void 0)return{ok:!0,doc:{}};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{ok:!1,reason:`not valid JSON (${err instanceof Error?err.message:String(err)})`}}if(!isObject(parsed))return{ok:!1,reason:"top level is not a JSON object"};if(parsed.hooks===void 0)return{ok:!0,doc:parsed};if(!isObject(parsed.hooks))return{ok:!1,reason:'"hooks" is not an object'};for(let[event,entries]of Object.entries(parsed.hooks))if(!Array.isArray(entries))return{ok:!1,reason:`"hooks.${event}" is not an array`};return{ok:!0,doc:parsed}}function mergeFlatHooks(format,current,install,inv=roveHookInvocation()){let verbs=format.eventMap.map((spec)=>spec.verb),{hooks:rawHooks,...rest}=current,hooks=isObject(rawHooks)?{...rawHooks}:{},quoting=hookCommandQuoting();for(let{event,verb}of format.eventMap){let kept=(Array.isArray(hooks[event])?hooks[event]:[]).filter((entry)=>!isRoveHook(entry,verbs));if(install){let command=quoteShellArgv([...inv,"hook",verb,...roveHookArgs(format.vendor)],quoting);kept.push(format.withType?{type:"command",command}:{command})}if(kept.length>0)hooks[event]=kept;else delete hooks[event]}return{version:1,...rest,hooks}}var CURSOR_HOOK_EVENT_MAP=[{event:"sessionStart",verb:"session-start"}],CURSOR_FORMAT={vendor:"cursor",eventMap:CURSOR_HOOK_EVENT_MAP};function cursorHooksPath(home=homedir()){let override=process.env.CURSOR_CONFIG_DIR?.trim();return join(override||join(home,".cursor"),"hooks.json")}function parseCursorHooks(raw){return parseFlatHooks(raw)}function mergeCursorHooks(current,install,inv=roveHookInvocation()){return mergeFlatHooks(CURSOR_FORMAT,current,install,inv)}class CursorHookAdapter{vendor="cursor";supportsHooks(){return!0}globalSettingsPath(){return cursorHooksPath()}activityDetailFromPayload(){return}cwdFromPayload(payload){let roots=payload.workspace_roots;return Array.isArray(roots)?firstString(...roots):void 0}sessionFromPayload(payload){let sessionId=firstString(payload.session_id,payload.conversation_id);if(!sessionId)return;let transcriptPath=firstString(payload.transcript_path);return{sessionId,...transcriptPath?{transcriptPath}:{}}}async installActivityHooks(settingsFilePath,opts={}){if(!existsSync(dirname(settingsFilePath)))return{ok:!0};let outcome=await editJsonSettings(settingsFilePath,(cur)=>mergeCursorHooks(cur,!0),parseCursorHooks);if(!outcome.ok&&!opts.quiet)process.stderr.write(`[rove hooks] cursor: skipped ${outcome.file}: ${outcome.reason}
|
|
3
|
-
`);return outcome}async removeActivityHooks(settingsFilePath){if(!existsSync(settingsFilePath))return;await editJsonSettings(settingsFilePath,(cur)=>mergeCursorHooks(cur,!1),parseCursorHooks)}hookConfigRefusal(raw){let parsed=parseCursorHooks(raw);return parsed.ok?void 0:parsed.reason}supportsWorktreeSync(){return!1}async removeWorktreeSyncHook(){}async removeWorktreeWatchHook(){}}function firstString(...values){for(let value of values)if(typeof value==="string"&&value)return value;return}import{homedir as homedir2}from"os";import{join as join2}from"path";import{existsSync as existsSync2}from"fs";import{dirname as dirname2}from"path";function sessionStartOnly(matcher){return[{event:"SessionStart",verb:"session-start",...matcher?{matcher}:{}}]}class SessionStartHookAdapter extends JsonHookAdapter{async installActivityHooks(settingsFilePath,opts={}){if(!existsSync2(dirname2(settingsFilePath)))return{ok:!0};return super.installActivityHooks(settingsFilePath,opts)}async removeActivityHooks(settingsFilePath){if(!existsSync2(settingsFilePath))return;await super.removeActivityHooks(settingsFilePath)}sessionFromPayload(payload){if(typeof payload.session_id!=="string"||!payload.session_id)return;return{sessionId:payload.session_id,...typeof payload.transcript_path==="string"&&payload.transcript_path?{transcriptPath:payload.transcript_path}:{}}}}var DEVIN_HOOK_EVENT_MAP=sessionStartOnly();function devinSettingsPath(home=homedir2()){let xdg=process.env.XDG_CONFIG_HOME?.trim();return join2(xdg||join2(home,".config"),"devin","config.json")}class DevinHookAdapter extends SessionStartHookAdapter{vendor="devin";eventMap=DEVIN_HOOK_EVENT_MAP;globalSettingsPath(){return devinSettingsPath()}}import{homedir as homedir3}from"os";import{join as join3}from"path";var DROID_HOOK_EVENT_MAP=sessionStartOnly();function droidSettingsPath(home=homedir3()){return join3(home,".factory","settings.json")}class DroidHookAdapter extends SessionStartHookAdapter{vendor="droid";eventMap=DROID_HOOK_EVENT_MAP;globalSettingsPath(){return droidSettingsPath()}}import{homedir as homedir4}from"os";import{join as join4}from"path";var QODERCLI_HOOK_EVENT_MAP=sessionStartOnly("*");function qodercliSettingsPath(home=homedir4()){let override=process.env.QODERCLI_CONFIG_DIR?.trim();return join4(override||join4(home,".qoder"),"settings.json")}class QodercliHookAdapter extends SessionStartHookAdapter{vendor="qodercli";eventMap=QODERCLI_HOOK_EVENT_MAP;globalSettingsPath(){return qodercliSettingsPath()}}var pluginEngines=new Map;function registerPluginEngine(id,spec){if(Object.hasOwn(CONTRIB_ENGINES,id))return!1;return pluginEngines.set(id,spec),!0}function clearPluginEngines(){pluginEngines.clear()}function pluginEngineIds(){return[...pluginEngines.keys()]}var GEMINI={rules:[{state:"blocked",any:["\u2502 apply this change","\u2502 allow execution","waiting for user confirmation"]},{state:"blocked",all:["do you want to proceed"],any:["yes"]},{state:"working",any:["esc to cancel"]}]},OPENCODE={rules:[{state:"blocked",any:["\u25B3 permission required"]},{state:"blocked",all:["esc dismiss"],any:["enter confirm","enter submit","enter toggle"]},{state:"working",any:["esc interrupt","esc to interrupt","ctrl+c to interrupt","esc again to interrupt"]},{state:"idle",any:["enter send"]}]},CURSOR={rules:[{state:"blocked",any:["press any key to log in"]},{state:"blocked",all:["proceed (y)"]},{state:"blocked",any:["run this command?","waiting for approval","skip (esc or n)","(y) (enter)"]},{state:"working",any:["esc to cancel","ctrl+c to stop"]}]},GROK={rules:[{state:"blocked",any:["\u26A0 action required","ctrl+o:yolo"]},{state:"blocked",all:["\u2503"],lineRegex:["^\\s*\u2503\\s+\\S+\\s+\\(\u25CB\\)"]},{state:"working",any:["[stop]"],lineRegex:["^\\s*[\\u2800-\\u28FF]"]}]},DROID={rules:[{state:"blocked",all:["enter to select","esc to cancel"],any:["> yes, allow","> no, cancel"]},{state:"blocked",all:["enter select","esc cancel"]},{state:"working",any:["esc to stop"]}]},AMP={rules:[{state:"blocked",any:["waiting for approval","run this command?","allow editing file:","allow creating file:","confirm tool call"]},{state:"working",lineRegex:["^\\s*\u2570\\s+\\S+\\s+(thinking|streaming|running tools|waiting)\\s+\u2500"]}]},CLINE={rules:[{state:"blocked",any:["let cline use this tool"]},{state:"blocked",all:["execute command?","yes"],any:["[act mode]","[plan mode]"]},{state:"blocked",all:["use this tool?","yes"],any:["[act mode]","[plan mode]"]}]},KIRO={rules:[{state:"blocked",all:["requires approval"],any:["yes, single permission","trust, always allow","no (tab to edit)","esc to close"]},{state:"blocked",all:["pending from subagents","tool approval"],any:["approve all pending","configure individually","exit (cancel subagents)"]},{state:"working",any:["kiro is working"]},{state:"working",all:["esc to cancel"],lineRegex:["^\\s*[\u25D4\u25D1\u25D5\u25CF]\\s+[A-Za-z]"]}]},MAKI={rules:[{state:"blocked",all:["permission required","y allow","n deny"]},{state:"blocked",all:["permission required"],any:["confirm allow","confirm deny"]},{state:"blocked",all:["permission required","enter deny","esc cancel"]},{state:"blocked",all:["plan complete","enter confirm"],any:["space toggle parallel","edit plan"]},{state:"working",bottomLines:1,lineRegex:["^( [\\u2800-\\u28FF]){1,2} \\[(BUILD|PLAN|BASH)\\]"]},{state:"idle",bottomLines:1,lineRegex:["^ \\[(BUILD|PLAN|BASH)\\]"]}]},ANTIGRAVITY={rules:[{state:"blocked",all:["requesting permission for:","do you want to proceed?"]},{state:"blocked",all:["requesting permission for:","tab amend","edit command"]},{state:"working",lineRegex:["^\\s*[\\u2800-\\u28FF]+\\s+[A-Za-z]+\\w*ing\\b"]},{state:"working",bottomLines:5,lineRegex:["\xB7\\s*[1-9][0-9]*\\s+task"]}]},DEVIN={rules:[{state:"blocked",bottomLines:8,all:["do you trust the authors of this directory?","yes, trust "]},{state:"blocked",bottomLines:8,all:["approve once","select","confirm","esc cancel"]},{state:"working",bottomLines:8,all:["running tools","esc to interrupt"]},{state:"working",bottomLines:6,all:["guide devin while it works"]},{state:"working",bottomLines:8,all:["reading shell ","timeout:"]},{state:"idle",bottomLines:8,all:["ask devin to build","features, fix bugs","your code"],lineRegex:["^\\s*\u276D Ask Devin to build"]},{state:"idle",bottomLines:6,all:["context:"],lineRegex:["^\\s*\u276D"]}]},QODERCLI={rules:[{state:"blocked",all:["waiting for user confirmation"],any:["yes","no","allow","reject"]},{state:"blocked",all:["awaiting approval"],any:["allow","reject"]},{state:"blocked",any:["permission required","allow once or always?","asking user","enter your response","review your answers:","shell awaiting input"]},{state:"working",any:["(esc to cancel,"]},{state:"working",lineRegex:["^\\s*[\\u2800-\\u28FF]\\s+.*[A-Za-z]"]}]},CONTRIB_ENGINES={gemini:{displayName:"Gemini CLI",defaultCommand:["gemini"],screenManifest:GEMINI},opencode:{displayName:"OpenCode",defaultCommand:["opencode"],screenManifest:OPENCODE,firstMessageDelivery:"paste"},cursor:{displayName:"Cursor Agent",defaultCommand:["cursor-agent"],screenManifest:CURSOR,createHookAdapter:()=>new CursorHookAdapter},grok:{displayName:"Grok CLI",defaultCommand:["grok"],screenManifest:GROK},droid:{displayName:"Droid",defaultCommand:["droid"],screenManifest:DROID,createHookAdapter:()=>new DroidHookAdapter},amp:{displayName:"Amp",defaultCommand:["amp"],screenManifest:AMP},devin:{displayName:"Devin",defaultCommand:["devin"],processNames:["devin-cli"],screenManifest:DEVIN,createHookAdapter:()=>new DevinHookAdapter},qodercli:{displayName:"Qoder CLI",defaultCommand:["qodercli"],processNames:["qoder","qoderclicn","qodercn"],screenManifest:QODERCLI,createHookAdapter:()=>new QodercliHookAdapter},cline:{displayName:"Cline",defaultCommand:["cline"],screenManifest:CLINE},kiro:{displayName:"Kiro CLI",defaultCommand:["kiro-cli"],processNames:["kiro"],screenManifest:KIRO},maki:{displayName:"Maki",defaultCommand:["maki"],screenManifest:MAKI},antigravity:{displayName:"Antigravity",defaultCommand:["agy"],processNames:["antigravity","antigravity-cli"],screenManifest:ANTIGRAVITY}};function isContribEngine(id){return Object.hasOwn(CONTRIB_ENGINES,id)||pluginEngines.has(id)}var CONTRIB_ENGINE_IDS=Object.keys(CONTRIB_ENGINES);function contribEngineEntry(id,base){let spec=CONTRIB_ENGINES[id]??pluginEngines.get(id);if(!spec)return base;return{...base,displayName:spec.displayName,defaultCommand:spec.defaultCommand,...spec.processNames?{processNames:spec.processNames}:{},screenManifest:spec.screenManifest,...spec.identity?{identity:spec.identity}:{},...spec.firstMessageDelivery?{firstMessageDelivery:spec.firstMessageDelivery}:{},...spec.createHookAdapter?{createHookAdapter:spec.createHookAdapter}:{}}}import{homedir as homedir6}from"os";import{spawnSync}from"child_process";import{existsSync as existsSync3,statSync}from"fs";import{homedir as homedir5}from"os";import path from"path";var defaultBinaryDeps={fileExists(p){try{return statSync(p).isFile()}catch{return!1}},env(name){return process.env[name]},home(){return homedir5()},which(name){let cmd=process.platform==="win32"?"where":"which",out=spawnSync(cmd,[name],{encoding:"utf8"});if(out.status!==0)return;let first=out.stdout.split(`
|
|
4
|
-
`).map((l)=>l.trim()).filter(Boolean)[0];if(!first)return;if(first.startsWith(`${name}:`)&&first.includes("aliased to")){let aliasTarget=first.split("aliased to")[1]?.trim();return aliasTarget&&existsSync3(aliasTarget)?aliasTarget:void 0}return first},readdir(p){try{return __require("fs").readdirSync(p)}catch{return[]}}};class BinaryNotFoundError extends Error{checkedPaths;constructor(label,hint,checkedPaths){super(`${label} not found. Checked: ${checkedPaths.join(", ")}. ${hint}`);this.name="BinaryNotFoundError",this.checkedPaths=checkedPaths}}function npmStyleDirs({deps,home},locations=["system","nvm","windowsNpm","npmGlobal","local","bun","bin"]){return locations.flatMap((location)=>{switch(location){case"system":return["/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin"];case"homebrew":return["/opt/homebrew/bin","/usr/local/bin"];case"nvm":{let bin=deps.env("NVM_BIN");return bin?[bin]:[]}case"windowsNpm":{if((deps.platform?.()??process.platform)!=="win32")return[];let appData=deps.env("APPDATA"),localAppData=deps.env("LOCALAPPDATA");return[...localAppData?[path.join(localAppData,"npm")]:[],...appData?[path.join(appData,"npm")]:[],path.join(home,"AppData/Roaming/npm")]}case"npmGlobal":return[path.join(home,".npm-global/bin")];case"local":return[path.join(home,".local/bin")];case"yarn":return[path.join(home,".yarn/bin")];case"bun":return[path.join(home,".bun/bin")];case"bin":return[path.join(home,"bin")]}})}function npmStyleBinaryCandidates(ctx,name){let names=(ctx.deps.platform?.()??process.platform)==="win32"?[`${name}.exe`,`${name}.cmd`,name]:[name];return npmStyleDirs(ctx).flatMap((dir)=>names.map((n)=>path.join(dir,n)))}function createBinaryFinder(spec){return async function(deps=defaultBinaryDeps){let checked=[],whichResult=deps.which(spec.name);if(whichResult){if(checked.push(`which:${whichResult}`),deps.fileExists(whichResult))return whichResult}for(let candidate of spec.candidates({deps,home:deps.home()}))if(checked.push(candidate),deps.fileExists(candidate))return candidate;throw spec.notFound(checked)}}class BobBinaryNotFoundError extends BinaryNotFoundError{constructor(checkedPaths){super("IBM Bob Shell binary","Ensure 'bob' is on PATH (for example `curl -fsSL https://bob.ibm.com/download/bobshell.sh | bash`).",checkedPaths);this.name="BobBinaryNotFoundError"}}var findBobBinary=createBinaryFinder({name:"bob",candidates:(ctx)=>npmStyleBinaryCandidates(ctx,"bob"),notFound:(checked)=>new BobBinaryNotFoundError(checked)});import path2 from"path";class ClaudeBinaryNotFoundError extends BinaryNotFoundError{constructor(checkedPaths){super("Claude Code binary","Ensure 'claude' is on PATH, or install at ~/.claude/local/claude.",checkedPaths);this.name="ClaudeBinaryNotFoundError"}}var findClaudeBinary=createBinaryFinder({name:"claude",candidates({deps,home}){let out=[path2.join(home,".claude","local","claude")];out.push(...npmStyleDirs({deps,home},["nvm"]).map((dir)=>path2.join(dir,"claude")));let nvmRoot=path2.join(home,".nvm","versions","node"),versions=(deps.readdir?.(nvmRoot)??[]).sort((a,b)=>b.localeCompare(a,void 0,{numeric:!0}));for(let v of versions)out.push(path2.join(nvmRoot,v,"bin","claude"));return out.push(...npmStyleDirs({deps,home},["system","local","npmGlobal","yarn","bun","bin"]).map((dir)=>path2.join(dir,"claude"))),out},notFound:(checked)=>new ClaudeBinaryNotFoundError(checked)});import path3 from"path";class CodexBinaryNotFoundError extends BinaryNotFoundError{constructor(checkedPaths){super("Codex CLI binary","Ensure 'codex' is on PATH (e.g. `brew install codex` or the official installer).",checkedPaths);this.name="CodexBinaryNotFoundError"}}var findCodexBinary=createBinaryFinder({name:"codex",candidates({deps,home}){return npmStyleDirs({deps,home},["system","nvm","local","bun","bin"]).map((dir)=>path3.join(dir,"codex"))},notFound:(checked)=>new CodexBinaryNotFoundError(checked)});class CopilotBinaryNotFoundError extends BinaryNotFoundError{constructor(checkedPaths){super("GitHub Copilot CLI binary","Ensure 'copilot' is on PATH (for example `npm install -g @github/copilot` or `brew install copilot-cli`).",checkedPaths);this.name="CopilotBinaryNotFoundError"}}var findCopilotBinary=createBinaryFinder({name:"copilot",candidates:(ctx)=>npmStyleBinaryCandidates(ctx,"copilot"),notFound:(checked)=>new CopilotBinaryNotFoundError(checked)});import path4 from"path";class KimiBinaryNotFoundError extends BinaryNotFoundError{constructor(checkedPaths){super("Kimi Code CLI binary","Ensure 'kimi' is on PATH or installed at ~/.kimi-code/bin/kimi.",checkedPaths);this.name="KimiBinaryNotFoundError"}}var findKimiBinary=createBinaryFinder({name:"kimi",candidates:(ctx)=>[path4.join(ctx.home,".kimi-code/bin"),...npmStyleDirs(ctx,["local","bin","homebrew"])].map((dir)=>path4.join(dir,"kimi")),notFound:(checked)=>new KimiBinaryNotFoundError(checked)});import path5 from"path";class PiFamilyBinaryNotFoundError extends BinaryNotFoundError{constructor(name,checkedPaths){super(`${name} CLI binary`,`Ensure '${name}' is on PATH (e.g. \`brew install ${name}\`, or \`npm i -g ${name==="omp"?"@oh-my-pi/pi-coding-agent":"@earendil-works/pi-coding-agent"}\`).`,checkedPaths);this.name="PiFamilyBinaryNotFoundError"}}function candidatesFor(name,ctx){let{home}=ctx,out=npmStyleDirs(ctx,["system","local","bun","bin"]).map((dir)=>path5.join(dir,name)),packageName=name==="omp"?"@oh-my-pi/pi-coding-agent":"@earendil-works/pi-coding-agent";for(let prefix of[path5.join(home,".npm-global"),"/usr/local","/opt/homebrew"])out.push(path5.join(prefix,"bin",name)),out.push(path5.join(prefix,"lib/node_modules",packageName,"dist","cli.js"));return out}var findPiBinary=createBinaryFinder({name:"pi",candidates:(ctx)=>candidatesFor("pi",ctx),notFound:(checked)=>new PiFamilyBinaryNotFoundError("pi",checked)}),findOmpBinary=createBinaryFinder({name:"omp",candidates:(ctx)=>candidatesFor("omp",ctx),notFound:(checked)=>new PiFamilyBinaryNotFoundError("omp",checked)});var defaultDeps={readFile(p){return readTextFileSyncBounded(p)},env(name){return process.env[name]},home(){return homedir6()},findClaudeBinary(){return findClaudeBinary()},findCodexBinary(){return findCodexBinary()},findBobBinary(){return findBobBinary()},findCopilotBinary(){return findCopilotBinary()},findKimiBinary(){return findKimiBinary()},findPiBinary(){return findPiBinary()},findOmpBinary(){return findOmpBinary()}};function decodeJwtPayload(jwt){let parts=jwt.split(".");if(parts.length!==3)return null;let payload=parts[1];if(!payload)return null;let b64=payload.replace(/-/g,"+").replace(/_/g,"/"),padded=b64+"=".repeat((4-b64.length%4)%4);try{let json=Buffer.from(padded,"base64").toString("utf8"),obj=JSON.parse(json);return typeof obj==="object"&&obj!==null?obj:null}catch{return null}}async function probeBinary(probe){try{return{found:!0,path:await probe()}}catch(err){if(err instanceof BinaryNotFoundError)return{found:!1,error:"not found on PATH"};return{found:!1,error:errorMessage(err)}}}var cachedDefaultVendors=null;async function probeAvailableVendors(deps){return(await Promise.all([["claude",()=>deps.findClaudeBinary()],["codex",()=>deps.findCodexBinary()],["copilot",()=>deps.findCopilotBinary()],["kimi",()=>deps.findKimiBinary()],["pi",()=>deps.findPiBinary()],["omp",()=>deps.findOmpBinary()]].map(async([vendor,probe])=>(await probeBinary(probe)).found?vendor:null))).filter((v)=>v!==null)}function detectAvailableVendors(deps=defaultDeps){if(deps!==defaultDeps)return probeAvailableVendors(deps);if(cachedDefaultVendors)return cachedDefaultVendors;let pending=probeAvailableVendors(deps).catch((err)=>{throw cachedDefaultVendors=null,err});return cachedDefaultVendors=pending,pending}function resetAvailableVendorsCache(){cachedDefaultVendors=null,cachedContribEngines=null}async function installedEngineIds(deps=defaultDeps){let builtins=await detectAvailableVendors(deps),contrib=await detectContribEngines();return[...new Set([...builtins,...getCustomEngineIds(),...contrib])]}async function availableEngineIds(deps=defaultDeps){let disabled=new Set(getDisabledEngineIds());return(await installedEngineIds(deps)).filter((id)=>!disabled.has(id))}var cachedContribEngines=null;function detectContribEngines(){if(cachedContribEngines)return cachedContribEngines;let which=globalThis.Bun?.which;return cachedContribEngines=Promise.resolve([...which?CONTRIB_ENGINE_IDS.filter((id)=>{let bin=CONTRIB_ENGINES[id]?.defaultCommand[0];return bin?which(bin)!==null:!1}):[],...pluginEngineIds()]),cachedContribEngines}async function detectClaudeAccount(deps=defaultDeps){let binary=await probeBinary(()=>deps.findClaudeBinary()),configPath=claudeGlobalConfigPath(deps.env,deps.home()),raw;try{raw=deps.readFile(configPath)}catch(err){return{binary,account:{kind:"none"},accountError:`read ${configPath}: ${errorMessage(err)}`}}if(raw===null)return{binary,account:{kind:"none"}};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{binary,account:{kind:"none"},accountError:`parse ${configPath}: ${errorMessage(err)}`}}let oauth=parsed?.oauthAccount;if(!oauth||typeof oauth!=="object")return{binary,account:{kind:"none"}};let o=oauth,email=typeof o.emailAddress==="string"?o.emailAddress:void 0;if(!email)return{binary,account:{kind:"none"}};return{binary,account:{kind:"oauth",email,organization:typeof o.organizationName==="string"?o.organizationName:void 0,displayName:typeof o.displayName==="string"?o.displayName:void 0,billingType:typeof o.billingType==="string"?o.billingType:void 0}}}async function detectCodexAccount(deps=defaultDeps){let binary=await probeBinary(()=>deps.findCodexBinary()),authPath=codexAuthPath(deps.env,deps.home()),raw;try{raw=deps.readFile(authPath)}catch(err){return{binary,account:{kind:"none"},accountError:`read ${authPath}: ${errorMessage(err)}`}}if(raw===null)return{binary,account:{kind:"none"}};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{binary,account:{kind:"none"},accountError:`parse ${authPath}: ${errorMessage(err)}`}}let obj=parsed??{},tokens=obj.tokens,idToken=typeof tokens?.id_token==="string"?tokens.id_token:void 0;if(idToken){let payload=decodeJwtPayload(idToken);if(!payload)return{binary,account:{kind:"none"},accountError:"codex id_token: malformed JWT"};let email=typeof payload.email==="string"?payload.email:void 0,authClaimRaw=payload["https://api.openai.com/auth"],authClaim=typeof authClaimRaw==="object"&&authClaimRaw!==null&&!Array.isArray(authClaimRaw)?authClaimRaw:void 0,plan=typeof authClaim?.chatgpt_plan_type==="string"?authClaim.chatgpt_plan_type:void 0;if(email)return{binary,account:{kind:"chatgpt",email,plan}};return{binary,account:{kind:"none"},accountError:"codex id_token: no email claim"}}let apiKey=obj.OPENAI_API_KEY;if(typeof apiKey==="string"&&apiKey.length>0)return{binary,account:{kind:"apikey"}};return{binary,account:{kind:"none"}}}async function detectCopilotAccount(deps=defaultDeps){let binary=await probeBinary(()=>deps.findCopilotBinary());for(let source of["COPILOT_GITHUB_TOKEN","GH_TOKEN","GITHUB_TOKEN"])if(deps.env(source)?.trim())return{binary,account:{kind:"token",source}};let configPath=copilotConfigPath(deps.env,deps.home()),raw;try{raw=deps.readFile(configPath)}catch(err){return{binary,account:{kind:"none"},accountError:`read ${configPath}: ${errorMessage(err)}`}}if(raw===null)return{binary,account:{kind:"none"}};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{binary,account:{kind:"none"},accountError:`parse ${configPath}: ${errorMessage(err)}`}}if(!isObject(parsed))return{binary,account:{kind:"none"}};if(hasStringDeep(parsed,["github_token","oauth_token","access_token","token","selectedUser","currentUser","user"]))return{binary,account:{kind:"oauth"}};return{binary,account:{kind:"none"}}}async function detectBobAccount(deps=defaultDeps){let binary=await probeBinary(()=>deps.findBobBinary()),secretsPath=bobAuthSecretsPath(deps.home()),raw;try{raw=deps.readFile(secretsPath)}catch(err){return{binary,account:{kind:"none"},accountError:`read ${secretsPath}: ${errorMessage(err)}`}}if(raw===null)return{binary,account:{kind:"none"}};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{binary,account:{kind:"none"},accountError:`parse ${secretsPath}: ${errorMessage(err)}`}}if(!isObject(parsed))return{binary,account:{kind:"none"}};let signedIn=Object.entries(parsed).some(([key,value])=>key.startsWith("bob.auth.tokens-")&&typeof value==="string"&&value.length>0);return{binary,account:signedIn?{kind:"oauth"}:{kind:"none"}}}async function detectKimiAccount(deps=defaultDeps){let binary=await probeBinary(()=>deps.findKimiBinary()),credPath=kimiCredentialsPath(deps.env,deps.home()),raw;try{raw=deps.readFile(credPath)}catch(err){return{binary,account:{kind:"none"},accountError:`read ${credPath}: ${errorMessage(err)}`}}if(raw===null)return{binary,account:{kind:"none"}};let parsed;try{parsed=JSON.parse(raw)}catch(err){return{binary,account:{kind:"none"},accountError:`parse ${credPath}: ${errorMessage(err)}`}}if(!isObject(parsed))return{binary,account:{kind:"none"}};let token=parsed.access_token;if(typeof token==="string"&&token.length>0)return{binary,account:{kind:"oauth"}};return{binary,account:{kind:"none"}}}function hasStringDeep(value,interestingKeys,depth=0){if(depth>4||!isObject(value))return!1;for(let[key,entry]of Object.entries(value)){if(interestingKeys.includes(key)&&typeof entry==="string"&&entry.length>0)return!0;if(isObject(entry)&&hasStringDeep(entry,interestingKeys,depth+1))return!0}return!1}
|
|
5
|
-
export{parseFlatHooks,mergeFlatHooks,registerPluginEngine,clearPluginEngines,pluginEngineIds,isContribEngine,CONTRIB_ENGINE_IDS,contribEngineEntry,resetAvailableVendorsCache,installedEngineIds,availableEngineIds,detectClaudeAccount,detectCodexAccount,detectCopilotAccount,detectBobAccount,detectKimiAccount};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{detectShell,installCompletions,recordWelcomeChoices,runPendingWelcomeInstalls,settleWelcomeInstall}from"./chunk-rxge7bh5.js";import"./chunk-2ks86x2d.js";import"./chunk-ke3t032y.js";import"./chunk-1qge84t7.js";import"./chunk-j6t7xvm3.js";import"./chunk-4ays3krf.js";import"./chunk-21ek142k.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-032g0ahy.js";import"./chunk-q3xt0mqt.js";import"./chunk-cmp64q4j.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{settleWelcomeInstall,runPendingWelcomeInstalls,recordWelcomeChoices,installCompletions,detectShell};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{MachineHub}from"./chunk-trjve2xz.js";import{COLORBLIND_KEY,DEFAULT_BASE_REF,DEFAULT_COLORBLIND,DEFAULT_GLYPHS,DEFAULT_GLYPH_SET,DEFAULT_PREFIX_TAP_PRESENTATION,DEFAULT_RUNNING_TITLE,DEFAULT_SCROLLBACK_ROWS,DEFAULT_TAB_ROW_HEIGHT,DEFAULT_TASK_COLORS,DEFAULT_WORKING_BORDER,GLYPH_SETS,GLYPH_SET_KEY,PREFIX_TAP_PRESENTATIONS,PREFIX_TAP_PRESENTATION_KEY,RAIL_FOLD_STYLE_KEY,RUNNING_TITLE_KEY,SCROLLBACK_ROWS_KEY,SCROLLBACK_ROWS_MAX,SCROLLBACK_ROWS_MIN,SPLIT_STYLE_KEY,TAB_ROW_HEIGHT_KEY,TAB_STRIP_HIDE_SINGLE_KEY,TAB_STRIP_MODES,TAB_STRIP_MODE_KEY,TASK_COLORS_KEY,WORKING_BORDER_KEY,ZEN_ACTIVE_KEY,ZEN_DEFAULT,appearanceChoices,buildCIPromptForWorktree,buildPRPrompt,cloneRepo,createKeybindingsFile,deriveFolderName,detailFragment,detectWorktreeOpener,diffCommentsKey,displayEndpoint,engineIntegrations,findAvailableFolderName,formatDiffComments,getCurrentBranch,issueChatTaskTitle,issueProjectPrompt,issueWorktreePrompt,listFiles,listLocalBranches,liveSourceProtocol,loadPreviewData,normalizeColorblind,normalizeGlyphSet,normalizePrefixTapPresentation,normalizeRunningTitle,normalizeScrollbackRows,normalizeSplitStyle,normalizeTabRowHeight,normalizeTaskColors,normalizeWorkingBorder,openExternally,openWorktree,planWorktreeHandoff,prChip,readPluginRows,resolveBase,resolveCloneTarget,resolveTabStripMode,setPluginEnabled,spawnDetached,statusFiles,statusFilesBranch,taskColor,unsentComments,validateCloneTarget,validateGitUrl,validateRepoPath}from"./chunk-phpt1d3e.js";import"./chunk-1tebqkdv.js";import"./chunk-h3q3r1py.js";import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import"./chunk-y1cb8pj5.js";import{DEFAULT_SOUND_VOLUME,RoveKeymap,SOUND_VOLUME_KEY,SOUND_VOLUME_STEPS,normalizeSoundVolume,prefixFirstStrokes,readKeybindingsFile,resetKeybindingsFileCache,resolveUserKeybindings}from"./chunk-yknavm97.js";import{RemoteOrchestrator,liveRowTokens}from"./chunk-pj3gnkfr.js";import{invokeVerb}from"./chunk-m2t2n474.js";import{executeVerb}from"./chunk-c0ksxg3z.js";import{buildContext,defaultApiRuntime}from"./chunk-bhm24ne6.js";import{AUTO_ROUTING_TIERS,autoRoutingKey,describeTierBlock,readAutoRoutingTable,readClassifierConfig,secretStatus,tierBlock}from"./chunk-zzzm2cfx.js";import{ensurePluginEnginesLoaded}from"./chunk-m3bz62v4.js";import"./chunk-kda565xs.js";import{listPaneLaunches}from"./chunk-s5k3g5ra.js";import"./chunk-cbc1h345.js";import{PROJECT_SIBLING_BASE,WORKTREE_BASE_CUSTOM_KEY,worktreeBaseKindOf}from"./chunk-07jq0271.js";import"./chunk-17e2tgyg.js";import{detectEngineStatus,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-34468esa.js";import"./chunk-4hestsjp.js";import{WORKTREE_BASE_KEY}from"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-p2jeq98m.js";import"./chunk-2bgmby1d.js";import{loadPluginRegistry}from"./chunk-vd8qqev9.js";import{DEFAULT_EDITOR_KIND,EDITOR_CUSTOM_KEY,EDITOR_KINDS,EDITOR_KIND_KEY,normalizeEditorKind}from"./chunk-r2c5nbcq.js";import"./chunk-atn06ncf.js";import"./chunk-nz9nmp4v.js";import"./chunk-qkehg2c1.js";import"./chunk-x8pk5cyf.js";import{expandHome,filterSubdirs,initialTabs,listSubdirs,moveTab,splitPathForDirSuggest,stripTrailingSlash,terminalTabsKey}from"./chunk-namxa4wy.js";import{AUTO_STATUS_KEY,DISPATCHER_KEY,resolveThemeSlotHex}from"./chunk-952aedqm.js";import"./chunk-resmnaxq.js";import"./chunk-sak1tphp.js";import"./chunk-4250pw6r.js";import{defaultEngineCommand,engineDisplayName,ensurePtyHostReachable,protocolEntry,roveApiInvocation}from"./chunk-cbd6y9at.js";import"./chunk-rxqdw6s5.js";import{DEFAULT_THEME,DEFAULT_THEME_MODE,FOCUS_ACCENT_SLOTS,THEME_MODE_PREFERENCES,defaultTransparentBackground,diffInks,resolveTheme}from"./chunk-zcadc92x.js";import"./chunk-vjvkkrzc.js";import{BUNDLED_THEME_JSONS,loadUserThemes}from"./chunk-pdvyfz3n.js";import"./chunk-r0etyq15.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-24dryfqb.js";import{engineEntry}from"./chunk-jp31bpgp.js";import"./chunk-2tfnscxk.js";import{installedEngineIds}from"./chunk-ccn7pq03.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import{resolvePreferredVendor}from"./chunk-a7m7w6d1.js";import"./chunk-55ajzrj6.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-kg9kmwt9.js";import"./chunk-6xppe9bj.js";import{invokeRouted}from"./chunk-a1wjg2cv.js";import"./chunk-x0rvg54z.js";import"./chunk-t5qayy7m.js";import"./chunk-q854fweb.js";import"./chunk-b7xjhgts.js";import{ApiError,REMOTE_CALLER}from"./chunk-568q390y.js";import"./chunk-zsfyj36g.js";import{ensureDaemonReachable}from"./chunk-9sta3ak4.js";import"./chunk-gaf6n1ea.js";import"./chunk-7j00hbq5.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-jnj2kk2h.js";import{roveCliInvocation}from"./chunk-9dregrj6.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import{ALL_VENDORS,isBuiltinVendor}from"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import{CURRENT_VERSION,checkLatestVersion,fetchReleaseNotes,fetchReleaseNotesRange}from"./chunk-j6t7xvm3.js";import{getSavedRepos,resolveMainRepoRoot}from"./chunk-21ek142k.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import{loadStateFile,patchStateFile,replaceStateFile,updateStateFile}from"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import{defaultUiPrefsStatePath,promptAttachmentsDir,resolveProductHomeDir,roveStateDir}from"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-032g0ahy.js";import{DEFAULT_LOCALE,LOCALES,isLocaleId}from"./chunk-q3xt0mqt.js";import"./chunk-cmp64q4j.js";import"./chunk-pxk2c2vj.js";import{RoveDaemonClient,isDaemonVersionStale}from"./chunk-s5a5dyab.js";import{MOD_INPUT_MAX,MOD_KEY_PATTERN,MOD_PANE_ID_PATTERN,ROVE_API_VERSION}from"./chunk-md094j05.js";import"./chunk-hq9tbzqa.js";import{samePath}from"./chunk-pn5ygqn6.js";import{defaultDaemonSocketPath,defaultPtyHostSocketPath}from"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{spawnSync}from"child_process";import{existsSync as existsSync3,readFileSync as readFileSync2}from"fs";import{join as join4}from"path";var QrCodeDataType=((QrCodeDataType2)=>{return QrCodeDataType2[QrCodeDataType2.Border=-1]="Border",QrCodeDataType2[QrCodeDataType2.Data=0]="Data",QrCodeDataType2[QrCodeDataType2.Function=1]="Function",QrCodeDataType2[QrCodeDataType2.Position=2]="Position",QrCodeDataType2[QrCodeDataType2.Timing=3]="Timing",QrCodeDataType2[QrCodeDataType2.Alignment=4]="Alignment",QrCodeDataType2})(QrCodeDataType||{}),LOW=[0,1],MEDIUM=[1,0],QUARTILE=[2,3],HIGH=[3,2],EccMap={L:LOW,M:MEDIUM,Q:QUARTILE,H:HIGH},NUMERIC_REGEX=/^\d*$/,ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+./:-]*$/,ALPHANUMERIC_CHARSET="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:",MIN_VERSION=1,MAX_VERSION=40,PENALTY_N1=3,PENALTY_N2=3,PENALTY_N3=40,PENALTY_N4=10,ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]];class QrCode{constructor(version,ecc,dataCodewords,msk){if(this.version=version,this.ecc=ecc,version<MIN_VERSION||version>MAX_VERSION)throw RangeError("Version value out of range");if(msk<-1||msk>7)throw RangeError("Mask value out of range");this.size=version*4+17;let row=Array.from({length:this.size}).fill(!1);for(let i=0;i<this.size;i++)this.modules.push(row.slice()),this.types.push(row.map(()=>0));this.drawFunctionPatterns();let allCodewords=this.addEccAndInterleave(dataCodewords);if(this.drawCodewords(allCodewords),msk===-1){let minPenalty=1e9;for(let i=0;i<8;i++){this.applyMask(i),this.drawFormatBits(i);let penalty=this.getPenaltyScore();if(penalty<minPenalty)msk=i,minPenalty=penalty;this.applyMask(i)}}this.mask=msk,this.applyMask(msk),this.drawFormatBits(msk)}size;mask;modules=[];types=[];getModule(x,y){return x>=0&&x<this.size&&y>=0&&y<this.size&&this.modules[y][x]}drawFunctionPatterns(){for(let i=0;i<this.size;i++)this.setFunctionModule(6,i,i%2===0,QrCodeDataType.Timing),this.setFunctionModule(i,6,i%2===0,QrCodeDataType.Timing);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);let alignPatPos=this.getAlignmentPatternPositions(),numAlign=alignPatPos.length;for(let i=0;i<numAlign;i++)for(let j=0;j<numAlign;j++)if(!(i===0&&j===0||i===0&&j===numAlign-1||i===numAlign-1&&j===0))this.drawAlignmentPattern(alignPatPos[i],alignPatPos[j]);this.drawFormatBits(0),this.drawVersion()}drawFormatBits(mask){let data=this.ecc[1]<<3|mask,rem=data;for(let i=0;i<10;i++)rem=rem<<1^(rem>>>9)*1335;let bits=(data<<10|rem)^21522;for(let i=0;i<=5;i++)this.setFunctionModule(8,i,getBit(bits,i));this.setFunctionModule(8,7,getBit(bits,6)),this.setFunctionModule(8,8,getBit(bits,7)),this.setFunctionModule(7,8,getBit(bits,8));for(let i=9;i<15;i++)this.setFunctionModule(14-i,8,getBit(bits,i));for(let i=0;i<8;i++)this.setFunctionModule(this.size-1-i,8,getBit(bits,i));for(let i=8;i<15;i++)this.setFunctionModule(8,this.size-15+i,getBit(bits,i));this.setFunctionModule(8,this.size-8,!0)}drawVersion(){if(this.version<7)return;let rem=this.version;for(let i=0;i<12;i++)rem=rem<<1^(rem>>>11)*7973;let bits=this.version<<12|rem;for(let i=0;i<18;i++){let color=getBit(bits,i),a=this.size-11+i%3,b=Math.floor(i/3);this.setFunctionModule(a,b,color),this.setFunctionModule(b,a,color)}}drawFinderPattern(x,y){for(let dy=-4;dy<=4;dy++)for(let dx=-4;dx<=4;dx++){let dist=Math.max(Math.abs(dx),Math.abs(dy)),xx=x+dx,yy=y+dy;if(xx>=0&&xx<this.size&&yy>=0&&yy<this.size)this.setFunctionModule(xx,yy,dist!==2&&dist!==4,QrCodeDataType.Position)}}drawAlignmentPattern(x,y){for(let dy=-2;dy<=2;dy++)for(let dx=-2;dx<=2;dx++)this.setFunctionModule(x+dx,y+dy,Math.max(Math.abs(dx),Math.abs(dy))!==1,QrCodeDataType.Alignment)}setFunctionModule(x,y,isDark,type=QrCodeDataType.Function){this.modules[y][x]=isDark,this.types[y][x]=type}addEccAndInterleave(data){let ver=this.version,ecl=this.ecc;if(data.length!==getNumDataCodewords(ver,ecl))throw RangeError("Invalid argument");let numBlocks=NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver],blockEccLen=ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver],rawCodewords=Math.floor(getNumRawDataModules(ver)/8),numShortBlocks=numBlocks-rawCodewords%numBlocks,shortBlockLen=Math.floor(rawCodewords/numBlocks),blocks=[],rsDiv=reedSolomonComputeDivisor(blockEccLen);for(let i=0,k=0;i<numBlocks;i++){let dat=data.slice(k,k+shortBlockLen-blockEccLen+(i<numShortBlocks?0:1));k+=dat.length;let ecc=reedSolomonComputeRemainder(dat,rsDiv);if(i<numShortBlocks)dat.push(0);blocks.push(dat.concat(ecc))}let result=[];for(let i=0;i<blocks[0].length;i++)blocks.forEach((block,j)=>{if(i!==shortBlockLen-blockEccLen||j>=numShortBlocks)result.push(block[i])});return result}drawCodewords(data){if(data.length!==Math.floor(getNumRawDataModules(this.version)/8))throw RangeError("Invalid argument");let i=0;for(let right=this.size-1;right>=1;right-=2){if(right===6)right=5;for(let vert=0;vert<this.size;vert++)for(let j=0;j<2;j++){let x=right-j,y=(right+1&2)===0?this.size-1-vert:vert;if(!this.types[y][x]&&i<data.length*8)this.modules[y][x]=getBit(data[i>>>3],7-(i&7)),i++}}}applyMask(mask){if(mask<0||mask>7)throw RangeError("Mask value out of range");for(let y=0;y<this.size;y++)for(let x=0;x<this.size;x++){let invert;switch(mask){case 0:invert=(x+y)%2===0;break;case 1:invert=y%2===0;break;case 2:invert=x%3===0;break;case 3:invert=(x+y)%3===0;break;case 4:invert=(Math.floor(x/3)+Math.floor(y/2))%2===0;break;case 5:invert=x*y%2+x*y%3===0;break;case 6:invert=(x*y%2+x*y%3)%2===0;break;case 7:invert=((x+y)%2+x*y%3)%2===0;break;default:throw Error("Unreachable")}if(!this.types[y][x]&&invert)this.modules[y][x]=!this.modules[y][x]}}getPenaltyScore(){let result=0;for(let y=0;y<this.size;y++){let runColor=!1,runX=0,runHistory=[0,0,0,0,0,0,0];for(let x=0;x<this.size;x++)if(this.modules[y][x]===runColor){if(runX++,runX===5)result+=PENALTY_N1;else if(runX>5)result++}else{if(this.finderPenaltyAddHistory(runX,runHistory),!runColor)result+=this.finderPenaltyCountPatterns(runHistory)*PENALTY_N3;runColor=this.modules[y][x],runX=1}result+=this.finderPenaltyTerminateAndCount(runColor,runX,runHistory)*PENALTY_N3}for(let x=0;x<this.size;x++){let runColor=!1,runY=0,runHistory=[0,0,0,0,0,0,0];for(let y=0;y<this.size;y++)if(this.modules[y][x]===runColor){if(runY++,runY===5)result+=PENALTY_N1;else if(runY>5)result++}else{if(this.finderPenaltyAddHistory(runY,runHistory),!runColor)result+=this.finderPenaltyCountPatterns(runHistory)*PENALTY_N3;runColor=this.modules[y][x],runY=1}result+=this.finderPenaltyTerminateAndCount(runColor,runY,runHistory)*PENALTY_N3}for(let y=0;y<this.size-1;y++)for(let x=0;x<this.size-1;x++){let color=this.modules[y][x];if(color===this.modules[y][x+1]&&color===this.modules[y+1][x]&&color===this.modules[y+1][x+1])result+=PENALTY_N2}let dark=0;for(let row of this.modules)dark=row.reduce((sum,color)=>sum+(color?1:0),dark);let total=this.size*this.size,k=Math.ceil(Math.abs(dark*20-total*10)/total)-1;return result+=k*PENALTY_N4,result}getAlignmentPatternPositions(){if(this.version===1)return[];else{let numAlign=Math.floor(this.version/7)+2,step=this.version===32?26:Math.ceil((this.version*4+4)/(numAlign*2-2))*2,result=[6];for(let pos=this.size-7;result.length<numAlign;pos-=step)result.splice(1,0,pos);return result}}finderPenaltyCountPatterns(runHistory){let n=runHistory[1],core=n>0&&runHistory[2]===n&&runHistory[3]===n*3&&runHistory[4]===n&&runHistory[5]===n;return(core&&runHistory[0]>=n*4&&runHistory[6]>=n?1:0)+(core&&runHistory[6]>=n*4&&runHistory[0]>=n?1:0)}finderPenaltyTerminateAndCount(currentRunColor,currentRunLength,runHistory){if(currentRunColor)this.finderPenaltyAddHistory(currentRunLength,runHistory),currentRunLength=0;return currentRunLength+=this.size,this.finderPenaltyAddHistory(currentRunLength,runHistory),this.finderPenaltyCountPatterns(runHistory)}finderPenaltyAddHistory(currentRunLength,runHistory){if(runHistory[0]===0)currentRunLength+=this.size;runHistory.pop(),runHistory.unshift(currentRunLength)}}function appendBits(val,len,bb){if(len<0||len>31||val>>>len!==0)throw RangeError("Value out of range");for(let i=len-1;i>=0;i--)bb.push(val>>>i&1)}function getBit(x,i){return(x>>>i&1)!==0}class QrSegment{constructor(mode,numChars,bitData){if(this.mode=mode,this.numChars=numChars,this.bitData=bitData,numChars<0)throw RangeError("Invalid argument");this.bitData=bitData.slice()}getData(){return this.bitData.slice()}}var MODE_NUMERIC=[1,10,12,14],MODE_ALPHANUMERIC=[2,9,11,13],MODE_BYTE=[4,8,16,16];function numCharCountBits(mode,ver){return mode[Math.floor((ver+7)/17)+1]}function makeBytes(data){let bb=[];for(let b of data)appendBits(b,8,bb);return new QrSegment(MODE_BYTE,data.length,bb)}function makeNumeric(digits){if(!isNumeric(digits))throw RangeError("String contains non-numeric characters");let bb=[];for(let i=0;i<digits.length;){let n=Math.min(digits.length-i,3);appendBits(Number.parseInt(digits.substring(i,i+n),10),n*3+1,bb),i+=n}return new QrSegment(MODE_NUMERIC,digits.length,bb)}function makeAlphanumeric(text){if(!isAlphanumeric(text))throw RangeError("String contains unencodable characters in alphanumeric mode");let bb=[],i;for(i=0;i+2<=text.length;i+=2){let temp=ALPHANUMERIC_CHARSET.indexOf(text.charAt(i))*45;temp+=ALPHANUMERIC_CHARSET.indexOf(text.charAt(i+1)),appendBits(temp,11,bb)}if(i<text.length)appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)),6,bb);return new QrSegment(MODE_ALPHANUMERIC,text.length,bb)}function makeSegments(text){if(text==="")return[];else if(isNumeric(text))return[makeNumeric(text)];else if(isAlphanumeric(text))return[makeAlphanumeric(text)];else return[makeBytes(toUtf8ByteArray(text))]}function isNumeric(text){return NUMERIC_REGEX.test(text)}function isAlphanumeric(text){return ALPHANUMERIC_REGEX.test(text)}function getTotalBits(segs,version){let result=0;for(let seg of segs){let ccbits=numCharCountBits(seg.mode,version);if(seg.numChars>=1<<ccbits)return Number.POSITIVE_INFINITY;result+=4+ccbits+seg.bitData.length}return result}function toUtf8ByteArray(str){str=encodeURI(str);let result=[];for(let i=0;i<str.length;i++)if(str.charAt(i)!=="%")result.push(str.charCodeAt(i));else result.push(Number.parseInt(str.substring(i+1,i+3),16)),i+=2;return result}function getNumRawDataModules(ver){if(ver<MIN_VERSION||ver>MAX_VERSION)throw RangeError("Version number out of range");let result=(16*ver+128)*ver+64;if(ver>=2){let numAlign=Math.floor(ver/7)+2;if(result-=(25*numAlign-10)*numAlign-55,ver>=7)result-=36}return result}function getNumDataCodewords(ver,ecl){return Math.floor(getNumRawDataModules(ver)/8)-ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver]*NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver]}function reedSolomonComputeDivisor(degree){if(degree<1||degree>255)throw RangeError("Degree out of range");let result=[];for(let i=0;i<degree-1;i++)result.push(0);result.push(1);let root=1;for(let i=0;i<degree;i++){for(let j=0;j<result.length;j++)if(result[j]=reedSolomonMultiply(result[j],root),j+1<result.length)result[j]^=result[j+1];root=reedSolomonMultiply(root,2)}return result}function reedSolomonComputeRemainder(data,divisor){let result=divisor.map((_)=>0);for(let b of data){let factor=b^result.shift();result.push(0),divisor.forEach((coef,i)=>result[i]^=reedSolomonMultiply(coef,factor))}return result}function reedSolomonMultiply(x,y){if(x>>>8!==0||y>>>8!==0)throw RangeError("Byte out of range");let z=0;for(let i=7;i>=0;i--)z=z<<1^(z>>>7)*285,z^=(y>>>i&1)*x;return z}function encodeSegments(segs,ecl,minVersion=1,maxVersion=40,mask=-1,boostEcl=!0){if(!(MIN_VERSION<=minVersion&&minVersion<=maxVersion&&maxVersion<=MAX_VERSION)||mask<-1||mask>7)throw RangeError("Invalid value");let version,dataUsedBits;for(version=minVersion;;version++){let dataCapacityBits2=getNumDataCodewords(version,ecl)*8,usedBits=getTotalBits(segs,version);if(usedBits<=dataCapacityBits2){dataUsedBits=usedBits;break}if(version>=maxVersion)throw RangeError("Data too long")}for(let newEcl of[MEDIUM,QUARTILE,HIGH])if(boostEcl&&dataUsedBits<=getNumDataCodewords(version,newEcl)*8)ecl=newEcl;let bb=[];for(let seg of segs){appendBits(seg.mode[0],4,bb),appendBits(seg.numChars,numCharCountBits(seg.mode,version),bb);for(let b of seg.getData())bb.push(b)}let dataCapacityBits=getNumDataCodewords(version,ecl)*8;appendBits(0,Math.min(4,dataCapacityBits-bb.length),bb),appendBits(0,(8-bb.length%8)%8,bb);for(let padByte=236;bb.length<dataCapacityBits;padByte^=253)appendBits(padByte,8,bb);let dataCodewords=Array.from({length:Math.ceil(bb.length/8)},()=>0);return bb.forEach((b,i)=>dataCodewords[i>>>3]|=b<<7-(i&7)),new QrCode(version,ecl,dataCodewords,mask)}function encode(data,options){let{ecc="L",boostEcc=!1,minVersion=1,maxVersion=40,maskPattern=-1,border=1}=options||{},segment=typeof data==="string"?makeSegments(data):Array.isArray(data)?[makeBytes(data)]:void 0;if(!segment)throw Error(`uqr only supports encoding string and binary data, but got: ${typeof data}`);let qr=encodeSegments(segment,EccMap[ecc],minVersion,maxVersion,maskPattern,boostEcc),result=addBorder({version:qr.version,maskPattern:qr.mask,size:qr.size,data:qr.modules,types:qr.types},border);if(options?.invert)result.data=result.data.map((row)=>row.map((mod)=>!mod));return options?.onEncoded?.(result),result}function addBorder(input,border=1){if(!border)return input;let{size}=input,newSize=size+border*2;input.size=newSize,input.data.forEach((row)=>{for(let i=0;i<border;i++)row.unshift(!1),row.push(!1)});for(let i=0;i<border;i++)input.data.unshift(Array.from({length:newSize},(_)=>!1)),input.data.push(Array.from({length:newSize},(_)=>!1));let b=QrCodeDataType.Border;input.types.forEach((row)=>{for(let i=0;i<border;i++)row.unshift(b),row.push(b)});for(let i=0;i<border;i++)input.types.unshift(Array.from({length:newSize},(_)=>b)),input.types.push(Array.from({length:newSize},(_)=>b));return input}function getDataAt(data,x,y,defaults=!1){if(x<0||y<0||x>=data.length||y>=data.length)return defaults;return data[y][x]}function renderUnicodeCompact(data,options={}){let palette={WHITE_ALL:"\u2588",WHITE_BLACK:"\u2580",BLACK_WHITE:"\u2584",BLACK_ALL:" "},result=encode(data,options),WHITE=!1,BLACK=!0,at=(x,y)=>getDataAt(result.data,x,y,!0),lines=[],line="";for(let row=0;row<result.size;row+=2){for(let col=0;col<result.size;col++)if(at(col,row)===!1&&at(col,row+1)===!1)line+=palette.WHITE_ALL;else if(at(col,row)===!1&&at(col,row+1)===!0)line+=palette.WHITE_BLACK;else if(at(col,row)===!0&&at(col,row+1)===!1)line+=palette.BLACK_WHITE;else line+=palette.BLACK_ALL;lines.push(line),line=""}return lines.join(`
|
|
3
|
-
`)}import{randomBytes,timingSafeEqual}from"crypto";import{chmodSync,existsSync,mkdirSync,readFileSync,writeFileSync}from"fs";import{dirname}from"path";function loadOrCreateToken(path,rotate=!1){if(!rotate&&existsSync(path)){let saved=readFileSync(path,"utf8").trim();if(/^[A-Za-z0-9_-]{43}$/.test(saved))return saved}let token=randomBytes(32).toString("base64url");return mkdirSync(dirname(path),{recursive:!0,mode:448}),writeFileSync(path,`${token}
|
|
4
|
-
`,{mode:384}),chmodSync(path,384),token}function tokenMatches(expected,presented){if(!presented)return!1;let a=Buffer.from(expected),b=Buffer.from(presented);if(a.length!==b.length)return!1;return timingSafeEqual(a,b)}var WEB_SUBPROTOCOL="rove.v1",TOKEN_SUBPROTOCOL_PREFIX="rove.bearer.";function presentedToken(req){let header=req.headers.get("authorization");if(header?.startsWith("Bearer "))return header.slice(7).trim();for(let offered of(req.headers.get("sec-websocket-protocol")??"").split(",")){let name=offered.trim();if(name.startsWith(TOKEN_SUBPROTOCOL_PREFIX))return name.slice(TOKEN_SUBPROTOCOL_PREFIX.length)}return null}function offersWebSubprotocol(req){return(req.headers.get("sec-websocket-protocol")??"").split(",").some((p)=>p.trim()===WEB_SUBPROTOCOL)}function webUrl(opts){let shown=opts.host.includes(":")?`[${opts.host}]`:opts.host;return`${opts.tls?`https://${shown}`:`http://${shown}:${opts.port}`}/#token=${opts.token}`}function pairingUrl(opts){let shown=opts.host.includes(":")?`[${opts.host}]`:opts.host,origin=opts.tls?`wss://${shown}`:`ws://${shown}:${opts.port}`,preset=opts.preset==="none"?"":`&preset=${opts.preset}`;return`${origin}/?token=${opts.token}${preset}`}import{createPublicKey,verify}from"crypto";class AccessDenied extends Error{constructor(reason){super(reason);this.name="AccessDenied"}}var fetchJwksOverHttps=async(url)=>{let res=await fetch(url,{signal:AbortSignal.timeout(1e4)});if(!res.ok)throw Error(`GET ${url} \u2192 ${res.status}`);let body=await res.json();if(!body||typeof body!=="object"||!("keys"in body)||!Array.isArray(body.keys))throw Error(`${url} did not return a JWKS`);return{keys:body.keys}},REFETCH_MIN_MS=60000,LEEWAY_S=30;function decodeSegment(segment,what){try{let value=JSON.parse(Buffer.from(segment,"base64url").toString("utf8"));if(value&&typeof value==="object"&&!Array.isArray(value))return value}catch{}throw new AccessDenied(`malformed JWT ${what}`)}function createAccessVerifier(access,deps={}){let fetchJwks=deps.fetchJwks??fetchJwksOverHttps,now=deps.now??Date.now,certsUrl=`${access.teamDomain}/cdn-cgi/access/certs`,keys=new Map,fetchedAt=Number.NEGATIVE_INFINITY,refresh=async()=>{fetchedAt=now();let jwks=await fetchJwks(certsUrl),next=new Map;for(let jwk of jwks.keys){if(jwk.kty!=="RSA"||!jwk.kid)continue;next.set(jwk.kid,createPublicKey({key:jwk,format:"jwk"}))}keys=next},keyFor=async(kid)=>{let key=keys.get(kid);if(!key&&now()-fetchedAt>=REFETCH_MIN_MS)await refresh(),key=keys.get(kid);if(!key)throw new AccessDenied(`no signing key ${kid} at ${certsUrl}`);return key};return{async verify(assertion){if(!assertion)throw new AccessDenied("missing Cf-Access-Jwt-Assertion header");let parts=assertion.split(".");if(parts.length!==3)throw new AccessDenied("malformed JWT");let[h,p,s]=parts,header=decodeSegment(h,"header");if(header.alg!=="RS256")throw new AccessDenied(`unexpected JWT alg ${String(header.alg)}`);if(typeof header.kid!=="string")throw new AccessDenied("JWT has no kid");let key=await keyFor(header.kid);if(!verify("RSA-SHA256",Buffer.from(`${h}.${p}`),key,Buffer.from(s,"base64url")))throw new AccessDenied("bad JWT signature");let claims=decodeSegment(p,"payload");if(claims.iss!==access.teamDomain)throw new AccessDenied(`JWT issuer ${String(claims.iss)} is not ${access.teamDomain}`);if(!(Array.isArray(claims.aud)?claims.aud:[claims.aud]).includes(access.aud))throw new AccessDenied("JWT audience does not match this Access application");let nowS=now()/1000;if(typeof claims.exp!=="number"||claims.exp+LEEWAY_S<nowS)throw new AccessDenied("JWT expired");if(typeof claims.nbf==="number"&&claims.nbf-LEEWAY_S>nowS)throw new AccessDenied("JWT not yet valid")}}}function teamDomainOf(team){let bare=team.trim().replace(/^https?:\/\//,"").replace(/\/.*$/,"");if(!/^[A-Za-z0-9-]+(\.cloudflareaccess\.com)?$/.test(bare))throw Error(`--cf-team must be a team name or <team>.cloudflareaccess.com, got ${team}`);return`https://${bare.endsWith(".cloudflareaccess.com")?bare:`${bare}.cloudflareaccess.com`}`}function parseBridgeArgs(argv,deps={}){let config=deps.config??{},hosts=[],preset="none",port=7878,publicHost=null,cfTeam=config.cfTeam,cfAud=config.cfAud,rotateToken=!1,qr=!0;for(let i=0;i<argv.length;i++){let arg=argv[i],value=()=>{let v=argv[++i];if(v===void 0||v.startsWith("--"))throw Error(`${arg} needs a value
|
|
5
|
-
usage: rove-bridge [--preset tailscale|cf] [--host <addr>]... [--port <n>]
|
|
6
|
-
[--public-host <name>] [--cf-team <team>] [--cf-aud <aud>]
|
|
7
|
-
[--rotate-token] [--no-qr]
|
|
8
|
-
|
|
9
|
-
(no preset) listen on 127.0.0.1 only (or each --host you name)
|
|
10
|
-
--preset tailscale listen on this Mac's Tailscale IPv4 only; fails if Tailscale
|
|
11
|
-
is not up. With --public-host <name> (a \`tailscale serve\`
|
|
12
|
-
HTTPS name) the phone dials wss://<name>.
|
|
13
|
-
--preset cf listen on 127.0.0.1 for cloudflared; every connection must
|
|
14
|
-
carry a valid Cloudflare Access JWT. Needs --public-host
|
|
15
|
-
(the tunnel hostname), --cf-team and --cf-aud.
|
|
16
|
-
--port <n> TCP port (default 7878)
|
|
17
|
-
--rotate-token mint a new pairing token, revoking every paired phone
|
|
18
|
-
--no-qr print the pairing URL without a QR code
|
|
19
|
-
|
|
20
|
-
--cf-team, --cf-aud and --public-host may also live in
|
|
21
|
-
<ROVE_HOME>/.rove/bridge/config.json as cfTeam, cfAud, publicHost.`);return v};if(arg==="--host")hosts.push(value());else if(arg==="--preset"){let p=value();if(p==="tailscale")preset="tailscale";else if(p==="cf"||p==="cloudflare")preset="cf";else throw Error(`--preset must be tailscale or cf, got ${p}`)}else if(arg==="--port"){let raw=value();if(port=Number(raw),!Number.isInteger(port)||port<1||port>65535)throw Error(`--port must be 1..65535, got ${raw}`)}else if(arg==="--public-host")publicHost=value();else if(arg==="--cf-team")cfTeam=value();else if(arg==="--cf-aud")cfAud=value();else if(arg==="--rotate-token")rotateToken=!0;else if(arg==="--no-qr")qr=!1;else throw Error(`unknown argument ${arg}
|
|
22
|
-
usage: rove-bridge [--preset tailscale|cf] [--host <addr>]... [--port <n>]
|
|
23
|
-
[--public-host <name>] [--cf-team <team>] [--cf-aud <aud>]
|
|
24
|
-
[--rotate-token] [--no-qr]
|
|
25
|
-
|
|
26
|
-
(no preset) listen on 127.0.0.1 only (or each --host you name)
|
|
27
|
-
--preset tailscale listen on this Mac's Tailscale IPv4 only; fails if Tailscale
|
|
28
|
-
is not up. With --public-host <name> (a \`tailscale serve\`
|
|
29
|
-
HTTPS name) the phone dials wss://<name>.
|
|
30
|
-
--preset cf listen on 127.0.0.1 for cloudflared; every connection must
|
|
31
|
-
carry a valid Cloudflare Access JWT. Needs --public-host
|
|
32
|
-
(the tunnel hostname), --cf-team and --cf-aud.
|
|
33
|
-
--port <n> TCP port (default 7878)
|
|
34
|
-
--rotate-token mint a new pairing token, revoking every paired phone
|
|
35
|
-
--no-qr print the pairing URL without a QR code
|
|
36
|
-
|
|
37
|
-
--cf-team, --cf-aud and --public-host may also live in
|
|
38
|
-
<ROVE_HOME>/.rove/bridge/config.json as cfTeam, cfAud, publicHost.`)}if(preset==="cf")publicHost??=config.publicHost??null;if(publicHost!==null&&!/^[A-Za-z0-9.-]+$/.test(publicHost))throw Error(`--public-host must be a bare hostname (no scheme, port or path), got ${publicHost}`);if(preset!=="none"&&hosts.length>0)throw Error("--host cannot be combined with --preset; the preset picks the address");let base={port,rotateToken,qr};if(preset==="tailscale"){let ts=deps.tailscale?.()??{ipv4:null,dnsName:null};if(!ts.ipv4)throw Error("--preset tailscale: `tailscale ip -4` returned no address \u2014 is Tailscale installed and up?");return{...base,preset,hosts:[ts.ipv4],publicHost:publicHost??ts.dnsName,tls:publicHost!==null,cloudflare:null}}if(preset==="cf"){if(!cfTeam||!cfAud)throw Error("--preset cf needs --cf-team and --cf-aud (or cfTeam/cfAud in bridge/config.json)");if(!publicHost)throw Error("--preset cf needs --public-host: the tunnel hostname the phone dials");return{...base,preset,hosts:["127.0.0.1"],publicHost,tls:!0,cloudflare:{teamDomain:teamDomainOf(cfTeam),aud:cfAud.trim()}}}return{...base,preset,hosts:hosts.length>0?[...new Set(hosts)]:["127.0.0.1"],publicHost:null,tls:!1,cloudflare:null}}class TaskFeed{read;now;latest=null;latestKey="";listeners=new Set;timer=null;inflight=null;constructor(read,now=Date.now){this.read=read;this.now=now}poke(){if(this.listeners.size===0||this.timer)return;this.timer=setTimeout(()=>{this.timer=null,this.refresh().catch(()=>{})},250)}refresh(){if(this.inflight)return this.inflight;let p=this.read().then((payload)=>{this.latest={payload,readAt:this.now()};let key=JSON.stringify(payload,(k,v)=>k==="forMs"?void 0:v);if(key!==this.latestKey){this.latestKey=key;for(let listener of this.listeners)listener(payload)}return payload});this.inflight=p;let clear=()=>{if(this.inflight===p)this.inflight=null};return p.then(clear,clear),p}current(){if(!this.latest)return this.refresh();let elapsed=Math.max(0,this.now()-this.latest.readAt),{payload}=this.latest;return Promise.resolve({...payload,tasks:payload.tasks.map((t)=>t.activity?{...t,activity:{...t.activity,forMs:t.activity.forMs+elapsed}}:t)})}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}class NoticeFeed{now;listeners=new Set;lastAt=0;constructor(now=Date.now){this.now=now}push(notice){if(!notice||typeof notice.title!=="string"||typeof notice.at!=="number")return;if(notice.at<=this.lastAt)return;if(this.lastAt=notice.at,this.now()-notice.at>1e4)return;let{title,body,kind,taskId,source,at}=notice,clean={title,kind:typeof kind==="string"?kind:"done",at,...body?{body}:{},...taskId?{taskId}:{},...source?{source}:{}};for(let listener of this.listeners)listener(clean)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}var BRIDGE_PROTOCOL_VERSION=1,OPS=["hello","api.invoke","tasks.subscribe","tasks.list","engines.list","repos.list","task.create","task.delete","task.land","task.tabs","tab.new","tab.close","term.attach","term.input","term.resize","term.detach","diff.files","diff.file","attention.dismiss"];function isCoreOp(op){return OPS.includes(op)}class BridgeError extends Error{code;detail;constructor(code,message,detail){super(message);this.code=code;this.detail=detail;this.name="BridgeError"}}function parseRequest(raw,known=isCoreOp){let frame;try{frame=JSON.parse(raw)}catch{throw new BridgeError("BAD_FRAME","frame is not JSON")}if(!frame||typeof frame!=="object"||Array.isArray(frame))throw new BridgeError("BAD_FRAME","frame is not an object");let{id,op,args}=frame;if(typeof id!=="number"||!Number.isSafeInteger(id))throw new BridgeError("BAD_FRAME","frame needs an integer id");if(typeof op!=="string"||!known(op))throw Object.assign(new BridgeError("UNKNOWN_OP",`unknown op: ${String(op)}`),{requestId:id});if(args!==void 0&&(args===null||typeof args!=="object"||Array.isArray(args)))throw Object.assign(new BridgeError("BAD_ARGS","args must be an object"),{requestId:id});return{id,op,args:args??{}}}function requestIdOf(err){let id=err&&typeof err==="object"&&"requestId"in err?err.requestId:null;return typeof id==="number"?id:null}function str(args,name){let v=args[name];if(typeof v!=="string"||v.length===0)throw new BridgeError("BAD_ARGS",`${name} must be a non-empty string`);return v}function optStr(args,name){let v=args[name];if(v===void 0||v===null||v==="")return;if(typeof v!=="string")throw new BridgeError("BAD_ARGS",`${name} must be a string`);return v}function optInt(args,name,min,max){let v=args[name];if(v===void 0||v===null)return;if(typeof v!=="number"||!Number.isInteger(v)||v<min||v>max)throw new BridgeError("BAD_ARGS",`${name} must be an integer in ${min}..${max}`);return v}function optBool(args,name){let v=args[name];if(v===void 0||v===null)return!1;if(typeof v!=="boolean")throw new BridgeError("BAD_ARGS",`${name} must be a boolean`);return v}function responseOk(id,result){return JSON.stringify({id,ok:!0,result:result??{}})}function responseError(id,code,message,detail){return JSON.stringify({id,ok:!1,error:{...detail,code,message}})}function pushEvent(event,data){return JSON.stringify({event,data})}function asBridgeError(err,fallback){let code=err&&typeof err==="object"&&"code"in err?err.code:void 0,data=err instanceof ApiError?err.data:void 0;return new BridgeError(typeof code==="string"?code:fallback,err instanceof Error?err.message:String(err),data)}function createBridgeApi(client){return{async verb(name,argv){try{return await invokeVerb(name,argv,{client})}catch(err){throw asBridgeError(err,"RPC_ERROR")}},async rpc(name,payload){try{return await client.request(name,payload)}catch(err){throw asBridgeError(err,"RPC_ERROR")}}}}class MachineStore{rows=[];set(statuses){this.rows=statuses.map((s)=>({alias:s.alias,hostLabel:s.hostLabel,state:s.state,version:s.version??null}))}get(){return this.rows}}var machineStore=new MachineStore;function createMachineOps(store=machineStore){return{"machines.list":{kind:"read",destructive:!1,wraps:"MachineHub.machinesSignal (the TUI sidebar's machine layer), held by the bridge",async run(){return{machines:store.get()}}}}}var machineOps=createMachineOps();class PromptFeed{now;listeners=new Set;seen=new Set;constructor(now=Date.now){this.now=now}push(prompt){if(!prompt||typeof prompt.promptId!=="string"||typeof prompt.title!=="string")return;if(typeof prompt.at!=="number"||this.now()-prompt.at>600000)return;if(this.seen.has(prompt.promptId))return;this.seen.add(prompt.promptId);let{promptId,title,placeholder,initial,at}=prompt,clean={promptId,title,at,...typeof placeholder==="string"?{placeholder}:{},...typeof initial==="string"?{initial}:{}};for(let listener of this.listeners)listener(clean)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}import{isAbsolute,normalize}from"path";function newTabInvocation(taskId,tab){let command=tab.engine?["--command",tab.engine]:[];if(tab.prompt!==void 0)return{verb:"send",argv:["--task-id",taskId,"--tab","new","--plain","--prompt",tab.prompt,...command]};return{verb:"tab-new",argv:["--task-id",taskId,"--kind",tab.kind,...command]}}function tabRows(rows){let nameOf=(vendor)=>vendor?engineDisplayName(vendor):null;return rows.map((t)=>({id:t.id,kind:t.kind,title:t.title??t.lastTitle??t.autoTitle,engineName:t.kind==="engine"?nameOf(t.liveVendor??t.vendor):null,liveEngine:t.kind==="engine"&&t.alive!==!1?nameOf(t.liveVendor):null,alive:t.alive,engineAlive:t.engineAlive,...t.split?{split:t.split}:{},...t.viewOf?{viewOf:t.viewOf}:{}}))}function verb(client,name,argv){return createBridgeApi(client).verb(name,argv)}async function tryRead(read){try{return await read()}catch{return null}}var ENGINE_CACHE_MS=60000;function engineFor(task,engines){let command=task.command?.trim(),preset=(command?engines.find((e)=>e.id===command||e.command===command):void 0)??engines.find((e)=>e.builtin&&e.protocol===task.vendor);if(preset)return{id:preset.id,name:preset.name};return task.vendor?{id:null,name:task.vendor}:null}function rowChanges(map,worktreePath){if(!map||!map.has(worktreePath))return;let c=map.get(worktreePath);if(!c)return{unreadable:!0};return{added:c.added,deleted:c.deleted,...c.ahead!==void 0?{ahead:c.ahead}:{},...c.behind!==void 0?{behind:c.behind}:{}}}function rowTokenChips(map,taskId,now){return liveRowTokens(map,taskId,now).map((t)=>({text:t.text,...t.tone?{tone:t.tone}:{},source:t.source,expiresAt:t.expiresAt}))}var PR_CHIP_BY_GLYPH={[DEFAULT_GLYPHS.conflict]:"conflict",[DEFAULT_GLYPHS.checksFailing]:"failing",[DEFAULT_GLYPHS.checksPassing]:"passing"};function prChipKind(task){let chip=prChip(task);return chip?PR_CHIP_BY_GLYPH[chip.glyph]??null:null}function attentionRows(items,tasks){let byId=new Map(tasks.map((t)=>[t.id,t]));return items.map((i)=>{let resumeAt=i.state==="rate_limited"&&i.taskId?byId.get(i.taskId)?.quotaResume?.resumeAt:void 0,label=i.detail?.routine?.name,automationId=i.detail?.routine?.automationId;return{taskId:i.taskId,tabId:i.tabId,state:i.state,unread:i.unread,at:i.at,...resumeAt?{resumeAt}:{},...label?{label}:{},...automationId?{automationId}:{}}})}function machineOf(task){let origin=task.origin;if(!origin||origin.machineId==="local")return{};return{machine:{id:origin.machineId,label:origin.hostLabel,...origin.stale?{stale:!0}:{}}}}function taskRows(tasks,activity,liveTaskIds,engines,now,extras){let byId=new Map(tasks.map((t)=>[t.id,t])),orderOf=new Map(tasks.map((t,i)=>[t.id,i]));return buildContext({repo:"",tasks,activity,liveTaskIds,attention:[],notes:[],now,limit:Number.MAX_SAFE_INTEGER}).tasks.flatMap((row)=>{let task=byId.get(row.taskId);if(!task)return[];let pr=task.prStatus,changes=rowChanges(extras?.changes??null,task.worktreePath),tokens=rowTokenChips(extras?.tokens,task.id,now),chip=prChipKind(task);return[{id:task.id,title:task.title,branch:task.branch,repo:task.repo,kind:task.kind??"task",status:task.status,group:row.group,rank:row.rank,activity:row.activity?{...row.activity,since:now-row.activity.forMs}:null,engine:engineFor(task,engines),pr:pr?{...pr.number!==void 0?{number:pr.number}:{},...pr.url?{url:pr.url}:{},lifecycle:pr.lifecycle,checkState:pr.checkState,...pr.reviewDecision?{reviewDecision:pr.reviewDecision}:{},...pr.mergeable?{mergeable:pr.mergeable}:{}}:null,report:task.report?{summary:task.report.summary??"",at:task.report.at}:null,deleting:task.deletion?.phase==="queued"||task.deletion?.phase==="running",pinned:task.pinned===!0,...task.routine?{routine:!0}:{},order:orderOf.get(task.id)??0,createdAt:task.createdAt,updatedAt:task.updatedAt,...machineOf(task),...changes?{changes}:{},...tokens.length>0?{rowTokens:tokens}:{},prChip:chip,...task.prompt!==void 0?{hasPrompt:!0}:{},prChipStale:chip!==null&&pr?.lastError!==void 0,...task.worktreePath?{}:{noWorktree:!0}}]})}function flatten(entries,scope){return entries.flatMap((e)=>e.children?.length?flatten(e.children,scope):[{path:e.path,status:e.status,added:e.added??null,deleted:e.deleted??null,scope}])}function createRoveOps(client,signals){let engineCache=null,engineLoad=null,engines=()=>{if(engineCache&&Date.now()-engineCache.at<ENGINE_CACHE_MS)return Promise.resolve(engineCache.engines);return engineLoad??=loadEngines().finally(()=>{engineLoad=null}),engineLoad},loadEngines=async()=>{let res=await verb(client,"engine-list",[]),rows=await Promise.all(res.engines.map(async({id,name,command,protocol,builtin,models})=>{let status=await tryRead(()=>detectEngineStatus(id));return{id,name,command,protocol,builtin,models:models??null,effortLevels:[...engineEntry(protocol).effortLevels??[]],acceptsModel:engineEntry(protocol).modelArgv!==void 0,...status?{ready:status.binary.found&&status.account?.kind!=="none"}:{}}}));return engineCache={at:Date.now(),engines:rows},rows},getTask=async(taskId)=>{return(await verb(client,"get-task",["--task-id",taskId])).task};return{async tasks(){let{tasks}=await client.request("task.list"),[inspect,inbox,live,engineRows]=await Promise.all([tryRead(()=>client.request("debug.inspect")),tryRead(()=>client.request("attention.list")),tryRead(()=>defaultApiRuntime.liveTaskIds()),tryRead(engines)]),now=Date.now(),local=taskRows(tasks,inspect?.activity?.tasks??null,live,engineRows??[],now,signals?{changes:signals.changes(),tokens:signals.tokens()}:void 0),remote=taskRows(signals?.remote?.()??[],null,null,engineRows??[],now).map((row)=>({...row,order:(row.order??0)+tasks.length}));return{tasks:[...local,...remote],attention:attentionRows(inbox?.items??[],tasks)}},engines,async repos(){let{tasks}=await client.request("task.list");return[...new Set([...getSavedRepos(),...tasks.map((t)=>t.repo)])].sort()},async createTask({repo,engine,prompt,title}){let argv=["--repo",repo];if(engine)argv.push("--command",engine);if(title)argv.push("--title",title);if(prompt)argv.push("--prompt",prompt);return{taskId:(await verb(client,"add",argv)).taskId}},async deleteTask(taskId,force){let argv=["--task-id",taskId,"--wait"];if(force)argv.push("--force");let res=await verb(client,"delete",argv);return{status:res.status??(res.queued?"queued":"removed")}},async landTask(taskId,strategy){let res=await verb(client,"land",["--task-id",taskId,"--strategy",strategy]);return{landedOn:res.landedOn,commit:res.commit}},async tabs(taskId){let res=await verb(client,"get-task",["--task-id",taskId]);return tabRows(res.tabs??[])},async newTab(taskId,tab){let call=newTabInvocation(taskId,tab),res=await verb(client,call.verb,call.argv),tabId=res.tabId??res.session?.split("::")[1];if(!tabId)throw new BridgeError("SESSION_FAILED","the new tab did not report its session");return{tabId}},async closeTab(taskId,tabId){await verb(client,"tab-close",["--task-id",taskId,"--tab",tabId])},worktreeOf:async(taskId)=>{let task=await getTask(taskId);if(!task.worktreePath)throw new BridgeError("NO_WORKTREE",`task ${taskId} has no worktree yet`);return task.worktreePath},viewedSession(taskId,tabId){let tab=loadStateFile()[terminalTabsKey(taskId)]?.tabs?.find((t)=>t.id===tabId);return tab?.kind==="engine"&&tab.ptyTask?{taskId:tab.ptyTask.id,tabId:"tab-1",cwd:tab.ptyTask.worktree}:null},async diffFiles(taskId){let task=await getTask(taskId);if(!task.worktreePath)return{base:null,files:[]};let base=await resolveBase(task.worktreePath,task.prStatus?.baseRef),[branch,working]=await Promise.all([base?statusFilesBranch(task.worktreePath,base):Promise.resolve([]),statusFiles(task.worktreePath)]);return{base,files:[...flatten(branch,"branch"),...flatten(working,"working")]}},async diffFile(taskId,path,scope){if(isAbsolute(path)||normalize(path).split(/[\\/]/).includes(".."))throw new BridgeError("BAD_ARGS","path must be relative to the worktree");let task=await getTask(taskId);if(!task.worktreePath)throw new BridgeError("NO_WORKTREE",`task ${taskId} has no worktree yet`);if(scope==="working")return loadPreviewData(task.worktreePath,path);let base=await resolveBase(task.worktreePath,task.prStatus?.baseRef);if(!base)throw new BridgeError("NO_BASE","could not resolve a base branch for this task");return loadPreviewData(task.worktreePath,path,{base})},async dismissAttention(taskId,tabId){await client.request("attention.dismiss",tabId?{taskId,tabId}:{taskId})}}}import{hostname as osHostname}from"os";import{unlinkSync}from"fs";import{join}from"path";var realDeps={installHooks:async()=>{let{ensureGlobalRoveHooks}=await import("./chunk-rj7fwa30.js");await ensureGlobalRoveHooks({quiet:!0})},uninstallHooks:async()=>{let{activityHookAdapters}=await import("./chunk-n92fz0hn.js");await Promise.all(activityHookAdapters().map(async(adapter)=>{try{await adapter.removeActivityHooks(adapter.globalSettingsPath())}catch{}}))},resetState:()=>{replaceStateFile({});try{unlinkSync(join(roveStateDir(),"tasks.json"))}catch(err){if(err.code!=="ENOENT")throw new BridgeError("RESET_FAILED",`could not remove tasks.json: ${err.message}`)}}};function createDevOps(deps){return{"engines.hooks.install":{kind:"write",destructive:!0,wraps:"Settings \u2192 Engines install row: ensureGlobalRoveHooks into every engine's own config",async run(){return await deps.installHooks(),{}}},"engines.hooks.uninstall":{kind:"write",destructive:!0,wraps:"Settings \u2192 Engines uninstall row: removeActivityHooks for every hook adapter",async run(){return await deps.uninstallHooks(),{}}},"dev.reset":{kind:"write",destructive:!0,wraps:"Settings \u2192 Dev reset: replaceStateFile({}), remove tasks.json, then daemon.stop {reason: restart} so its in-memory tasks go too (worktrees and engine history stay)",async run(_args,{api}){return deps.resetState(),await api.rpc("daemon.stop",{reason:"restart"}).catch(()=>{return}),{}}},"daemon.restart":{kind:"write",destructive:!0,wraps:"Settings \u2192 Dev restart: daemon RPC daemon.stop {reason: restart} (PTY host and engine sessions keep running)",async run(_args,{api}){return await api.rpc("daemon.stop",{reason:"restart"}).catch(()=>{return}),{}}}}}var devOps=createDevOps(realDeps);function flag(name,value){return`--${name}=${value}`}function oneOf(args,name,values){let v=args[name];if(typeof v!=="string"||!values.includes(v))throw new BridgeError("BAD_ARGS",`${name} must be one of ${values.join("|")}`);return v}function optOneOf(args,name,values){let v=args[name];if(v===void 0||v===null||v==="")return;return oneOf(args,name,values)}function bool(args,name){let v=args[name];if(typeof v!=="boolean")throw new BridgeError("BAD_ARGS",`${name} must be a boolean`);return v}function text(args,name,max){let v=args[name];if(typeof v!=="string"||v.trim().length===0)throw new BridgeError("BAD_ARGS",`${name} must be non-empty text`);if(v.length>max)throw new BridgeError("BAD_ARGS",`${name} is longer than ${max} characters`);return v}function optText(args,name,max){let v=args[name];if(v===void 0||v===null||v==="")return;return text(args,name,max)}function taskId(args,name="taskId"){let v=args[name];if(typeof v!=="string"||!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(v))throw new BridgeError("BAD_ARGS",`${name} is not a task id`);return v}function tabId(args,name="tabId"){let v=args[name];if(typeof v!=="string"||!/^tab-\d{1,6}$/.test(v))throw new BridgeError("BAD_ARGS",`${name} is not a tab id`);return v}function absPath(args,name){let v=args[name];if(typeof v!=="string"||!v.startsWith("/")||v.includes("\x00"))throw new BridgeError("BAD_ARGS",`${name} must be an absolute path`);return v}var MAX_FILES=50000,MAX_NOTES=200,NOTE_MAX=4000,PATH_MAX=1024,MAX_LINE=1e7,stateNoteStore={read(id){let notes=[];return updateStateFile((state)=>{let v=state[diffCommentsKey(id)];return notes=Array.isArray(v)?v:[],!1}),notes},update(id,mutate){updateStateFile((state)=>{let v=state[diffCommentsKey(id)];state[diffCommentsKey(id)]=mutate(Array.isArray(v)?v:[]);return})}},defaultDeps={listFiles:(worktree)=>listFiles(worktree),notes:stateNoteStore,now:Date.now,newId:()=>crypto.randomUUID()};async function worktreeOf(api,id){let path=(await api.verb("get-task",[flag("task-id",id)])).task.worktreePath;if(!path)throw new BridgeError("NO_WORKTREE",`task ${id} has no worktree yet`);return path}function relPath(args,name){let v=text(args,name,PATH_MAX);if(v.startsWith("/")||v.includes("\x00")||v.split(/[\\/]/).includes(".."))throw new BridgeError("BAD_ARGS",`${name} must be relative to the worktree`);return v}function lineNo(args,name){let v=optInt(args,name,1,MAX_LINE);if(v===void 0)throw new BridgeError("BAD_ARGS",`${name} must be an integer in 1..${MAX_LINE}`);return v}var samePath2=(a,b)=>a.replace(/^\/private\//,"/")===b.replace(/^\/private\//,"/");function createFilesOps(deps=defaultDeps){let spec=(s)=>s;return{"files.list":spec({kind:"read",destructive:!1,wraps:"listFiles(worktree) \u2014 tracked + untracked-not-ignored files",async run(args,{api}){let worktree=await worktreeOf(api,taskId(args)),all=await deps.listFiles(worktree),truncated=all.length>MAX_FILES;return{files:truncated?all.slice(0,MAX_FILES):all,truncated}}}),"review.list":spec({kind:"read",destructive:!1,wraps:"state.json diffComments.<taskId>",async run(args){let notes=deps.notes.read(taskId(args));return{notes,unsent:unsentComments(notes).length}}}),"review.add":spec({kind:"write",destructive:!1,wraps:"state.json diffComments.<taskId> (append)",async run(args){let id=taskId(args),line=lineNo(args,"line"),startLine=optInt(args,"startLine",1,MAX_LINE);if(startLine!==void 0&&startLine>line)throw new BridgeError("BAD_ARGS","startLine is after line");let note={id:deps.newId(),filePath:relPath(args,"filePath"),...startLine!==void 0&&startLine!==line?{startLine}:{},line,body:text(args,"body",NOTE_MAX),createdAt:deps.now()};return deps.notes.update(id,(cur)=>{if(cur.length>=MAX_NOTES)throw new BridgeError("TOO_MANY_NOTES",`a task keeps at most ${MAX_NOTES} notes`);return[...cur,note]}),{note}}}),"review.remove":spec({kind:"write",destructive:!0,wraps:"state.json diffComments.<taskId> (drop one note)",async run(args){let id=taskId(args),noteId=text(args,"id",128),removed=!1;return deps.notes.update(id,(cur)=>{let next=cur.filter((c)=>c.id!==noteId);return removed=next.length!==cur.length,next}),{removed}}}),"review.send":spec({kind:"write",destructive:!1,wraps:"rove api send --plain (all unsent notes as one prompt; sentAt only on confirmed delivery)",async run(args,{api}){let id=taskId(args),tab=args.tabId===void 0||args.tabId===null||args.tabId===""?void 0:tabId(args),unsent=unsentComments(deps.notes.read(id));if(unsent.length===0)return{sent:0,delivered:!0};let worktree=await worktreeOf(api,id).catch(()=>{return}),prompt=formatDiffComments(unsent,worktree),res=await api.verb("send",[flag("task-id",id),"--plain",flag("prompt",prompt),...tab?[flag("tab",tab)]:[]]);if(res.delivered!==!0||res.targetState)return{sent:0,delivered:!1,reason:reasonText(res.targetDetail??res.reason)??(res.targetState?`engine is ${res.targetState}`:"not confirmed")};let batch=new Set(unsent.map((c)=>c.id)),sentAt=deps.now();return deps.notes.update(id,(cur)=>cur.map((c)=>batch.has(c.id)&&c.sentAt===void 0?{...c,sentAt}:c)),{sent:unsent.length,delivered:!0}}}),"worktrees.list":spec({kind:"read",destructive:!1,wraps:"daemon RPC worktree.list {network} + task.list (taskId/taskKind joined by path)",async run(args,{api}){let network=args.network===void 0?!0:args.network===!0;if(args.network!==void 0&&typeof args.network!=="boolean")throw new BridgeError("BAD_ARGS","network must be a boolean");let[list,tasks]=await Promise.all([api.rpc("worktree.list",{network}),api.rpc("task.list")]);return{projects:list.projects.map((p)=>({repo:p.repo,worktrees:p.worktrees.map((w)=>{let t=tasks.tasks.find((x)=>x.worktreePath&&samePath2(x.worktreePath,w.path));return t?{...w,taskId:t.id,taskKind:t.kind??"task"}:w})}))}}}),"worktrees.remove":spec({kind:"write",destructive:!0,wraps:"daemon RPC worktree.remove {path, force}",async run(args,{api}){let path=absPath(args,"path"),force=bool(args,"force");if(!(await api.rpc("worktree.list",{network:!1})).projects.some((p)=>p.worktrees.some((w)=>w.path===path)))throw new BridgeError("UNKNOWN_WORKTREE","that path is not a listed worktree");try{let res=await api.rpc("worktree.remove",{path,force});return{removed:res.removed,...res.residue?{residue:res.residue}:{}}}catch(err){if(err instanceof BridgeError&&err.message.startsWith("DIRTY_WORKTREE: "))throw new BridgeError("DIRTY_WORKTREE",err.message.slice(16));throw err}}})}}function reasonText(reason){if(reason===void 0||reason===null||reason==="")return;return typeof reason==="string"?reason:JSON.stringify(reason)}var filesOps=createFilesOps();var CURSOR=/^[A-Za-z0-9._~=-]{1,1024}$/;function given(args,name){let v=args[name];return v!==void 0&&v!==null&&v!==""}function optCursor(args){let raw=optText(args,"cursor",1024);if(raw===void 0)return;if(!CURSOR.test(raw))throw new BridgeError("BAD_ARGS","cursor is not a read-output cursor");return raw}var insightOps={"output.read":{kind:"read",destructive:!1,wraps:"rove api read-output (structured engine history, else a labeled terminal tail)",run(args,{api}){let argv=[flag("task-id",taskId(args))];if(given(args,"tab"))argv.push(flag("tab",tabId(args,"tab")));let source=optOneOf(args,"source",["auto","history","terminal"]);if(source)argv.push(flag("source",source));let cursor=optCursor(args);if(cursor)argv.push(flag("cursor",cursor));let limit=optInt(args,"limit",1,50);if(limit!==void 0)argv.push(flag("limit",limit));return api.verb("read-output",argv)}},"repo.digest":{kind:"read",destructive:!1,wraps:"rove api digest",run(args,{api}){let argv=[flag("repo",absPath(args,"repo"))],days=optInt(args,"sinceDays",1,365);if(days!==void 0)argv.push(flag("since-days",days));return api.verb("digest",argv)}},"turns.list":{kind:"read",destructive:!1,wraps:"rove api agent-turns",run(args,{api}){let argv=[];if(given(args,"taskId"))argv.push(flag("task-id",taskId(args)));if(given(args,"repo"))argv.push(flag("repo",absPath(args,"repo")));let days=optInt(args,"sinceDays",1,365);if(days!==void 0)argv.push(flag("since-days",days));let limit=optInt(args,"limit",1,500);if(limit!==void 0)argv.push(flag("limit",limit));return api.verb("agent-turns",argv)}}};var CHORD_MAX=64,realDeps2={read(){return resetKeybindingsFileCache(),readKeybindingsFile()},create:createKeybindingsFile,fireAction(target){let[cmd,...rest]=[...roveCliInvocation(),"plugin","action","invoke",target];return spawnDetached(cmd,rest,{onError:(err)=>console.warn(`[rove/plugins] ${target}: ${String(err)}`)})},platform:process.platform},same=(a,b)=>JSON.stringify(a??null)===JSON.stringify(b??null);function copyKeymap(){return RoveKeymap.map((row)=>({id:row.id,scope:row.scope,keys:[...row.keys],...row.prefixKeys?{prefixKeys:[...row.prefixKeys]}:{},...row.hint?{hint:{...row.hint}}:{}}))}function createKeybindingsOps(deps=realDeps2){return{"keybindings.get":{kind:"read",destructive:!1,wraps:"helper resolveUserKeybindings (the TUI's keybindings.yaml parser) on a copy of the default keymap",async run(){let file=deps.read(),rows=copyKeymap(),{report,prefix}=resolveUserKeybindings(file,rows,deps.platform),changed=[];for(let row of rows){let base=RoveKeymap.find((candidate)=>candidate.id===row.id);if(base&&same(base.keys,row.keys)&&same(base.prefixKeys,row.prefixKeys)&&same(base.hint,row.hint))continue;changed.push({id:row.id,keys:row.keys,...row.prefixKeys?{prefixKeys:row.prefixKeys}:{},...row.hint?{hint:row.hint}:{}})}return{path:report.path,exists:report.exists,rows:changed,prefix:{key:prefix.key,firstStrokes:prefixFirstStrokes(prefix),timeoutMs:prefix.timeoutMs},plugins:report.plugins,applied:report.applied,warnings:report.warnings}}},"keybindings.createFile":{kind:"write",destructive:!1,wraps:"helper createKeybindingsFile (the fixed, fully commented starter; never overwrites)",async run(){let file=deps.read();if(file.exists)return{path:file.path,created:!1};return{path:file.path,created:deps.create(file.path)}}},"plugin.chordAction":{kind:"write",destructive:!1,wraps:"rove plugin action invoke <target> (detached), only for an `action:` bound to this chord in keybindings.yaml",async run(a){let chord=str(a,"chord");if(chord.length>CHORD_MAX)throw new BridgeError("BAD_ARGS","chord is too long");let file=deps.read(),{report}=resolveUserKeybindings(file,copyKeymap(),deps.platform),bound=report.plugins.find((p)=>p.chord===chord&&p.kind==="action");if(!bound)throw new BridgeError("NOT_BOUND",`${chord} is not bound to a plugin action`);if(!deps.fireAction(bound.target))throw new BridgeError("SESSION_FAILED",`could not start plugin action ${bound.target}`);return{target:bound.target}}}}}var keybindingsOps=createKeybindingsOps();var PATH_MAX2=1000,PANE_ID=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,launchDeps={panes(){return listPaneLaunches({socketPath:defaultDaemonSocketPath(),binPath:ROVE_PRODUCT_NAME}).map((p)=>({id:`${p.pluginId}.${p.paneId}`,title:p.title,placement:p.placement}))}};async function tabNew(api,id,kind,extra){let res=await api.verb("tab-new",[flag("task-id",id),flag("kind",kind),...extra]);if(!res.tabId)throw new BridgeError("SESSION_FAILED","the new tab did not report its id");return{tabId:res.tabId,...res.leaf?{leaf:res.leaf}:{}}}var launchOps={"file.openInEditor":{kind:"write",destructive:!1,wraps:"rove api tab-new --kind editor (the Mac's configured editor on a file inside the task's worktree)",async run(a,{api}){let rel=optStr(a,"path")??"";if(!rel||rel.length>PATH_MAX2||rel.startsWith("/")||rel.includes("\x00")||rel.split(/[\\/]/).includes(".."))throw new BridgeError("BAD_ARGS","path must be relative to the worktree");let{tabId:opened}=await tabNew(api,taskId(a),"editor",[flag("file",rel)]);return{tabId:opened}}},"plugin.panes":{kind:"read",destructive:!1,wraps:"helper listPaneLaunches (panes of enabled plugins)",async run(){return{panes:launchDeps.panes()}}},"plugin.paneOpen":{kind:"write",destructive:!1,wraps:"rove api tab-new --kind pane (a registered plugin pane; its argv comes from the manifest)",async run(a,{api}){let pane=str(a,"pane");if(!PANE_ID.test(pane))throw new BridgeError("BAD_ARGS","pane is not a plugin pane id");let extra=[flag("pane",pane)];if(a.tabId!==void 0&&a.tabId!==null)extra.push(flag("tab",tabId(a)));return tabNew(api,taskId(a),"pane",extra)}},"tab.openViewport":{kind:"write",destructive:!1,wraps:"rove api tab-new --kind viewport (a tab showing another task's first engine session)",async run(a,{api}){let{tabId:opened}=await tabNew(api,taskId(a),"viewport",[flag("view-task",taskId(a,"viewTaskId"))]);return{tabId:opened}}}};var PLUGIN_ID=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;function control(a){let plugin=text(a,"plugin",128),pane=text(a,"pane",64),key=text(a,"key",64);if(!PLUGIN_ID.test(plugin)||!MOD_PANE_ID_PATTERN.test(pane)||!MOD_KEY_PATTERN.test(key))throw new BridgeError("BAD_ARGS","plugin, pane or key is not a mod id");return{plugin,pane,key}}function delivered(res){if(!res.ok)throw new BridgeError("MOD_UNAVAILABLE",`the mod did not get it (${res.reason??"unknown"})`);return{}}var modsOps={"mod.press":{kind:"write",destructive:!1,wraps:"daemon RPC mod.press (forwards a button key to the mod that drew it)",async run(a,{api}){return delivered(await api.rpc("mod.press",control(a)))}},"mod.submit":{kind:"write",destructive:!1,wraps:"daemon RPC mod.submit (forwards an input field's text to the mod that drew it)",async run(a,{api}){let value=a.value;if(typeof value!=="string")throw new BridgeError("BAD_ARGS","value must be text");if(value.length>MOD_INPUT_MAX)throw new BridgeError("BAD_ARGS",`value is longer than ${MOD_INPUT_MAX} characters`);return delivered(await api.rpc("mod.submit",{...control(a),value}))}}};var ISSUE_STATUSES=["open","doing","hold","done"],TITLE_MAX=300,BODY_MAX=20000,NAME_MAX=120,PROMPT_MAX=20000,EVENT_LIMIT=12;function issueId(args){let id=optInt(args,"id",1,1e9);if(id===void 0)throw new BridgeError("BAD_ARGS","id must be an issue number");return id}function cron(args,name){let v=text(args,name,120).trim();if(!/^[0-9A-Za-z*/,\-?#LW]+(?: [0-9A-Za-z*/,\-?#LW]+){4}$/.test(v))throw new BridgeError("BAD_ARGS",`${name} must be five space-separated cron fields`);return v}function setIfPresent(argv,name,value){if(value!==void 0)argv.push(flag(name,value))}var pagesOps={"issue.repos":{kind:"read",destructive:!1,wraps:"daemon RPC issue.repos",run:(_args,{api})=>api.rpc("issue.repos",{})},"issue.list":{kind:"read",destructive:!1,wraps:"rove api issue-list",run:(args,{api})=>api.verb("issue-list",[flag("repo",absPath(args,"repo"))])},"issue.create":{kind:"write",destructive:!1,wraps:"rove api issue-create",run:(args,{api})=>{let argv=[flag("repo",absPath(args,"repo")),flag("title",text(args,"title",TITLE_MAX).trim())];return setIfPresent(argv,"body",optText(args,"body",BODY_MAX)),api.verb("issue-create",argv)}},"issue.update":{kind:"write",destructive:!1,wraps:"rove api issue-update (title/body and/or task link; task=none unlinks; clearBody stores one space, the verb cannot send an empty body)",run:(args,{api})=>{let title=optText(args,"title",TITLE_MAX),typed=optText(args,"body",BODY_MAX);if(optBool(args,"clearBody")&&typed!==void 0)throw new BridgeError("BAD_ARGS","body and clearBody are exclusive");let body=optBool(args,"clearBody")?" ":typed,task=optStr(args,"task")===void 0?void 0:taskId(args,"task");if(title===void 0&&body===void 0&&task===void 0)throw new BridgeError("BAD_ARGS","issue.update needs title, body and/or task");let argv=[flag("repo",absPath(args,"repo")),flag("id",issueId(args))];return setIfPresent(argv,"title",title?.trim()),setIfPresent(argv,"body",body),setIfPresent(argv,"task",task),api.verb("issue-update",argv)}},"issue.setStatus":{kind:"write",destructive:!1,wraps:"rove api issue-update --status",run:(args,{api})=>api.verb("issue-update",[flag("repo",absPath(args,"repo")),flag("id",issueId(args)),flag("status",oneOf(args,"status",ISSUE_STATUSES))])},"issue.delete":{kind:"write",destructive:!0,wraps:"rove api issue-delete (the tracker record only; a linked task and worktree stay)",run:(args,{api})=>api.verb("issue-delete",[flag("repo",absPath(args,"repo")),flag("id",issueId(args))])},"issue.prompt":{kind:"read",destructive:!1,wraps:"rove api issue-list + the kanban drawer's issueWorktreePrompt/issueProjectPrompt helpers",async run(args,{api}){let where=oneOf(args,"where",["worktree","project"]),id=issueId(args),issue=(await api.verb("issue-list",[flag("repo",absPath(args,"repo"))])).issues.find((i)=>i.id===id);if(!issue)throw new BridgeError("ISSUE_NOT_FOUND",`no issue #${id}`);let cli=roveApiInvocation();return{title:issueChatTaskTitle(issue),prompt:where==="worktree"?issueWorktreePrompt(issue,cli):issueProjectPrompt(issue,cli)}}},"task.events":{kind:"read",destructive:!1,wraps:"daemon RPC task.recentEvents, newest first, as the drawer's EVENTS rows",async run(args,{api}){let id=taskId(args),limit=optInt(args,"limit",1,100)??EVENT_LIMIT;try{return{events:(await api.rpc("task.recentEvents",{taskId:id})).events.slice(-limit).reverse().map((event)=>({kind:event.kind,at:event.at,tail:[detailFragment(event),event.vendor??""].filter((part)=>part.length>0).join(" \xB7 ")}))}}catch(err){if(err instanceof Error&&/task not found/i.test(err.message))return{events:[]};throw err}}},"routine.list":{kind:"read",destructive:!1,wraps:"rove api routine-list",run:(_args,{api})=>api.verb("routine-list",[])},"routine.create":{kind:"write",destructive:!1,wraps:"rove api routine-create (name, repo, prompt, schedule, optional existing conversation targetTask+targetTab; never a precheck)",run:(args,{api})=>{let argv=[flag("repo",absPath(args,"repo")),flag("name",text(args,"name",NAME_MAX).trim()),flag("prompt",text(args,"prompt",PROMPT_MAX)),flag("schedule",cron(args,"schedule"))],hasTask=optStr(args,"targetTask")!==void 0,hasTab=optStr(args,"targetTab")!==void 0;if(hasTask!==hasTab)throw new BridgeError("BAD_ARGS","targetTask and targetTab go together");if(hasTask)argv.push(flag("target-task",taskId(args,"targetTask")),flag("target-tab",tabId(args,"targetTab")));return api.verb("routine-create",argv)}},"routine.update":{kind:"write",destructive:!1,wraps:"rove api routine-update (name, prompt, schedule; never a precheck)",run:(args,{api})=>{let name=optText(args,"name",NAME_MAX),prompt=optText(args,"prompt",PROMPT_MAX),schedule=optStr(args,"schedule")===void 0?void 0:cron(args,"schedule");if(name===void 0&&prompt===void 0&&schedule===void 0)throw new BridgeError("BAD_ARGS","routine.update needs name, prompt and/or schedule");let argv=[flag("id",taskId(args,"id"))];return setIfPresent(argv,"name",name?.trim()),setIfPresent(argv,"prompt",prompt),setIfPresent(argv,"schedule",schedule),api.verb("routine-update",argv)}},"routine.setEnabled":{kind:"write",destructive:!1,wraps:"rove api routine-update --enabled",run:(args,{api})=>api.verb("routine-update",[flag("id",taskId(args,"id")),flag("enabled",String(bool(args,"enabled")))])},"routine.runNow":{kind:"write",destructive:!1,wraps:"rove api routine-run-now (skips the precheck; the schedule does not shift)",run:(args,{api})=>api.verb("routine-run-now",[flag("id",taskId(args,"id"))])},"routine.runs":{kind:"read",destructive:!1,wraps:"rove api routine-runs",run:(args,{api})=>api.verb("routine-runs",[flag("id",taskId(args,"id"))])},"routine.delete":{kind:"write",destructive:!0,wraps:"rove api routine-delete (the routine and its history; tasks it created stay)",run:(args,{api})=>api.verb("routine-delete",[flag("id",taskId(args,"id"))])},"attention.dismissRoutine":{kind:"write",destructive:!1,wraps:"daemon RPC attention.dismissRoutine (a routine episode is keyed on its schedule, not a task)",run:(args,{api})=>api.rpc("attention.dismissRoutine",{automationId:taskId(args,"automationId")})},"workitem.list":{kind:"read",destructive:!1,wraps:"daemon RPC workitem.list (same call as rove api workitem-list, plus refresh)",run:(args,{api})=>{let state=optOneOf(args,"state",["open","closed","all"]),assignee=optOneOf(args,"assignee",["@me"]),search=optText(args,"search",200),limit=optInt(args,"limit",1,50);return api.rpc("workitem.list",{repo:absPath(args,"repo"),...state?{state}:{},...assignee?{assignee}:{},...search?{search}:{},...limit!==void 0?{limit}:{},...optBool(args,"refresh")?{refresh:!0}:{}})}},"workitem.links":{kind:"read",destructive:!1,wraps:"daemon RPC task.list, folded to the tasks already started from a GitHub issue of this repo",async run(args,{api}){let repo=absPath(args,"repo"),{tasks}=await api.rpc("task.list",{});return{links:tasks.flatMap((task)=>task.linkedWorkItem?.number!==void 0&&samePath(task.repo,repo)?[{number:task.linkedWorkItem.number,taskId:task.id}]:[])}}},"workitem.start":{kind:"write",destructive:!1,wraps:"rove api workitem-start",run(args,{api}){let number=optInt(args,"number",1,1e9);if(number===void 0)throw new BridgeError("BAD_ARGS","number must be an issue number");let argv=[flag("repo",absPath(args,"repo")),flag("number",number)];return setIfPresent(argv,"vendor",optOneOf(args,"engine",ALL_VENDORS)),api.verb("workitem-start",argv)}}};var KEY_HINTS_ENABLED_KEY="hints.keyboard.enabled",PANE_HINT_USED_KEYS=["hints.sidebar.used","hints.files.used"],RAIL_FOLD_STYLES=appearanceChoices("railFold",[]).map((c)=>c.value),bool2=(key,fallback,extra)=>({kind:"bool",read:(s)=>typeof s[key]==="boolean"?s[key]:fallback,write:(v)=>({[key]:v,...extra?.(v)})}),choice=(key,choices,read,stored=(v)=>v)=>({kind:"enum",choices:()=>choices,read:(s)=>read(s[key]),write:(v)=>({[key]:stored(v)})}),appearance=(setting)=>appearanceChoices(setting,[]).map((c)=>c.value),text2=(raw)=>typeof raw==="string"?raw.trim():"";function worktreeKind(state){return worktreeBaseKindOf(text2(state[WORKTREE_BASE_KEY]))}function worktreeCustomPath(state){return text2(state[WORKTREE_BASE_CUSTOM_KEY])||(worktreeKind(state)==="custom"?text2(state[WORKTREE_BASE_KEY]):"")}var WORKTREE_KINDS=["default","nextToProject","custom"],PREF_DEFS={locale:choice("locale",LOCALES.map((l)=>l.id),(raw)=>isLocaleId(raw)?raw:DEFAULT_LOCALE),theme:{kind:"enum",choices:(themes)=>themes,read:(s)=>typeof s.activeTheme==="string"&&s.activeTheme?s.activeTheme:DEFAULT_THEME,write:(v)=>({activeTheme:v})},themeMode:choice("themeMode",THEME_MODE_PREFERENCES,(raw)=>THEME_MODE_PREFERENCES.includes(raw)?raw:DEFAULT_THEME_MODE),transparent:bool2("transparentBackground",defaultTransparentBackground()),focusAccent:choice("focusAccent",FOCUS_ACCENT_SLOTS,(raw)=>FOCUS_ACCENT_SLOTS.includes(raw)?raw:"primary"),splitStyle:choice(SPLIT_STYLE_KEY,appearance("splitStyle"),normalizeSplitStyle),railFold:choice(RAIL_FOLD_STYLE_KEY,RAIL_FOLD_STYLES,(raw)=>RAIL_FOLD_STYLES.includes(raw)?raw:"glyphs"),tabRowHeight:choice(TAB_ROW_HEIGHT_KEY,appearance("tabRowHeight"),(raw)=>normalizeTabRowHeight(raw??DEFAULT_TAB_ROW_HEIGHT)),workingBorder:choice(WORKING_BORDER_KEY,appearance("workingBorder"),(raw)=>normalizeWorkingBorder(raw??DEFAULT_WORKING_BORDER)),taskColors:choice(TASK_COLORS_KEY,appearance("taskColors"),(raw)=>normalizeTaskColors(raw??DEFAULT_TASK_COLORS)),glyphSet:choice(GLYPH_SET_KEY,appearance("glyphSet"),(raw)=>normalizeGlyphSet(raw??DEFAULT_GLYPH_SET)),colorblind:choice(COLORBLIND_KEY,appearance("colorblind"),(raw)=>normalizeColorblind(raw??DEFAULT_COLORBLIND)),runningTitle:choice(RUNNING_TITLE_KEY,appearance("runningTitle"),(raw)=>normalizeRunningTitle(raw??DEFAULT_RUNNING_TITLE)),toast:bool2("notifications.toast.enabled",!0),sound:bool2("notifications.sound.enabled",!0),soundVolume:choice(SOUND_VOLUME_KEY,SOUND_VOLUME_STEPS,(raw)=>normalizeSoundVolume(raw??DEFAULT_SOUND_VOLUME)),crossTask:bool2("notifications.crossTask.enabled",!0),keyHints:bool2(KEY_HINTS_ENABLED_KEY,!0,(on)=>on?Object.fromEntries(PANE_HINT_USED_KEYS.map((k)=>[k,!1])):{}),zen:bool2(ZEN_ACTIVE_KEY,ZEN_DEFAULT),editorKind:choice(EDITOR_KIND_KEY,EDITOR_KINDS,(raw)=>normalizeEditorKind(raw??DEFAULT_EDITOR_KIND)),worktreeBase:{kind:"enum",choices:()=>WORKTREE_KINDS,read:(s)=>worktreeKind(s),write:(kind,s)=>{let current=text2(s[WORKTREE_BASE_KEY]),remember=worktreeKind(s)==="custom"&&kind!=="custom"?{[WORKTREE_BASE_CUSTOM_KEY]:current}:{};if(kind==="default")return{...remember,[WORKTREE_BASE_KEY]:""};if(kind==="nextToProject")return{...remember,[WORKTREE_BASE_KEY]:PROJECT_SIBLING_BASE};let custom=worktreeCustomPath(s);if(!custom)throw new BridgeError("BAD_ARGS","no custom worktree base is remembered; set one in the TUI");return{[WORKTREE_BASE_KEY]:custom}}},scrollbackRows:{kind:"int",min:SCROLLBACK_ROWS_MIN,max:SCROLLBACK_ROWS_MAX,read:(s)=>normalizeScrollbackRows(s[SCROLLBACK_ROWS_KEY]??DEFAULT_SCROLLBACK_ROWS),write:(v)=>({[SCROLLBACK_ROWS_KEY]:normalizeScrollbackRows(v)})},tabStrip:{kind:"enum",choices:()=>TAB_STRIP_MODES,read:(s)=>resolveTabStripMode(s[TAB_STRIP_MODE_KEY],s[TAB_STRIP_HIDE_SINGLE_KEY]),write:(v)=>({[TAB_STRIP_MODE_KEY]:v})},prefixTap:choice(PREFIX_TAP_PRESENTATION_KEY,PREFIX_TAP_PRESENTATIONS,(raw)=>normalizePrefixTapPresentation(raw??DEFAULT_PREFIX_TAP_PRESENTATION)),remoteProjects:bool2("experimental.remoteProjects",!1),autoStatus:bool2(AUTO_STATUS_KEY,!1),dispatcher:bool2(DISPATCHER_KEY,!1)};function prefInfo(state){return{editorCustomSet:text2(state[EDITOR_CUSTOM_KEY]).length>0,worktreeCustomPath:worktreeCustomPath(state)}}function checkPrefValue(name,def,value,themes){let bad=(why)=>{throw new BridgeError("BAD_ARGS",`${name} ${why}`)};if(def.kind==="bool")return typeof value==="boolean"?value:bad("must be a boolean");if(def.kind==="int"){if(typeof value!=="number"||!Number.isInteger(value))return bad("must be an integer");return value<def.min||value>def.max?bad(`must be ${def.min}\u2013${def.max}`):value}let choices=def.choices(themes);if((typeof value==="string"||typeof value==="number")&&choices.includes(value))return value;return bad(`must be one of ${choices.join("|")}`)}var SLOTS={text:null,background:null,textMuted:"text",backgroundPanel:"background",backgroundElement:"background",backgroundMenu:"backgroundElement",border:"text",borderActive:"border",borderSubtle:"border",primary:"text",secondary:"text",accent:"primary",error:"text",warning:"text",success:"text",info:"text",diffAdded:"success",diffRemoved:"error",diffLineNumber:"textMuted",syntaxType:"info",diffAddedBg:"background",diffRemovedBg:"background"},hex2=(n)=>n.toString(16).padStart(2,"0"),rgbHex=(c)=>`#${c.toInts().slice(0,3).map(hex2).join("")}`;function palette(theme,mode){let out={},slot=(name)=>{let known=out[name];if(known)return known;let fallback=SLOTS[name],value=resolveThemeSlotHex(theme,name,mode)??(fallback?slot(fallback):name==="background"?"#000000":"#ffffff");return out[name]=value,value};for(let name of Object.keys(SLOTS))slot(name);let cb=diffInks(resolveTheme(theme,mode),!0);return out.diffAddedColorblind=rgbHex(cb.added),out.diffAddedBgColorblind=rgbHex(cb.addedBg),out}function taskColors(theme,mode,ids){let resolved=resolveTheme(theme,mode);return Object.fromEntries(ids.map((id)=>[id,rgbHex(taskColor(id,resolved))]))}var realDeps3={load:loadStateFile,patch:(patch)=>{patchStateFile(patch)},themes:()=>{let user=loadUserThemes(),names=new Set(user.map((u)=>u.name));return[...Object.entries(BUNDLED_THEME_JSONS).filter(([name])=>!names.has(name)).map(([name,theme])=>({name,bundled:!0,theme})),...user.map((u)=>({name:u.name,bundled:!1,theme:u.theme}))]}},MAX_TASK_IDS=500,MODES=["dark","light"];function readAll(deps,state){let themes=deps.themes(),names=themes.map((t)=>t.name),prefs={},options={};for(let[name,def]of Object.entries(PREF_DEFS))if(prefs[name]=def.read(state),def.kind==="enum")options[name]=def.choices(names);else if(def.kind==="int")options[name]={min:def.min,max:def.max};return{prefs,options,info:prefInfo(state),themes}}function createPrefsOps(deps){return{"prefs.get":{kind:"read",destructive:!1,wraps:"state.json Settings keys read through the TUI normalizers, plus resolved theme palettes and glyph sets",async run(){let{prefs,options,info,themes}=readAll(deps,deps.load());return{prefs,options,info,glyphSets:GLYPH_SETS,themes:themes.map((t)=>({name:t.name,bundled:t.bundled,dark:palette(t.theme,"dark"),light:palette(t.theme,"light")}))}}},"prefs.set":{kind:"write",destructive:!1,wraps:"state.json: one allowlisted Settings key per call, value checked against the TUI's own choices",async run(args){let name=args.key;if(typeof name!=="string"||!Object.hasOwn(PREF_DEFS,name))throw new BridgeError("BAD_ARGS",`key must be one of ${Object.keys(PREF_DEFS).join("|")}`);let def=PREF_DEFS[name],state=deps.load(),names=deps.themes().map((t)=>t.name),value=checkPrefValue(name,def,args.value,names);deps.patch(def.write(value,state));let{prefs}=readAll(deps,deps.load());return{key:name,value:prefs[name],prefs}}},"theme.taskColors":{kind:"read",destructive:!1,wraps:"the TUI's taskColor(taskId, theme) for each id under one theme and mode",async run(args){let{themes}=readAll(deps,deps.load()),theme=themes.find((t)=>t.name===args.theme);if(!theme)throw new BridgeError("BAD_ARGS","theme is not an installed theme");let mode=MODES.find((m)=>m===args.mode);if(!mode)throw new BridgeError("BAD_ARGS","mode must be dark|light");let ids=args.taskIds;if(!Array.isArray(ids)||ids.length>MAX_TASK_IDS||!ids.every((id)=>typeof id==="string"&&id.length<=64))throw new BridgeError("BAD_ARGS",`taskIds must be at most ${MAX_TASK_IDS} task ids`);return{colors:taskColors(theme.theme,mode,ids)}}}}}var prefsOps=createPrefsOps(realDeps3);var PROMPT_ID=/^[A-Za-z0-9-]{1,64}$/,ANSWER_MAX=4000,promptOps={"ui.promptReply":{kind:"write",destructive:!1,wraps:"daemon RPC ui.promptReply (answers or cancels a plugin's input dialog; first answer wins)",async run(a,{api}){let promptId=a.promptId;if(typeof promptId!=="string"||!PROMPT_ID.test(promptId))throw new BridgeError("BAD_ARGS","promptId is not a prompt id");let value=a.value;if(value!==void 0&&(typeof value!=="string"||value.length>ANSWER_MAX))throw new BridgeError("BAD_ARGS",`value must be text of at most ${ANSWER_MAX} characters`);if(!(await api.rpc("ui.promptReply",{promptId,...value!==void 0?{value}:{}})).ok)throw new BridgeError("PROMPT_GONE","this question was already answered or timed out");return{}}}};var NAME_MAX2=60,realDeps4={load:loadStateFile,patch:(patch)=>{patchStateFile(patch)},installed:installedEngineIds,statuses:detectEngineStatuses,integrations:engineIntegrations,engineName:engineDisplayName,defaultCommand:defaultEngineCommand};function strings(state,key){let raw=state[key];return Array.isArray(raw)?raw.filter((s)=>typeof s==="string"&&s.trim().length>0):[]}function trimmed(state,key){let raw=state[key];return typeof raw==="string"?raw.trim():""}async function engineIds(deps,state){return[...new Set([...ALL_VENDORS,...strings(state,"customEngineIds"),...await deps.installed()])]}function canBeDefault(state,id){return isBuiltinVendor(id)||strings(state,"customEngineIds").includes(id)}function effectiveDefault(state,ids){let off=strings(state,"disabledEngineIds"),stored=trimmed(state,"defaultVendor");if(stored&&canBeDefault(state,stored)&&!off.includes(stored))return stored;return ids.find((id)=>canBeDefault(state,id)&&!off.includes(id))??null}function listedId(args,ids){let id=text(args,"id",64);if(!ids.includes(id))throw new BridgeError("BAD_ARGS",`${id} is not a listed engine`);return id}function createEngineOps(deps){let without=(list,id)=>list.filter((x)=>x!==id);function afterLeaving(state,ids,id,off){let remaining=ids.filter((x)=>x!==id&&!off.includes(x));if(remaining.length===0)throw new BridgeError("LAST_ENGINE","this is the last enabled engine; it stays on");if(effectiveDefault(state,ids)!==id)return{};let next=remaining.find((x)=>canBeDefault(state,x));if(!next)throw new BridgeError("LAST_ENGINE","no other enabled engine can take over as the default");return{defaultVendor:next}}return{"engines.settings":{kind:"read",destructive:!1,wraps:"settings Engines section: registry + detectEngineStatuses + engineIntegrations + state.json switches",async run(){let state=deps.load(),ids=await engineIds(deps,state),[statuses,integrations]=await Promise.all([deps.statuses(ids).catch(()=>[]),Promise.resolve(deps.integrations(ids)).catch(()=>[])]),off=strings(state,"disabledEngineIds"),custom=strings(state,"customEngineIds"),current=effectiveDefault(state,ids);return{defaultId:current,engines:ids.map((id)=>{let status=statuses.find((s)=>s.vendor===id),integration=integrations.find((i)=>i.vendor===id),override=trimmed(state,`engineCommand.${id}`),command=override?override.split(/\s+/):deps.defaultCommand(id),account=status?.account;return{id,name:deps.engineName(id),builtin:isBuiltinVendor(id),custom:custom.includes(id),enabled:!off.includes(id),isDefault:id===current,canBeDefault:canBeDefault(state,id),binary:command[0]??null,customized:override.length>0||trimmed(state,`engineName.${id}`).length>0,protocol:trimmed(state,`engineProtocol.${id}`)||null,binaryFound:status?status.binary.found:null,binaryPath:status?.binary.found?status.binary.path??null:null,login:!status||account===null||account===void 0||status.accountError?"unknown":account.kind==="none"?"no":"yes",hooks:integration?.hooksSupported?integration.hookState:"unsupported",markers:integration?.markers??!1,screen:integration?.screen??!1,...integration?.configIssue?{configIssue:integration.configIssue}:{}}})}}},"engine.setEnabled":{kind:"write",destructive:!0,wraps:"state.json disabledEngineIds (+ defaultVendor handoff), as Settings \u2192 Engines `space`",async run(args){let state=deps.load(),ids=await engineIds(deps,state),id=listedId(args,ids),enabled=bool(args,"enabled"),off=strings(state,"disabledEngineIds");if(enabled)deps.patch({disabledEngineIds:without(off,id)});else if(!off.includes(id)){let handoff=afterLeaving(state,ids,id,off);deps.patch({disabledEngineIds:[...off,id],...handoff})}return{id,enabled}}},"engine.setDefault":{kind:"write",destructive:!0,wraps:"state.json defaultVendor (+ re-enables it), as Settings \u2192 Engines `d`",async run(args){let state=deps.load(),ids=await engineIds(deps,state),id=listedId(args,ids);if(!canBeDefault(state,id))throw new BridgeError("BAD_ARGS",`${id} cannot be the default; only built-in and custom engines can`);let off=strings(state,"disabledEngineIds");return deps.patch({defaultVendor:id,...off.includes(id)?{disabledEngineIds:without(off,id)}:{}}),{id}}},"engine.rename":{kind:"write",destructive:!0,wraps:"state.json engineName.<id>, as Settings \u2192 Engines `r` (blank clears)",async run(args){let state=deps.load(),id=listedId(args,await engineIds(deps,state)),raw=typeof args.name==="string"?args.name.trim():"";if(raw.length>NAME_MAX2||/[\u0000-\u001f\u007f]/.test(raw))throw new BridgeError("BAD_ARGS",`name must be at most ${NAME_MAX2} printable characters`);return deps.patch({[`engineName.${id}`]:raw.length>0?raw:void 0}),{id,name:raw.length>0?raw:deps.engineName(id)}}},"engine.reset":{kind:"write",destructive:!0,wraps:"state.json engineCommand/engineName/engineProtocol/customEngineIds, as Settings \u2192 Engines `x`",async run(args){let state=deps.load(),ids=await engineIds(deps,state),id=listedId(args,ids),clear={[`engineCommand.${id}`]:void 0,[`engineName.${id}`]:void 0},custom=strings(state,"customEngineIds");if(!custom.includes(id))return deps.patch(clear),{id,removed:!1};let off=strings(state,"disabledEngineIds"),handoff=off.includes(id)?{}:afterLeaving(state,ids,id,off);return deps.patch({...clear,[`engineProtocol.${id}`]:void 0,customEngineIds:without(custom,id),disabledEngineIds:without(off,id),...handoff}),{id,removed:!0}}}}}var engineOps=createEngineOps(realDeps4);var taskOpDeps={savedRepos:()=>getSavedRepos(),listLocalBranches,getCurrentBranch,validateRepoPath,cloneRepo,validateGitUrl,validateCloneTarget,resolveCloneTarget,findAvailableFolderName,deriveFolderName},GIT_REF=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,199}$/,MODEL=/^[A-Za-z0-9][A-Za-z0-9._:/@+-]{0,99}$/,EFFORT_LEVEL=/^[a-z0-9][a-z0-9-]{0,19}$/,ENGINE_ID=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,FOLDER=/^[A-Za-z0-9_][A-Za-z0-9._-]{0,99}$/;function gitRef(args,name){let v=args[name];if(typeof v!=="string"||!GIT_REF.test(v)||v.includes("..")||v.includes("//")||v.includes("/.")||v.endsWith("/")||v.endsWith(".")||v.endsWith(".lock"))throw new BridgeError("BAD_ARGS",`${name} is not a valid git ref name`);return v}function optGitRef(args,name){let v=args[name];return v===void 0||v===null||v===""?void 0:gitRef(args,name)}function model(args,name="model"){let v=args[name];if(typeof v!=="string"||!MODEL.test(v))throw new BridgeError("BAD_ARGS",`${name} is not a model id`);return v}function optModel(args,name="model"){let v=args[name];return v===void 0||v===null||v===""?void 0:model(args,name)}function effortLevel(args,name="level"){let v=args[name];if(typeof v!=="string"||!EFFORT_LEVEL.test(v))throw new BridgeError("BAD_ARGS",`${name} is not an effort level`);return v}async function knownEngineIds(ctx){let res=await ctx.api.verb("engine-list",[]);return new Set((res.engines??[]).map((e)=>e.id))}function checkEngineShape(id,name){if(typeof id!=="string"||!ENGINE_ID.test(id))throw new BridgeError("BAD_ARGS",`${name} is not an engine id`);return id}async function engineId(args,name,ctx){let id=checkEngineShape(args[name],name);if(!(await knownEngineIds(ctx)).has(id))throw new BridgeError("UNKNOWN_ENGINE",`${name} ${id} is not a known engine`);return id}var FANOUT_CAP=10;function parseAgents(args,name="agents"){let raw=args[name];if(typeof raw!=="string"||raw.length===0||raw.length>300)throw new BridgeError("BAD_ARGS",`${name} must be engine:count pairs like claude:2,codex:1`);let plan=[],total=0;for(let part of raw.split(",")){let m=/^([^:]+):(\d{1,2})$/.exec(part);if(!m)throw new BridgeError("BAD_ARGS",`${name} entry "${part}" must be engine:count`);let id=checkEngineShape(m[1],name),n=Number.parseInt(m[2],10);if(n<1)throw new BridgeError("BAD_ARGS",`${name} count for ${id} must be at least 1`);if(plan.some((p)=>p.id===id))throw new BridgeError("BAD_ARGS",`${name} names ${id} twice`);if(total+=n,total>FANOUT_CAP)throw new BridgeError("BAD_ARGS",`${name} asks for more than ${FANOUT_CAP} agents`);plan.push({id,n})}return plan}async function checkAgentEngines(plan,ctx){let known=await knownEngineIds(ctx);for(let{id}of plan)if(!known.has(id))throw new BridgeError("UNKNOWN_ENGINE",`agents engine ${id} is not a known engine`)}async function knownRepo(args,ctx,name="repo"){let repo=absPath(args,name);if(taskOpDeps.savedRepos().includes(repo))return repo;let{tasks}=await ctx.api.rpc("task.list");if(!tasks.some((t)=>t.repo===repo))throw new BridgeError("UNKNOWN_REPO",`${repo} is not a known project`);return repo}var URL_SCHEME=/^(https?|ssh|git):\/\/[A-Za-z0-9[]\S*$/i,URL_SCP=/^[A-Za-z0-9._-]+@[A-Za-z0-9][A-Za-z0-9.-]*:\S+$/;function cloneUrl(args,name="url"){let v=args[name];if(typeof v!=="string")throw new BridgeError("BAD_ARGS",`${name} must be a git URL`);let url=v.trim(),lower=url.toLowerCase();if(url.length===0||url.length>2000||url.startsWith("-")||lower.startsWith("ext::")||lower.startsWith("fd::")||lower.startsWith("file:")||url.includes("@-")||/\p{Cc}/u.test(url)||!(URL_SCHEME.test(url)||URL_SCP.test(url)))throw new BridgeError("BAD_ARGS",`${name} must be an https, http, ssh or git URL (or user@host:path)`);return url}function cloneFolder(folder){if(!FOLDER.test(folder)||folder==="."||folder==="..")throw new BridgeError("BAD_ARGS","folder must be one plain directory name");return folder}var MODE_KEY="autoRouting.classifier",ENDPOINT_KEY="autoRouting.classifierEndpoint",CLASSIFIER_MODES=["off","jev","custom"],real={...realDeps4,secret:(name)=>secretStatus(name).source},str2=(v)=>typeof v==="string"?v.trim():"";async function pickable(deps,ids){return ids.map((id)=>{let entry=protocolEntry(id);return{id,name:deps.engineName(id),effortLevels:entry.effortLevels??[],takesModel:Boolean(entry.modelArgv)}})}function classifierView(deps,state){let config=readClassifierConfig((key)=>state[key]),mode=config.mode.kind==="url"?"custom":config.mode.kind==="jev"?"jev":"off",endpoint=displayEndpoint(config.mode.kind,str2(state[MODE_KEY]),str2(state[ENDPOINT_KEY])),host="";try{host=endpoint?new URL(endpoint).host:""}catch{host=""}return{mode,endpointHost:host,canCustom:str2(state[ENDPOINT_KEY]).length>0&&readClassifierConfig((k)=>k===MODE_KEY?state[ENDPOINT_KEY]:state[k]).mode.kind==="url",threshold:config.threshold,keyConfigured:config.keyEnv!==void 0,keySource:config.keyEnv?deps.secret(config.keyEnv):"none",...config.keyEnv?{keyEnv:config.keyEnv}:{}}}function createRoutingOps(deps){return{"autoRouting.get":{kind:"read",destructive:!1,wraps:"settings Auto routing section: readAutoRoutingTable + tierBlock over the engine statuses + readClassifierConfig",async run(){let state=deps.load(),ids=await engineIds(deps,state),statuses=await deps.statuses(ids).catch(()=>[]),table=readAutoRoutingTable((key)=>state[key]),engineSet=new Set(ids);return{configured:table!==null,tiers:table?AUTO_ROUTING_TIERS.map((tier)=>{let target=table[tier],block=tierBlock(target,{engineIds:engineSet,accountKind:(engine)=>statuses.find((s)=>s.vendor===engine)?.account?.kind??null});return{tier,engine:target.engine,engineName:deps.engineName(target.engine),model:target.model??null,effort:target.effort??null,block:block?describeTierBlock(block):null}}):[],engines:await pickable(deps,ids),classifier:classifierView(deps,state)}}},"autoRouting.setTier":{kind:"write",destructive:!0,wraps:"state.json autoRouting.<tier>.engine|model|effort, as the Auto routing row's engine picker",async run(args){let tier=oneOf(args,"tier",AUTO_ROUTING_TIERS),state=deps.load(),engine=(await pickable(deps,await engineIds(deps,state))).find((e)=>e.id===args.engine);if(!engine)throw new BridgeError("BAD_ARGS","engine is not a listed engine");let model2=optModel(args,"model")??"";if(model2&&!engine.takesModel)throw new BridgeError("BAD_ARGS",`${engine.id} takes no model`);let effort=typeof args.effort==="string"?args.effort:"";if(effort&&!engine.effortLevels.includes(effort))throw new BridgeError("BAD_ARGS",`effort must be one of ${engine.effortLevels.join("|")||"(none)"}`);return deps.patch({[autoRoutingKey(tier,"engine")]:engine.id,[autoRoutingKey(tier,"model")]:model2,[autoRoutingKey(tier,"effort")]:effort}),{tier,engine:engine.id,model:model2||null,effort:effort||null}}},"autoRouting.setClassifier":{kind:"write",destructive:!0,wraps:"state.json autoRouting.classifier: off | jev | the endpoint the TUI remembered (never a client-sent URL)",async run(args){let mode=oneOf(args,"mode",CLASSIFIER_MODES),state=deps.load(),view=classifierView(deps,state),live=str2(state[MODE_KEY]),remember=view.mode==="custom"&&live?{[ENDPOINT_KEY]:live}:{};if(mode==="custom"){if(!view.canCustom)throw new BridgeError("BAD_ARGS","no custom endpoint is remembered; set one in the TUI");deps.patch({[MODE_KEY]:str2(state[ENDPOINT_KEY])})}else deps.patch({...remember,[MODE_KEY]:mode});return{mode}}}}}var routingOps=createRoutingOps(real);class UsageStore{rows=null;sessions=null;set(snapshot){this.rows=snapshot===null?null:[...snapshot.entries()].map(([vendor,usage])=>({vendor,capturedAt:usage.capturedAt,windows:usage.windows.map(({kind,label,percent,resetsAt})=>({kind,label,percent,resetsAt}))})).sort((a,b)=>a.vendor.localeCompare(b.vendor))}get(){return this.rows}setContext(map){this.sessions=map}context(session){return this.sessions?.get(session)??null}}var usageStore=new UsageStore;var PLUGIN_ID2=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,CATEGORY=/^[a-z0-9][a-z0-9-]{0,39}$/,realDeps5={usage:usageStore,bridgeVersion:CURRENT_VERSION,engineName:engineDisplayName,listPlugins:()=>readPluginRows(),pluginIds:()=>loadPluginRegistry().plugins.map((p)=>p.id),setPluginEnabled:(id,enabled)=>setPluginEnabled(id,enabled)};function createSettingsOps(deps){return{"usage.get":{kind:"read",destructive:!1,wraps:"the orchestrator's usageSnapshotSignal (daemon usage.snapshot) and, given taskId+tabId, its contextUsageSignal for that session; both held by the bridge",async run(args){let rows=deps.usage.get(),usage=rows===null?null:rows.map((row)=>({...row,name:deps.engineName(row.vendor)}));if(args.taskId===void 0)return{usage};return{usage,context:deps.usage.context(`${taskId(args)}::${tabId(args)}`)}}},"daemon.info":{kind:"read",destructive:!1,wraps:"daemon RPC daemon.status, compared with the bridge's own Rove build (isDaemonVersionStale)",async run(_args,{api}){let status=await api.rpc("daemon.status",{});return{daemonVersion:status.roveVersion??null,bridgeVersion:deps.bridgeVersion,stale:isDaemonVersionStale(status.roveVersion,deps.bridgeVersion),...status.uptimeMs!==void 0?{uptimeMs:status.uptimeMs}:{},...status.startedAt!==void 0?{startedAt:status.startedAt}:{},...status.taskCount!==void 0?{taskCount:status.taskCount}:{},...status.attachedClients!==void 0?{attachedClients:status.attachedClients}:{},...status.automationHold!==void 0?{automationHold:status.automationHold}:{}}}},"plugins.list":{kind:"read",destructive:!1,wraps:"settings Plugins section's readPluginRows (registry + manifest + last run)",async run(){return{plugins:deps.listPlugins().map((p)=>({id:p.id,version:p.version,enabled:p.enabled,linked:p.linked,platformOk:p.platformOk,hooksDeclared:p.hooksDeclared,updateAvailable:p.updateAvailable,declares:p.declares,lastRun:p.lastRun?{at:p.lastRun.at,label:p.lastRun.label,ok:p.lastRun.ok,running:p.lastRun.running}:null}))}}},"plugin.setEnabled":{kind:"write",destructive:!0,wraps:"settings Plugins section's setPluginEnabled (plugins.json; the daemon file-watches it)",async run(args){let id=text(args,"id",64);if(!PLUGIN_ID2.test(id)||!deps.pluginIds().includes(id))throw new BridgeError("BAD_ARGS",`${id} is not an installed plugin`);let enabled=bool(args,"enabled");return deps.setPluginEnabled(id,enabled),{id,enabled}}},"feedback.send":{kind:"write",destructive:!0,wraps:"rove api feedback (GitHub Discussion in the Rove repo's Feedback category, via gh)",run(args,{api}){let argv=[flag("title",text(args,"title",200).trim()),flag("body",text(args,"body",1e4))],category=optText(args,"category",40);if(category!==void 0){if(!CATEGORY.test(category))throw new BridgeError("BAD_ARGS","category is not a category slug");argv.push(flag("category",category))}return api.verb("feedback",argv)}}}}var settingsOps=createSettingsOps(realDeps5);import{existsSync as existsSync2,realpathSync,statSync}from"fs";import{homedir}from"os";import{extname,join as join2,sep}from"path";var SUBDIR_CAP=200,PATH_MAX3=1000;function reorderPersistedTab(taskId2,tab,delta){let moved=!1;return updateStateFile((store)=>{let state=store[terminalTabsKey(taskId2)];if(!state||!Array.isArray(state.tabs))return!1;let next=moveTab(state,tab,delta);if(next===state)return!1;store[terminalTabsKey(taskId2)]=next,moved=!0;return}),moved}function canonical(path){try{return realpathSync(path)}catch{return null}}function runnable(path){let info=statSync(path);return!info.isFile()||(info.mode&73)!==0}var OPENABLE=new Set("pdf png jpg jpeg gif webp bmp tif tiff heic svg ico mp3 wav m4a aac flac ogg mp4 m4v mov webm mkv avi ttf otf".split(" ")),realDeps6={openExternal:openExternally,detectOpener:detectWorktreeOpener,openWorktree,exists:existsSync2,canonical,runnable,homeDir:homedir,buildCIPrompt:buildCIPromptForWorktree,reorderTab:reorderPersistedTab};function typedPath(args,name){let v=args[name];if(typeof v!=="string"||v.length>PATH_MAX3||v.includes("\x00"))throw new BridgeError("BAD_ARGS",`${name} must be a path`);let trimmed2=v.trim();if(!(trimmed2.startsWith("/")||trimmed2.startsWith("~")))throw new BridgeError("BAD_ARGS",`${name} must be absolute or start with ~`);return trimmed2}function clearable(args,name,check){let v=args[name];if(v===void 0||v===null)return;return v===""?"":check(args,name)}async function worktreeAndBranch(ctx,id){let res=await ctx.api.verb("get-task",[flag("task-id",id)]),{worktreePath,branch,prStatus}=res.task;if(!worktreePath)throw new BridgeError("NO_WORKTREE",`task ${id} has no worktree yet`);return{worktree:worktreePath,branch:branch??"",prNumber:prStatus?.number}}function taskOps(deps=realDeps6){return{"task.landPreflight":{kind:"read",destructive:!1,wraps:"rpc task.landPreflight",async run(a,{api}){return(await api.rpc("task.landPreflight",{taskId:taskId(a)})).result}},"task.syncBase":{kind:"write",destructive:!1,wraps:"rpc task.syncBase (merge base into the worktree)",async run(a,{api}){let res=await api.rpc("task.syncBase",{taskId:taskId(a)});return{baseRef:res.result.baseRef,alreadyCurrent:res.result.alreadyCurrent===!0}}},"task.fixChecks":{kind:"write",destructive:!1,wraps:"rpc pr.failingChecks + buildCIPromptForWorktree + rove api send --plain",async run(a,ctx){let id=taskId(a),{worktree,branch,prNumber}=await worktreeAndBranch(ctx,id),read=await ctx.api.rpc("pr.failingChecks",{taskId:id}),checks=read.checks??[];if(read.unavailable)return{outcome:"unavailable",detail:read.unavailable.detail};if(checks.length===0)return{outcome:"none"};let state={checks,totalFailing:read.totalFailing??checks.length},prompt=await deps.buildCIPrompt(worktree,{branch:branch||"HEAD",...prNumber===void 0?{}:{prNumber},...state}),argv=[flag("task-id",id),"--plain",flag("prompt",prompt)];if(a.tabId!==void 0&&a.tabId!==null)argv.push(flag("tab",tabId(a)));return await ctx.api.verb("send",argv),{outcome:"sent"}}},"task.openEditor":{kind:"write",destructive:!1,wraps:"helpers detectWorktreeOpener + openWorktree (the TUI's `o`) on the task's worktree, via ensure-worktree",async run(a,{api}){let id=taskId(a),path=(await api.verb("get-task",[flag("task-id",id)])).task.worktreePath??"";if(!path||!deps.exists(path))path=(await api.verb("ensure-worktree",[flag("task-id",id)])).worktreePath??"";if(!path||!deps.exists(path))throw new BridgeError("NO_WORKTREE","this task has no worktree on disk");let opener=deps.detectOpener();if(!opener)return{outcome:"noEditor"};if(!deps.openWorktree(path,opener))return{outcome:"failed",label:opener.label};return{outcome:"opened",label:opener.label}}},"task.openScratch":{kind:"write",destructive:!1,wraps:"rpc task.openDir {dir: $HOME, scratch: true}",async run(a,ctx){let vendor=optStr(a,"engine")===void 0?void 0:await engineId(a,"engine",ctx);return{taskId:(await ctx.api.rpc("task.openDir",{dir:deps.homeDir(),scratch:!0,...vendor?{vendor}:{}})).taskId}}},"task.setEngine":{kind:"write",destructive:!1,wraps:"rpc task.setVendor (engine + reasoning level + model; '' clears)",async run(a,ctx){let id=taskId(a),vendor=await engineId(a,"engine",ctx),effort=clearable(a,"effort",(args,n)=>effortLevel(args,n)),mdl=clearable(a,"model",(args,n)=>model(args,n));return await ctx.api.rpc("task.setVendor",{taskId:id,vendor,...effort===void 0?{}:{effort},...mdl===void 0?{}:{model:mdl}}),{}}},"tab.move":{kind:"write",destructive:!1,wraps:"state.json terminalTabs.<task> order (moveTab)",async run(a){let direction=oneOf(a,"direction",["up","down"]);return{moved:deps.reorderTab(taskId(a),tabId(a),direction==="up"?-1:1)}}},"file.openExternal":{kind:"write",destructive:!1,wraps:"helper openExternally (the Mac's `open`) on a media/document file inside the task's worktree",async run(a,{api}){let rel=optStr(a,"path")??"";if(!rel||rel.length>PATH_MAX3||rel.startsWith("/")||rel.includes("\x00")||rel.split(/[\\/]/).includes(".."))throw new BridgeError("BAD_ARGS","path must be relative to the worktree");let worktree=(await api.verb("get-task",[flag("task-id",taskId(a))])).task.worktreePath;if(!worktree)throw new BridgeError("NO_WORKTREE","this task has no worktree yet");let root=deps.canonical(worktree),abs=deps.canonical(join2(worktree,rel));if(!root||!abs)throw new BridgeError("NOT_FOUND",`${rel} does not exist`);if(abs!==root&&!abs.startsWith(root.endsWith(sep)?root:root+sep))throw new BridgeError("BAD_ARGS","path is outside the worktree");if(!OPENABLE.has(extname(abs).slice(1).toLowerCase())||deps.runnable(abs))throw new BridgeError("NOT_OPENABLE","only images, audio, video, PDFs and fonts open in the system app");return deps.openExternal(abs),{}}},"fs.subdirs":{kind:"read",destructive:!1,wraps:"helpers splitPathForDirSuggest + listSubdirs + filterSubdirs",async run(a){let split=splitPathForDirSuggest(typedPath(a,"path")),names=filterSubdirs(listSubdirs(split.base),split.filter);return{base:split.base,home:deps.homeDir(),names:names.slice(0,SUBDIR_CAP)}}},"repo.probe":{kind:"read",destructive:!1,wraps:"helpers validateRepoPath + listLocalBranches + getCurrentBranch (+ rpc worktree.discoverAdoptable)",async run(a,{api}){let repo=stripTrailingSlash(expandHome(typedPath(a,"path"))),reason=taskOpDeps.validateRepoPath(repo);if(reason)return{ok:!1,repo,reason};let out={ok:!0,repo,branches:taskOpDeps.listLocalBranches(repo),current:taskOpDeps.getCurrentBranch(repo)};if(a.adoptable===!0){let found=await api.rpc("worktree.discoverAdoptable",{repo});out.worktrees=found.worktrees??[]}return out}}}}var TASKOPS_OPS=taskOps();var STATUSES=["backlog","in_progress","in_review","done","canceled","error"],DIRECTIONS=["up","down","top"],PROMPT_MAX2=1e5;function write(wraps,run,destructive=!1){return{kind:"write",destructive,wraps,run:async(args,ctx)=>run(args,ctx)}}async function done(call){return await call,{}}async function spawn(args,ctx){let repo=absPath(args,"repo"),title=optText(args,"title",200),prompt=optText(args,"prompt",PROMPT_MAX2),branch=optGitRef(args,"branch"),baseBranch=optGitRef(args,"baseBranch"),mdl=optModel(args),effort=args.effort===void 0||args.effort===null||args.effort===""?void 0:effortLevel(args,"effort"),count=optInt(args,"count",1,10),agentsGiven=args.agents!==void 0&&args.agents!==null&&args.agents!=="",status=optOneOf(args,"status",STATUSES),pin=optBool(args,"pin"),engineGiven=args.engine!==void 0&&args.engine!==null&&args.engine!=="",parallel=count!==void 0||agentsGiven;if(count!==void 0&&agentsGiven)throw new BridgeError("BAD_ARGS","count and agents are exclusive");if(parallel&&!prompt)throw new BridgeError("BAD_ARGS","count/agents need a prompt");if(parallel&&branch)throw new BridgeError("BAD_ARGS","branch cannot be shared by parallel tasks");if(agentsGiven&&engineGiven)throw new BridgeError("BAD_ARGS","engine conflicts with agents");let plan=agentsGiven?parseAgents(args):void 0;if(plan)await checkAgentEngines(plan,ctx);let engine=engineGiven?await engineId(args,"engine",ctx):void 0,argv=[flag("repo",repo)];if(title)argv.push(flag("title",title));if(branch)argv.push(flag("branch",branch));if(baseBranch)argv.push(flag("base-branch",baseBranch));if(engine)argv.push(flag("command",engine));if(effort)argv.push(flag("effort",effort));if(mdl)argv.push(flag("model",mdl));if(count!==void 0)argv.push(flag("count",count));if(plan)argv.push(flag("agents",plan.map((p)=>`${p.id}:${p.n}`).join(",")));if(status)argv.push(flag("status",status));if(pin)argv.push(flag("pin","true"));if(prompt)argv.push(flag("prompt",prompt));let res=await ctx.api.verb("add",argv);if(Array.isArray(res.tasks))return{taskIds:res.tasks.flatMap((t)=>typeof t.taskId==="string"?[t.taskId]:[]),...res.groupId?{groupId:res.groupId}:{}};if(typeof res.taskId!=="string")throw new BridgeError("BAD_RESULT","add returned no task id");return{taskIds:[res.taskId]}}var PROGRESS_GAP_MS=150;async function clone(args,ctx){let url=cloneUrl(args),parentDir=absPath(args,"parentDir"),urlProblem=taskOpDeps.validateGitUrl(url);if(urlProblem)throw new BridgeError("BAD_ARGS",urlProblem);let given2=optStr(args,"folder"),folder=cloneFolder(given2??taskOpDeps.findAvailableFolderName(parentDir,taskOpDeps.deriveFolderName(url))),targetProblem=taskOpDeps.validateCloneTarget(parentDir,folder);if(targetProblem)throw new BridgeError("BAD_ARGS",targetProblem);let lastSent=0,result=await taskOpDeps.cloneRepo(url,taskOpDeps.resolveCloneTarget(parentDir,folder),(line)=>{let now=Date.now();if(now-lastSent<PROGRESS_GAP_MS)return;lastSent=now,ctx.progress?.(line)});if(!result.ok)throw new BridgeError("CLONE_FAILED",result.error);return{path:result.path}}async function adopt(args,ctx){let repo=await knownRepo(args,ctx),worktreePath=absPath(args,"worktreePath"),branch=optGitRef(args,"branch"),title=optText(args,"title",200),engine=args.engine===void 0||args.engine===null||args.engine===""?void 0:await engineId(args,"engine",ctx);if(!((await ctx.api.rpc("worktree.discoverAdoptable",{repo})).worktrees??[]).some((w)=>w.path===worktreePath))throw new BridgeError("NOT_ADOPTABLE",`${worktreePath} is not an adoptable worktree of ${repo}`);return{taskId:(await ctx.api.rpc("worktree.adopt",{repo,worktreePath,...branch?{branch}:{},...title?{title}:{},...engine?{vendor:engine}:{}})).task.id}}var TASK_WRITE_OPS={"task.spawn":write("verb add",spawn),"task.rename":write("verb update --task-id --title",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("title",text(a,"title",200))]))),"task.setBranch":write("verb update --task-id --branch",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("branch",gitRef(a,"branch"))]))),"task.setCommand":write("verb update --task-id --command=<engine id>",async(a,c)=>{let id=taskId(a),engine=await engineId(a,"engine",c),res=await c.api.verb("update",[flag("task-id",id),flag("command",engine)]);return res.protocol?{protocol:res.protocol}:{}}),"task.setModel":write("verb update --task-id --model",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("model",model(a))]))),"task.setEffort":write("verb update --task-id --effort",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("effort",effortLevel(a))]))),"task.setStatus":write("verb update --task-id --status",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("status",oneOf(a,"status",STATUSES))]))),"task.pin":write("verb update --task-id --pinned",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("pinned",String(bool(a,"pinned")))]))),"task.move":write("rpc task.move",(a,c)=>done(c.api.rpc("task.move",{taskId:taskId(a),direction:oneOf(a,"direction",DIRECTIONS)}))),"project.forget":write("rpc project.forget",async(a,c)=>done(c.api.rpc("project.forget",{repo:await knownRepo(a,c)})),!0),"notes.delete":write("verb note-delete --repo --id",async(a,c)=>{let repo=await knownRepo(a,c),id=optInt(a,"id",1,Number.MAX_SAFE_INTEGER);if(id===void 0)throw new BridgeError("BAD_ARGS","id must be an integer in 1..");return{deleted:(await c.api.verb("note-delete",[flag("repo",repo),flag("id",id)])).deleted===!0}},!0),"task.openMain":write("rpc task.ensureMain",async(a,c)=>{let repo=absPath(a,"repo"),problem=taskOpDeps.validateRepoPath(repo);if(problem)throw new BridgeError("BAD_ARGS",problem);return{taskId:(await c.api.rpc("task.ensureMain",{repo})).task.id}}),"worktree.adopt":write("rpc worktree.adopt",adopt),"repo.clone":write("helper cloneRepo (git clone, fixed argv)",clone),"task.ensureWorktree":write("verb ensure-worktree --task-id",async(a,c)=>{let res=await c.api.verb("ensure-worktree",[flag("task-id",taskId(a))]);if(typeof res.worktreePath!=="string")throw new BridgeError("BAD_RESULT","ensure-worktree returned no path");return{worktreePath:res.worktreePath}}),"task.removeWorktree":write("verb remove-worktree --task-id --force",async(a,c)=>{let argv=[flag("task-id",taskId(a))];if(optBool(a,"force"))argv.push(flag("force","true"));let res=await c.api.verb("remove-worktree",argv);return{removed:res.removed===!0,...res.worktreePath?{worktreePath:res.worktreePath}:{},...res.branch?{branch:res.branch}:{}}},!0)};var TAIL_MAX=2000;function read(wraps,run){return{kind:"read",destructive:!1,wraps,run}}async function taskGet(args,ctx){let t=(await ctx.api.verb("get-task",[flag("task-id",taskId(args))])).task,pr=t.prStatus;return{task:{id:t.id,title:t.title,repo:t.repo,branch:t.branch,worktreePath:t.worktreePath,kind:t.kind??"task",status:t.status,pinned:t.pinned===!0,...t.vendor?{engine:t.vendor}:{},...t.command?{command:t.command}:{},...t.model?{model:t.model}:{},...t.modelEffort?{effort:t.modelEffort}:{},...t.prompt?{prompt:t.prompt}:{},...t.baseRef?{baseRef:t.baseRef}:{},...t.groupId?{groupId:t.groupId}:{},createdAt:t.createdAt,updatedAt:t.updatedAt,...pr?{pr:{...pr.number!==void 0?{number:pr.number}:{},...pr.url?{url:pr.url}:{},lifecycle:pr.lifecycle,checkState:pr.checkState,...pr.reviewDecision?{reviewDecision:pr.reviewDecision}:{},...pr.mergeable?{mergeable:pr.mergeable}:{},...pr.baseRef?{baseRef:pr.baseRef}:{}}}:{},...t.report?{report:{summary:t.report.summary??"",at:t.report.at}}:{}}}}async function taskInfo(args,ctx){let id=taskId(args),row=(await ctx.api.verb("collect",[flag("task-ids",id)])).tasks?.[0];if(!row)throw new BridgeError("NOT_FOUND",`no task ${id}`);return{taskId:row.taskId,running:row.running??null,activity:row.activity?{state:row.activity.state,forMs:row.activity.forMs}:null,changes:row.changes?{added:row.changes.added,deleted:row.changes.deleted}:null,base:row.base?{baseRef:row.base.baseRef,ahead:row.base.ahead,behind:row.base.behind}:null,tabs:(row.tabs??[]).map((tab)=>{let exit=tab.exit,tail=exit?.tail?.join(`
|
|
39
|
-
`).slice(-TAIL_MAX);return{id:tab.id,kind:tab.kind,alive:tab.alive??null,...exit?{exit:{code:exit.code,signal:exit.signal,...exit.layer?{cause:exit.layer}:{}}}:{},...tail?{tail}:{}}})}}async function repoBranches(args,ctx){let repo=await knownRepo(args,ctx);return{branches:taskOpDeps.listLocalBranches(repo),current:taskOpDeps.getCurrentBranch(repo)}}async function notesList(args,ctx){let repo=await knownRepo(args,ctx);return{notes:(await ctx.api.verb("note-list",[flag("repo",repo)])).notes??[]}}async function worktreeAdoptable(args,ctx){let repo=await knownRepo(args,ctx),res=await ctx.api.rpc("worktree.discoverAdoptable",{repo});return{worktrees:res.worktrees??[],unreadable:res.unreadable??[]}}var TASK_OPS={"task.get":read("verb get-task --task-id",taskGet),"task.info":read("verb collect --task-ids (first row, trimmed)",taskInfo),"repo.branches":read("helpers listLocalBranches + getCurrentBranch",repoBranches),"notes.list":read("verb note-list --repo",notesList),"worktree.adoptable":read("rpc worktree.discoverAdoptable",worktreeAdoptable),...TASK_WRITE_OPS};import{randomBytes as randomBytes2}from"crypto";import{mkdirSync as mkdirSync2,writeFileSync as writeFileSync2}from"fs";import{join as join3}from"path";var ATTACHMENT_TYPES={"image/png":{ext:"png",kind:"image",magic:[137,80,78,71,13,10,26,10]},"image/jpeg":{ext:"jpg",kind:"image",magic:[255,216,255]},"image/gif":{ext:"gif",kind:"image",magic:[71,73,70,56]},"image/webp":{ext:"webp",kind:"image",magic:[82,73,70,70]},"application/pdf":{ext:"pdf",kind:"pdf",magic:[37,80,68,70]}},MAX_ATTACHMENT_BYTES=5242880,MAX_ATTEMPTS=5,PROMPT_MAX3=1e5,realDeps7={attachmentsDir:promptAttachmentsDir,now:()=>new Date,nonce:()=>randomBytes2(4).toString("hex"),writeFile(path,bytes){mkdirSync2(join3(path,".."),{recursive:!0,mode:448}),writeFileSync2(path,bytes,{mode:384})},readTab(task,tab){return loadStateFile()[terminalTabsKey(task)]?.tabs?.find((t)=>t.id===tab)},planHandoff:planWorktreeHandoff,prPrompt:buildPRPrompt};function gitRef2(args,name){let v=args[name];if(!(typeof v==="string"&&v.length<=200&&/^[A-Za-z0-9][A-Za-z0-9._/@+-]*$/.test(v)&&!v.includes("..")&&!v.includes("//")&&!v.endsWith("/")&&!v.endsWith(".")&&!v.endsWith(".lock")&&!v.includes("@{")))throw new BridgeError("BAD_ARGS",`${name} is not a branch name`);return v}function engineId2(args,name="engine"){let v=optStr(args,name);if(v===void 0)return;if(!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(v))throw new BridgeError("BAD_ARGS",`${name} is not an engine id`);return v}function tabTitle(args){let title=text(args,"title",80).trim();if(/[\u0000-\u001f\u007f]/.test(title))throw new BridgeError("BAD_ARGS","title must be one line");return title}async function worktreeOf2(api,id){let res=await api.verb("get-task",[flag("task-id",id)]);if(!res.task.worktreePath)throw new BridgeError("NO_WORKTREE",`task ${id} has no worktree yet`);return{task:res.task,worktree:res.task.worktreePath}}function matchesMagic(mime,bytes){let{magic}=ATTACHMENT_TYPES[mime];if(bytes.length<magic.length||!magic.every((b,i)=>bytes[i]===b))return!1;return mime!=="image/webp"||Buffer.from(bytes.subarray(8,12)).toString("ascii")==="WEBP"}function terminalOps(deps=realDeps7){return{"tab.states":{kind:"read",destructive:!1,wraps:"daemon RPC debug.inspect (activity.tabs of one task)",async run(a,{api}){let id=taskId(a),res=await api.rpc("debug.inspect"),tabs={};for(let[tab,entry]of Object.entries(res?.activity?.tabs?.[id]??{}))if(typeof entry?.state==="string"&&typeof entry.at==="number")tabs[tab]={state:entry.state,at:entry.at};return{tabs}}},"tab.rename":{kind:"write",destructive:!1,wraps:"rove api update --tab",async run(a,{api}){return await api.verb("update",[flag("task-id",taskId(a)),flag("tab",tabId(a)),flag("title",tabTitle(a))]),{}}},"tab.interrupt":{kind:"write",destructive:!1,wraps:"rove api interrupt",async run(a,{api}){let argv=[flag("task-id",taskId(a))];if(a.tabId!==void 0&&a.tabId!==null)argv.push(flag("tab",tabId(a)));return await api.verb("interrupt",argv),{}}},"tab.forkTask":{kind:"write",destructive:!1,wraps:"rove api add --base-branch (--count for attempts)",async run(a,{api}){let count=optInt(a,"count",1,MAX_ATTEMPTS)??1,argv=[flag("repo",absPath(a,"repo")),flag("base-branch",gitRef2(a,"baseBranch")),flag("prompt",text(a,"prompt",PROMPT_MAX3))],engine=engineId2(a);if(engine)argv.push(flag("command",engine));let title=optText(a,"title",200);if(title)argv.push(flag("title",title));if(count>1)argv.push(flag("count",count));let res=await api.verb("add",argv),taskIds=res.tasks?res.tasks.map((t)=>t.taskId):res.taskId?[res.taskId]:[];if(taskIds.length===0)throw new BridgeError("ADD_FAILED","no task was created");return{taskIds}}},"tab.handoff":{kind:"read",destructive:!1,wraps:"planWorktreeHandoff (transcript handoff prompt)",async run(a,{api}){let id=taskId(a),tab=tabId(a),{task,worktree}=await worktreeOf2(api,id),active=deps.readTab(id,tab)??initialTabs().tabs[0],tabVendor=(active.kind==="engine"?active.vendor:void 0)??task.vendor,plan=await deps.planHandoff(active,liveSourceProtocol(active,tabVendor),worktree);return plan.kind==="handoff"?{kind:"handoff",prompt:plan.prompt}:plan.kind==="no-transcript"?{kind:plan.kind,engine:plan.engine}:{kind:plan.kind}}},"tab.requestPR":{kind:"write",destructive:!1,wraps:"buildPRPrompt + rove api send --plain",async run(a,{api}){let id=taskId(a),{worktree}=await worktreeOf2(api,id),argv=[flag("task-id",id),"--plain",flag("prompt",await deps.prPrompt(worktree))];if(a.tabId!==void 0&&a.tabId!==null)argv.push(flag("tab",tabId(a)));return await api.verb("send",argv),{}}},"attachment.put":{kind:"write",destructive:!1,wraps:"writes ~/.rove/attachments/<generated name> (tui/lib/attachments.ts layout)",async run(a){let mime=str(a,"mime");if(!Object.hasOwn(ATTACHMENT_TYPES,mime))throw new BridgeError("BAD_ARGS",`mime must be one of ${Object.keys(ATTACHMENT_TYPES).join("|")}`);let type=ATTACHMENT_TYPES[mime],encoded=str(a,"data");if(encoded.length>Math.ceil(MAX_ATTACHMENT_BYTES*4/3)+4)throw new BridgeError("TOO_LARGE",`attachment is larger than ${MAX_ATTACHMENT_BYTES} bytes`);let bytes=Buffer.from(encoded,"base64");if(bytes.length===0)throw new BridgeError("BAD_ARGS","data is empty");if(bytes.length>MAX_ATTACHMENT_BYTES)throw new BridgeError("TOO_LARGE",`attachment is larger than ${MAX_ATTACHMENT_BYTES} bytes`);if(!matchesMagic(mime,bytes))throw new BridgeError("BAD_ARGS",`data is not a ${type.ext} file`);let stamp=deps.now().toISOString().slice(0,10).replaceAll("-",""),path=join3(deps.attachmentsDir(),`attach-${stamp}-${deps.nonce()}.${type.ext}`);return deps.writeFile(path,bytes),{path,kind:type.kind,bytes:bytes.length}}}}}var TERMINAL_OPS=terminalOps();var VERSION=/^\d+\.\d+\.\d+$/,realDeps8={current:CURRENT_VERSION,check:(force)=>checkLatestVersion({force}),notesRange:(current,latest)=>fetchReleaseNotesRange({current,latest}),notes:fetchReleaseNotes};function createUpdateOps(deps=realDeps8){return{"update.check":{kind:"read",destructive:!1,wraps:"checkLatestVersion + fetchReleaseNotesRange (npm registry, GitHub releases)",async run(args){let info=await deps.check(optBool(args,"force")===!0),notes=info?.hasUpdate?await deps.notesRange(info.current,info.latest):[];return{current:deps.current,info,notes}}},"release.notes":{kind:"read",destructive:!1,wraps:"fetchReleaseNotes (GitHub release body for vX.Y.Z)",async run(args){let version=text(args,"version",32);if(!VERSION.test(version))throw new BridgeError("BAD_ARGS","version must be x.y.z");return{notes:await deps.notes(version)}}}}}var updateOps=createUpdateOps();import{basename}from"path";var chip=(id)=>({id,name:engineDisplayName(id)}),welcomeDeps={cwd:()=>process.cwd(),gitOnPath:()=>Bun.which("git")!==null,async engines(){return probeableEngineIds().then(detectEngineStatuses).then(summarizeEngines).catch(()=>({usable:[],signedOut:[]}))},repoOf(dir){try{return validateRepoPath(dir)===null?resolveMainRepoRoot(dir):null}catch{return null}},branchOf:(dir)=>getCurrentBranch(dir),preferredEngine:(repo)=>resolvePreferredVendor(repo)},welcomeOps={"welcome.env":{kind:"read",destructive:!1,wraps:"helpers probeableEngineIds + detectEngineStatuses, firstTaskRepo",async run(){let[{usable,signedOut},git]=await Promise.all([welcomeDeps.engines(),welcomeDeps.gitOnPath()]),dir=welcomeDeps.cwd(),repo=welcomeDeps.repoOf(dir),start=null;if(repo!==null&&git&&usable.length>0){let pref=welcomeDeps.preferredEngine(repo);start={repo,label:basename(repo),baseRef:welcomeDeps.branchOf(dir)??welcomeDeps.branchOf(repo)??DEFAULT_BASE_REF,engine:usable.includes(pref)?pref:usable[0]??pref}}return{engines:usable.map(chip),signedOut:signedOut.map(chip),git,start}}}};var LEAF=/^leaf-\d{1,4}$/,TITLE_MAX2=80;function leafId(a){let v=a.leafId;if(v===void 0||v===null||v==="")return;if(typeof v!=="string"||!LEAF.test(v))throw new BridgeError("BAD_ARGS","leafId is not a pane id");return v}function paneTitle(a){let v=a.title;if(v===void 0||v===null)return"";if(typeof v!=="string"||v.length>TITLE_MAX2||/[\u0000-\u001f\u007f]/.test(v))throw new BridgeError("BAD_ARGS",`title must be one line of at most ${TITLE_MAX2} characters`);return v.trim()}var WORKSPACE_OPS={"tab.split":{kind:"write",destructive:!0,wraps:"rove api tab-split",async run(a,{api}){let action=oneOf(a,"action",["open","close","rename","reset"]),leaf=leafId(a);if(action!=="open"&&!leaf)throw new BridgeError("BAD_ARGS",`leafId is required to ${action}`);let cols=optInt(a,"cols",1,1000),rows=optInt(a,"rows",1,500);if(cols===void 0!==(rows===void 0))throw new BridgeError("BAD_ARGS","cols and rows go together");let argv=[flag("task-id",taskId(a)),flag("tab",tabId(a)),flag("action",action)];if(leaf)argv.push(flag("leaf",leaf));if(action==="open")argv.push(flag("direction",optOneOf(a,"direction",["right","down"])??"right"));if(action==="rename")argv.push(flag("title",paneTitle(a)));if(cols!==void 0&&rows!==void 0)argv.push(flag("cols",cols),flag("rows",rows));let res=await api.verb("tab-split",argv);return{leaf:res.leaf,changed:res.changed,split:res.split}}}};function mergeOpTables(...tables){let merged={};for(let table of tables)for(let[name,spec]of Object.entries(table)){if(name in merged)throw new BridgeError("DUPLICATE_OP",`op ${name} is registered twice`);merged[name]=spec}return merged}var AREA_OPS=mergeOpTables(TASK_OPS,TERMINAL_OPS,filesOps,pagesOps,settingsOps,engineOps,insightOps,updateOps,machineOps,devOps,prefsOps,routingOps,TASKOPS_OPS,WORKSPACE_OPS,welcomeOps,keybindingsOps,launchOps,modsOps,promptOps);class TerminalForwarder{pty;send;attached=new Set;offs;constructor(pty,send){this.pty=pty;this.send=send;this.offs=[pty.on("pty.data",(frame)=>{let{key,data}=frame.payload;if(this.attached.has(key))this.send(pushEvent("term.data",{stream:key,data}))}),pty.on("pty.exit",(frame)=>{let{key,code}=frame.payload;if(this.attached.has(key))this.send(pushEvent("term.exit",{stream:key,code:code??null}))})]}async attach(taskId2,tabId2,cwd,size,leafId2){let stream=leafId2?`${taskId2}::${tabId2}::${leafId2}`:`${taskId2}::${tabId2}`,{sessions}=await this.pty.request("pty.list"),session=sessions.find((s)=>s.key===stream);if(!session)throw new BridgeError("TAB_NOT_LIVE",`tab ${tabId2} has no hosted session`);if(!session.alive&&session.restored){let peek=await this.pty.request("pty.peek",{key:stream});return{stream,alive:!1,replay:peek.data}}this.attached.add(stream);try{let open=await this.pty.request("pty.open",{key:stream,cwd,...size?{cols:size.cols,rows:size.rows}:{}});return{stream,alive:open.alive,replay:open.replay}}catch(err){throw this.attached.delete(stream),err}}async input(stream,data){this.requireAttached(stream),await this.pty.request("pty.write",{key:stream,data})}async resize(stream,cols,rows){this.requireAttached(stream),await this.pty.request("pty.resize",{key:stream,cols,rows})}async detach(stream){if(!this.attached.delete(stream))return;await this.pty.request("pty.detach",{key:stream})}dispose(){for(let off of this.offs)off();this.attached.clear(),this.pty.close()}requireAttached(stream){if(!this.attached.has(stream))throw new BridgeError("NOT_ATTACHED",`not attached to ${stream}`)}}import{stat}from"fs/promises";import{resolve,sep as sep2}from"path";var SECURITY_HEADERS={"Content-Security-Policy":"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'","X-Content-Type-Options":"nosniff","Referrer-Policy":"no-referrer"};async function serveWebFile(web,req){if(req.method!=="GET"&&req.method!=="HEAD")return null;let root=resolve(web.root),pathname;try{pathname=decodeURIComponent(new URL(req.url).pathname)}catch{return new Response(`bad path
|
|
40
|
-
`,{status:400})}let target=resolve(root,`.${pathname}`);if(target!==root&&!target.startsWith(root+sep2))return new Response(`not found
|
|
41
|
-
`,{status:404});let isFile=await stat(target).then((s)=>s.isFile(),()=>!1),file=Bun.file(target);if(!isFile){if(pathname.startsWith("/assets/"))return new Response(`not found
|
|
42
|
-
`,{status:404});if(file=Bun.file(resolve(root,"index.html")),!await file.exists())return new Response(`web client not built
|
|
43
|
-
`,{status:503})}let cache=target.startsWith(resolve(root,"assets")+sep2)?"public, max-age=31536000, immutable":"no-cache";return new Response(req.method==="HEAD"?null:file,{headers:{...SECURITY_HEADERS,"Content-Type":file.type,"Cache-Control":cache}})}async function handle(deps,ws,req){let{ops}=deps,a=req.args,conn=ws.data,terminal=()=>{return conn.terminal??=new TerminalForwarder(deps.openPty(),(frame)=>ws.send(frame)),conn.terminal};if(DESTRUCTIVE_CORE[req.op])logDestructive(deps,req);switch(req.op){case"hello":return{protocol:BRIDGE_PROTOCOL_VERSION,apiVersion:ROVE_API_VERSION,roveVersion:deps.roveVersion,host:osHostname()};case"api.invoke":{if(!deps.invoke)throw new BridgeError("UNKNOWN_OP","this bridge does not serve verbs");let verb2=str(a,"verb"),params=a.params??{};if(typeof params!=="object"||params===null||Array.isArray(params))throw new BridgeError("BAD_ARGS","params must be an object keyed by flag name");if(DESTRUCTIVE_VERBS.has(verb2))logDestructiveVerb(deps,verb2,params);let envelope=await deps.invoke(verb2,params,optStr(a,"machine"));if(envelope.ok)return envelope.result;throw new BridgeError(envelope.error.code,envelope.error.message,envelope.error)}case"tasks.subscribe":{let snapshot=await deps.feed.current();return conn.unsubscribeTasks??=deps.feed.subscribe((payload)=>ws.send(pushEvent("tasks",payload))),conn.unsubscribeTabs??=deps.tabs?.subscribe((taskIds)=>ws.send(pushEvent("tabs",{taskIds})))??null,snapshot}case"tasks.list":return deps.feed.refresh();case"engines.list":return{engines:await ops.engines()};case"repos.list":return{repos:await ops.repos()};case"task.create":return ops.createTask({repo:str(a,"repo"),engine:optStr(a,"engine"),prompt:optStr(a,"prompt"),title:optStr(a,"title")});case"task.delete":return ops.deleteTask(str(a,"taskId"),optBool(a,"force"));case"task.land":{let strategy=optStr(a,"strategy")??"merge";if(strategy!=="merge"&&strategy!=="squash")throw new BridgeError("BAD_ARGS","strategy is merge|squash");return ops.landTask(str(a,"taskId"),strategy)}case"task.tabs":return{tabs:await ops.tabs(str(a,"taskId"))};case"tab.new":{let prompt=optStr(a,"prompt"),kind=optStr(a,"kind")??"engine";if(kind!=="shell"&&kind!=="engine")throw new BridgeError("BAD_ARGS","kind is shell|engine");let engine=optStr(a,"engine");if(kind==="shell"&&(prompt!==void 0||engine!==void 0))throw new BridgeError("BAD_ARGS","a shell tab takes no prompt or engine");return ops.newTab(str(a,"taskId"),{kind,prompt,engine})}case"tab.close":return await ops.closeTab(str(a,"taskId"),str(a,"tabId")),{};case"term.attach":{let taskId2=str(a,"taskId"),tabId2=str(a,"tabId"),leafId2=optStr(a,"leafId");if(leafId2!==void 0&&!/^leaf-\d{1,4}$/.test(leafId2))throw new BridgeError("BAD_ARGS","leafId is not a pane id");let cols=optInt(a,"cols",10,1000),rows=optInt(a,"rows",4,500);if(cols===void 0!==(rows===void 0))throw new BridgeError("BAD_ARGS","cols and rows go together");let shown=ops.viewedSession(taskId2,tabId2),cwd=shown?.cwd??await ops.worktreeOf(taskId2);return terminal().attach(shown?.taskId??taskId2,shown?.tabId??tabId2,cwd,cols!==void 0&&rows!==void 0?{cols,rows}:void 0,leafId2)}case"term.input":{let data=a.data;if(typeof data!=="string")throw new BridgeError("BAD_ARGS","data must be a string");return await terminal().input(str(a,"stream"),data),{}}case"term.resize":return await terminal().resize(str(a,"stream"),optInt(a,"cols",10,1000)??80,optInt(a,"rows",4,500)??24),{};case"term.detach":return await conn.terminal?.detach(str(a,"stream")),{};case"diff.files":return ops.diffFiles(str(a,"taskId"));case"diff.file":{let scope=str(a,"scope");if(scope!=="branch"&&scope!=="working")throw new BridgeError("BAD_ARGS","scope is branch|working");return ops.diffFile(str(a,"taskId"),str(a,"path"),scope)}case"attention.dismiss":return await ops.dismissAttention(str(a,"taskId"),optStr(a,"tabId")),{};default:{let spec=(deps.areaOps??AREA_OPS)[req.op];if(!spec)throw new BridgeError("UNKNOWN_OP",`unknown op: ${req.op}`);if(spec.destructive)logDestructive(deps,req);return spec.run(a,{api:deps.api,progress:(line)=>ws.send(pushEvent("op.progress",{id:req.id,line}))})}}}var DESTRUCTIVE_CORE={"task.delete":!0,"task.land":!0,"tab.close":!0},DESTRUCTIVE_VERBS=new Set(["delete","land","remove-worktree","tab-close","issue-delete","routine-delete","note-delete"]);function logDestructiveVerb(deps,verb2,params){let ids=["task-id","tab","id"].filter((key)=>typeof params[key]==="string"||typeof params[key]==="number").map((key)=>`${key}=${String(params[key])}`);(deps.log??((line)=>console.error(line)))(`[rove-bridge] api.invoke ${verb2} ${ids.join(" ")}`.trimEnd())}function logDestructive(deps,req){let ids=["taskId","tabId","path"].filter((key)=>typeof req.args[key]==="string").map((key)=>`${key}=${String(req.args[key])}`);(deps.log??((line)=>console.error(line)))(`[rove-bridge] ${req.op} ${ids.join(" ")}`.trimEnd())}async function onMessage(deps,ws,raw){let req,area=deps.areaOps??AREA_OPS;try{req=parseRequest(raw,(op)=>isCoreOp(op)||Object.hasOwn(area,op))}catch(err){let e=err instanceof BridgeError?err:new BridgeError("BAD_FRAME",String(err));ws.send(responseError(requestIdOf(err),e.code,e.message));return}try{ws.send(responseOk(req.id,await handle(deps,ws,req)))}catch(err){let code=err instanceof BridgeError?err.code:"INTERNAL",detail=err instanceof BridgeError?err.detail:void 0;ws.send(responseError(req.id,code,err instanceof Error?err.message:String(err),detail))}}function sameHost(origin,host){try{return host!==null&&new URL(origin).host===host.toLowerCase()}catch{return!1}}function startBridgeServer(deps,listen){return Bun.serve({hostname:listen.hostname,port:listen.port,async fetch(req,server){let log=deps.log??((line)=>console.error(line)),from=req.headers.get("cf-connecting-ip")??server.requestIP(req)?.address??"?";if(deps.access)try{await deps.access.verify(req.headers.get("cf-access-jwt-assertion"))}catch(err){return log(`[rove-bridge] 401 from ${from}: Cloudflare Access \u2014 ${err instanceof Error?err.message:String(err)}`),new Response(`unauthorized
|
|
44
|
-
`,{status:401})}if(req.headers.get("upgrade")?.toLowerCase()!=="websocket"&&deps.web){let file=await serveWebFile(deps.web,req);if(file)return file}let origin=req.headers.get("origin");if(origin!==null&&!sameHost(origin,req.headers.get("host")))return log(`[rove-bridge] 403 from ${from}: cross-origin upgrade from ${origin}`),new Response(`forbidden
|
|
45
|
-
`,{status:403});if(!tokenMatches(deps.token,presentedToken(req)))return log(`[rove-bridge] 401 from ${from}: missing or wrong bearer token`),new Response(`unauthorized
|
|
46
|
-
`,{status:401});let data={terminal:null,unsubscribeTasks:null,unsubscribeTabs:null,unsubscribeNotices:null,unsubscribeMods:null,unsubscribePrompts:null},headers=offersWebSubprotocol(req)?{"Sec-WebSocket-Protocol":WEB_SUBPROTOCOL}:void 0;if(server.upgrade(req,{data,headers}))return;return new Response(`rove-bridge speaks WebSocket only
|
|
47
|
-
`,{status:426})},websocket:{open(ws){if(ws.data.unsubscribeNotices=deps.notices?.subscribe((n)=>ws.send(pushEvent("notice",n)))??null,ws.data.unsubscribePrompts=deps.prompts?.subscribe((p)=>ws.send(pushEvent("prompt",p)))??null,deps.mods)ws.send(pushEvent("mods",{panes:deps.mods.current()})),ws.data.unsubscribeMods=deps.mods.subscribe((panes)=>ws.send(pushEvent("mods",{panes})))},maxPayloadLength:8388608,message(ws,message){onMessage(deps,ws,typeof message==="string"?message:message.toString("utf8"))},close(ws){ws.data.unsubscribeTasks?.(),ws.data.unsubscribeTabs?.(),ws.data.unsubscribeNotices?.(),ws.data.unsubscribeMods?.(),ws.data.unsubscribePrompts?.(),ws.data.terminal?.dispose()}}})}class TabFeed{read;latest;listeners=new Set;constructor(read2){this.read=read2;this.latest=this.snapshots()}check(){let next=this.snapshots(),changed=new Set;for(let[id,json]of next)if(this.latest.get(id)!==json)changed.add(id);for(let id of this.latest.keys())if(!next.has(id))changed.add(id);if(this.latest=next,changed.size===0)return;let taskIds=[...changed];for(let listener of this.listeners)listener(taskIds)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}snapshots(){let out=new Map;for(let[key,value]of Object.entries(this.read()))if(key.startsWith("terminalTabs."))out.set(key.slice(13),JSON.stringify(value));return out}}var TICK_MS=15000,TABS_DEBOUNCE_MS=200,TAILSCALE_BINARIES=["tailscale","/Applications/Tailscale.app/Contents/MacOS/Tailscale"];function tailscaleInfo(){for(let bin of TAILSCALE_BINARIES){let ip=spawnSync(bin,["ip","-4"],{encoding:"utf8",timeout:5000}),ipv4=ip.status===0?ip.stdout.split(`
|
|
48
|
-
`)[0]?.trim()??"":"";if(!ipv4)continue;let status=spawnSync(bin,["status","--json"],{encoding:"utf8",timeout:5000}),dnsName=null;try{let self=JSON.parse(status.stdout).Self;if(self&&typeof self==="object"&&"DNSName"in self&&typeof self.DNSName==="string")dnsName=self.DNSName.replace(/\.$/,"")||null}catch{}return{ipv4,dnsName}}return{ipv4:null,dnsName:null}}function readConfig(path){if(!existsSync3(path))return{};let raw=JSON.parse(readFileSync2(path,"utf8"));if(!raw||typeof raw!=="object")throw Error(`${path} must hold a JSON object`);let fields=new Map(Object.entries(raw)),pick=(k)=>{let v=fields.get(k);return typeof v==="string"&&v.trim()?v.trim():void 0};return{cfTeam:pick("cfTeam"),cfAud:pick("cfAud"),publicHost:pick("publicHost")}}async function runBridge(argv,opts){let home=resolveProductHomeDir(),bridgeDir=join4(home,".rove","bridge"),args;try{args=parseBridgeArgs(argv,{config:readConfig(join4(bridgeDir,"config.json")),tailscale:tailscaleInfo})}catch(err){console.error(`${opts.name}: ${err instanceof Error?err.message:String(err)}`),process.exit(2)}Reflect.deleteProperty(process.env,"ROVE_TASK_ID"),Reflect.deleteProperty(process.env,"ROVE_TAB_ID"),ensurePluginEnginesLoaded();let token=loadOrCreateToken(join4(bridgeDir,"token"),args.rotateToken),daemonSocket=await ensureDaemonReachable(void 0,"autospawn");await ensurePtyHostReachable();let orchestrator=new RemoteOrchestrator(new RoveDaemonClient(daemonSocket),{role:"gui",graphicsOut:()=>{}});await orchestrator.init();let hub=new MachineHub(orchestrator);hub.attach();let machines=hub.machinesSignal();machineStore.set(machines.get()),machines.subscribe(()=>machineStore.set(machines.get()));let verbClient=new RoveDaemonClient(daemonSocket),ops=createRoveOps(verbClient,{changes:()=>orchestrator.worktreeChangesSignal()(),tokens:()=>orchestrator.rowTokensSignal()(),remote:()=>hub.tasksSignal().get().filter((task)=>task.origin&&task.origin.machineId!=="local").map((task)=>({...task,kind:task.kind??"task",pinned:task.pinned??!1}))}),feed=new TaskFeed(()=>ops.tasks());for(let signal of[orchestrator.tasksSignal(),orchestrator.engineStateSignal(),orchestrator.attentionInboxSignal(),orchestrator.worktreeChangesSignal(),orchestrator.rowTokensSignal(),hub.tasksSignal()])signal.subscribe(()=>feed.poke());let usage=orchestrator.usageSnapshotSignal();usageStore.set(usage()),usage.subscribe(()=>usageStore.set(usage()));let context=orchestrator.contextUsageSignal();usageStore.setContext(context()),context.subscribe(()=>usageStore.setContext(context())),setInterval(()=>feed.poke(),TICK_MS);let notices=new NoticeFeed,noticeStore=orchestrator.noticeStore();noticeStore.subscribe(()=>notices.push(noticeStore.get()));let prompts=new PromptFeed,promptStore=orchestrator.uiPromptStore();promptStore.subscribe(()=>prompts.push(promptStore.get()));let modPanes=orchestrator.modPanesSignal(),mods={current:()=>modPanes.get(),subscribe:(listener)=>modPanes.subscribe(()=>listener(modPanes.get()))},statePath=defaultUiPrefsStatePath(),tabs=new TabFeed(()=>{try{let raw=JSON.parse(readFileSync2(statePath,"utf8"));return raw&&typeof raw==="object"?raw:{}}catch{return{}}});startFileWatchTrigger({filePath:statePath,debounceMs:TABS_DEBOUNCE_MS,onTrigger:()=>tabs.check(),onError:()=>{}});let ptySocket=defaultPtyHostSocketPath(),deps={token,ops,feed,notices,prompts,mods,tabs,openPty:()=>new RoveDaemonClient(ptySocket),roveVersion:CURRENT_VERSION,api:createBridgeApi(verbClient),invoke:(verb2,params,machine)=>invokeRouted({verb:verb2,params,machine,isLocalTask:(id)=>verbClient.request("task.get",{taskId:id}).then(()=>!0,()=>!1),runHere:()=>executeVerb(verb2,{params},{client:verbClient,caller:REMOTE_CALLER})}),...args.cloudflare?{access:createAccessVerifier(args.cloudflare)}:{},...opts.web?{web:opts.web}:{}},servers=args.hosts.map((hostname)=>{try{return startBridgeServer(deps,{hostname,port:args.port})}catch(err){if(!(err&&typeof err==="object"&&("code"in err)&&err.code==="EADDRINUSE"))throw err;console.error(`${opts.name}: ${hostname}:${args.port} is already in use (another rove-bridge?). Stop it or pass --port <n>.`),process.exit(2)}});console.log(`${opts.name} ${CURRENT_VERSION} \u2014 Rove home ${home}`);for(let server of servers){let host=server.hostname??"127.0.0.1",port=server.port??args.port;if(console.log(`listening on ${host}:${port}${args.preset==="none"?"":` (preset ${args.preset})`}`),host==="0.0.0.0"||host==="::")console.log(" WARNING: all interfaces, plain ws:// \u2014 prefer --preset tailscale or --preset cf");let publicHost=args.publicHost??host;if(opts.web)console.log(`
|
|
49
|
-
open: ${webUrl({host:publicHost,port,token,tls:args.tls})}`);let url=pairingUrl({host:publicHost,port,token,tls:args.tls,preset:args.preset});if(console.log(`${opts.web?"":`
|
|
50
|
-
`}pair: ${url}`),args.qr&&!opts.web)console.log(renderUnicodeCompact(url))}if(args.cloudflare)console.log(`
|
|
51
|
-
Cloudflare Access: team ${args.cloudflare.teamDomain}, every connection needs a valid JWT for this AUD.`),console.log(`Point the tunnel at http://127.0.0.1:${args.port} (e.g. ingress service for ${args.publicHost}).`);console.log(`
|
|
52
|
-
The ${opts.web?"links are passwords":"pairing URL is a password"}. \`--rotate-token\` revokes every paired phone${opts.web?" and browser":""}.`)}export{runBridge};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{PS_PROBE_TIMEOUT_MS,engineProcessIn,foregroundEngine,foregroundEngineIn,hasAncestor,parsePsSnapshot,psSnapshot,psSnapshotWith,vendorFromArgv}from"./chunk-24dryfqb.js";import"./chunk-jp31bpgp.js";import"./chunk-2tfnscxk.js";import"./chunk-ccn7pq03.js";import"./chunk-w7zv47mp.js";import"./chunk-2brn8e1y.js";import"./chunk-jnj2kk2h.js";import"./chunk-9dregrj6.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import"./chunk-21ek142k.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import{PsProbeUnavailableError}from"./chunk-pxk2c2vj.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{vendorFromArgv,psSnapshotWith,psSnapshot,parsePsSnapshot,hasAncestor,foregroundEngineIn,foregroundEngine,engineProcessIn,PsProbeUnavailableError,PS_PROBE_TIMEOUT_MS};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{ReleaseNotesBody,bootPaneHost,pageCloseBindings,runShellUpdater,useBindings,useT,useTheme}from"./chunk-jn7vr075.js";import"./chunk-yknavm97.js";import"./chunk-pj3gnkfr.js";import{$jsx,$jsxs,useRenderer}from"./chunk-29kvfqeh.js";import{require_react_production}from"./chunk-2wd4744g.js";import"./chunk-764bsyb0.js";import"./chunk-e8pv3b92.js";import"./chunk-atn06ncf.js";import"./chunk-zcadc92x.js";import"./chunk-vjvkkrzc.js";import"./chunk-pdvyfz3n.js";import"./chunk-55ajzrj6.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-6xppe9bj.js";import"./chunk-9sta3ak4.js";import"./chunk-gaf6n1ea.js";import"./chunk-7j00hbq5.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-xy8be792.js";import{BREAKING_VERSIONS,CURRENT_VERSION,breakingVersionsCrossed,fetchReleaseNotes,fetchReleaseSummaries,updateCommandFor}from"./chunk-j6t7xvm3.js";import"./chunk-40dgv828.js";import"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-032g0ahy.js";import"./chunk-q3xt0mqt.js";import"./chunk-cmp64q4j.js";import"./chunk-s5a5dyab.js";import"./chunk-md094j05.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import{__toESM}from"./chunk-91sykzqq.js";import{TextAttributes}from"@opentui/core";var import_react2=__toESM(require_react_production(),1);var RELEASE_LIMIT=20;function VersionsPage(props){let{theme}=useTheme(),t=useT(),renderer=useRenderer(),[releases,setReleases]=import_react2.useState(null),[cursor,setCursor]=import_react2.useState(0),[notes,setNotes]=import_react2.useState({}),[status,setStatus]=import_react2.useState(null),selected=releases?.[cursor],crossings=selected?breakingVersionsCrossed(CURRENT_VERSION,selected.version):[],loadSummaries=props.fetchSummaries??fetchReleaseSummaries,loadNotes=props.fetchNotes??fetchReleaseNotes;import_react2.useEffect(()=>{loadSummaries(RELEASE_LIMIT).then((fetched)=>setReleases(fetched))},[loadSummaries]);let selectedVersion=selected?.version;import_react2.useEffect(()=>{if(selectedVersion===void 0||notes[selectedVersion]!==void 0)return;setNotes((cache)=>({...cache,[selectedVersion]:"loading"})),loadNotes(selectedVersion).then((fetched)=>{setNotes((cache)=>({...cache,[selectedVersion]:fetched??"missing"}))})},[selectedVersion,notes,loadNotes]);function move(delta){let count=releases?.length??0;if(count===0)return;setCursor((index)=>(index+delta+count)%count)}async function installSelected(){if(!selected)return;setStatus(t("update.statusRunningUpdater")),await new Promise((resolve)=>setTimeout(resolve,30)),await runShellUpdater({renderer,t,targetLabel:selected.version,command:updateCommandFor(selected.version)})}useBindings(()=>({bindings:[{key:"up",cmd:()=>move(-1)},{key:"down",cmd:()=>move(1)},{key:"k",cmd:()=>move(-1)},{key:"j",cmd:()=>move(1)},{key:"return",cmd:()=>void installSelected()},{key:"u",cmd:()=>void installSelected()},...pageCloseBindings(props.onClose)]}));let selectedNotes=selectedVersion===void 0?void 0:notes[selectedVersion];return $jsxs("box",{flexDirection:"column",flexGrow:1,paddingTop:1,paddingLeft:2,paddingRight:2,children:[$jsxs("box",{flexDirection:"row",justifyContent:"space-between",flexShrink:0,children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"none",children:t("update.versions.pageTitle")}),$jsx("text",{fg:theme.textMuted,wrapMode:"none",onMouseUp:props.onClose,children:t("update.versions.closeHint")})]}),$jsxs("box",{flexDirection:"row",flexGrow:1,paddingTop:1,gap:2,children:[$jsxs("box",{flexDirection:"column",width:26,flexShrink:0,children:[releases===null?$jsx("text",{fg:theme.textMuted,children:t("update.versions.loading")}):null,releases!==null&&releases.length===0?$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("update.versions.unavailable")}):null,(releases??[]).map((release,index)=>{let active=index===cursor,tags=[release.version===CURRENT_VERSION?t("update.versions.tagCurrent"):"",index===0?t("update.versions.tagLatest"):"",BREAKING_VERSIONS.includes(release.version)?t("update.versions.tagBreaking"):""].filter(Boolean).join(" ");return $jsxs("box",{flexDirection:"row",gap:1,paddingLeft:1,backgroundColor:active?theme.primary:void 0,onMouseUp:()=>setCursor(index),children:[$jsxs("text",{fg:active?theme.selectedListItemText:theme.text,attributes:release.version===CURRENT_VERSION?TextAttributes.BOLD:void 0,wrapMode:"none",children:["v",release.version]}),tags?$jsx("text",{fg:active?theme.selectedListItemText:theme.textMuted,wrapMode:"none",children:tags}):null]},release.version)})]}),$jsxs("box",{flexDirection:"column",flexGrow:1,flexShrink:1,children:[$jsx("scrollbox",{flexGrow:1,flexShrink:1,stickyScroll:!1,verticalScrollbarOptions:{trackOptions:{foregroundColor:"transparent"}},children:$jsxs("box",{flexDirection:"column",paddingRight:1,paddingBottom:1,gap:0,children:[selectedNotes==="loading"?$jsx("text",{fg:theme.textMuted,children:t("update.loadingNotes")}):null,selectedNotes==="missing"?$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("update.notesUnavailable")}):null,selectedNotes!==void 0&&selectedNotes!=="loading"&&selectedNotes!=="missing"?$jsx(ReleaseNotesBody,{body:selectedNotes.body}):null]})}),crossings.length>0?$jsx("text",{fg:theme.warning,wrapMode:"word",children:t("update.versions.breakingWarning",{versions:crossings.join(", ")})}):null]})]}),status?$jsx("text",{fg:theme.info,wrapMode:"word",children:status}):null,$jsx("box",{flexShrink:0,paddingTop:1,children:$jsx("text",{fg:theme.textMuted,attributes:TextAttributes.DIM,wrapMode:"none",children:t("update.versions.footerHint")})})]})}var INLINE_ROWS=24;async function startVersionsHost(){await bootPaneHost({inlineRows:INLINE_ROWS,setup:()=>({root:()=>$jsx(VersionsPage,{onClose:()=>process.exit(0)})})})}export{startVersionsHost,VersionsPage};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{JsonHookAdapter,editJsonSettings,isObject,removeRoveHooks,vendorConfigHome}from"./chunk-9dregrj6.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{__require}from"./chunk-91sykzqq.js";import{join}from"path";var CLAUDE_HOOK_EVENT_MAP=[{event:"SessionStart",verb:"session-start"},{event:"UserPromptSubmit",verb:"turn-start"},{event:"Stop",verb:"turn-complete"},{event:"StopFailure",verb:"turn-failed"},{event:"Notification",matcher:"permission_prompt",verb:"awaiting-input"},{event:"Notification",matcher:"elicitation_dialog",verb:"awaiting-input"},{event:"SessionEnd",verb:"session-end"},{event:"PreCompact",verb:"pre-compact"},{event:"PostCompact",verb:"post-compact"},{event:"SubagentStart",verb:"subagent-start"},{event:"SubagentStop",verb:"subagent-stop"},{event:"PreToolUse",verb:"tool-pre"},{event:"PostToolUse",verb:"tool-post"},{event:"PostToolUseFailure",verb:"tool-failed"}],ROVE_HOOK_EVENTS=[...new Set(CLAUDE_HOOK_EVENT_MAP.map((e)=>e.event))];function failureFromErrorType(errorType){if(typeof errorType!=="string")return"other";if(errorType==="rate_limit"||errorType==="overloaded")return"rate_limit";if(errorType==="billing_error")return"billing";return"other"}function claudeSettingsPath(){return join(vendorConfigHome("claude"),"settings.json")}var WORKTREE_SYNC_VERB="worktree-created";function mergeWorktreeSyncHook(current,command){let{hooks:rawHooks,...restSettings}=current,{WorktreeCreate,...otherHooks}=isObject(rawHooks)?rawHooks:{},prior=Array.isArray(WorktreeCreate)?WorktreeCreate:[],kept=removeRoveHooks(prior,[WORKTREE_SYNC_VERB]);if(command!==null)kept.push({hooks:[{type:"command",command}]});let nextHooks={...otherHooks};if(kept.length>0)nextHooks.WorktreeCreate=kept;return Object.keys(nextHooks).length>0?{...restSettings,hooks:nextHooks}:{...restSettings}}class ClaudeHookAdapter extends JsonHookAdapter{vendor="claude";eventMap=CLAUDE_HOOK_EVENT_MAP;globalSettingsPath(){return claudeSettingsPath()}activityDetailFromPayload(kind,payload){if(kind==="turn-failed")return{failure:failureFromErrorType(payload.error_type)};if(kind==="awaiting-input")return{waiting:payload.notification_type==="elicitation_dialog"?"input":"permission"};if(kind==="tool-pre"||kind==="tool-post"||kind==="tool-failed")return{tool:{...typeof payload.tool_name==="string"?{name:payload.tool_name}:{},...typeof payload.tool_use_id==="string"?{id:payload.tool_use_id}:{}}};if(kind==="pre-compact"||kind==="post-compact")return{compact:{trigger:payload.trigger==="manual"?"manual":"auto"}};if(kind==="subagent-start"||kind==="subagent-stop")return{subagent:{...typeof payload.agent_type==="string"?{type:payload.agent_type}:{},...typeof payload.agent_id==="string"?{id:payload.agent_id}:{}}};return}sessionFromPayload(payload){if(typeof payload.session_id!=="string"||!payload.session_id)return;return{sessionId:payload.session_id,...typeof payload.transcript_path==="string"&&payload.transcript_path?{transcriptPath:payload.transcript_path}:{}}}isUnattendedSession(env){return env.CLAUDE_CODE_SESSION_ATTENDED==="0"}async externallyManagedHooks(){let{isRovePluginEnabled,detectLegacyInstalls,migrationHint}=await import("./chunk-vwpcv7j1.js");if(!isRovePluginEnabled())return;let notice=migrationHint(detectLegacyInstalls(),ROVE_PRODUCT_NAME);return notice?{notice}:{}}supportsWorktreeSync(){return!0}async removeWorktreeSyncHook(settingsFilePath){await editJsonSettings(settingsFilePath,(cur)=>mergeWorktreeSyncHook(cur,null))}}
|
|
3
|
-
export{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath,ClaudeHookAdapter};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{isEngineActivityKind}from"./chunk-17e2tgyg.js";import{loadPluginRegistry,readPluginManifest}from"./chunk-vd8qqev9.js";import{activityHookAdapters}from"./chunk-jp31bpgp.js";import{flagValue}from"./chunk-zsfyj36g.js";import{connectIfRunning}from"./chunk-9sta3ak4.js";import{getPersistedString,setPersistedString}from"./chunk-21ek142k.js";import{readRoveEnv}from"./chunk-nc46gddg.js";import{join,resolve}from"path";var STDIN_READ_TIMEOUT_MS=500;async function readTextWithTimeout(read,timeoutMs=STDIN_READ_TIMEOUT_MS){let raceTimer;try{return await Promise.race([read(),new Promise((resolve2)=>{raceTimer=setTimeout(()=>resolve2(""),timeoutMs)})])}finally{if(raceTimer!==void 0)clearTimeout(raceTimer)}}async function readStdinText(){let bun=globalThis.Bun;if(bun)return bun.stdin.text();if(process.stdin.isTTY)return"";let chunks=[];try{for await(let chunk of process.stdin)chunks.push(chunk)}finally{process.stdin.destroy()}return Buffer.concat(chunks).toString("utf8")}async function readStdinPayload(){try{let text=await readTextWithTimeout(readStdinText);if(!text.trim())return{};let parsed=JSON.parse(text);return parsed&&typeof parsed==="object"&&!Array.isArray(parsed)?parsed:{}}catch{return{}}}async function runHookSubcommand(argv){let[verb,...rest]=argv;if(verb==="setup"){await runHookSetup(rest);return}if(verb==="cleanup"){await runHookCleanup();return}try{if(!verb||!isEngineActivityKind(verb))return;let payload=await readStdinPayload(),payloadFlag=flagValue(rest,"--payload");if(payloadFlag)try{let extra=JSON.parse(payloadFlag);if(extra&&typeof extra==="object"&&!Array.isArray(extra))Object.assign(payload,extra)}catch{}let taskId=flagValue(rest,"--task-id"),envTaskId=process.env.ROVE_TASK_ID,envTabId=process.env.ROVE_TAB_ID,engine=flagValue(rest,"--engine"),adapters=activityHookAdapters().filter((a)=>!engine||a.vendor===engine);if(!taskId&&adapters.some((a)=>a.isUnattendedSession?.(process.env)===!0))return;let cwd=typeof payload.cwd==="string"&&payload.cwd?payload.cwd:void 0;for(let adapter of adapters){if(cwd)break;cwd=adapter.cwdFromPayload?.(payload)}cwd||=process.cwd();let detail;for(let adapter of adapters)if(detail=adapter.activityDetailFromPayload(verb,payload),detail)break;let session;for(let adapter of adapters)if(session=adapter.sessionFromPayload(payload),session)break;let client=await connectIfRunning();if(!client)return;try{let effectiveTaskId=taskId??envTaskId;await client.request("engine.reportEvent",{...effectiveTaskId?{taskId:effectiveTaskId}:{cwd},kind:verb,...engine?{engine}:{},...envTabId?{tabId:envTabId}:{},...detail?{detail}:{},...session?{sessionId:session.sessionId}:{},...session?.transcriptPath?{transcriptPath:session.transcriptPath}:{}})}finally{client.close()}}catch(err){if(readRoveEnv("HOOK_DEBUG"))console.error(`[rove hook] ${verb} failed:`,err instanceof Error?err.message:String(err))}}var SYNC_SETTING_KEY="externalWorktreeSync";function worktreeSyncAdapters(){return activityHookAdapters().filter((a)=>a.supportsWorktreeSync())}function globalSettingsPath(){return worktreeSyncAdapters()[0]?.globalSettingsPath()}function persistedSyncPath(stored){if(!stored||stored==="off")return;if(stored==="global")return globalSettingsPath();if(stored.startsWith("repo:"))return join(resolve(stored.slice(5)),".claude","settings.json");return stored}async function ensureGlobalRoveHooks(opts={}){try{let toolEvents=pluginsWantToolEvents();for(let a of activityHookAdapters()){let external=await a.externallyManagedHooks?.();if(external){if(external.notice)process.stderr.write(`
|
|
3
|
-
${external.notice}
|
|
4
|
-
`);continue}let enginePath=a.globalSettingsPath();if(!enginePath)continue;await a.installActivityHooks(enginePath,{toolEvents,quiet:opts.quiet}),await a.removeWorktreeWatchHook(enginePath)}await cleanupWorktreeSyncHook()}catch{}}function pluginsWantToolEvents(){try{for(let entry of loadPluginRegistry().plugins){if(!entry.enabled)continue;try{if(readPluginManifest(entry.root).manifest.events.some((e)=>e.on.startsWith("tool.")))return!0}catch{}}}catch{}return!1}async function cleanupWorktreeSyncHook(){let adapters=worktreeSyncAdapters();if(adapters.length===0)return;let stored=getPersistedString(SYNC_SETTING_KEY),paths=new Set;for(let adapter of adapters){let file=adapter.globalSettingsPath();if(file)paths.add(file)}let prev=persistedSyncPath(stored);if(prev)paths.add(prev);for(let a of adapters)for(let p of paths)await a.removeWorktreeSyncHook(p);if(stored!=="off")setPersistedString(SYNC_SETTING_KEY,"off")}async function runHookCleanup(){let claude=activityHookAdapters().find((a)=>a.vendor==="claude"),path=claude?.globalSettingsPath();if(!claude||!path){process.stdout.write(`rove hook cleanup: no Claude hook adapter \u2014 nothing to do.
|
|
5
|
-
`);return}await claude.removeActivityHooks(path),await claude.removeWorktreeWatchHook(path),process.stdout.write([`rove hook cleanup: removed Rove's settings-managed hooks from ${path}.`,"Only Rove's own entries were touched; your other hooks are intact.","The Claude Code plugin's hooks.json now carries these events (if the plugin","is not installed, the next Rove launch reinstalls the settings-managed set).",""].join(`
|
|
6
|
-
`))}async function runHookSetup(_argv){await cleanupWorktreeSyncHook(),process.stdout.write(["rove hook setup is deprecated and now a no-op (cleanup only).","","The old external-worktree sync used a global WorktreeCreate hook, which is","a VCS provider hook \u2014 its presence broke `claude --worktree` / EnterWorktree","in every repo. Any hook Rove previously installed has been removed.","","Sync is now automatic: a `claude --worktree` (or any session) started in a","worktree under a repo Rove already tracks is adopted as a task on launch.","To adopt existing worktrees on demand, use the New Task dialog or `rove adopt`.",""].join(`
|
|
7
|
-
`))}
|
|
8
|
-
export{readTextWithTimeout,readStdinText,runHookSubcommand,ensureGlobalRoveHooks};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{API_VERBS,VERBS,VERB_ALIASES,VERB_GROUPS,findVerb,unknownVerbError}from"./chunk-bhm24ne6.js";import"./chunk-zzzm2cfx.js";import"./chunk-m3bz62v4.js";import"./chunk-kda565xs.js";import"./chunk-s5k3g5ra.js";import"./chunk-cbc1h345.js";import"./chunk-07jq0271.js";import"./chunk-17e2tgyg.js";import"./chunk-34468esa.js";import"./chunk-4hestsjp.js";import"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-p2jeq98m.js";import"./chunk-2bgmby1d.js";import"./chunk-vd8qqev9.js";import"./chunk-r2c5nbcq.js";import"./chunk-atn06ncf.js";import"./chunk-nz9nmp4v.js";import"./chunk-qkehg2c1.js";import"./chunk-x8pk5cyf.js";import"./chunk-namxa4wy.js";import"./chunk-952aedqm.js";import"./chunk-resmnaxq.js";import"./chunk-sak1tphp.js";import"./chunk-4250pw6r.js";import"./chunk-cbd6y9at.js";import"./chunk-rxqdw6s5.js";import"./chunk-zcadc92x.js";import"./chunk-vjvkkrzc.js";import"./chunk-pdvyfz3n.js";import"./chunk-r0etyq15.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-24dryfqb.js";import"./chunk-jp31bpgp.js";import"./chunk-2tfnscxk.js";import"./chunk-ccn7pq03.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import"./chunk-6xppe9bj.js";import"./chunk-b7xjhgts.js";import"./chunk-568q390y.js";import"./chunk-zsfyj36g.js";import"./chunk-9sta3ak4.js";import"./chunk-gaf6n1ea.js";import"./chunk-7j00hbq5.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-jnj2kk2h.js";import"./chunk-9dregrj6.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import"./chunk-j6t7xvm3.js";import"./chunk-21ek142k.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-032g0ahy.js";import"./chunk-q3xt0mqt.js";import"./chunk-cmp64q4j.js";import"./chunk-pxk2c2vj.js";import"./chunk-s5a5dyab.js";import"./chunk-md094j05.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{unknownVerbError,findVerb,VERB_GROUPS,VERB_ALIASES,VERBS,API_VERBS};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{booleanFlagsOf,callVerb,errorBody,errorEnvelope,runVerb,successEnvelope,toApiError}from"./chunk-c0ksxg3z.js";import{VerbArgs,apiUsage,findVerb,parseFlags,takeIdentityWarning,unknownVerbError,validateAgainstSpec,verbHelp}from"./chunk-bhm24ne6.js";import{ensurePluginEnginesLoaded}from"./chunk-m3bz62v4.js";import{openDaemonSession}from"./chunk-kda565xs.js";import{LOCAL_MACHINE,forwardVerb,requireMachine,routeTarget}from"./chunk-a1wjg2cv.js";import{ApiError}from"./chunk-568q390y.js";import{argvHasFlag}from"./chunk-zsfyj36g.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{ROVE_API_VERSION}from"./chunk-md094j05.js";function takeMachineFlag(argv){let rest=[],machine;for(let i=0;i<argv.length;i++){let arg=argv[i];if(arg==="--machine")machine=argv[i+1],i+=1;else if(arg.startsWith("--machine="))machine=arg.slice(10);else rest.push(arg)}return{machine:machine||void 0,rest}}function forwardParams(verb,flags){if(!flags.has("prompt-file")||!verb.flags.some((f)=>f.name==="prompt"))return Object.fromEntries(flags);let text=new VerbArgs(verb,flags).promptText(),params=Object.fromEntries([...flags].filter(([name])=>name!=="prompt-file"));return text===void 0?params:{...params,prompt:text}}var envelopeMode=!1;function writeJson(value,pretty,stream=process.stdout){stream.write(`${pretty?JSON.stringify(value,null,2):JSON.stringify(value)}
|
|
3
|
-
`)}function emit(value,pretty){let warning=takeIdentityWarning(),payload=warning&&value&&typeof value==="object"&&!Array.isArray(value)?{...value,identityWarning:warning}:value;writeJson(envelopeMode?successEnvelope(payload):payload,pretty)}function fail(message,code,exitCode=1,data){let error=errorBody(new ApiError(message,code,data));if(envelopeMode)writeJson({apiVersion:ROVE_API_VERSION,ok:!1,error},!1);else writeJson({error},!1,process.stderr);process.exit(exitCode)}var USAGE_ERROR_CODES=new Set(["BAD_VERB","UNKNOWN_VERB","BAD_FLAG","MISSING_FLAG","MISSING_VERB","BAD_DAEMON","UNKNOWN_MACHINE"]);async function invokeVerb(verbName,argv,deps){return runVerb(verbName,{argv},deps)}async function runApiSubcommand(argv){let[verbName,...withMachine]=argv,{machine,rest}=takeMachineFlag(withMachine);if(envelopeMode=argvHasFlag(rest,"--envelope"),!verbName||verbName==="--help"||verbName==="-h"||verbName==="help"){if(!verbName)fail(apiUsage(),"MISSING_VERB",2);process.stdout.write(`${apiUsage()}
|
|
4
|
-
`);return}ensurePluginEnginesLoaded();let verb=findVerb(verbName);if(!verb){let err=unknownVerbError(verbName);fail(`${err.message}
|
|
5
|
-
${apiUsage()}`,err.code,2,err.data)}let parsed;try{parsed=parseFlags(rest,booleanFlagsOf(verb))}catch(err){if(err instanceof ApiError)fail(err.message,err.code,2,err.data);fail(errorMessage(err),"BAD_FLAG",2)}if(parsed.help){process.stdout.write(`${verbHelp(verb)}
|
|
6
|
-
`);return}try{validateAgainstSpec(verb,parsed.flags)}catch(err){if(err instanceof ApiError)fail(err.message,err.code,2,err.data);fail(errorMessage(err),"BAD_FLAG",2)}if(machine!==void 0&&machine!==LOCAL_MACHINE){await runForwarded(verb,parsed,async()=>requireMachine(machine));return}let session=null;if(!verb.offline)try{session=await openDaemonSession()}catch(err){fail(`could not reach or start the Rove daemon: ${errorMessage(err)}`,"BAD_DAEMON",2,{hint:"check whether the daemon is up (and why it is not), then retry the same command",nextCommandArgs:["daemon","status"]})}let taskId=machine===LOCAL_MACHINE?void 0:parsed.flags.get("task-id"),client=session?.client??null,target=taskId&&client?await machineHolding(taskId,client):null;if(target){session?.close(),await runForwarded(verb,parsed,async()=>target);return}try{let result=await callVerb(verb,parsed.flags,{client:session?.client??null});emit(result,parsed.pretty)}catch(err){if(err instanceof ApiError&&err.code==="PARTIAL_FANOUT"){if(envelopeMode)writeJson(errorEnvelope(err),parsed.pretty);else emit(err.data,parsed.pretty);session?.close(),process.exit(3)}let apiErr=toApiError(err);fail(apiErr.message,apiErr.code,USAGE_ERROR_CODES.has(apiErr.code)?2:1,apiErr.data)}finally{session?.close()}}async function machineHolding(taskId,client){try{return await routeTarget({taskId,isLocalTask:async(id)=>{try{return await client.request("task.get",{taskId:id}),!0}catch{return!1}}})}catch(err){let apiErr=toApiError(err);fail(apiErr.message,apiErr.code,1,apiErr.data)}}async function runForwarded(verb,parsed,resolve){let envelope;try{let entry=await resolve();envelope=await forwardVerb(entry,verb.name,forwardParams(verb,parsed.flags))}catch(err){let apiErr=toApiError(err);fail(apiErr.message,apiErr.code,USAGE_ERROR_CODES.has(apiErr.code)?2:1,apiErr.data)}if(envelope.ok){emit(envelope.result,parsed.pretty);return}let{message,code,...data}=envelope.error;if(code==="PARTIAL_FANOUT"){if(envelopeMode)writeJson(envelope,parsed.pretty);else emit(data,parsed.pretty);process.exit(3)}fail(message,code,USAGE_ERROR_CODES.has(code)?2:1,data)}export{invokeVerb,runApiSubcommand};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{machineTasks}from"./chunk-a1wjg2cv.js";import"./chunk-x0rvg54z.js";import"./chunk-t5qayy7m.js";import{dedupeMachines,listMachines}from"./chunk-q854fweb.js";import"./chunk-b7xjhgts.js";import"./chunk-568q390y.js";import"./chunk-2brn8e1y.js";import"./chunk-7kysxgbq.js";import"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-s5a5dyab.js";import"./chunk-md094j05.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";async function mergeTaskList(local){let machines=dedupeMachines(listMachines());if(machines.length===0)return local;let tasks=(local.tasks??[]).map((task)=>({...task,origin:{machineId:"local",hostLabel:"local"}}));for(let entry of machines){let remote=await machineTasks(entry);if(!remote)continue;let hostLabel=entry.alias;for(let task of remote)tasks.push({...task,origin:{machineId:entry.alias,hostLabel}})}return{tasks}}export{mergeTaskList};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{NoopHookAdapter,activityHookAdapters,createEngineHookAdapter}from"./chunk-jp31bpgp.js";import"./chunk-2tfnscxk.js";import"./chunk-ccn7pq03.js";import"./chunk-w7zv47mp.js";import"./chunk-2brn8e1y.js";import"./chunk-jnj2kk2h.js";import"./chunk-9dregrj6.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import"./chunk-21ek142k.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{createEngineHookAdapter,activityHookAdapters,NoopHookAdapter};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{TaskIndexStore}from"./chunk-h7y9v8k1.js";import"./chunk-qkehg2c1.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-hq9tbzqa.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{TaskIndexStore};
|