@sma1lboy/kobe 0.8.175 → 0.8.176
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/index.js +1 -1
- package/dist/cli/kobe-run.js +1 -1
- package/dist/cli/rove-run.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -79,7 +79,7 @@ You were spawned by Rove task ${J}. When the work is finished, send your outcome
|
|
|
79
79
|
`).split(`
|
|
80
80
|
`).map((X)=>(X.split("\r").pop()??"").slice(0,aG0));while(J.length>0&&(J[J.length-1]??"").trim()==="")J.pop();return J.slice(-oG0)}function mu($=Zj()){try{let Z=JSON.parse(dG0($,"utf8"));if(Z===null||typeof Z!=="object"||Array.isArray(Z))return{};return Z}catch{return{}}}function PT($,Z=Zj()){if($.key.startsWith("::"))return;if($.exit.code===0&&$.exit.signal===null)return;let J=mu(Z);J[$.key]={key:$.key,pid:$.pid,code:$.exit.code,signal:$.exit.signal,at:$.exit.at,tail:ku($.tail)};let X=Object.values(J).sort((z,G)=>z.at<G.at?1:-1).slice(0,iG0);lG0(nG0(Z),{recursive:!0}),pG0(Z,JSON.stringify(Object.fromEntries(X.map((z)=>[z.key,z])),null,2),"utf8")}var iG0=50,oG0=40,aG0=500,rG0;var hj=c(()=>{T7();rG0=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[@-_]/g});var cu={};A$(cu,{setRepoLastActiveVendor:()=>lJ,setGlobalDefaultVendor:()=>ST,resolvePreferredVendor:()=>B9,getRepoLastActiveVendor:()=>uu,getGlobalDefaultVendor:()=>uj});function TT($,Z){let J=$?.trim();if(!J)return;if(l5(J)||Z.includes(J))return J;return}function uu($){return TT(E5(hu+$),w2())}function lJ($,Z){Z6(hu+$,Z)}function uj(){let $=w2();return TT(E5("defaultVendor"),$)??TT(E5("lastSelectedVendor"),$)}function ST($){Z6("defaultVendor",$)}function B9($){return($?uu($):void 0)??uj()??H4}var hu="lastActiveVendor.";var CZ=c(()=>{P7();d5();A4()});function z8($=process.env){return{...$,...IT}}var IT;var dJ=c(()=>{IT={GIT_OPTIONAL_LOCKS:"0"}});function lu($){return $>="0"&&$<="7"}function nu($,Z){let J=[],X="",z=()=>{if(X.length>0){for(let W of sG0.encode(X))J.push(W);X=""}},G=Z+1;while(G<$.length){let W=$[G];if(W==='"'){G++;break}if(W==="\\"){let q=$[G+1];if(q===void 0){X+="\\",G++;continue}switch(q){case"a":z(),J.push(7),G+=2;break;case"b":z(),J.push(8),G+=2;break;case"t":z(),J.push(9),G+=2;break;case"n":z(),J.push(10),G+=2;break;case"v":z(),J.push(11),G+=2;break;case"f":z(),J.push(12),G+=2;break;case"r":z(),J.push(13),G+=2;break;case'"':X+='"',G+=2;break;case"\\":X+="\\",G+=2;break;default:if(lu(q)){let U="",B=G+1;while(B<$.length&&U.length<3&&lu($[B]))U+=$[B],B++;z(),J.push(Number.parseInt(U,8)&255),G=B}else X+=q,G+=2;break}}else X+=W,G++}return z(),{value:tG0.decode(new Uint8Array(J)),end:G}}function AZ($){if($.length===0||$[0]!=='"')return $;return nu($,0).value}function iu($,Z){if($[0]==='"'){let X=nu($,0);if($.startsWith(Z,X.end))return{orig:X.value,neu:AZ($.slice(X.end+Z.length))};return null}let J=$.indexOf(Z);if(J<0)return null;return{orig:$.slice(0,J),neu:AZ($.slice(J+Z.length))}}function du($,Z,J){if(Z.length===0&&$.endsWith("/")&&J.startsWith("/"))return $+J.slice(1);return $+Z+J}function eG0($){let Z=$.indexOf("{");if(Z>=0){let X=$.indexOf("}",Z),z=$.indexOf(" => ",Z);if(X>Z&&z>=0&&z<X){let G=$.slice(0,Z),W=$.slice(Z+1,z),q=$.slice(z+4,X),U=$.slice(X+1);return{path:du(G,q,U),origPath:du(G,W,U)}}}let J=iu($," => ");if(J)return{path:J.neu,origPath:J.orig};return{path:AZ($)}}function cj($){let Z=[];for(let J of $.split(`
|
|
81
81
|
`)){let X=J.replace(/\r$/,"");if(X.length<4)continue;if(X.startsWith("##"))continue;let z=X[0],G=X[1];if(X[2]!==" ")continue;let W=X.slice(3);if(z==="R"||z==="C"||G==="R"||G==="C"){let q=iu(W," -> ");if(q){Z.push({x:z,y:G,path:q.neu,origPath:q.orig});continue}}Z.push({x:z,y:G,path:AZ(W)})}return Z}function pu($){if($==="-")return null;let Z=Number.parseInt($,10);return Number.isNaN(Z)?null:Z}function ou($){let Z=[];for(let J of $.split(`
|
|
82
|
-
`)){let X=J.replace(/\r$/,"");if(X.length===0)continue;let z=X.indexOf("\t");if(z<0)continue;let G=X.indexOf("\t",z+1);if(G<0)continue;let W=X.slice(G+1);if(W.length===0)continue;let q=eG0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:pu(X.slice(0,z)),deleted:pu(X.slice(z+1,G))})}return Z}var sG0,tG0;var lj=c(()=>{sG0=new TextEncoder,tG0=new TextDecoder});var au={};A$(au,{sameWorktreeChanges:()=>FF,readWorktreeChanges:()=>ZW0,pickPushedChanges:()=>ET,parsePorcelain:()=>OH});import{spawnSync as $W0}from"child_process";function FF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function ET($,Z){if(!$)return null;return $.get(Z)??dj}function ZW0($){if(!$)return dj;try{let Z=$W0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return dj;return OH(Z.stdout)}catch{return dj}}function OH($){let Z=0,J=0;for(let{x:X,y:z}of cj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var dj;var jH=c(()=>{dJ();lj();dj={added:0,deleted:0}});var eu={};A$(eu,{resolveBaseRef:()=>su,readBranchSignals:()=>XW0,parseShortstat:()=>tu});import{spawnSync as JW0}from"child_process";function pj($,Z){try{let J=JW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function su($){let Z=pj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(pj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function tu($){let Z=(J)=>{let X=$.match(J);return X?Number.parseInt(X[1]??"0",10):0};return{files:Z(/(\d+) files? changed/),insertions:Z(/(\d+) insertions?\(\+\)/),deletions:Z(/(\d+) deletions?\(-\)/)}}function XW0($){if(!$)return ru;let Z=su($);if(!Z)return ru;let J=pj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=pj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:tu(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var ru;var $c=c(()=>{dJ();ru={baseRef:null,ahead:null,diff:null}});async function QW0($,Z,J){let X;try{X=await $T()}catch(z){throw new K1(`failed to start PTY host for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}try{if($.tab&&$.tab!=="new"){let O=U2({command:$.command,vendor:$.vendor,effort:$.modelEffort})[0];return await XT(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?vu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=cQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);HH(G,Z);let B=qH({task:{id:$.id,kind:$.kind,vendor:G,repo:$.repo},worktreePath:Z,shell:process.env.SHELL?.trim()||"/bin/zsh",argv:q,promptIntent:$.newTask?{kind:"new-task",prompt:J,spawnerTaskId:(await zH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await JT(X.rpc,{id:$.id,engineBin:q[0]},Z,J,B,{forceNew:z!==void 0});if(M.started&&!M.engineReady)throw new K1(`failed to start hosted engine session for ${$.id}`,"SESSION_FAILED");if(M.started&&U)if(z)gu($.id,z,U);else AT($.id,U);else if(!z)AT($.id);return M}catch(z){if(z instanceof K1)throw z;throw new K1(`hosted engine session failed for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}finally{X.close()}}async function wT($,Z,J,X=zW0){let z=Z.worktreePath;if(!z)z=(await $.request("task.ensureWorktree",{taskId:Z.id})).worktreePath;if(!z)throw new K1(`task ${Z.id} has no worktree`,"NO_WORKTREE");let G=await X.deliverHosted(Z,z,J);if(!G)throw new K1(`failed to start hosted engine session for ${Z.id}`,"SESSION_FAILED");return G}var zW0,MF;var NF=c(()=>{q9();B7();Dj();Pj();Tj();YF();Uj();DT();$8();zW0={deliverHosted:QW0};MF={isTaskRunning:async($)=>(await MF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await XH();if(J)try{Z=await QH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (NZ(),sO)),B=Z.filter((M)=>M.alive&&typeof M.pid==="number"&&M.pid>0);if(B.length>0){let M=q(await U());X=new Map(B.map((O)=>[O.key,W(M,O.pid)?.vendor??null]))}}catch{}let z={};try{z=(await Promise.resolve().then(() => (hj(),RT))).readPtyExitRecords()}catch{}let G=xu($);return{tabs:yu(G,$,Z,z,X),running:bu(G,$,Z)}},deliverPrompt:($,Z,J)=>wT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (A4(),mq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (CZ(),cu));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (jH(),au))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => ($c(),eu))).readBranchSignals($),tearDownSession:async($)=>{let Z=await XH();if(Z)try{await QT(Z.rpc,eR(await QH(Z.rpc),$))}catch{}finally{Z.close()}}}});var nj;var Zc=c(()=>{nj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.175",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://github.com/Sma1lboy/rove#readme",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react-task-dialogs":"KOBE_DEV=1 bun ./src/tui-react/component/mock-dialogs-host.tsx","dev:mock-react-filetree":"KOBE_DEV=1 bun ./src/tui-react/panes/filetree/mock-host.tsx","dev:mock-react-sidebar":"KOBE_DEV=1 bun ./src/tui-react/panes/sidebar/mock-host.tsx","dev:mock-react-terminal":"KOBE_DEV=1 bun ./src/tui-react/panes/terminal/mock-host.tsx","dev:mock-react-dialogs":"KOBE_DEV=1 bun ./src/tui-react/mock/dialogs-host.tsx","dev:mock-react-workspace":"KOBE_DEV=1 bun ./src/tui-react/workspace/mock-host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:with-web":"bun run build",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.14","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","kobe-web":"workspace:*","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]}});var Xc={};A$(Xc,{repoSlug:()=>oY,releasePageUrl:()=>vT,recommendedGlobalInstallCommand:()=>yT,isNewerSemver:()=>xT,fetchReleaseSummaries:()=>OF,fetchReleaseNotesRange:()=>gT,fetchReleaseNotes:()=>bT,compareSemver:()=>C3,checkLatestVersion:()=>aY,breakingVersionsCrossed:()=>LF,UPDATE_SCRIPT_URL:()=>ij,UPDATE_COMMAND:()=>DZ,PACKAGE_NAME:()=>fT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function oY(){let $=nj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function yT(){return`npm install -g ${fT}@latest`}function LF($,Z,J=pJ){let[X,z]=C3($,Z)<=0?[$,Z]:[Z,$];return J.filter((G)=>C3(G,X)>0&&C3(G,z)<=0)}async function GW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),oj);try{let X=$.replace("/","%2F"),z=await fetch(`https://registry.npmjs.org/${X}/latest`,{signal:Z.signal,headers:{accept:"application/json"}});if(!z.ok)return null;let G=await z.json();if(typeof G.version!=="string")return null;return G.version}catch{return null}finally{clearTimeout(J)}}function xT($,Z){return C3($,Z)>0}function C3($,Z){let J=(G)=>G.split("-")[0]??G,X=J($).split(".").map((G)=>Number.parseInt(G,10)),z=J(Z).split(".").map((G)=>Number.parseInt(G,10));for(let G=0;G<3;G++){let W=X[G]??0,q=z[G]??0;if(Number.isNaN(W)||Number.isNaN(q))return 0;if(W>q)return 1;if(W<q)return-1}return 0}async function aY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:xT(Z,D$)};if(fq()&&!$.force)return null;let J=await GW0(fT);if(!J)return null;return{current:D$,latest:J,hasUpdate:xT(J,D$)}}function Jc($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function bT($){let Z=oY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),oj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases/tags/${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return null;let W=await G.json();if(typeof W.body!=="string"||typeof W.html_url!=="string")return null;return{body:W.body,url:W.html_url,version:$}}catch{return null}finally{clearTimeout(z)}}async function gT($){let Z=oY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),oj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return[];let W=await G.json();if(!Array.isArray(W))return[];return W.map((q)=>{let U=Jc(q.tag_name);if(!U||typeof q.html_url!=="string"||typeof q.body!=="string")return null;if(C3(U,$.current)<=0)return null;if(C3(U,$.latest)>0)return null;return{version:U,url:q.html_url,body:q.body}}).filter((q)=>q!==null)}catch{return[]}finally{clearTimeout(z)}}async function OF($=12){let Z=oY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),oj);try{let z=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${$}`,{signal:J.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!z.ok)return[];let G=await z.json();if(!Array.isArray(G))return[];return G.map((W)=>{let q=Jc(W.tag_name);if(!q||typeof W.html_url!=="string")return null;return{version:q,url:W.html_url}}).filter((W)=>W!==null)}catch{return[]}finally{clearTimeout(X)}}function vT($){let Z=oY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,fT,ij="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",DZ,pJ,oj=3000;var c8=c(()=>{Zc();j5();D$=nj.version,fT=nj.name;DZ=`curl -fsSL ${ij} | sh`;pJ=[]});function i4($){if(!$.client)throw new K1("daemon required","BAD_DAEMON");return $.client}async function Z4($,Z,J){return i4($).request(Z,J)}async function Qc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (G9(),oR)),Promise.resolve().then(() => (T7(),dR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=c(()=>{$8()});async function WW0($){let Z=$.args.require("command"),J=lQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===uY?{generic:!0}:{}}}var zc,Yc;var kT=c(()=>{q9();f2();B2();zc={name:"engine-list",summary:"List every engine Rove can launch \u2014 built-ins and your registered presets \u2014 each with its RAW launch command, exactly as it runs. Copy one into `add --command` / `send --tab new --command` verbatim, or edit its flags first. `protocol` is the adapter Rove speaks to it (history, trust, delivery); `generic` = none, which still runs fine but loses transcript reads. Returns { engines }.",flags:[],offline:!0,handler:async()=>({engines:nm()})};Yc={name:"set-command",summary:"Set a task's engine launch command (takes effect on the next session rebuild). The protocol Rove speaks to it is derived from the command \u2014 the result reports which one, `generic` when the command names no engine Rove knows.",flags:[$$.taskId(),{...$$.command(),required:!0}],handler:WW0}});function Hc($){let Z=$.args.str("precheck");if(Z===void 0)return{};if(Z.length===0)return{precheck:null};return{precheck:{command:Z,timeoutSeconds:$.args.int("precheck-timeout")??120}}}var Gc,Wc,qc,Uc;var Bc=c(()=>{f2();B2();Gc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Wc=[{name:"precheck",type:"string",placeholder:"CMD",description:"Shell command run in the repo BEFORE the engine starts. Non-zero exit skips the run without spawning an agent \u2014 the cheap way to avoid burning a turn when nothing changed."},{name:"precheck-timeout",type:"int",placeholder:"SEC",description:"Seconds before the precheck is killed and the run skipped (default 120)."}],qc={name:"grace",type:"int",placeholder:"MIN",description:"How late a missed occurrence may still run when the daemon was down (default 60). Only the most recent missed occurrence is ever run."};Uc=[{name:"routine-list",summary:"List scheduled routines with their next run time.",flags:[],handler:($)=>Z4($,"automation.list",{})},{name:"routine-create",summary:"Schedule a prompt. Each firing creates a fresh task (worktree + engine) and delivers it. An enabled routine keeps the daemon alive so it fires with no TUI attached.",flags:[$$.repo(),{name:"name",type:"string",required:!0,placeholder:"N",description:"Routine name."},$$.prompt(!0,"Text delivered as the new session's first message."),{...Gc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Wc,qc,{name:"disabled",type:"bool",description:"Create it paused instead of active."}],handler:($)=>Z4($,"automation.create",{repo:$.args.requirePath("repo"),name:$.args.require("name"),prompt:$.args.require("prompt"),schedule:$.args.require("schedule"),...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")?{baseRef:$.args.str("base-branch")}:{},...Hc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{},...$.args.bool("disabled")?{enabled:!1}:{}})},{name:"routine-update",summary:"Change a routine. A new --schedule re-anchors its next run; --precheck '' clears the precheck.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"name",type:"string",placeholder:"N",description:"New name."},$$.prompt(!1,"New prompt."),Gc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Wc,qc],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),...$.args.str("name")!==void 0?{name:$.args.str("name")}:{},...$.args.str("prompt")!==void 0?{prompt:$.args.str("prompt")}:{},...$.args.str("schedule")!==void 0?{schedule:$.args.str("schedule")}:{},...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")!==void 0?{baseRef:$.args.str("base-branch")}:{},...Hc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{}})},{name:"routine-set-enabled",summary:"Pause or resume a routine. Disabling the last active one releases the daemon's keep-alive hold.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"enabled",type:"bool",required:!0,description:"true to resume, false to pause."}],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),enabled:$.args.bool("enabled")})},{name:"routine-delete",summary:"Delete a routine and its run history. Tasks it already created are untouched.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.delete",{id:$.args.require("id")})},{name:"routine-run-now",summary:"Run a routine immediately, skipping its precheck (asking for it IS the answer). Does not shift its schedule.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runNow",{id:$.args.require("id")})},{name:"routine-runs",summary:"Run history, newest first. Statuses: dispatched, skipped_precheck (nothing to do), skipped_missed, skipped_unavailable, dispatch_failed.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runs",{id:$.args.require("id")})}]});async function Kc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:lQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Fc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Mc($){let{args:Z,runtime:J}=$,X=await J.resolveRepoRoot(Z.requirePath("repo")),z=Z.int("count"),G=Z.str("agents");if(z!==void 0||G)return HW0($,X,z,G);return qW0($,X)}async function qW0($,Z){let J=i4($),{args:X}=$,z=await Kc($,Z),G={repo:Z,...await YT(),...Fc(z)},W=X.str("title");if(W)G.title=W;let q=X.str("branch");if(q)G.branch=q;let U=X.str("base-branch");if(U)G.baseRef=U;let B=await J.request("task.create",G),M=B.taskId;if(X.bool("activate"))await J.request("task.setActive",{taskId:M});let O=X.enumOf("status");if(O)await J.request("task.status",{taskId:M,status:O});let N=X.bool("pin");if(N!==void 0)await J.request("task.pin",{taskId:M,pinned:N});let j=B.task;if(O||N!==void 0)j=(await J.request("task.get",{taskId:M})).task;let D=X.str("prompt");if(!D)return{taskId:M,task:j,started:!1};let C=await $.runtime.deliverPrompt(J,{id:M,worktreePath:j.worktreePath,kind:j.kind,vendor:j.vendor,command:j.command,modelEffort:j.modelEffort,repo:j.repo,newTask:!0},D);if(j=(await J.request("task.get",{taskId:M})).task,!C.delivered)throw new K1(`task ${M} created but the prompt was not delivered (paste did not land)`,"NOT_DELIVERED",{taskId:M});return{taskId:M,task:j,started:C.started,engineReady:C.engineReady,session:C.session,delivered:C.delivered}}async function HW0($,Z,J,X){let z=i4($),{args:G}=$,W=G.str("prompt");if(!W)throw new K1("--count/--agents spawn parallel attempts of ONE prompt \u2014 pass --prompt","MISSING_FLAG",L3("add"));if(G.str("branch"))throw new K1("--branch names ONE branch and cannot be shared by parallel siblings \u2014 drop it (each sibling gets its own auto branch) or spawn them one at a time","BAD_FLAG",L3("add"));if(X){let E=J!==void 0?"--count":G.str("command")?"--command":null;if(E)throw new K1(`${E} conflicts with --agents, which already names each sibling's engine and how many \u2014 pass one or the other`,"BAD_FLAG",L3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Kc($,Z),M=X?Nj(X):Lj(J??1,B.vendor??"claude");if(M.length>OZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${OZ} \u2014 spawn in batches`,"BAD_FLAG");let O=BO(),N=[],j=null,D=await YT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Fc(w)};if(q)f.title=M.length>1?`${q} #${E+1}/${M.length}`:q;if(U)f.baseRef=U;try{let y=await z.request("task.create",f);N.push({taskId:y.taskId,vendor:T,task:y.task})}catch(y){let h=y instanceof K1?y.code:"CREATE_FAILED",p=y instanceof Error?y.message:String(y);j={vendor:T,error:{message:p,code:h}};break}}let C=await Promise.allSettled(N.map(({taskId:E,vendor:T,task:w})=>$.runtime.deliverPrompt(z,{id:E,worktreePath:w.worktreePath,kind:w.kind,vendor:T,command:w.command,modelEffort:w.modelEffort,repo:w.repo,newTask:!0},W))),_=[],g=[];if(C.forEach((E,T)=>{let{taskId:w,vendor:f}=N[T];if(E.status==="fulfilled"&&E.value.delivered){_.push({ok:!0,taskId:w,vendor:f,started:E.value.started,engineReady:E.value.engineReady,session:E.value.session});return}let y=E.status==="rejected"?E.reason:new K1(`prompt was not confirmed in ${w}'s engine`,"NOT_DELIVERED"),h=y instanceof K1?y.code:"DELIVER_FAILED",p=y instanceof Error?y.message:String(y);g.push({ok:!1,taskId:w,vendor:f,error:{message:p,code:h}})}),j)g.push({ok:!1,vendor:j.vendor,error:j.error});let I={count:N.length,requested:M.length,groupId:O,tasks:_,failures:g};if(g.length>0)throw new K1(`add delivered ${_.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Nc=c(()=>{q9();bP();YF();f2();B2();$8()});var aj;var mT=c(()=>{aj=["backlog","in_progress","in_review","done","canceled","error"]});var Lc;var Oc=c(()=>{f2();Nc();mT();Lc=[{name:"add",summary:`Create a task (shows in the sidebar immediately). With --prompt it also starts the engine and delivers it. PARALLEL ATTEMPTS: --count N spawns N sibling tasks of the SAME prompt, each in its own worktree/branch (--agents claude:2,codex:1 for a mixed fleet); capped at ${OZ}, prefer 3-4. Does NOT steal focus \u2014 pass --activate to make it the active task. Alias: spawn-task.`,flags:[$$.repo(),$$.title(),{name:"branch",type:"string",placeholder:"B",description:"Explicit branch name (else derived from the title in the repo's own style). Single task only."},{name:"base-branch",type:"string",placeholder:"B",description:"Base ref the worktree branches from."},$$.command(),{name:"count",type:"int",placeholder:"N",description:`Spawn N sibling tasks of one prompt (parallel attempts, cap ${OZ}). Requires --prompt.`},{name:"agents",type:"string",placeholder:"claude:2,codex:1",description:"Per-ENGINE counts for a mixed parallel round (alternative to --count). Engine ids only \u2014 see `engine-list`."},{name:"status",type:"enum",values:aj,default:"backlog",description:"Initial lifecycle status."},{name:"pin",type:"bool",description:"Pin the task to the top of the sidebar."},{name:"activate",type:"bool",default:"false",description:"Make this the active task (pulls every mounted TUI's Tasks-pane focus). Off by default."},$$.prompt(!1,"Optional first message \u2014 when set, materializes the worktree, starts the engine, and pastes it. Required with --count/--agents.")],handler:Mc}]});var jc,Vc;var _c=c(()=>{hJ();f2();B2();NF();$8();jc={name:"pane-open",summary:"Open a terminal pane in a task's workspace: split the focused tab (default, or --tab's tab) or open a separate command tab, optionally running a command. Broadcast over the daemon's tab.open channel \u2014 an attached TUI showing the task performs the split. Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"tab",type:"string",placeholder:"TAB",description:"Host tab for the split (e.g. tab-3) instead of the focused tab (split placement only)."},{name:"command",type:"string",placeholder:"CMD",description:"Shell command the pane runs (via the login shell's `-ilc`, so pipes/args and your shell rc's PATH/exports work); the pane closes when it exits. Omit for an interactive shell."},{name:"direction",type:"enum",values:["right","down"],default:"right",description:"Split orientation relative to the active pane (split placement only)."},{name:"placement",type:"enum",values:["split","tab"],default:"split",description:"`split` joins the focused tab's split group; `tab` opens a separate command tab."},{name:"title",type:"string",placeholder:"TEXT",description:`Pane label (default: the command's first word, else "shell").`}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("command"),z=y2({fallback:"/bin/sh"}),G=X?[z,"-ilc",X]:[z,"-il"],W=$.args.str("title")??(X?X.trim().split(/\s+/)[0]??"shell":"shell"),q=$.args.str("tab");return Z4($,"tab.open",{taskId:J,argv:G,title:W,...q!==void 0?{tabId:q}:{},placement:$.args.str("placement")??"split",direction:$.args.str("direction")??"right"})}},Vc={name:"pane-close",summary:"Close panes opened by pane-open: every split pane / command tab in the task whose label matches --title. Broadcast over the daemon's tab.close channel \u2014 an attached TUI showing the task performs the close (headless no-op). Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Pane label to close \u2014 the --title the pane was opened with (engine panes are never closed)."},{name:"tab",type:"string",placeholder:"TAB",description:"Scope the title match to one tab (e.g. tab-3) instead of every tab of the task."}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("tab");return Z4($,"tab.close",{taskId:J,title:$.args.str("title"),...X!==void 0?{tabId:X}:{}})}}});var hT,jF,uT,cT="DIRTY_WORKTREE",lT,dT,UW0="TASK_DELETING",nQ,BW0="MAIN_CHECKOUT_DIRTY",pT,KW0="EMPTY_BRANCH",nT,rj="EMPTY_BRANCH_DIRTY_WORKTREE",iT,FW0="LAND_CONFLICT",sj;var nJ=c(()=>{hT=class hT extends Error{from;to;taskId;constructor($,Z,J){super(`illegal transition for task ${J}: ${$} -> ${Z}`);this.from=$;this.to=Z;this.taskId=J;this.name="IllegalTransitionError"}};jF=class jF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};uT=class uT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};lT=class lT extends Error{taskId;constructor($){super(`${cT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};dT=class dT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};nQ=class nQ extends Error{taskId;constructor($){super(`${UW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};pT=class pT extends Error{repo;dir;constructor($,Z){super(`${BW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};nT=class nT extends Error{branch;landedOn;constructor($,Z){super(`${KW0}: '${$}' has no commits ahead of '${Z}' \u2014 landing it would be a no-op (the worker may not have delivered anything)`);this.branch=$;this.landedOn=Z;this.name="EmptyBranchError"}};iT=class iT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${rj}: '${$}' has no commits ahead of '${Z}' but its worktree ${J} has uncommitted changes (${z}) \u2014 commit them in the worktree first, then land again`);this.branch=$;this.landedOn=Z;this.worktreePath=J;this.files=X;this.name="EmptyBranchDirtyWorktreeError"}};sj=class sj extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${FW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function MW0($,Z,J){let X=await zH(),z=X?.taskId;if(!z||z===Z)return J;let G=z;try{let U=await $.request("task.get",{taskId:z});G=U.task.title||U.task.branch||z}catch{}let W=V3(),q=`--task-id ${z} --tab ${X.tabId}`;return`[ROVE PEER] from "${G}" (task ${z} \u2014 load the Rove agent skill FIRST (registered as /rove; legacy /kobe installs still work), then reply: \`${W} send ${q} --prompt "<text>"\`; verb reference: \`${W} schema\`): ${J}`}async function Cc($){let Z=$.args.str("title"),J=$.args.str("body"),X=$.args.str("task");if(Z===void 0&&J===void 0&&X===void 0)throw new K1("issue-update requires --title, --body, and/or --task","MISSING_FLAG");let z=$.args.requirePath("repo"),G=$.args.int("id"),W;if(Z!==void 0||J!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:{type:"update",id:G,title:Z,body:J}});if(X!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:X==="none"?{type:"unlink",id:G}:{type:"link",id:G,taskId:X}});return W}async function Ac($){let Z=i4($),J=$.args.require("prompt"),X=$.args.str("tab");if(X&&X!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(X))throw new K1(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(X)})`,"BAD_TAB");let z=$.args.str("command");if(z&&X!=="new")throw new K1(`--command only applies to a new tab; pass --tab new (got --tab ${X??"<canonical>"})`,"BAD_FLAG",L3("send"));let G=z?lQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await mm(Z);if(M){if(W=M.taskId,X===void 0)X=await hm($.runtime,M)}else{let O=await uJ(Z);if(!O)throw new K1("no --task-id given and no active task \u2014 open a task first or pass --task-id","MISSING_TARGET");W=O}}let q=await Z.request("task.get",{taskId:W}),U=$.args.bool("plain")?J:await MW0(Z,W,J),B=await $.runtime.deliverPrompt(Z,{id:W,worktreePath:q.task.worktreePath,kind:q.task.kind,vendor:q.task.vendor,command:q.task.command,modelEffort:z?void 0:q.task.modelEffort,repo:q.task.repo,tab:X,tabVendor:G,tabCommand:z},U);if(!B.delivered)throw new K1(`prompt was not confirmed in ${W}'s engine (paste did not land)`,"NOT_DELIVERED");return{ok:!0,taskId:W,session:B.session,started:B.started,engineReady:B.engineReady}}async function NW0($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("prompt"),z=$.args.str("tab"),G=await Z.request("session.deliver",{taskId:J,text:X,...z!==void 0?{tabId:z}:{},source:"dispatcher"});return{ok:!0,taskId:J,...z!==void 0?{tabId:z}:{},routed:"session.deliver",...G?.clients!==void 0?{clients:G.clients}:{}}}async function Pc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Rc($){let Z=i4($),J=$.args.require("task-id"),X=await Z.request("task.get",{taskId:J}),{tabs:z,running:G}=await $.runtime.taskTabs(J);return{task:X.task,running:G,tabs:z}}async function Tc($){return i4($).request("task.list")}async function Sc($){let Z=i4($),X=$.args.bool("none")?null:$.args.require("task-id");return await Z.request("task.setActive",{taskId:X}),{ok:!0,activeTaskId:X}}async function Ic($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("archived")??!0,z=await Z.request("task.archive",{taskId:J,archived:X});if(X)await $.runtime.tearDownSession(J);return z}async function Ec($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("force")??!1,z=$.args.bool("delete-branch")??!1,G=await Z.request("task.delete",{taskId:J,force:X,deleteBranch:z});return await $.runtime.tearDownSession(J),G}async function wc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.str("strategy")==="squash"?"squash":"merge",z=$.args.bool("remove-worktree")??!1,G;try{G=await Z.request("task.land",{taskId:J,strategy:X,deleteBranch:$.args.bool("delete-branch")??!1,archive:$.args.bool("then-archive")??!1,removeWorktree:z,...z?{callerCwd:process.cwd()}:{}})}catch(W){throw LW0(W,J)}return{ok:!0,taskId:J,...G.result}}function LW0($,Z){let J=M1($);if(!J.includes(rj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,rj,{hint:"the worker wrote files but never committed them \u2014 send it back to commit its own work, then land again",nextCommandArgs:["api","send","--task-id",Z,"--prompt",`your work is uncommitted on ${X} \u2014 commit it yourself with a proper message, then report back`]})}async function xc($){let Z=i4($),{args:J}=$,X={repo:J.requirePath("repo"),worktreePath:J.requirePath("worktree")},z=J.str("branch");if(z)X.branch=z;let G=J.str("command");if(G)X.command=G,X.vendor=lQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Dc;var VH=c(()=>{q9();B7();nJ();YF();f2();B2();NF();$8();Dc={name:"dispatch",summary:"Route text into a task's live session via the daemon's session.deliver channel. The dispatcher's messenger (docs/design/dispatcher.md); unlike `send`, it requires an already-hosted session.",flags:[$$.taskId(!0),$$.prompt(!0,"Text delivered into the task's engine session."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:"Deliver into exactly this tab (e.g. tab-3) instead of the canonical engine tab."}],handler:NW0}});var fc;var yc=c(()=>{f2();B2();_c();VH();fc=[{name:"send",summary:"Paste a follow-up prompt into a task's running engine (one full turn). Without --task-id, a task spawned from another Rove session replies to its dispatcher's tab (then that task's live canonical engine; nothing alive = DISPATCHER_UNREACHABLE, never a silent spawn); otherwise the active task. Sent from inside another Rove task ($ROVE_TASK_ID), the prompt is prefixed with [ROVE PEER] provenance \u2014 who sent it and how to reply (tab-precise) \u2014 so agent-to-agent messaging needs no coordinator.",flags:[$$.taskId(!1),$$.prompt(!0,"Text pasted + submitted into the engine pane."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Tab addressing: "new" spawns the prompt in a fresh engine tab; "tab-N" delivers to that exact alive tab (error when dead/absent). Omitted = the canonical engine tab.'},{...$$.command(),description:"Engine launch command for a `--tab new` tab \u2014 the API twin of the TUI's ctrl+e pick. Lets one worktree run two agents on the same files (e.g. hand the stuck work to codex without leaving the branch). An engine id from `engine-list` or a full command line; pinned to that tab, so it survives restarts and a later set-command on the task. Only valid with --tab new."},{name:"plain",type:"bool",required:!1,description:"Deliver the prompt verbatim \u2014 skip the [ROVE PEER] provenance prefix."}],handler:Ac},Dc,{name:"note",summary:"File a one-line field note \u2014 a resolved, repo-level gotcha worth sharing. Appended to the repo's durable note store (every future session on this repo starts with it) and forwarded to the dispatcher session for live relay (docs/design/dispatcher.md).",flags:[$$.taskId(!0),{name:"text",type:"string",required:!0,placeholder:"TEXT",description:"One line: the verified conclusion another session could act on."}],handler:Pc},{name:"note-list",summary:"Read a repo's accumulated field notes, newest first. Returns { notes }.",flags:[$$.repo(!0)],handler:($)=>Z4($,"note.list",{repo:$.args.requirePath("repo")})},jc,Vc,{name:"notify",summary:"Show a toast in every attached Rove UI \u2014 broadcast over the daemon's notice.event channel. Agents/scripts use it to surface 'done / needs input / error' moments without touching the task's session.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Toast text (one line)."},{name:"kind",type:"string",default:"done",placeholder:"KIND",description:`Free-form kind tag. "done", "needs_input" and "error" get the TUI's severity styling/unread mark; any other value renders neutrally.`},$$.taskId(!1),{name:"source",type:"string",placeholder:"TAG",description:"Free-form origin tag (e.g. an agent name) recorded on the event."}],handler:async($)=>{return Z4($,"notice.send",{title:$.args.str("title"),kind:$.args.str("kind")??"done",taskId:$.args.str("task-id"),source:$.args.str("source")})}},{name:"prompt",summary:"Ask the human for a line of text through the attached TUI's input dialog (plugins' host-provided prompt). Blocks until answered, cancelled, or timed out; returns { value } or { cancelled, reason }.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Dialog title (shown verbatim)."},{name:"placeholder",type:"string",placeholder:"TEXT",description:"Input placeholder."},{name:"initial",type:"string",placeholder:"TEXT",description:"Pre-filled input value."},{name:"timeout",type:"string",placeholder:"MS",description:"Give up after this many milliseconds (default 120000, max 600000)."}],handler:async($)=>{let Z=$.args.str("timeout"),J=Z?Number.parseInt(Z,10):void 0;return Z4($,"ui.prompt",{title:$.args.str("title"),placeholder:$.args.str("placeholder"),initial:$.args.str("initial"),...J&&Number.isFinite(J)?{timeoutMs:J}:{}})}},{name:"set-active",summary:"Set the shared active task (the focus every Tasks pane highlights). Pass --none to clear.",flags:[$$.taskId(!1),{name:"none",type:"bool",description:"Clear the active task instead of setting one."}],handler:Sc}]});var bc;var gc=c(()=>{f2();B2();kT();mT();bc=[{name:"rename",summary:"Set a task's title.",flags:[$$.taskId(),{name:"title",type:"string",required:!0,placeholder:"T",description:"New title."}],handler:($)=>Z4($,"task.rename",{taskId:$.args.require("task-id"),title:$.args.require("title")})},{name:"set-branch",summary:"Rename a task's branch (git branch -m if materialized, else recorded).",flags:[$$.taskId(),{name:"branch",type:"string",required:!0,placeholder:"B",description:"New branch name."}],handler:($)=>Z4($,"task.setBranch",{taskId:$.args.require("task-id"),branch:$.args.require("branch")})},Yc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:aj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as OW0}from"child_process";function _W0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function vc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function kc($,Z){let J=Z?.map((X)=>typeof X.message==="string"?X.message:null).filter((X)=>!!X);if(J&&J.length>0)return J.join("; ");return $.trim()||"GitHub CLI returned an empty response"}function mc($,Z,J){let X=["api","graphql","-f",`query=${$}`];for(let[U,B]of Object.entries(Z))X.push("-f",`${U}=${B}`);let z=J.spawn("gh",X,{encoding:"utf8"});if(z.error)throw Error(`failed to run gh: ${z.error.message}`);let G=typeof z.stdout==="string"?z.stdout:String(z.stdout??""),W=typeof z.stderr==="string"?z.stderr:String(z.stderr??""),q;try{q=JSON.parse(G)}catch{throw Error(`failed to parse gh response: ${kc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(kc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function CW0($){return`${$}
|
|
82
|
+
`)){let X=J.replace(/\r$/,"");if(X.length===0)continue;let z=X.indexOf("\t");if(z<0)continue;let G=X.indexOf("\t",z+1);if(G<0)continue;let W=X.slice(G+1);if(W.length===0)continue;let q=eG0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:pu(X.slice(0,z)),deleted:pu(X.slice(z+1,G))})}return Z}var sG0,tG0;var lj=c(()=>{sG0=new TextEncoder,tG0=new TextDecoder});var au={};A$(au,{sameWorktreeChanges:()=>FF,readWorktreeChanges:()=>ZW0,pickPushedChanges:()=>ET,parsePorcelain:()=>OH});import{spawnSync as $W0}from"child_process";function FF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function ET($,Z){if(!$)return null;return $.get(Z)??dj}function ZW0($){if(!$)return dj;try{let Z=$W0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return dj;return OH(Z.stdout)}catch{return dj}}function OH($){let Z=0,J=0;for(let{x:X,y:z}of cj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var dj;var jH=c(()=>{dJ();lj();dj={added:0,deleted:0}});var eu={};A$(eu,{resolveBaseRef:()=>su,readBranchSignals:()=>XW0,parseShortstat:()=>tu});import{spawnSync as JW0}from"child_process";function pj($,Z){try{let J=JW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function su($){let Z=pj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(pj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function tu($){let Z=(J)=>{let X=$.match(J);return X?Number.parseInt(X[1]??"0",10):0};return{files:Z(/(\d+) files? changed/),insertions:Z(/(\d+) insertions?\(\+\)/),deletions:Z(/(\d+) deletions?\(-\)/)}}function XW0($){if(!$)return ru;let Z=su($);if(!Z)return ru;let J=pj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=pj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:tu(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var ru;var $c=c(()=>{dJ();ru={baseRef:null,ahead:null,diff:null}});async function QW0($,Z,J){let X;try{X=await $T()}catch(z){throw new K1(`failed to start PTY host for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}try{if($.tab&&$.tab!=="new"){let O=U2({command:$.command,vendor:$.vendor,effort:$.modelEffort})[0];return await XT(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?vu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=cQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);HH(G,Z);let B=qH({task:{id:$.id,kind:$.kind,vendor:G,repo:$.repo},worktreePath:Z,shell:process.env.SHELL?.trim()||"/bin/zsh",argv:q,promptIntent:$.newTask?{kind:"new-task",prompt:J,spawnerTaskId:(await zH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await JT(X.rpc,{id:$.id,engineBin:q[0]},Z,J,B,{forceNew:z!==void 0});if(M.started&&!M.engineReady)throw new K1(`failed to start hosted engine session for ${$.id}`,"SESSION_FAILED");if(M.started&&U)if(z)gu($.id,z,U);else AT($.id,U);else if(!z)AT($.id);return M}catch(z){if(z instanceof K1)throw z;throw new K1(`hosted engine session failed for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}finally{X.close()}}async function wT($,Z,J,X=zW0){let z=Z.worktreePath;if(!z)z=(await $.request("task.ensureWorktree",{taskId:Z.id})).worktreePath;if(!z)throw new K1(`task ${Z.id} has no worktree`,"NO_WORKTREE");let G=await X.deliverHosted(Z,z,J);if(!G)throw new K1(`failed to start hosted engine session for ${Z.id}`,"SESSION_FAILED");return G}var zW0,MF;var NF=c(()=>{q9();B7();Dj();Pj();Tj();YF();Uj();DT();$8();zW0={deliverHosted:QW0};MF={isTaskRunning:async($)=>(await MF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await XH();if(J)try{Z=await QH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (NZ(),sO)),B=Z.filter((M)=>M.alive&&typeof M.pid==="number"&&M.pid>0);if(B.length>0){let M=q(await U());X=new Map(B.map((O)=>[O.key,W(M,O.pid)?.vendor??null]))}}catch{}let z={};try{z=(await Promise.resolve().then(() => (hj(),RT))).readPtyExitRecords()}catch{}let G=xu($);return{tabs:yu(G,$,Z,z,X),running:bu(G,$,Z)}},deliverPrompt:($,Z,J)=>wT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (A4(),mq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (CZ(),cu));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (jH(),au))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => ($c(),eu))).readBranchSignals($),tearDownSession:async($)=>{let Z=await XH();if(Z)try{await QT(Z.rpc,eR(await QH(Z.rpc),$))}catch{}finally{Z.close()}}}});var nj;var Zc=c(()=>{nj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.176",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://github.com/Sma1lboy/rove#readme",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react-task-dialogs":"KOBE_DEV=1 bun ./src/tui-react/component/mock-dialogs-host.tsx","dev:mock-react-filetree":"KOBE_DEV=1 bun ./src/tui-react/panes/filetree/mock-host.tsx","dev:mock-react-sidebar":"KOBE_DEV=1 bun ./src/tui-react/panes/sidebar/mock-host.tsx","dev:mock-react-terminal":"KOBE_DEV=1 bun ./src/tui-react/panes/terminal/mock-host.tsx","dev:mock-react-dialogs":"KOBE_DEV=1 bun ./src/tui-react/mock/dialogs-host.tsx","dev:mock-react-workspace":"KOBE_DEV=1 bun ./src/tui-react/workspace/mock-host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:with-web":"bun run build",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.14","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","kobe-web":"workspace:*","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]}});var Xc={};A$(Xc,{repoSlug:()=>oY,releasePageUrl:()=>vT,recommendedGlobalInstallCommand:()=>yT,isNewerSemver:()=>xT,fetchReleaseSummaries:()=>OF,fetchReleaseNotesRange:()=>gT,fetchReleaseNotes:()=>bT,compareSemver:()=>C3,checkLatestVersion:()=>aY,breakingVersionsCrossed:()=>LF,UPDATE_SCRIPT_URL:()=>ij,UPDATE_COMMAND:()=>DZ,PACKAGE_NAME:()=>fT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function oY(){let $=nj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function yT(){return`npm install -g ${fT}@latest`}function LF($,Z,J=pJ){let[X,z]=C3($,Z)<=0?[$,Z]:[Z,$];return J.filter((G)=>C3(G,X)>0&&C3(G,z)<=0)}async function GW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),oj);try{let X=$.replace("/","%2F"),z=await fetch(`https://registry.npmjs.org/${X}/latest`,{signal:Z.signal,headers:{accept:"application/json"}});if(!z.ok)return null;let G=await z.json();if(typeof G.version!=="string")return null;return G.version}catch{return null}finally{clearTimeout(J)}}function xT($,Z){return C3($,Z)>0}function C3($,Z){let J=(G)=>G.split("-")[0]??G,X=J($).split(".").map((G)=>Number.parseInt(G,10)),z=J(Z).split(".").map((G)=>Number.parseInt(G,10));for(let G=0;G<3;G++){let W=X[G]??0,q=z[G]??0;if(Number.isNaN(W)||Number.isNaN(q))return 0;if(W>q)return 1;if(W<q)return-1}return 0}async function aY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:xT(Z,D$)};if(fq()&&!$.force)return null;let J=await GW0(fT);if(!J)return null;return{current:D$,latest:J,hasUpdate:xT(J,D$)}}function Jc($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function bT($){let Z=oY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),oj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases/tags/${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return null;let W=await G.json();if(typeof W.body!=="string"||typeof W.html_url!=="string")return null;return{body:W.body,url:W.html_url,version:$}}catch{return null}finally{clearTimeout(z)}}async function gT($){let Z=oY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),oj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return[];let W=await G.json();if(!Array.isArray(W))return[];return W.map((q)=>{let U=Jc(q.tag_name);if(!U||typeof q.html_url!=="string"||typeof q.body!=="string")return null;if(C3(U,$.current)<=0)return null;if(C3(U,$.latest)>0)return null;return{version:U,url:q.html_url,body:q.body}}).filter((q)=>q!==null)}catch{return[]}finally{clearTimeout(z)}}async function OF($=12){let Z=oY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),oj);try{let z=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${$}`,{signal:J.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!z.ok)return[];let G=await z.json();if(!Array.isArray(G))return[];return G.map((W)=>{let q=Jc(W.tag_name);if(!q||typeof W.html_url!=="string")return null;return{version:q,url:W.html_url}}).filter((W)=>W!==null)}catch{return[]}finally{clearTimeout(X)}}function vT($){let Z=oY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,fT,ij="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",DZ,pJ,oj=3000;var c8=c(()=>{Zc();j5();D$=nj.version,fT=nj.name;DZ=`curl -fsSL ${ij} | sh`;pJ=[]});function i4($){if(!$.client)throw new K1("daemon required","BAD_DAEMON");return $.client}async function Z4($,Z,J){return i4($).request(Z,J)}async function Qc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (G9(),oR)),Promise.resolve().then(() => (T7(),dR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=c(()=>{$8()});async function WW0($){let Z=$.args.require("command"),J=lQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===uY?{generic:!0}:{}}}var zc,Yc;var kT=c(()=>{q9();f2();B2();zc={name:"engine-list",summary:"List every engine Rove can launch \u2014 built-ins and your registered presets \u2014 each with its RAW launch command, exactly as it runs. Copy one into `add --command` / `send --tab new --command` verbatim, or edit its flags first. `protocol` is the adapter Rove speaks to it (history, trust, delivery); `generic` = none, which still runs fine but loses transcript reads. Returns { engines }.",flags:[],offline:!0,handler:async()=>({engines:nm()})};Yc={name:"set-command",summary:"Set a task's engine launch command (takes effect on the next session rebuild). The protocol Rove speaks to it is derived from the command \u2014 the result reports which one, `generic` when the command names no engine Rove knows.",flags:[$$.taskId(),{...$$.command(),required:!0}],handler:WW0}});function Hc($){let Z=$.args.str("precheck");if(Z===void 0)return{};if(Z.length===0)return{precheck:null};return{precheck:{command:Z,timeoutSeconds:$.args.int("precheck-timeout")??120}}}var Gc,Wc,qc,Uc;var Bc=c(()=>{f2();B2();Gc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Wc=[{name:"precheck",type:"string",placeholder:"CMD",description:"Shell command run in the repo BEFORE the engine starts. Non-zero exit skips the run without spawning an agent \u2014 the cheap way to avoid burning a turn when nothing changed."},{name:"precheck-timeout",type:"int",placeholder:"SEC",description:"Seconds before the precheck is killed and the run skipped (default 120)."}],qc={name:"grace",type:"int",placeholder:"MIN",description:"How late a missed occurrence may still run when the daemon was down (default 60). Only the most recent missed occurrence is ever run."};Uc=[{name:"routine-list",summary:"List scheduled routines with their next run time.",flags:[],handler:($)=>Z4($,"automation.list",{})},{name:"routine-create",summary:"Schedule a prompt. Each firing creates a fresh task (worktree + engine) and delivers it. An enabled routine keeps the daemon alive so it fires with no TUI attached.",flags:[$$.repo(),{name:"name",type:"string",required:!0,placeholder:"N",description:"Routine name."},$$.prompt(!0,"Text delivered as the new session's first message."),{...Gc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Wc,qc,{name:"disabled",type:"bool",description:"Create it paused instead of active."}],handler:($)=>Z4($,"automation.create",{repo:$.args.requirePath("repo"),name:$.args.require("name"),prompt:$.args.require("prompt"),schedule:$.args.require("schedule"),...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")?{baseRef:$.args.str("base-branch")}:{},...Hc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{},...$.args.bool("disabled")?{enabled:!1}:{}})},{name:"routine-update",summary:"Change a routine. A new --schedule re-anchors its next run; --precheck '' clears the precheck.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"name",type:"string",placeholder:"N",description:"New name."},$$.prompt(!1,"New prompt."),Gc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Wc,qc],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),...$.args.str("name")!==void 0?{name:$.args.str("name")}:{},...$.args.str("prompt")!==void 0?{prompt:$.args.str("prompt")}:{},...$.args.str("schedule")!==void 0?{schedule:$.args.str("schedule")}:{},...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")!==void 0?{baseRef:$.args.str("base-branch")}:{},...Hc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{}})},{name:"routine-set-enabled",summary:"Pause or resume a routine. Disabling the last active one releases the daemon's keep-alive hold.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"enabled",type:"bool",required:!0,description:"true to resume, false to pause."}],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),enabled:$.args.bool("enabled")})},{name:"routine-delete",summary:"Delete a routine and its run history. Tasks it already created are untouched.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.delete",{id:$.args.require("id")})},{name:"routine-run-now",summary:"Run a routine immediately, skipping its precheck (asking for it IS the answer). Does not shift its schedule.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runNow",{id:$.args.require("id")})},{name:"routine-runs",summary:"Run history, newest first. Statuses: dispatched, skipped_precheck (nothing to do), skipped_missed, skipped_unavailable, dispatch_failed.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runs",{id:$.args.require("id")})}]});async function Kc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:lQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Fc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Mc($){let{args:Z,runtime:J}=$,X=await J.resolveRepoRoot(Z.requirePath("repo")),z=Z.int("count"),G=Z.str("agents");if(z!==void 0||G)return HW0($,X,z,G);return qW0($,X)}async function qW0($,Z){let J=i4($),{args:X}=$,z=await Kc($,Z),G={repo:Z,...await YT(),...Fc(z)},W=X.str("title");if(W)G.title=W;let q=X.str("branch");if(q)G.branch=q;let U=X.str("base-branch");if(U)G.baseRef=U;let B=await J.request("task.create",G),M=B.taskId;if(X.bool("activate"))await J.request("task.setActive",{taskId:M});let O=X.enumOf("status");if(O)await J.request("task.status",{taskId:M,status:O});let N=X.bool("pin");if(N!==void 0)await J.request("task.pin",{taskId:M,pinned:N});let j=B.task;if(O||N!==void 0)j=(await J.request("task.get",{taskId:M})).task;let D=X.str("prompt");if(!D)return{taskId:M,task:j,started:!1};let C=await $.runtime.deliverPrompt(J,{id:M,worktreePath:j.worktreePath,kind:j.kind,vendor:j.vendor,command:j.command,modelEffort:j.modelEffort,repo:j.repo,newTask:!0},D);if(j=(await J.request("task.get",{taskId:M})).task,!C.delivered)throw new K1(`task ${M} created but the prompt was not delivered (paste did not land)`,"NOT_DELIVERED",{taskId:M});return{taskId:M,task:j,started:C.started,engineReady:C.engineReady,session:C.session,delivered:C.delivered}}async function HW0($,Z,J,X){let z=i4($),{args:G}=$,W=G.str("prompt");if(!W)throw new K1("--count/--agents spawn parallel attempts of ONE prompt \u2014 pass --prompt","MISSING_FLAG",L3("add"));if(G.str("branch"))throw new K1("--branch names ONE branch and cannot be shared by parallel siblings \u2014 drop it (each sibling gets its own auto branch) or spawn them one at a time","BAD_FLAG",L3("add"));if(X){let E=J!==void 0?"--count":G.str("command")?"--command":null;if(E)throw new K1(`${E} conflicts with --agents, which already names each sibling's engine and how many \u2014 pass one or the other`,"BAD_FLAG",L3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Kc($,Z),M=X?Nj(X):Lj(J??1,B.vendor??"claude");if(M.length>OZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${OZ} \u2014 spawn in batches`,"BAD_FLAG");let O=BO(),N=[],j=null,D=await YT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Fc(w)};if(q)f.title=M.length>1?`${q} #${E+1}/${M.length}`:q;if(U)f.baseRef=U;try{let y=await z.request("task.create",f);N.push({taskId:y.taskId,vendor:T,task:y.task})}catch(y){let h=y instanceof K1?y.code:"CREATE_FAILED",p=y instanceof Error?y.message:String(y);j={vendor:T,error:{message:p,code:h}};break}}let C=await Promise.allSettled(N.map(({taskId:E,vendor:T,task:w})=>$.runtime.deliverPrompt(z,{id:E,worktreePath:w.worktreePath,kind:w.kind,vendor:T,command:w.command,modelEffort:w.modelEffort,repo:w.repo,newTask:!0},W))),_=[],g=[];if(C.forEach((E,T)=>{let{taskId:w,vendor:f}=N[T];if(E.status==="fulfilled"&&E.value.delivered){_.push({ok:!0,taskId:w,vendor:f,started:E.value.started,engineReady:E.value.engineReady,session:E.value.session});return}let y=E.status==="rejected"?E.reason:new K1(`prompt was not confirmed in ${w}'s engine`,"NOT_DELIVERED"),h=y instanceof K1?y.code:"DELIVER_FAILED",p=y instanceof Error?y.message:String(y);g.push({ok:!1,taskId:w,vendor:f,error:{message:p,code:h}})}),j)g.push({ok:!1,vendor:j.vendor,error:j.error});let I={count:N.length,requested:M.length,groupId:O,tasks:_,failures:g};if(g.length>0)throw new K1(`add delivered ${_.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Nc=c(()=>{q9();bP();YF();f2();B2();$8()});var aj;var mT=c(()=>{aj=["backlog","in_progress","in_review","done","canceled","error"]});var Lc;var Oc=c(()=>{f2();Nc();mT();Lc=[{name:"add",summary:`Create a task (shows in the sidebar immediately). With --prompt it also starts the engine and delivers it. PARALLEL ATTEMPTS: --count N spawns N sibling tasks of the SAME prompt, each in its own worktree/branch (--agents claude:2,codex:1 for a mixed fleet); capped at ${OZ}, prefer 3-4. Does NOT steal focus \u2014 pass --activate to make it the active task. Alias: spawn-task.`,flags:[$$.repo(),$$.title(),{name:"branch",type:"string",placeholder:"B",description:"Explicit branch name (else derived from the title in the repo's own style). Single task only."},{name:"base-branch",type:"string",placeholder:"B",description:"Base ref the worktree branches from."},$$.command(),{name:"count",type:"int",placeholder:"N",description:`Spawn N sibling tasks of one prompt (parallel attempts, cap ${OZ}). Requires --prompt.`},{name:"agents",type:"string",placeholder:"claude:2,codex:1",description:"Per-ENGINE counts for a mixed parallel round (alternative to --count). Engine ids only \u2014 see `engine-list`."},{name:"status",type:"enum",values:aj,default:"backlog",description:"Initial lifecycle status."},{name:"pin",type:"bool",description:"Pin the task to the top of the sidebar."},{name:"activate",type:"bool",default:"false",description:"Make this the active task (pulls every mounted TUI's Tasks-pane focus). Off by default."},$$.prompt(!1,"Optional first message \u2014 when set, materializes the worktree, starts the engine, and pastes it. Required with --count/--agents.")],handler:Mc}]});var jc,Vc;var _c=c(()=>{hJ();f2();B2();NF();$8();jc={name:"pane-open",summary:"Open a terminal pane in a task's workspace: split the focused tab (default, or --tab's tab) or open a separate command tab, optionally running a command. Broadcast over the daemon's tab.open channel \u2014 an attached TUI showing the task performs the split. Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"tab",type:"string",placeholder:"TAB",description:"Host tab for the split (e.g. tab-3) instead of the focused tab (split placement only)."},{name:"command",type:"string",placeholder:"CMD",description:"Shell command the pane runs (via the login shell's `-ilc`, so pipes/args and your shell rc's PATH/exports work); the pane closes when it exits. Omit for an interactive shell."},{name:"direction",type:"enum",values:["right","down"],default:"right",description:"Split orientation relative to the active pane (split placement only)."},{name:"placement",type:"enum",values:["split","tab"],default:"split",description:"`split` joins the focused tab's split group; `tab` opens a separate command tab."},{name:"title",type:"string",placeholder:"TEXT",description:`Pane label (default: the command's first word, else "shell").`}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("command"),z=y2({fallback:"/bin/sh"}),G=X?[z,"-ilc",X]:[z,"-il"],W=$.args.str("title")??(X?X.trim().split(/\s+/)[0]??"shell":"shell"),q=$.args.str("tab");return Z4($,"tab.open",{taskId:J,argv:G,title:W,...q!==void 0?{tabId:q}:{},placement:$.args.str("placement")??"split",direction:$.args.str("direction")??"right"})}},Vc={name:"pane-close",summary:"Close panes opened by pane-open: every split pane / command tab in the task whose label matches --title. Broadcast over the daemon's tab.close channel \u2014 an attached TUI showing the task performs the close (headless no-op). Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Pane label to close \u2014 the --title the pane was opened with (engine panes are never closed)."},{name:"tab",type:"string",placeholder:"TAB",description:"Scope the title match to one tab (e.g. tab-3) instead of every tab of the task."}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("tab");return Z4($,"tab.close",{taskId:J,title:$.args.str("title"),...X!==void 0?{tabId:X}:{}})}}});var hT,jF,uT,cT="DIRTY_WORKTREE",lT,dT,UW0="TASK_DELETING",nQ,BW0="MAIN_CHECKOUT_DIRTY",pT,KW0="EMPTY_BRANCH",nT,rj="EMPTY_BRANCH_DIRTY_WORKTREE",iT,FW0="LAND_CONFLICT",sj;var nJ=c(()=>{hT=class hT extends Error{from;to;taskId;constructor($,Z,J){super(`illegal transition for task ${J}: ${$} -> ${Z}`);this.from=$;this.to=Z;this.taskId=J;this.name="IllegalTransitionError"}};jF=class jF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};uT=class uT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};lT=class lT extends Error{taskId;constructor($){super(`${cT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};dT=class dT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};nQ=class nQ extends Error{taskId;constructor($){super(`${UW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};pT=class pT extends Error{repo;dir;constructor($,Z){super(`${BW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};nT=class nT extends Error{branch;landedOn;constructor($,Z){super(`${KW0}: '${$}' has no commits ahead of '${Z}' \u2014 landing it would be a no-op (the worker may not have delivered anything)`);this.branch=$;this.landedOn=Z;this.name="EmptyBranchError"}};iT=class iT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${rj}: '${$}' has no commits ahead of '${Z}' but its worktree ${J} has uncommitted changes (${z}) \u2014 commit them in the worktree first, then land again`);this.branch=$;this.landedOn=Z;this.worktreePath=J;this.files=X;this.name="EmptyBranchDirtyWorktreeError"}};sj=class sj extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${FW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function MW0($,Z,J){let X=await zH(),z=X?.taskId;if(!z||z===Z)return J;let G=z;try{let U=await $.request("task.get",{taskId:z});G=U.task.title||U.task.branch||z}catch{}let W=V3(),q=`--task-id ${z} --tab ${X.tabId}`;return`[ROVE PEER] from "${G}" (task ${z} \u2014 load the Rove agent skill FIRST (registered as /rove; legacy /kobe installs still work), then reply: \`${W} send ${q} --prompt "<text>"\`; verb reference: \`${W} schema\`): ${J}`}async function Cc($){let Z=$.args.str("title"),J=$.args.str("body"),X=$.args.str("task");if(Z===void 0&&J===void 0&&X===void 0)throw new K1("issue-update requires --title, --body, and/or --task","MISSING_FLAG");let z=$.args.requirePath("repo"),G=$.args.int("id"),W;if(Z!==void 0||J!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:{type:"update",id:G,title:Z,body:J}});if(X!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:X==="none"?{type:"unlink",id:G}:{type:"link",id:G,taskId:X}});return W}async function Ac($){let Z=i4($),J=$.args.require("prompt"),X=$.args.str("tab");if(X&&X!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(X))throw new K1(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(X)})`,"BAD_TAB");let z=$.args.str("command");if(z&&X!=="new")throw new K1(`--command only applies to a new tab; pass --tab new (got --tab ${X??"<canonical>"})`,"BAD_FLAG",L3("send"));let G=z?lQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await mm(Z);if(M){if(W=M.taskId,X===void 0)X=await hm($.runtime,M)}else{let O=await uJ(Z);if(!O)throw new K1("no --task-id given and no active task \u2014 open a task first or pass --task-id","MISSING_TARGET");W=O}}let q=await Z.request("task.get",{taskId:W}),U=$.args.bool("plain")?J:await MW0(Z,W,J),B=await $.runtime.deliverPrompt(Z,{id:W,worktreePath:q.task.worktreePath,kind:q.task.kind,vendor:q.task.vendor,command:q.task.command,modelEffort:z?void 0:q.task.modelEffort,repo:q.task.repo,tab:X,tabVendor:G,tabCommand:z},U);if(!B.delivered)throw new K1(`prompt was not confirmed in ${W}'s engine (paste did not land)`,"NOT_DELIVERED");return{ok:!0,taskId:W,session:B.session,started:B.started,engineReady:B.engineReady}}async function NW0($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("prompt"),z=$.args.str("tab"),G=await Z.request("session.deliver",{taskId:J,text:X,...z!==void 0?{tabId:z}:{},source:"dispatcher"});return{ok:!0,taskId:J,...z!==void 0?{tabId:z}:{},routed:"session.deliver",...G?.clients!==void 0?{clients:G.clients}:{}}}async function Pc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Rc($){let Z=i4($),J=$.args.require("task-id"),X=await Z.request("task.get",{taskId:J}),{tabs:z,running:G}=await $.runtime.taskTabs(J);return{task:X.task,running:G,tabs:z}}async function Tc($){return i4($).request("task.list")}async function Sc($){let Z=i4($),X=$.args.bool("none")?null:$.args.require("task-id");return await Z.request("task.setActive",{taskId:X}),{ok:!0,activeTaskId:X}}async function Ic($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("archived")??!0,z=await Z.request("task.archive",{taskId:J,archived:X});if(X)await $.runtime.tearDownSession(J);return z}async function Ec($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("force")??!1,z=$.args.bool("delete-branch")??!1,G=await Z.request("task.delete",{taskId:J,force:X,deleteBranch:z});return await $.runtime.tearDownSession(J),G}async function wc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.str("strategy")==="squash"?"squash":"merge",z=$.args.bool("remove-worktree")??!1,G;try{G=await Z.request("task.land",{taskId:J,strategy:X,deleteBranch:$.args.bool("delete-branch")??!1,archive:$.args.bool("then-archive")??!1,removeWorktree:z,...z?{callerCwd:process.cwd()}:{}})}catch(W){throw LW0(W,J)}return{ok:!0,taskId:J,...G.result}}function LW0($,Z){let J=M1($);if(!J.includes(rj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,rj,{hint:"the worker wrote files but never committed them \u2014 send it back to commit its own work, then land again",nextCommandArgs:["api","send","--task-id",Z,"--prompt",`your work is uncommitted on ${X} \u2014 commit it yourself with a proper message, then report back`]})}async function xc($){let Z=i4($),{args:J}=$,X={repo:J.requirePath("repo"),worktreePath:J.requirePath("worktree")},z=J.str("branch");if(z)X.branch=z;let G=J.str("command");if(G)X.command=G,X.vendor=lQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Dc;var VH=c(()=>{q9();B7();nJ();YF();f2();B2();NF();$8();Dc={name:"dispatch",summary:"Route text into a task's live session via the daemon's session.deliver channel. The dispatcher's messenger (docs/design/dispatcher.md); unlike `send`, it requires an already-hosted session.",flags:[$$.taskId(!0),$$.prompt(!0,"Text delivered into the task's engine session."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:"Deliver into exactly this tab (e.g. tab-3) instead of the canonical engine tab."}],handler:NW0}});var fc;var yc=c(()=>{f2();B2();_c();VH();fc=[{name:"send",summary:"Paste a follow-up prompt into a task's running engine (one full turn). Without --task-id, a task spawned from another Rove session replies to its dispatcher's tab (then that task's live canonical engine; nothing alive = DISPATCHER_UNREACHABLE, never a silent spawn); otherwise the active task. Sent from inside another Rove task ($ROVE_TASK_ID), the prompt is prefixed with [ROVE PEER] provenance \u2014 who sent it and how to reply (tab-precise) \u2014 so agent-to-agent messaging needs no coordinator.",flags:[$$.taskId(!1),$$.prompt(!0,"Text pasted + submitted into the engine pane."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Tab addressing: "new" spawns the prompt in a fresh engine tab; "tab-N" delivers to that exact alive tab (error when dead/absent). Omitted = the canonical engine tab.'},{...$$.command(),description:"Engine launch command for a `--tab new` tab \u2014 the API twin of the TUI's ctrl+e pick. Lets one worktree run two agents on the same files (e.g. hand the stuck work to codex without leaving the branch). An engine id from `engine-list` or a full command line; pinned to that tab, so it survives restarts and a later set-command on the task. Only valid with --tab new."},{name:"plain",type:"bool",required:!1,description:"Deliver the prompt verbatim \u2014 skip the [ROVE PEER] provenance prefix."}],handler:Ac},Dc,{name:"note",summary:"File a one-line field note \u2014 a resolved, repo-level gotcha worth sharing. Appended to the repo's durable note store (every future session on this repo starts with it) and forwarded to the dispatcher session for live relay (docs/design/dispatcher.md).",flags:[$$.taskId(!0),{name:"text",type:"string",required:!0,placeholder:"TEXT",description:"One line: the verified conclusion another session could act on."}],handler:Pc},{name:"note-list",summary:"Read a repo's accumulated field notes, newest first. Returns { notes }.",flags:[$$.repo(!0)],handler:($)=>Z4($,"note.list",{repo:$.args.requirePath("repo")})},jc,Vc,{name:"notify",summary:"Show a toast in every attached Rove UI \u2014 broadcast over the daemon's notice.event channel. Agents/scripts use it to surface 'done / needs input / error' moments without touching the task's session.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Toast text (one line)."},{name:"kind",type:"string",default:"done",placeholder:"KIND",description:`Free-form kind tag. "done", "needs_input" and "error" get the TUI's severity styling/unread mark; any other value renders neutrally.`},$$.taskId(!1),{name:"source",type:"string",placeholder:"TAG",description:"Free-form origin tag (e.g. an agent name) recorded on the event."}],handler:async($)=>{return Z4($,"notice.send",{title:$.args.str("title"),kind:$.args.str("kind")??"done",taskId:$.args.str("task-id"),source:$.args.str("source")})}},{name:"prompt",summary:"Ask the human for a line of text through the attached TUI's input dialog (plugins' host-provided prompt). Blocks until answered, cancelled, or timed out; returns { value } or { cancelled, reason }.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Dialog title (shown verbatim)."},{name:"placeholder",type:"string",placeholder:"TEXT",description:"Input placeholder."},{name:"initial",type:"string",placeholder:"TEXT",description:"Pre-filled input value."},{name:"timeout",type:"string",placeholder:"MS",description:"Give up after this many milliseconds (default 120000, max 600000)."}],handler:async($)=>{let Z=$.args.str("timeout"),J=Z?Number.parseInt(Z,10):void 0;return Z4($,"ui.prompt",{title:$.args.str("title"),placeholder:$.args.str("placeholder"),initial:$.args.str("initial"),...J&&Number.isFinite(J)?{timeoutMs:J}:{}})}},{name:"set-active",summary:"Set the shared active task (the focus every Tasks pane highlights). Pass --none to clear.",flags:[$$.taskId(!1),{name:"none",type:"bool",description:"Clear the active task instead of setting one."}],handler:Sc}]});var bc;var gc=c(()=>{f2();B2();kT();mT();bc=[{name:"rename",summary:"Set a task's title.",flags:[$$.taskId(),{name:"title",type:"string",required:!0,placeholder:"T",description:"New title."}],handler:($)=>Z4($,"task.rename",{taskId:$.args.require("task-id"),title:$.args.require("title")})},{name:"set-branch",summary:"Rename a task's branch (git branch -m if materialized, else recorded).",flags:[$$.taskId(),{name:"branch",type:"string",required:!0,placeholder:"B",description:"New branch name."}],handler:($)=>Z4($,"task.setBranch",{taskId:$.args.require("task-id"),branch:$.args.require("branch")})},Yc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:aj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as OW0}from"child_process";function _W0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function vc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function kc($,Z){let J=Z?.map((X)=>typeof X.message==="string"?X.message:null).filter((X)=>!!X);if(J&&J.length>0)return J.join("; ");return $.trim()||"GitHub CLI returned an empty response"}function mc($,Z,J){let X=["api","graphql","-f",`query=${$}`];for(let[U,B]of Object.entries(Z))X.push("-f",`${U}=${B}`);let z=J.spawn("gh",X,{encoding:"utf8"});if(z.error)throw Error(`failed to run gh: ${z.error.message}`);let G=typeof z.stdout==="string"?z.stdout:String(z.stdout??""),W=typeof z.stderr==="string"?z.stderr:String(z.stderr??""),q;try{q=JSON.parse(G)}catch{throw Error(`failed to parse gh response: ${kc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(kc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function CW0($){return`${$}
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
Submitted from Rove ${D$}.`}function _H($,Z={}){let J=vc($.title,"feedback title"),X=CW0(vc($.body,"feedback body")),z=(Z.repoSlug??oY)();if(!z)throw Error("package repository is not a GitHub repository");let{owner:G,name:W}=_W0(z),q=$.categorySlug?.trim()||oT,U={spawn:Z.spawn??OW0},M=mc(jW0,{owner:G,name:W},U).repository,O=M?.id;if(!O)throw Error(`GitHub repository not found: ${z}`);let N=M.discussionCategories?.nodes?.find((C)=>C.slug===q);if(!N)throw Error(`GitHub Discussion category not found: ${q}`);let D=mc(VW0,{repositoryId:O,categoryId:N.id,title:J,body:X},U).createDiscussion?.discussion;if(!D?.url||typeof D.number!=="number")throw Error("GitHub did not return the created Discussion");return{number:D.number,url:D.url}}var oT="feedback",jW0=`
|
package/dist/cli/kobe-run.js
CHANGED
|
@@ -79,7 +79,7 @@ You were spawned by Rove task ${J}. When the work is finished, send your outcome
|
|
|
79
79
|
`).split(`
|
|
80
80
|
`).map((X)=>(X.split("\r").pop()??"").slice(0,tG0));while(J.length>0&&(J[J.length-1]??"").trim()==="")J.pop();return J.slice(-sG0)}function uu($=Jj()){try{let Z=JSON.parse(iG0($,"utf8"));if(Z===null||typeof Z!=="object"||Array.isArray(Z))return{};return Z}catch{return{}}}function RT($,Z=Jj()){if($.key.startsWith("::"))return;if($.exit.code===0&&$.exit.signal===null)return;let J=uu(Z);J[$.key]={key:$.key,pid:$.pid,code:$.exit.code,signal:$.exit.signal,at:$.exit.at,tail:hu($.tail)};let X=Object.values(J).sort((z,G)=>z.at<G.at?1:-1).slice(0,rG0);nG0(aG0(Z),{recursive:!0}),oG0(Z,JSON.stringify(Object.fromEntries(X.map((z)=>[z.key,z])),null,2),"utf8")}var rG0=50,sG0=40,tG0=500,eG0;var uj=c(()=>{T7();eG0=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[@-_]/g});var du={};A$(du,{setRepoLastActiveVendor:()=>lJ,setGlobalDefaultVendor:()=>IT,resolvePreferredVendor:()=>B9,getRepoLastActiveVendor:()=>lu,getGlobalDefaultVendor:()=>cj});function ST($,Z){let J=$?.trim();if(!J)return;if(l5(J)||Z.includes(J))return J;return}function lu($){return ST(E5(cu+$),w2())}function lJ($,Z){Z6(cu+$,Z)}function cj(){let $=w2();return ST(E5("defaultVendor"),$)??ST(E5("lastSelectedVendor"),$)}function IT($){Z6("defaultVendor",$)}function B9($){return($?lu($):void 0)??cj()??H4}var cu="lastActiveVendor.";var CZ=c(()=>{P7();d5();A4()});function z8($=process.env){return{...$,...ET}}var ET;var dJ=c(()=>{ET={GIT_OPTIONAL_LOCKS:"0"}});function pu($){return $>="0"&&$<="7"}function ou($,Z){let J=[],X="",z=()=>{if(X.length>0){for(let W of $W0.encode(X))J.push(W);X=""}},G=Z+1;while(G<$.length){let W=$[G];if(W==='"'){G++;break}if(W==="\\"){let q=$[G+1];if(q===void 0){X+="\\",G++;continue}switch(q){case"a":z(),J.push(7),G+=2;break;case"b":z(),J.push(8),G+=2;break;case"t":z(),J.push(9),G+=2;break;case"n":z(),J.push(10),G+=2;break;case"v":z(),J.push(11),G+=2;break;case"f":z(),J.push(12),G+=2;break;case"r":z(),J.push(13),G+=2;break;case'"':X+='"',G+=2;break;case"\\":X+="\\",G+=2;break;default:if(pu(q)){let U="",B=G+1;while(B<$.length&&U.length<3&&pu($[B]))U+=$[B],B++;z(),J.push(Number.parseInt(U,8)&255),G=B}else X+=q,G+=2;break}}else X+=W,G++}return z(),{value:ZW0.decode(new Uint8Array(J)),end:G}}function AZ($){if($.length===0||$[0]!=='"')return $;return ou($,0).value}function au($,Z){if($[0]==='"'){let X=ou($,0);if($.startsWith(Z,X.end))return{orig:X.value,neu:AZ($.slice(X.end+Z.length))};return null}let J=$.indexOf(Z);if(J<0)return null;return{orig:$.slice(0,J),neu:AZ($.slice(J+Z.length))}}function nu($,Z,J){if(Z.length===0&&$.endsWith("/")&&J.startsWith("/"))return $+J.slice(1);return $+Z+J}function JW0($){let Z=$.indexOf("{");if(Z>=0){let X=$.indexOf("}",Z),z=$.indexOf(" => ",Z);if(X>Z&&z>=0&&z<X){let G=$.slice(0,Z),W=$.slice(Z+1,z),q=$.slice(z+4,X),U=$.slice(X+1);return{path:nu(G,q,U),origPath:nu(G,W,U)}}}let J=au($," => ");if(J)return{path:J.neu,origPath:J.orig};return{path:AZ($)}}function lj($){let Z=[];for(let J of $.split(`
|
|
81
81
|
`)){let X=J.replace(/\r$/,"");if(X.length<4)continue;if(X.startsWith("##"))continue;let z=X[0],G=X[1];if(X[2]!==" ")continue;let W=X.slice(3);if(z==="R"||z==="C"||G==="R"||G==="C"){let q=au(W," -> ");if(q){Z.push({x:z,y:G,path:q.neu,origPath:q.orig});continue}}Z.push({x:z,y:G,path:AZ(W)})}return Z}function iu($){if($==="-")return null;let Z=Number.parseInt($,10);return Number.isNaN(Z)?null:Z}function ru($){let Z=[];for(let J of $.split(`
|
|
82
|
-
`)){let X=J.replace(/\r$/,"");if(X.length===0)continue;let z=X.indexOf("\t");if(z<0)continue;let G=X.indexOf("\t",z+1);if(G<0)continue;let W=X.slice(G+1);if(W.length===0)continue;let q=JW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:iu(X.slice(0,z)),deleted:iu(X.slice(z+1,G))})}return Z}var $W0,ZW0;var dj=c(()=>{$W0=new TextEncoder,ZW0=new TextDecoder});var su={};A$(su,{sameWorktreeChanges:()=>FF,readWorktreeChanges:()=>QW0,pickPushedChanges:()=>wT,parsePorcelain:()=>OH});import{spawnSync as XW0}from"child_process";function FF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function wT($,Z){if(!$)return null;return $.get(Z)??pj}function QW0($){if(!$)return pj;try{let Z=XW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return pj;return OH(Z.stdout)}catch{return pj}}function OH($){let Z=0,J=0;for(let{x:X,y:z}of lj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var pj;var jH=c(()=>{dJ();dj();pj={added:0,deleted:0}});var Zc={};A$(Zc,{resolveBaseRef:()=>eu,readBranchSignals:()=>YW0,parseShortstat:()=>$c});import{spawnSync as zW0}from"child_process";function nj($,Z){try{let J=zW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function eu($){let Z=nj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(nj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function $c($){let Z=(J)=>{let X=$.match(J);return X?Number.parseInt(X[1]??"0",10):0};return{files:Z(/(\d+) files? changed/),insertions:Z(/(\d+) insertions?\(\+\)/),deletions:Z(/(\d+) deletions?\(-\)/)}}function YW0($){if(!$)return tu;let Z=eu($);if(!Z)return tu;let J=nj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=nj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:$c(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var tu;var Jc=c(()=>{dJ();tu={baseRef:null,ahead:null,diff:null}});async function GW0($,Z,J){let X;try{X=await ZT()}catch(z){throw new K1(`failed to start PTY host for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}try{if($.tab&&$.tab!=="new"){let O=U2({command:$.command,vendor:$.vendor,effort:$.modelEffort})[0];return await QT(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?mu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=cQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);HH(G,Z);let B=qH({task:{id:$.id,kind:$.kind,vendor:G,repo:$.repo},worktreePath:Z,shell:process.env.SHELL?.trim()||"/bin/zsh",argv:q,promptIntent:$.newTask?{kind:"new-task",prompt:J,spawnerTaskId:(await zH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await XT(X.rpc,{id:$.id,engineBin:q[0]},Z,J,B,{forceNew:z!==void 0});if(M.started&&!M.engineReady)throw new K1(`failed to start hosted engine session for ${$.id}`,"SESSION_FAILED");if(M.started&&U)if(z)ku($.id,z,U);else DT($.id,U);else if(!z)DT($.id);return M}catch(z){if(z instanceof K1)throw z;throw new K1(`hosted engine session failed for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}finally{X.close()}}async function xT($,Z,J,X=WW0){let z=Z.worktreePath;if(!z)z=(await $.request("task.ensureWorktree",{taskId:Z.id})).worktreePath;if(!z)throw new K1(`task ${Z.id} has no worktree`,"NO_WORKTREE");let G=await X.deliverHosted(Z,z,J);if(!G)throw new K1(`failed to start hosted engine session for ${Z.id}`,"SESSION_FAILED");return G}var WW0,MF;var NF=c(()=>{q9();B7();Pj();Rj();Sj();YF();Bj();PT();$8();WW0={deliverHosted:GW0};MF={isTaskRunning:async($)=>(await MF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await XH();if(J)try{Z=await QH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (NZ(),tO)),B=Z.filter((M)=>M.alive&&typeof M.pid==="number"&&M.pid>0);if(B.length>0){let M=q(await U());X=new Map(B.map((O)=>[O.key,W(M,O.pid)?.vendor??null]))}}catch{}let z={};try{z=(await Promise.resolve().then(() => (uj(),TT))).readPtyExitRecords()}catch{}let G=yu($);return{tabs:gu(G,$,Z,z,X),running:vu(G,$,Z)}},deliverPrompt:($,Z,J)=>xT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (A4(),mq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (CZ(),du));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (jH(),su))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (Jc(),Zc))).readBranchSignals($),tearDownSession:async($)=>{let Z=await XH();if(Z)try{await zT(Z.rpc,$T(await QH(Z.rpc),$))}catch{}finally{Z.close()}}}});var ij;var Xc=c(()=>{ij={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.175",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://github.com/Sma1lboy/rove#readme",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react-task-dialogs":"KOBE_DEV=1 bun ./src/tui-react/component/mock-dialogs-host.tsx","dev:mock-react-filetree":"KOBE_DEV=1 bun ./src/tui-react/panes/filetree/mock-host.tsx","dev:mock-react-sidebar":"KOBE_DEV=1 bun ./src/tui-react/panes/sidebar/mock-host.tsx","dev:mock-react-terminal":"KOBE_DEV=1 bun ./src/tui-react/panes/terminal/mock-host.tsx","dev:mock-react-dialogs":"KOBE_DEV=1 bun ./src/tui-react/mock/dialogs-host.tsx","dev:mock-react-workspace":"KOBE_DEV=1 bun ./src/tui-react/workspace/mock-host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:with-web":"bun run build",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.14","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","kobe-web":"workspace:*","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]}});var zc={};A$(zc,{repoSlug:()=>oY,releasePageUrl:()=>kT,recommendedGlobalInstallCommand:()=>bT,isNewerSemver:()=>fT,fetchReleaseSummaries:()=>OF,fetchReleaseNotesRange:()=>vT,fetchReleaseNotes:()=>gT,compareSemver:()=>C3,checkLatestVersion:()=>aY,breakingVersionsCrossed:()=>LF,UPDATE_SCRIPT_URL:()=>oj,UPDATE_COMMAND:()=>DZ,PACKAGE_NAME:()=>yT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function oY(){let $=ij.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function bT(){return`npm install -g ${yT}@latest`}function LF($,Z,J=pJ){let[X,z]=C3($,Z)<=0?[$,Z]:[Z,$];return J.filter((G)=>C3(G,X)>0&&C3(G,z)<=0)}async function HW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),aj);try{let X=$.replace("/","%2F"),z=await fetch(`https://registry.npmjs.org/${X}/latest`,{signal:Z.signal,headers:{accept:"application/json"}});if(!z.ok)return null;let G=await z.json();if(typeof G.version!=="string")return null;return G.version}catch{return null}finally{clearTimeout(J)}}function fT($,Z){return C3($,Z)>0}function C3($,Z){let J=(G)=>G.split("-")[0]??G,X=J($).split(".").map((G)=>Number.parseInt(G,10)),z=J(Z).split(".").map((G)=>Number.parseInt(G,10));for(let G=0;G<3;G++){let W=X[G]??0,q=z[G]??0;if(Number.isNaN(W)||Number.isNaN(q))return 0;if(W>q)return 1;if(W<q)return-1}return 0}async function aY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:fT(Z,D$)};if(fq()&&!$.force)return null;let J=await HW0(yT);if(!J)return null;return{current:D$,latest:J,hasUpdate:fT(J,D$)}}function Qc($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function gT($){let Z=oY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases/tags/${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return null;let W=await G.json();if(typeof W.body!=="string"||typeof W.html_url!=="string")return null;return{body:W.body,url:W.html_url,version:$}}catch{return null}finally{clearTimeout(z)}}async function vT($){let Z=oY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return[];let W=await G.json();if(!Array.isArray(W))return[];return W.map((q)=>{let U=Qc(q.tag_name);if(!U||typeof q.html_url!=="string"||typeof q.body!=="string")return null;if(C3(U,$.current)<=0)return null;if(C3(U,$.latest)>0)return null;return{version:U,url:q.html_url,body:q.body}}).filter((q)=>q!==null)}catch{return[]}finally{clearTimeout(z)}}async function OF($=12){let Z=oY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),aj);try{let z=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${$}`,{signal:J.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!z.ok)return[];let G=await z.json();if(!Array.isArray(G))return[];return G.map((W)=>{let q=Qc(W.tag_name);if(!q||typeof W.html_url!=="string")return null;return{version:q,url:W.html_url}}).filter((W)=>W!==null)}catch{return[]}finally{clearTimeout(X)}}function kT($){let Z=oY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,yT,oj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",DZ,pJ,aj=3000;var c8=c(()=>{Xc();j5();D$=ij.version,yT=ij.name;DZ=`curl -fsSL ${oj} | sh`;pJ=[]});function i4($){if(!$.client)throw new K1("daemon required","BAD_DAEMON");return $.client}async function Z4($,Z,J){return i4($).request(Z,J)}async function Yc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (G9(),aR)),Promise.resolve().then(() => (T7(),pR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=c(()=>{$8()});async function UW0($){let Z=$.args.require("command"),J=lQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===uY?{generic:!0}:{}}}var Gc,Wc;var mT=c(()=>{q9();f2();B2();Gc={name:"engine-list",summary:"List every engine Rove can launch \u2014 built-ins and your registered presets \u2014 each with its RAW launch command, exactly as it runs. Copy one into `add --command` / `send --tab new --command` verbatim, or edit its flags first. `protocol` is the adapter Rove speaks to it (history, trust, delivery); `generic` = none, which still runs fine but loses transcript reads. Returns { engines }.",flags:[],offline:!0,handler:async()=>({engines:om()})};Wc={name:"set-command",summary:"Set a task's engine launch command (takes effect on the next session rebuild). The protocol Rove speaks to it is derived from the command \u2014 the result reports which one, `generic` when the command names no engine Rove knows.",flags:[$$.taskId(),{...$$.command(),required:!0}],handler:UW0}});function Bc($){let Z=$.args.str("precheck");if(Z===void 0)return{};if(Z.length===0)return{precheck:null};return{precheck:{command:Z,timeoutSeconds:$.args.int("precheck-timeout")??120}}}var qc,Hc,Uc,Kc;var Fc=c(()=>{f2();B2();qc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Hc=[{name:"precheck",type:"string",placeholder:"CMD",description:"Shell command run in the repo BEFORE the engine starts. Non-zero exit skips the run without spawning an agent \u2014 the cheap way to avoid burning a turn when nothing changed."},{name:"precheck-timeout",type:"int",placeholder:"SEC",description:"Seconds before the precheck is killed and the run skipped (default 120)."}],Uc={name:"grace",type:"int",placeholder:"MIN",description:"How late a missed occurrence may still run when the daemon was down (default 60). Only the most recent missed occurrence is ever run."};Kc=[{name:"routine-list",summary:"List scheduled routines with their next run time.",flags:[],handler:($)=>Z4($,"automation.list",{})},{name:"routine-create",summary:"Schedule a prompt. Each firing creates a fresh task (worktree + engine) and delivers it. An enabled routine keeps the daemon alive so it fires with no TUI attached.",flags:[$$.repo(),{name:"name",type:"string",required:!0,placeholder:"N",description:"Routine name."},$$.prompt(!0,"Text delivered as the new session's first message."),{...qc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Hc,Uc,{name:"disabled",type:"bool",description:"Create it paused instead of active."}],handler:($)=>Z4($,"automation.create",{repo:$.args.requirePath("repo"),name:$.args.require("name"),prompt:$.args.require("prompt"),schedule:$.args.require("schedule"),...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{},...$.args.bool("disabled")?{enabled:!1}:{}})},{name:"routine-update",summary:"Change a routine. A new --schedule re-anchors its next run; --precheck '' clears the precheck.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"name",type:"string",placeholder:"N",description:"New name."},$$.prompt(!1,"New prompt."),qc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Hc,Uc],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),...$.args.str("name")!==void 0?{name:$.args.str("name")}:{},...$.args.str("prompt")!==void 0?{prompt:$.args.str("prompt")}:{},...$.args.str("schedule")!==void 0?{schedule:$.args.str("schedule")}:{},...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")!==void 0?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{}})},{name:"routine-set-enabled",summary:"Pause or resume a routine. Disabling the last active one releases the daemon's keep-alive hold.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"enabled",type:"bool",required:!0,description:"true to resume, false to pause."}],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),enabled:$.args.bool("enabled")})},{name:"routine-delete",summary:"Delete a routine and its run history. Tasks it already created are untouched.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.delete",{id:$.args.require("id")})},{name:"routine-run-now",summary:"Run a routine immediately, skipping its precheck (asking for it IS the answer). Does not shift its schedule.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runNow",{id:$.args.require("id")})},{name:"routine-runs",summary:"Run history, newest first. Statuses: dispatched, skipped_precheck (nothing to do), skipped_missed, skipped_unavailable, dispatch_failed.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runs",{id:$.args.require("id")})}]});async function Mc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:lQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Nc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Lc($){let{args:Z,runtime:J}=$,X=await J.resolveRepoRoot(Z.requirePath("repo")),z=Z.int("count"),G=Z.str("agents");if(z!==void 0||G)return KW0($,X,z,G);return BW0($,X)}async function BW0($,Z){let J=i4($),{args:X}=$,z=await Mc($,Z),G={repo:Z,...await GT(),...Nc(z)},W=X.str("title");if(W)G.title=W;let q=X.str("branch");if(q)G.branch=q;let U=X.str("base-branch");if(U)G.baseRef=U;let B=await J.request("task.create",G),M=B.taskId;if(X.bool("activate"))await J.request("task.setActive",{taskId:M});let O=X.enumOf("status");if(O)await J.request("task.status",{taskId:M,status:O});let N=X.bool("pin");if(N!==void 0)await J.request("task.pin",{taskId:M,pinned:N});let j=B.task;if(O||N!==void 0)j=(await J.request("task.get",{taskId:M})).task;let D=X.str("prompt");if(!D)return{taskId:M,task:j,started:!1};let C=await $.runtime.deliverPrompt(J,{id:M,worktreePath:j.worktreePath,kind:j.kind,vendor:j.vendor,command:j.command,modelEffort:j.modelEffort,repo:j.repo,newTask:!0},D);if(j=(await J.request("task.get",{taskId:M})).task,!C.delivered)throw new K1(`task ${M} created but the prompt was not delivered (paste did not land)`,"NOT_DELIVERED",{taskId:M});return{taskId:M,task:j,started:C.started,engineReady:C.engineReady,session:C.session,delivered:C.delivered}}async function KW0($,Z,J,X){let z=i4($),{args:G}=$,W=G.str("prompt");if(!W)throw new K1("--count/--agents spawn parallel attempts of ONE prompt \u2014 pass --prompt","MISSING_FLAG",L3("add"));if(G.str("branch"))throw new K1("--branch names ONE branch and cannot be shared by parallel siblings \u2014 drop it (each sibling gets its own auto branch) or spawn them one at a time","BAD_FLAG",L3("add"));if(X){let E=J!==void 0?"--count":G.str("command")?"--command":null;if(E)throw new K1(`${E} conflicts with --agents, which already names each sibling's engine and how many \u2014 pass one or the other`,"BAD_FLAG",L3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Mc($,Z),M=X?Lj(X):Oj(J??1,B.vendor??"claude");if(M.length>OZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${OZ} \u2014 spawn in batches`,"BAD_FLAG");let O=KO(),N=[],j=null,D=await GT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Nc(w)};if(q)f.title=M.length>1?`${q} #${E+1}/${M.length}`:q;if(U)f.baseRef=U;try{let y=await z.request("task.create",f);N.push({taskId:y.taskId,vendor:T,task:y.task})}catch(y){let h=y instanceof K1?y.code:"CREATE_FAILED",p=y instanceof Error?y.message:String(y);j={vendor:T,error:{message:p,code:h}};break}}let C=await Promise.allSettled(N.map(({taskId:E,vendor:T,task:w})=>$.runtime.deliverPrompt(z,{id:E,worktreePath:w.worktreePath,kind:w.kind,vendor:T,command:w.command,modelEffort:w.modelEffort,repo:w.repo,newTask:!0},W))),_=[],g=[];if(C.forEach((E,T)=>{let{taskId:w,vendor:f}=N[T];if(E.status==="fulfilled"&&E.value.delivered){_.push({ok:!0,taskId:w,vendor:f,started:E.value.started,engineReady:E.value.engineReady,session:E.value.session});return}let y=E.status==="rejected"?E.reason:new K1(`prompt was not confirmed in ${w}'s engine`,"NOT_DELIVERED"),h=y instanceof K1?y.code:"DELIVER_FAILED",p=y instanceof Error?y.message:String(y);g.push({ok:!1,taskId:w,vendor:f,error:{message:p,code:h}})}),j)g.push({ok:!1,vendor:j.vendor,error:j.error});let I={count:N.length,requested:M.length,groupId:O,tasks:_,failures:g};if(g.length>0)throw new K1(`add delivered ${_.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Oc=c(()=>{q9();gP();YF();f2();B2();$8()});var rj;var hT=c(()=>{rj=["backlog","in_progress","in_review","done","canceled","error"]});var jc;var Vc=c(()=>{f2();Oc();hT();jc=[{name:"add",summary:`Create a task (shows in the sidebar immediately). With --prompt it also starts the engine and delivers it. PARALLEL ATTEMPTS: --count N spawns N sibling tasks of the SAME prompt, each in its own worktree/branch (--agents claude:2,codex:1 for a mixed fleet); capped at ${OZ}, prefer 3-4. Does NOT steal focus \u2014 pass --activate to make it the active task. Alias: spawn-task.`,flags:[$$.repo(),$$.title(),{name:"branch",type:"string",placeholder:"B",description:"Explicit branch name (else derived from the title in the repo's own style). Single task only."},{name:"base-branch",type:"string",placeholder:"B",description:"Base ref the worktree branches from."},$$.command(),{name:"count",type:"int",placeholder:"N",description:`Spawn N sibling tasks of one prompt (parallel attempts, cap ${OZ}). Requires --prompt.`},{name:"agents",type:"string",placeholder:"claude:2,codex:1",description:"Per-ENGINE counts for a mixed parallel round (alternative to --count). Engine ids only \u2014 see `engine-list`."},{name:"status",type:"enum",values:rj,default:"backlog",description:"Initial lifecycle status."},{name:"pin",type:"bool",description:"Pin the task to the top of the sidebar."},{name:"activate",type:"bool",default:"false",description:"Make this the active task (pulls every mounted TUI's Tasks-pane focus). Off by default."},$$.prompt(!1,"Optional first message \u2014 when set, materializes the worktree, starts the engine, and pastes it. Required with --count/--agents.")],handler:Lc}]});var _c,Cc;var Ac=c(()=>{hJ();f2();B2();NF();$8();_c={name:"pane-open",summary:"Open a terminal pane in a task's workspace: split the focused tab (default, or --tab's tab) or open a separate command tab, optionally running a command. Broadcast over the daemon's tab.open channel \u2014 an attached TUI showing the task performs the split. Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"tab",type:"string",placeholder:"TAB",description:"Host tab for the split (e.g. tab-3) instead of the focused tab (split placement only)."},{name:"command",type:"string",placeholder:"CMD",description:"Shell command the pane runs (via the login shell's `-ilc`, so pipes/args and your shell rc's PATH/exports work); the pane closes when it exits. Omit for an interactive shell."},{name:"direction",type:"enum",values:["right","down"],default:"right",description:"Split orientation relative to the active pane (split placement only)."},{name:"placement",type:"enum",values:["split","tab"],default:"split",description:"`split` joins the focused tab's split group; `tab` opens a separate command tab."},{name:"title",type:"string",placeholder:"TEXT",description:`Pane label (default: the command's first word, else "shell").`}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("command"),z=y2({fallback:"/bin/sh"}),G=X?[z,"-ilc",X]:[z,"-il"],W=$.args.str("title")??(X?X.trim().split(/\s+/)[0]??"shell":"shell"),q=$.args.str("tab");return Z4($,"tab.open",{taskId:J,argv:G,title:W,...q!==void 0?{tabId:q}:{},placement:$.args.str("placement")??"split",direction:$.args.str("direction")??"right"})}},Cc={name:"pane-close",summary:"Close panes opened by pane-open: every split pane / command tab in the task whose label matches --title. Broadcast over the daemon's tab.close channel \u2014 an attached TUI showing the task performs the close (headless no-op). Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Pane label to close \u2014 the --title the pane was opened with (engine panes are never closed)."},{name:"tab",type:"string",placeholder:"TAB",description:"Scope the title match to one tab (e.g. tab-3) instead of every tab of the task."}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("tab");return Z4($,"tab.close",{taskId:J,title:$.args.str("title"),...X!==void 0?{tabId:X}:{}})}}});var uT,jF,cT,lT="DIRTY_WORKTREE",dT,pT,FW0="TASK_DELETING",nQ,MW0="MAIN_CHECKOUT_DIRTY",nT,NW0="EMPTY_BRANCH",iT,sj="EMPTY_BRANCH_DIRTY_WORKTREE",oT,LW0="LAND_CONFLICT",tj;var nJ=c(()=>{uT=class uT extends Error{from;to;taskId;constructor($,Z,J){super(`illegal transition for task ${J}: ${$} -> ${Z}`);this.from=$;this.to=Z;this.taskId=J;this.name="IllegalTransitionError"}};jF=class jF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};cT=class cT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};dT=class dT extends Error{taskId;constructor($){super(`${lT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};pT=class pT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};nQ=class nQ extends Error{taskId;constructor($){super(`${FW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};nT=class nT extends Error{repo;dir;constructor($,Z){super(`${MW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};iT=class iT extends Error{branch;landedOn;constructor($,Z){super(`${NW0}: '${$}' has no commits ahead of '${Z}' \u2014 landing it would be a no-op (the worker may not have delivered anything)`);this.branch=$;this.landedOn=Z;this.name="EmptyBranchError"}};oT=class oT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${sj}: '${$}' has no commits ahead of '${Z}' but its worktree ${J} has uncommitted changes (${z}) \u2014 commit them in the worktree first, then land again`);this.branch=$;this.landedOn=Z;this.worktreePath=J;this.files=X;this.name="EmptyBranchDirtyWorktreeError"}};tj=class tj extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${LW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function OW0($,Z,J){let X=await zH(),z=X?.taskId;if(!z||z===Z)return J;let G=z;try{let U=await $.request("task.get",{taskId:z});G=U.task.title||U.task.branch||z}catch{}let W=V3(),q=`--task-id ${z} --tab ${X.tabId}`;return`[ROVE PEER] from "${G}" (task ${z} \u2014 load the Rove agent skill FIRST (registered as /rove; legacy /kobe installs still work), then reply: \`${W} send ${q} --prompt "<text>"\`; verb reference: \`${W} schema\`): ${J}`}async function Dc($){let Z=$.args.str("title"),J=$.args.str("body"),X=$.args.str("task");if(Z===void 0&&J===void 0&&X===void 0)throw new K1("issue-update requires --title, --body, and/or --task","MISSING_FLAG");let z=$.args.requirePath("repo"),G=$.args.int("id"),W;if(Z!==void 0||J!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:{type:"update",id:G,title:Z,body:J}});if(X!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:X==="none"?{type:"unlink",id:G}:{type:"link",id:G,taskId:X}});return W}async function Pc($){let Z=i4($),J=$.args.require("prompt"),X=$.args.str("tab");if(X&&X!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(X))throw new K1(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(X)})`,"BAD_TAB");let z=$.args.str("command");if(z&&X!=="new")throw new K1(`--command only applies to a new tab; pass --tab new (got --tab ${X??"<canonical>"})`,"BAD_FLAG",L3("send"));let G=z?lQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await um(Z);if(M){if(W=M.taskId,X===void 0)X=await cm($.runtime,M)}else{let O=await uJ(Z);if(!O)throw new K1("no --task-id given and no active task \u2014 open a task first or pass --task-id","MISSING_TARGET");W=O}}let q=await Z.request("task.get",{taskId:W}),U=$.args.bool("plain")?J:await OW0(Z,W,J),B=await $.runtime.deliverPrompt(Z,{id:W,worktreePath:q.task.worktreePath,kind:q.task.kind,vendor:q.task.vendor,command:q.task.command,modelEffort:z?void 0:q.task.modelEffort,repo:q.task.repo,tab:X,tabVendor:G,tabCommand:z},U);if(!B.delivered)throw new K1(`prompt was not confirmed in ${W}'s engine (paste did not land)`,"NOT_DELIVERED");return{ok:!0,taskId:W,session:B.session,started:B.started,engineReady:B.engineReady}}async function jW0($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("prompt"),z=$.args.str("tab"),G=await Z.request("session.deliver",{taskId:J,text:X,...z!==void 0?{tabId:z}:{},source:"dispatcher"});return{ok:!0,taskId:J,...z!==void 0?{tabId:z}:{},routed:"session.deliver",...G?.clients!==void 0?{clients:G.clients}:{}}}async function Tc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Sc($){let Z=i4($),J=$.args.require("task-id"),X=await Z.request("task.get",{taskId:J}),{tabs:z,running:G}=await $.runtime.taskTabs(J);return{task:X.task,running:G,tabs:z}}async function Ic($){return i4($).request("task.list")}async function Ec($){let Z=i4($),X=$.args.bool("none")?null:$.args.require("task-id");return await Z.request("task.setActive",{taskId:X}),{ok:!0,activeTaskId:X}}async function wc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("archived")??!0,z=await Z.request("task.archive",{taskId:J,archived:X});if(X)await $.runtime.tearDownSession(J);return z}async function xc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("force")??!1,z=$.args.bool("delete-branch")??!1,G=await Z.request("task.delete",{taskId:J,force:X,deleteBranch:z});return await $.runtime.tearDownSession(J),G}async function fc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.str("strategy")==="squash"?"squash":"merge",z=$.args.bool("remove-worktree")??!1,G;try{G=await Z.request("task.land",{taskId:J,strategy:X,deleteBranch:$.args.bool("delete-branch")??!1,archive:$.args.bool("then-archive")??!1,removeWorktree:z,...z?{callerCwd:process.cwd()}:{}})}catch(W){throw VW0(W,J)}return{ok:!0,taskId:J,...G.result}}function VW0($,Z){let J=M1($);if(!J.includes(sj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,sj,{hint:"the worker wrote files but never committed them \u2014 send it back to commit its own work, then land again",nextCommandArgs:["api","send","--task-id",Z,"--prompt",`your work is uncommitted on ${X} \u2014 commit it yourself with a proper message, then report back`]})}async function yc($){let Z=i4($),{args:J}=$,X={repo:J.requirePath("repo"),worktreePath:J.requirePath("worktree")},z=J.str("branch");if(z)X.branch=z;let G=J.str("command");if(G)X.command=G,X.vendor=lQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Rc;var VH=c(()=>{q9();B7();nJ();YF();f2();B2();NF();$8();Rc={name:"dispatch",summary:"Route text into a task's live session via the daemon's session.deliver channel. The dispatcher's messenger (docs/design/dispatcher.md); unlike `send`, it requires an already-hosted session.",flags:[$$.taskId(!0),$$.prompt(!0,"Text delivered into the task's engine session."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:"Deliver into exactly this tab (e.g. tab-3) instead of the canonical engine tab."}],handler:jW0}});var bc;var gc=c(()=>{f2();B2();Ac();VH();bc=[{name:"send",summary:"Paste a follow-up prompt into a task's running engine (one full turn). Without --task-id, a task spawned from another Rove session replies to its dispatcher's tab (then that task's live canonical engine; nothing alive = DISPATCHER_UNREACHABLE, never a silent spawn); otherwise the active task. Sent from inside another Rove task ($ROVE_TASK_ID), the prompt is prefixed with [ROVE PEER] provenance \u2014 who sent it and how to reply (tab-precise) \u2014 so agent-to-agent messaging needs no coordinator.",flags:[$$.taskId(!1),$$.prompt(!0,"Text pasted + submitted into the engine pane."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Tab addressing: "new" spawns the prompt in a fresh engine tab; "tab-N" delivers to that exact alive tab (error when dead/absent). Omitted = the canonical engine tab.'},{...$$.command(),description:"Engine launch command for a `--tab new` tab \u2014 the API twin of the TUI's ctrl+e pick. Lets one worktree run two agents on the same files (e.g. hand the stuck work to codex without leaving the branch). An engine id from `engine-list` or a full command line; pinned to that tab, so it survives restarts and a later set-command on the task. Only valid with --tab new."},{name:"plain",type:"bool",required:!1,description:"Deliver the prompt verbatim \u2014 skip the [ROVE PEER] provenance prefix."}],handler:Pc},Rc,{name:"note",summary:"File a one-line field note \u2014 a resolved, repo-level gotcha worth sharing. Appended to the repo's durable note store (every future session on this repo starts with it) and forwarded to the dispatcher session for live relay (docs/design/dispatcher.md).",flags:[$$.taskId(!0),{name:"text",type:"string",required:!0,placeholder:"TEXT",description:"One line: the verified conclusion another session could act on."}],handler:Tc},{name:"note-list",summary:"Read a repo's accumulated field notes, newest first. Returns { notes }.",flags:[$$.repo(!0)],handler:($)=>Z4($,"note.list",{repo:$.args.requirePath("repo")})},_c,Cc,{name:"notify",summary:"Show a toast in every attached Rove UI \u2014 broadcast over the daemon's notice.event channel. Agents/scripts use it to surface 'done / needs input / error' moments without touching the task's session.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Toast text (one line)."},{name:"kind",type:"string",default:"done",placeholder:"KIND",description:`Free-form kind tag. "done", "needs_input" and "error" get the TUI's severity styling/unread mark; any other value renders neutrally.`},$$.taskId(!1),{name:"source",type:"string",placeholder:"TAG",description:"Free-form origin tag (e.g. an agent name) recorded on the event."}],handler:async($)=>{return Z4($,"notice.send",{title:$.args.str("title"),kind:$.args.str("kind")??"done",taskId:$.args.str("task-id"),source:$.args.str("source")})}},{name:"prompt",summary:"Ask the human for a line of text through the attached TUI's input dialog (plugins' host-provided prompt). Blocks until answered, cancelled, or timed out; returns { value } or { cancelled, reason }.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Dialog title (shown verbatim)."},{name:"placeholder",type:"string",placeholder:"TEXT",description:"Input placeholder."},{name:"initial",type:"string",placeholder:"TEXT",description:"Pre-filled input value."},{name:"timeout",type:"string",placeholder:"MS",description:"Give up after this many milliseconds (default 120000, max 600000)."}],handler:async($)=>{let Z=$.args.str("timeout"),J=Z?Number.parseInt(Z,10):void 0;return Z4($,"ui.prompt",{title:$.args.str("title"),placeholder:$.args.str("placeholder"),initial:$.args.str("initial"),...J&&Number.isFinite(J)?{timeoutMs:J}:{}})}},{name:"set-active",summary:"Set the shared active task (the focus every Tasks pane highlights). Pass --none to clear.",flags:[$$.taskId(!1),{name:"none",type:"bool",description:"Clear the active task instead of setting one."}],handler:Ec}]});var vc;var kc=c(()=>{f2();B2();mT();hT();vc=[{name:"rename",summary:"Set a task's title.",flags:[$$.taskId(),{name:"title",type:"string",required:!0,placeholder:"T",description:"New title."}],handler:($)=>Z4($,"task.rename",{taskId:$.args.require("task-id"),title:$.args.require("title")})},{name:"set-branch",summary:"Rename a task's branch (git branch -m if materialized, else recorded).",flags:[$$.taskId(),{name:"branch",type:"string",required:!0,placeholder:"B",description:"New branch name."}],handler:($)=>Z4($,"task.setBranch",{taskId:$.args.require("task-id"),branch:$.args.require("branch")})},Wc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:rj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as _W0}from"child_process";function DW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function mc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function hc($,Z){let J=Z?.map((X)=>typeof X.message==="string"?X.message:null).filter((X)=>!!X);if(J&&J.length>0)return J.join("; ");return $.trim()||"GitHub CLI returned an empty response"}function uc($,Z,J){let X=["api","graphql","-f",`query=${$}`];for(let[U,B]of Object.entries(Z))X.push("-f",`${U}=${B}`);let z=J.spawn("gh",X,{encoding:"utf8"});if(z.error)throw Error(`failed to run gh: ${z.error.message}`);let G=typeof z.stdout==="string"?z.stdout:String(z.stdout??""),W=typeof z.stderr==="string"?z.stderr:String(z.stderr??""),q;try{q=JSON.parse(G)}catch{throw Error(`failed to parse gh response: ${hc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(hc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function PW0($){return`${$}
|
|
82
|
+
`)){let X=J.replace(/\r$/,"");if(X.length===0)continue;let z=X.indexOf("\t");if(z<0)continue;let G=X.indexOf("\t",z+1);if(G<0)continue;let W=X.slice(G+1);if(W.length===0)continue;let q=JW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:iu(X.slice(0,z)),deleted:iu(X.slice(z+1,G))})}return Z}var $W0,ZW0;var dj=c(()=>{$W0=new TextEncoder,ZW0=new TextDecoder});var su={};A$(su,{sameWorktreeChanges:()=>FF,readWorktreeChanges:()=>QW0,pickPushedChanges:()=>wT,parsePorcelain:()=>OH});import{spawnSync as XW0}from"child_process";function FF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function wT($,Z){if(!$)return null;return $.get(Z)??pj}function QW0($){if(!$)return pj;try{let Z=XW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return pj;return OH(Z.stdout)}catch{return pj}}function OH($){let Z=0,J=0;for(let{x:X,y:z}of lj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var pj;var jH=c(()=>{dJ();dj();pj={added:0,deleted:0}});var Zc={};A$(Zc,{resolveBaseRef:()=>eu,readBranchSignals:()=>YW0,parseShortstat:()=>$c});import{spawnSync as zW0}from"child_process";function nj($,Z){try{let J=zW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function eu($){let Z=nj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(nj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function $c($){let Z=(J)=>{let X=$.match(J);return X?Number.parseInt(X[1]??"0",10):0};return{files:Z(/(\d+) files? changed/),insertions:Z(/(\d+) insertions?\(\+\)/),deletions:Z(/(\d+) deletions?\(-\)/)}}function YW0($){if(!$)return tu;let Z=eu($);if(!Z)return tu;let J=nj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=nj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:$c(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var tu;var Jc=c(()=>{dJ();tu={baseRef:null,ahead:null,diff:null}});async function GW0($,Z,J){let X;try{X=await ZT()}catch(z){throw new K1(`failed to start PTY host for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}try{if($.tab&&$.tab!=="new"){let O=U2({command:$.command,vendor:$.vendor,effort:$.modelEffort})[0];return await QT(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?mu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=cQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);HH(G,Z);let B=qH({task:{id:$.id,kind:$.kind,vendor:G,repo:$.repo},worktreePath:Z,shell:process.env.SHELL?.trim()||"/bin/zsh",argv:q,promptIntent:$.newTask?{kind:"new-task",prompt:J,spawnerTaskId:(await zH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await XT(X.rpc,{id:$.id,engineBin:q[0]},Z,J,B,{forceNew:z!==void 0});if(M.started&&!M.engineReady)throw new K1(`failed to start hosted engine session for ${$.id}`,"SESSION_FAILED");if(M.started&&U)if(z)ku($.id,z,U);else DT($.id,U);else if(!z)DT($.id);return M}catch(z){if(z instanceof K1)throw z;throw new K1(`hosted engine session failed for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}finally{X.close()}}async function xT($,Z,J,X=WW0){let z=Z.worktreePath;if(!z)z=(await $.request("task.ensureWorktree",{taskId:Z.id})).worktreePath;if(!z)throw new K1(`task ${Z.id} has no worktree`,"NO_WORKTREE");let G=await X.deliverHosted(Z,z,J);if(!G)throw new K1(`failed to start hosted engine session for ${Z.id}`,"SESSION_FAILED");return G}var WW0,MF;var NF=c(()=>{q9();B7();Pj();Rj();Sj();YF();Bj();PT();$8();WW0={deliverHosted:GW0};MF={isTaskRunning:async($)=>(await MF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await XH();if(J)try{Z=await QH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (NZ(),tO)),B=Z.filter((M)=>M.alive&&typeof M.pid==="number"&&M.pid>0);if(B.length>0){let M=q(await U());X=new Map(B.map((O)=>[O.key,W(M,O.pid)?.vendor??null]))}}catch{}let z={};try{z=(await Promise.resolve().then(() => (uj(),TT))).readPtyExitRecords()}catch{}let G=yu($);return{tabs:gu(G,$,Z,z,X),running:vu(G,$,Z)}},deliverPrompt:($,Z,J)=>xT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (A4(),mq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (CZ(),du));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (jH(),su))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (Jc(),Zc))).readBranchSignals($),tearDownSession:async($)=>{let Z=await XH();if(Z)try{await zT(Z.rpc,$T(await QH(Z.rpc),$))}catch{}finally{Z.close()}}}});var ij;var Xc=c(()=>{ij={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.176",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://github.com/Sma1lboy/rove#readme",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react-task-dialogs":"KOBE_DEV=1 bun ./src/tui-react/component/mock-dialogs-host.tsx","dev:mock-react-filetree":"KOBE_DEV=1 bun ./src/tui-react/panes/filetree/mock-host.tsx","dev:mock-react-sidebar":"KOBE_DEV=1 bun ./src/tui-react/panes/sidebar/mock-host.tsx","dev:mock-react-terminal":"KOBE_DEV=1 bun ./src/tui-react/panes/terminal/mock-host.tsx","dev:mock-react-dialogs":"KOBE_DEV=1 bun ./src/tui-react/mock/dialogs-host.tsx","dev:mock-react-workspace":"KOBE_DEV=1 bun ./src/tui-react/workspace/mock-host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:with-web":"bun run build",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.14","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","kobe-web":"workspace:*","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]}});var zc={};A$(zc,{repoSlug:()=>oY,releasePageUrl:()=>kT,recommendedGlobalInstallCommand:()=>bT,isNewerSemver:()=>fT,fetchReleaseSummaries:()=>OF,fetchReleaseNotesRange:()=>vT,fetchReleaseNotes:()=>gT,compareSemver:()=>C3,checkLatestVersion:()=>aY,breakingVersionsCrossed:()=>LF,UPDATE_SCRIPT_URL:()=>oj,UPDATE_COMMAND:()=>DZ,PACKAGE_NAME:()=>yT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function oY(){let $=ij.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function bT(){return`npm install -g ${yT}@latest`}function LF($,Z,J=pJ){let[X,z]=C3($,Z)<=0?[$,Z]:[Z,$];return J.filter((G)=>C3(G,X)>0&&C3(G,z)<=0)}async function HW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),aj);try{let X=$.replace("/","%2F"),z=await fetch(`https://registry.npmjs.org/${X}/latest`,{signal:Z.signal,headers:{accept:"application/json"}});if(!z.ok)return null;let G=await z.json();if(typeof G.version!=="string")return null;return G.version}catch{return null}finally{clearTimeout(J)}}function fT($,Z){return C3($,Z)>0}function C3($,Z){let J=(G)=>G.split("-")[0]??G,X=J($).split(".").map((G)=>Number.parseInt(G,10)),z=J(Z).split(".").map((G)=>Number.parseInt(G,10));for(let G=0;G<3;G++){let W=X[G]??0,q=z[G]??0;if(Number.isNaN(W)||Number.isNaN(q))return 0;if(W>q)return 1;if(W<q)return-1}return 0}async function aY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:fT(Z,D$)};if(fq()&&!$.force)return null;let J=await HW0(yT);if(!J)return null;return{current:D$,latest:J,hasUpdate:fT(J,D$)}}function Qc($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function gT($){let Z=oY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases/tags/${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return null;let W=await G.json();if(typeof W.body!=="string"||typeof W.html_url!=="string")return null;return{body:W.body,url:W.html_url,version:$}}catch{return null}finally{clearTimeout(z)}}async function vT($){let Z=oY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return[];let W=await G.json();if(!Array.isArray(W))return[];return W.map((q)=>{let U=Qc(q.tag_name);if(!U||typeof q.html_url!=="string"||typeof q.body!=="string")return null;if(C3(U,$.current)<=0)return null;if(C3(U,$.latest)>0)return null;return{version:U,url:q.html_url,body:q.body}}).filter((q)=>q!==null)}catch{return[]}finally{clearTimeout(z)}}async function OF($=12){let Z=oY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),aj);try{let z=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${$}`,{signal:J.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!z.ok)return[];let G=await z.json();if(!Array.isArray(G))return[];return G.map((W)=>{let q=Qc(W.tag_name);if(!q||typeof W.html_url!=="string")return null;return{version:q,url:W.html_url}}).filter((W)=>W!==null)}catch{return[]}finally{clearTimeout(X)}}function kT($){let Z=oY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,yT,oj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",DZ,pJ,aj=3000;var c8=c(()=>{Xc();j5();D$=ij.version,yT=ij.name;DZ=`curl -fsSL ${oj} | sh`;pJ=[]});function i4($){if(!$.client)throw new K1("daemon required","BAD_DAEMON");return $.client}async function Z4($,Z,J){return i4($).request(Z,J)}async function Yc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (G9(),aR)),Promise.resolve().then(() => (T7(),pR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=c(()=>{$8()});async function UW0($){let Z=$.args.require("command"),J=lQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===uY?{generic:!0}:{}}}var Gc,Wc;var mT=c(()=>{q9();f2();B2();Gc={name:"engine-list",summary:"List every engine Rove can launch \u2014 built-ins and your registered presets \u2014 each with its RAW launch command, exactly as it runs. Copy one into `add --command` / `send --tab new --command` verbatim, or edit its flags first. `protocol` is the adapter Rove speaks to it (history, trust, delivery); `generic` = none, which still runs fine but loses transcript reads. Returns { engines }.",flags:[],offline:!0,handler:async()=>({engines:om()})};Wc={name:"set-command",summary:"Set a task's engine launch command (takes effect on the next session rebuild). The protocol Rove speaks to it is derived from the command \u2014 the result reports which one, `generic` when the command names no engine Rove knows.",flags:[$$.taskId(),{...$$.command(),required:!0}],handler:UW0}});function Bc($){let Z=$.args.str("precheck");if(Z===void 0)return{};if(Z.length===0)return{precheck:null};return{precheck:{command:Z,timeoutSeconds:$.args.int("precheck-timeout")??120}}}var qc,Hc,Uc,Kc;var Fc=c(()=>{f2();B2();qc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Hc=[{name:"precheck",type:"string",placeholder:"CMD",description:"Shell command run in the repo BEFORE the engine starts. Non-zero exit skips the run without spawning an agent \u2014 the cheap way to avoid burning a turn when nothing changed."},{name:"precheck-timeout",type:"int",placeholder:"SEC",description:"Seconds before the precheck is killed and the run skipped (default 120)."}],Uc={name:"grace",type:"int",placeholder:"MIN",description:"How late a missed occurrence may still run when the daemon was down (default 60). Only the most recent missed occurrence is ever run."};Kc=[{name:"routine-list",summary:"List scheduled routines with their next run time.",flags:[],handler:($)=>Z4($,"automation.list",{})},{name:"routine-create",summary:"Schedule a prompt. Each firing creates a fresh task (worktree + engine) and delivers it. An enabled routine keeps the daemon alive so it fires with no TUI attached.",flags:[$$.repo(),{name:"name",type:"string",required:!0,placeholder:"N",description:"Routine name."},$$.prompt(!0,"Text delivered as the new session's first message."),{...qc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Hc,Uc,{name:"disabled",type:"bool",description:"Create it paused instead of active."}],handler:($)=>Z4($,"automation.create",{repo:$.args.requirePath("repo"),name:$.args.require("name"),prompt:$.args.require("prompt"),schedule:$.args.require("schedule"),...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{},...$.args.bool("disabled")?{enabled:!1}:{}})},{name:"routine-update",summary:"Change a routine. A new --schedule re-anchors its next run; --precheck '' clears the precheck.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"name",type:"string",placeholder:"N",description:"New name."},$$.prompt(!1,"New prompt."),qc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Hc,Uc],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),...$.args.str("name")!==void 0?{name:$.args.str("name")}:{},...$.args.str("prompt")!==void 0?{prompt:$.args.str("prompt")}:{},...$.args.str("schedule")!==void 0?{schedule:$.args.str("schedule")}:{},...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")!==void 0?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{}})},{name:"routine-set-enabled",summary:"Pause or resume a routine. Disabling the last active one releases the daemon's keep-alive hold.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"enabled",type:"bool",required:!0,description:"true to resume, false to pause."}],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),enabled:$.args.bool("enabled")})},{name:"routine-delete",summary:"Delete a routine and its run history. Tasks it already created are untouched.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.delete",{id:$.args.require("id")})},{name:"routine-run-now",summary:"Run a routine immediately, skipping its precheck (asking for it IS the answer). Does not shift its schedule.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runNow",{id:$.args.require("id")})},{name:"routine-runs",summary:"Run history, newest first. Statuses: dispatched, skipped_precheck (nothing to do), skipped_missed, skipped_unavailable, dispatch_failed.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runs",{id:$.args.require("id")})}]});async function Mc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:lQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Nc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Lc($){let{args:Z,runtime:J}=$,X=await J.resolveRepoRoot(Z.requirePath("repo")),z=Z.int("count"),G=Z.str("agents");if(z!==void 0||G)return KW0($,X,z,G);return BW0($,X)}async function BW0($,Z){let J=i4($),{args:X}=$,z=await Mc($,Z),G={repo:Z,...await GT(),...Nc(z)},W=X.str("title");if(W)G.title=W;let q=X.str("branch");if(q)G.branch=q;let U=X.str("base-branch");if(U)G.baseRef=U;let B=await J.request("task.create",G),M=B.taskId;if(X.bool("activate"))await J.request("task.setActive",{taskId:M});let O=X.enumOf("status");if(O)await J.request("task.status",{taskId:M,status:O});let N=X.bool("pin");if(N!==void 0)await J.request("task.pin",{taskId:M,pinned:N});let j=B.task;if(O||N!==void 0)j=(await J.request("task.get",{taskId:M})).task;let D=X.str("prompt");if(!D)return{taskId:M,task:j,started:!1};let C=await $.runtime.deliverPrompt(J,{id:M,worktreePath:j.worktreePath,kind:j.kind,vendor:j.vendor,command:j.command,modelEffort:j.modelEffort,repo:j.repo,newTask:!0},D);if(j=(await J.request("task.get",{taskId:M})).task,!C.delivered)throw new K1(`task ${M} created but the prompt was not delivered (paste did not land)`,"NOT_DELIVERED",{taskId:M});return{taskId:M,task:j,started:C.started,engineReady:C.engineReady,session:C.session,delivered:C.delivered}}async function KW0($,Z,J,X){let z=i4($),{args:G}=$,W=G.str("prompt");if(!W)throw new K1("--count/--agents spawn parallel attempts of ONE prompt \u2014 pass --prompt","MISSING_FLAG",L3("add"));if(G.str("branch"))throw new K1("--branch names ONE branch and cannot be shared by parallel siblings \u2014 drop it (each sibling gets its own auto branch) or spawn them one at a time","BAD_FLAG",L3("add"));if(X){let E=J!==void 0?"--count":G.str("command")?"--command":null;if(E)throw new K1(`${E} conflicts with --agents, which already names each sibling's engine and how many \u2014 pass one or the other`,"BAD_FLAG",L3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Mc($,Z),M=X?Lj(X):Oj(J??1,B.vendor??"claude");if(M.length>OZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${OZ} \u2014 spawn in batches`,"BAD_FLAG");let O=KO(),N=[],j=null,D=await GT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Nc(w)};if(q)f.title=M.length>1?`${q} #${E+1}/${M.length}`:q;if(U)f.baseRef=U;try{let y=await z.request("task.create",f);N.push({taskId:y.taskId,vendor:T,task:y.task})}catch(y){let h=y instanceof K1?y.code:"CREATE_FAILED",p=y instanceof Error?y.message:String(y);j={vendor:T,error:{message:p,code:h}};break}}let C=await Promise.allSettled(N.map(({taskId:E,vendor:T,task:w})=>$.runtime.deliverPrompt(z,{id:E,worktreePath:w.worktreePath,kind:w.kind,vendor:T,command:w.command,modelEffort:w.modelEffort,repo:w.repo,newTask:!0},W))),_=[],g=[];if(C.forEach((E,T)=>{let{taskId:w,vendor:f}=N[T];if(E.status==="fulfilled"&&E.value.delivered){_.push({ok:!0,taskId:w,vendor:f,started:E.value.started,engineReady:E.value.engineReady,session:E.value.session});return}let y=E.status==="rejected"?E.reason:new K1(`prompt was not confirmed in ${w}'s engine`,"NOT_DELIVERED"),h=y instanceof K1?y.code:"DELIVER_FAILED",p=y instanceof Error?y.message:String(y);g.push({ok:!1,taskId:w,vendor:f,error:{message:p,code:h}})}),j)g.push({ok:!1,vendor:j.vendor,error:j.error});let I={count:N.length,requested:M.length,groupId:O,tasks:_,failures:g};if(g.length>0)throw new K1(`add delivered ${_.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Oc=c(()=>{q9();gP();YF();f2();B2();$8()});var rj;var hT=c(()=>{rj=["backlog","in_progress","in_review","done","canceled","error"]});var jc;var Vc=c(()=>{f2();Oc();hT();jc=[{name:"add",summary:`Create a task (shows in the sidebar immediately). With --prompt it also starts the engine and delivers it. PARALLEL ATTEMPTS: --count N spawns N sibling tasks of the SAME prompt, each in its own worktree/branch (--agents claude:2,codex:1 for a mixed fleet); capped at ${OZ}, prefer 3-4. Does NOT steal focus \u2014 pass --activate to make it the active task. Alias: spawn-task.`,flags:[$$.repo(),$$.title(),{name:"branch",type:"string",placeholder:"B",description:"Explicit branch name (else derived from the title in the repo's own style). Single task only."},{name:"base-branch",type:"string",placeholder:"B",description:"Base ref the worktree branches from."},$$.command(),{name:"count",type:"int",placeholder:"N",description:`Spawn N sibling tasks of one prompt (parallel attempts, cap ${OZ}). Requires --prompt.`},{name:"agents",type:"string",placeholder:"claude:2,codex:1",description:"Per-ENGINE counts for a mixed parallel round (alternative to --count). Engine ids only \u2014 see `engine-list`."},{name:"status",type:"enum",values:rj,default:"backlog",description:"Initial lifecycle status."},{name:"pin",type:"bool",description:"Pin the task to the top of the sidebar."},{name:"activate",type:"bool",default:"false",description:"Make this the active task (pulls every mounted TUI's Tasks-pane focus). Off by default."},$$.prompt(!1,"Optional first message \u2014 when set, materializes the worktree, starts the engine, and pastes it. Required with --count/--agents.")],handler:Lc}]});var _c,Cc;var Ac=c(()=>{hJ();f2();B2();NF();$8();_c={name:"pane-open",summary:"Open a terminal pane in a task's workspace: split the focused tab (default, or --tab's tab) or open a separate command tab, optionally running a command. Broadcast over the daemon's tab.open channel \u2014 an attached TUI showing the task performs the split. Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"tab",type:"string",placeholder:"TAB",description:"Host tab for the split (e.g. tab-3) instead of the focused tab (split placement only)."},{name:"command",type:"string",placeholder:"CMD",description:"Shell command the pane runs (via the login shell's `-ilc`, so pipes/args and your shell rc's PATH/exports work); the pane closes when it exits. Omit for an interactive shell."},{name:"direction",type:"enum",values:["right","down"],default:"right",description:"Split orientation relative to the active pane (split placement only)."},{name:"placement",type:"enum",values:["split","tab"],default:"split",description:"`split` joins the focused tab's split group; `tab` opens a separate command tab."},{name:"title",type:"string",placeholder:"TEXT",description:`Pane label (default: the command's first word, else "shell").`}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("command"),z=y2({fallback:"/bin/sh"}),G=X?[z,"-ilc",X]:[z,"-il"],W=$.args.str("title")??(X?X.trim().split(/\s+/)[0]??"shell":"shell"),q=$.args.str("tab");return Z4($,"tab.open",{taskId:J,argv:G,title:W,...q!==void 0?{tabId:q}:{},placement:$.args.str("placement")??"split",direction:$.args.str("direction")??"right"})}},Cc={name:"pane-close",summary:"Close panes opened by pane-open: every split pane / command tab in the task whose label matches --title. Broadcast over the daemon's tab.close channel \u2014 an attached TUI showing the task performs the close (headless no-op). Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Pane label to close \u2014 the --title the pane was opened with (engine panes are never closed)."},{name:"tab",type:"string",placeholder:"TAB",description:"Scope the title match to one tab (e.g. tab-3) instead of every tab of the task."}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("tab");return Z4($,"tab.close",{taskId:J,title:$.args.str("title"),...X!==void 0?{tabId:X}:{}})}}});var uT,jF,cT,lT="DIRTY_WORKTREE",dT,pT,FW0="TASK_DELETING",nQ,MW0="MAIN_CHECKOUT_DIRTY",nT,NW0="EMPTY_BRANCH",iT,sj="EMPTY_BRANCH_DIRTY_WORKTREE",oT,LW0="LAND_CONFLICT",tj;var nJ=c(()=>{uT=class uT extends Error{from;to;taskId;constructor($,Z,J){super(`illegal transition for task ${J}: ${$} -> ${Z}`);this.from=$;this.to=Z;this.taskId=J;this.name="IllegalTransitionError"}};jF=class jF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};cT=class cT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};dT=class dT extends Error{taskId;constructor($){super(`${lT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};pT=class pT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};nQ=class nQ extends Error{taskId;constructor($){super(`${FW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};nT=class nT extends Error{repo;dir;constructor($,Z){super(`${MW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};iT=class iT extends Error{branch;landedOn;constructor($,Z){super(`${NW0}: '${$}' has no commits ahead of '${Z}' \u2014 landing it would be a no-op (the worker may not have delivered anything)`);this.branch=$;this.landedOn=Z;this.name="EmptyBranchError"}};oT=class oT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${sj}: '${$}' has no commits ahead of '${Z}' but its worktree ${J} has uncommitted changes (${z}) \u2014 commit them in the worktree first, then land again`);this.branch=$;this.landedOn=Z;this.worktreePath=J;this.files=X;this.name="EmptyBranchDirtyWorktreeError"}};tj=class tj extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${LW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function OW0($,Z,J){let X=await zH(),z=X?.taskId;if(!z||z===Z)return J;let G=z;try{let U=await $.request("task.get",{taskId:z});G=U.task.title||U.task.branch||z}catch{}let W=V3(),q=`--task-id ${z} --tab ${X.tabId}`;return`[ROVE PEER] from "${G}" (task ${z} \u2014 load the Rove agent skill FIRST (registered as /rove; legacy /kobe installs still work), then reply: \`${W} send ${q} --prompt "<text>"\`; verb reference: \`${W} schema\`): ${J}`}async function Dc($){let Z=$.args.str("title"),J=$.args.str("body"),X=$.args.str("task");if(Z===void 0&&J===void 0&&X===void 0)throw new K1("issue-update requires --title, --body, and/or --task","MISSING_FLAG");let z=$.args.requirePath("repo"),G=$.args.int("id"),W;if(Z!==void 0||J!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:{type:"update",id:G,title:Z,body:J}});if(X!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:X==="none"?{type:"unlink",id:G}:{type:"link",id:G,taskId:X}});return W}async function Pc($){let Z=i4($),J=$.args.require("prompt"),X=$.args.str("tab");if(X&&X!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(X))throw new K1(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(X)})`,"BAD_TAB");let z=$.args.str("command");if(z&&X!=="new")throw new K1(`--command only applies to a new tab; pass --tab new (got --tab ${X??"<canonical>"})`,"BAD_FLAG",L3("send"));let G=z?lQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await um(Z);if(M){if(W=M.taskId,X===void 0)X=await cm($.runtime,M)}else{let O=await uJ(Z);if(!O)throw new K1("no --task-id given and no active task \u2014 open a task first or pass --task-id","MISSING_TARGET");W=O}}let q=await Z.request("task.get",{taskId:W}),U=$.args.bool("plain")?J:await OW0(Z,W,J),B=await $.runtime.deliverPrompt(Z,{id:W,worktreePath:q.task.worktreePath,kind:q.task.kind,vendor:q.task.vendor,command:q.task.command,modelEffort:z?void 0:q.task.modelEffort,repo:q.task.repo,tab:X,tabVendor:G,tabCommand:z},U);if(!B.delivered)throw new K1(`prompt was not confirmed in ${W}'s engine (paste did not land)`,"NOT_DELIVERED");return{ok:!0,taskId:W,session:B.session,started:B.started,engineReady:B.engineReady}}async function jW0($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("prompt"),z=$.args.str("tab"),G=await Z.request("session.deliver",{taskId:J,text:X,...z!==void 0?{tabId:z}:{},source:"dispatcher"});return{ok:!0,taskId:J,...z!==void 0?{tabId:z}:{},routed:"session.deliver",...G?.clients!==void 0?{clients:G.clients}:{}}}async function Tc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Sc($){let Z=i4($),J=$.args.require("task-id"),X=await Z.request("task.get",{taskId:J}),{tabs:z,running:G}=await $.runtime.taskTabs(J);return{task:X.task,running:G,tabs:z}}async function Ic($){return i4($).request("task.list")}async function Ec($){let Z=i4($),X=$.args.bool("none")?null:$.args.require("task-id");return await Z.request("task.setActive",{taskId:X}),{ok:!0,activeTaskId:X}}async function wc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("archived")??!0,z=await Z.request("task.archive",{taskId:J,archived:X});if(X)await $.runtime.tearDownSession(J);return z}async function xc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("force")??!1,z=$.args.bool("delete-branch")??!1,G=await Z.request("task.delete",{taskId:J,force:X,deleteBranch:z});return await $.runtime.tearDownSession(J),G}async function fc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.str("strategy")==="squash"?"squash":"merge",z=$.args.bool("remove-worktree")??!1,G;try{G=await Z.request("task.land",{taskId:J,strategy:X,deleteBranch:$.args.bool("delete-branch")??!1,archive:$.args.bool("then-archive")??!1,removeWorktree:z,...z?{callerCwd:process.cwd()}:{}})}catch(W){throw VW0(W,J)}return{ok:!0,taskId:J,...G.result}}function VW0($,Z){let J=M1($);if(!J.includes(sj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,sj,{hint:"the worker wrote files but never committed them \u2014 send it back to commit its own work, then land again",nextCommandArgs:["api","send","--task-id",Z,"--prompt",`your work is uncommitted on ${X} \u2014 commit it yourself with a proper message, then report back`]})}async function yc($){let Z=i4($),{args:J}=$,X={repo:J.requirePath("repo"),worktreePath:J.requirePath("worktree")},z=J.str("branch");if(z)X.branch=z;let G=J.str("command");if(G)X.command=G,X.vendor=lQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Rc;var VH=c(()=>{q9();B7();nJ();YF();f2();B2();NF();$8();Rc={name:"dispatch",summary:"Route text into a task's live session via the daemon's session.deliver channel. The dispatcher's messenger (docs/design/dispatcher.md); unlike `send`, it requires an already-hosted session.",flags:[$$.taskId(!0),$$.prompt(!0,"Text delivered into the task's engine session."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:"Deliver into exactly this tab (e.g. tab-3) instead of the canonical engine tab."}],handler:jW0}});var bc;var gc=c(()=>{f2();B2();Ac();VH();bc=[{name:"send",summary:"Paste a follow-up prompt into a task's running engine (one full turn). Without --task-id, a task spawned from another Rove session replies to its dispatcher's tab (then that task's live canonical engine; nothing alive = DISPATCHER_UNREACHABLE, never a silent spawn); otherwise the active task. Sent from inside another Rove task ($ROVE_TASK_ID), the prompt is prefixed with [ROVE PEER] provenance \u2014 who sent it and how to reply (tab-precise) \u2014 so agent-to-agent messaging needs no coordinator.",flags:[$$.taskId(!1),$$.prompt(!0,"Text pasted + submitted into the engine pane."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Tab addressing: "new" spawns the prompt in a fresh engine tab; "tab-N" delivers to that exact alive tab (error when dead/absent). Omitted = the canonical engine tab.'},{...$$.command(),description:"Engine launch command for a `--tab new` tab \u2014 the API twin of the TUI's ctrl+e pick. Lets one worktree run two agents on the same files (e.g. hand the stuck work to codex without leaving the branch). An engine id from `engine-list` or a full command line; pinned to that tab, so it survives restarts and a later set-command on the task. Only valid with --tab new."},{name:"plain",type:"bool",required:!1,description:"Deliver the prompt verbatim \u2014 skip the [ROVE PEER] provenance prefix."}],handler:Pc},Rc,{name:"note",summary:"File a one-line field note \u2014 a resolved, repo-level gotcha worth sharing. Appended to the repo's durable note store (every future session on this repo starts with it) and forwarded to the dispatcher session for live relay (docs/design/dispatcher.md).",flags:[$$.taskId(!0),{name:"text",type:"string",required:!0,placeholder:"TEXT",description:"One line: the verified conclusion another session could act on."}],handler:Tc},{name:"note-list",summary:"Read a repo's accumulated field notes, newest first. Returns { notes }.",flags:[$$.repo(!0)],handler:($)=>Z4($,"note.list",{repo:$.args.requirePath("repo")})},_c,Cc,{name:"notify",summary:"Show a toast in every attached Rove UI \u2014 broadcast over the daemon's notice.event channel. Agents/scripts use it to surface 'done / needs input / error' moments without touching the task's session.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Toast text (one line)."},{name:"kind",type:"string",default:"done",placeholder:"KIND",description:`Free-form kind tag. "done", "needs_input" and "error" get the TUI's severity styling/unread mark; any other value renders neutrally.`},$$.taskId(!1),{name:"source",type:"string",placeholder:"TAG",description:"Free-form origin tag (e.g. an agent name) recorded on the event."}],handler:async($)=>{return Z4($,"notice.send",{title:$.args.str("title"),kind:$.args.str("kind")??"done",taskId:$.args.str("task-id"),source:$.args.str("source")})}},{name:"prompt",summary:"Ask the human for a line of text through the attached TUI's input dialog (plugins' host-provided prompt). Blocks until answered, cancelled, or timed out; returns { value } or { cancelled, reason }.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Dialog title (shown verbatim)."},{name:"placeholder",type:"string",placeholder:"TEXT",description:"Input placeholder."},{name:"initial",type:"string",placeholder:"TEXT",description:"Pre-filled input value."},{name:"timeout",type:"string",placeholder:"MS",description:"Give up after this many milliseconds (default 120000, max 600000)."}],handler:async($)=>{let Z=$.args.str("timeout"),J=Z?Number.parseInt(Z,10):void 0;return Z4($,"ui.prompt",{title:$.args.str("title"),placeholder:$.args.str("placeholder"),initial:$.args.str("initial"),...J&&Number.isFinite(J)?{timeoutMs:J}:{}})}},{name:"set-active",summary:"Set the shared active task (the focus every Tasks pane highlights). Pass --none to clear.",flags:[$$.taskId(!1),{name:"none",type:"bool",description:"Clear the active task instead of setting one."}],handler:Ec}]});var vc;var kc=c(()=>{f2();B2();mT();hT();vc=[{name:"rename",summary:"Set a task's title.",flags:[$$.taskId(),{name:"title",type:"string",required:!0,placeholder:"T",description:"New title."}],handler:($)=>Z4($,"task.rename",{taskId:$.args.require("task-id"),title:$.args.require("title")})},{name:"set-branch",summary:"Rename a task's branch (git branch -m if materialized, else recorded).",flags:[$$.taskId(),{name:"branch",type:"string",required:!0,placeholder:"B",description:"New branch name."}],handler:($)=>Z4($,"task.setBranch",{taskId:$.args.require("task-id"),branch:$.args.require("branch")})},Wc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:rj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as _W0}from"child_process";function DW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function mc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function hc($,Z){let J=Z?.map((X)=>typeof X.message==="string"?X.message:null).filter((X)=>!!X);if(J&&J.length>0)return J.join("; ");return $.trim()||"GitHub CLI returned an empty response"}function uc($,Z,J){let X=["api","graphql","-f",`query=${$}`];for(let[U,B]of Object.entries(Z))X.push("-f",`${U}=${B}`);let z=J.spawn("gh",X,{encoding:"utf8"});if(z.error)throw Error(`failed to run gh: ${z.error.message}`);let G=typeof z.stdout==="string"?z.stdout:String(z.stdout??""),W=typeof z.stderr==="string"?z.stderr:String(z.stderr??""),q;try{q=JSON.parse(G)}catch{throw Error(`failed to parse gh response: ${hc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(hc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function PW0($){return`${$}
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
Submitted from Rove ${D$}.`}function _H($,Z={}){let J=mc($.title,"feedback title"),X=PW0(mc($.body,"feedback body")),z=(Z.repoSlug??oY)();if(!z)throw Error("package repository is not a GitHub repository");let{owner:G,name:W}=DW0(z),q=$.categorySlug?.trim()||aT,U={spawn:Z.spawn??_W0},M=uc(CW0,{owner:G,name:W},U).repository,O=M?.id;if(!O)throw Error(`GitHub repository not found: ${z}`);let N=M.discussionCategories?.nodes?.find((C)=>C.slug===q);if(!N)throw Error(`GitHub Discussion category not found: ${q}`);let D=uc(AW0,{repositoryId:O,categoryId:N.id,title:J,body:X},U).createDiscussion?.discussion;if(!D?.url||typeof D.number!=="number")throw Error("GitHub did not return the created Discussion");return{number:D.number,url:D.url}}var aT="feedback",CW0=`
|
package/dist/cli/rove-run.js
CHANGED
|
@@ -79,7 +79,7 @@ You were spawned by Rove task ${J}. When the work is finished, send your outcome
|
|
|
79
79
|
`).split(`
|
|
80
80
|
`).map((X)=>(X.split("\r").pop()??"").slice(0,tG0));while(J.length>0&&(J[J.length-1]??"").trim()==="")J.pop();return J.slice(-sG0)}function uu($=Jj()){try{let Z=JSON.parse(iG0($,"utf8"));if(Z===null||typeof Z!=="object"||Array.isArray(Z))return{};return Z}catch{return{}}}function RT($,Z=Jj()){if($.key.startsWith("::"))return;if($.exit.code===0&&$.exit.signal===null)return;let J=uu(Z);J[$.key]={key:$.key,pid:$.pid,code:$.exit.code,signal:$.exit.signal,at:$.exit.at,tail:hu($.tail)};let X=Object.values(J).sort((z,G)=>z.at<G.at?1:-1).slice(0,rG0);nG0(aG0(Z),{recursive:!0}),oG0(Z,JSON.stringify(Object.fromEntries(X.map((z)=>[z.key,z])),null,2),"utf8")}var rG0=50,sG0=40,tG0=500,eG0;var uj=c(()=>{T7();eG0=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[@-_]/g});var du={};A$(du,{setRepoLastActiveVendor:()=>lJ,setGlobalDefaultVendor:()=>IT,resolvePreferredVendor:()=>B9,getRepoLastActiveVendor:()=>lu,getGlobalDefaultVendor:()=>cj});function ST($,Z){let J=$?.trim();if(!J)return;if(l5(J)||Z.includes(J))return J;return}function lu($){return ST(E5(cu+$),w2())}function lJ($,Z){Z6(cu+$,Z)}function cj(){let $=w2();return ST(E5("defaultVendor"),$)??ST(E5("lastSelectedVendor"),$)}function IT($){Z6("defaultVendor",$)}function B9($){return($?lu($):void 0)??cj()??H4}var cu="lastActiveVendor.";var CZ=c(()=>{P7();d5();A4()});function z8($=process.env){return{...$,...ET}}var ET;var dJ=c(()=>{ET={GIT_OPTIONAL_LOCKS:"0"}});function pu($){return $>="0"&&$<="7"}function ou($,Z){let J=[],X="",z=()=>{if(X.length>0){for(let W of $W0.encode(X))J.push(W);X=""}},G=Z+1;while(G<$.length){let W=$[G];if(W==='"'){G++;break}if(W==="\\"){let q=$[G+1];if(q===void 0){X+="\\",G++;continue}switch(q){case"a":z(),J.push(7),G+=2;break;case"b":z(),J.push(8),G+=2;break;case"t":z(),J.push(9),G+=2;break;case"n":z(),J.push(10),G+=2;break;case"v":z(),J.push(11),G+=2;break;case"f":z(),J.push(12),G+=2;break;case"r":z(),J.push(13),G+=2;break;case'"':X+='"',G+=2;break;case"\\":X+="\\",G+=2;break;default:if(pu(q)){let U="",B=G+1;while(B<$.length&&U.length<3&&pu($[B]))U+=$[B],B++;z(),J.push(Number.parseInt(U,8)&255),G=B}else X+=q,G+=2;break}}else X+=W,G++}return z(),{value:ZW0.decode(new Uint8Array(J)),end:G}}function AZ($){if($.length===0||$[0]!=='"')return $;return ou($,0).value}function au($,Z){if($[0]==='"'){let X=ou($,0);if($.startsWith(Z,X.end))return{orig:X.value,neu:AZ($.slice(X.end+Z.length))};return null}let J=$.indexOf(Z);if(J<0)return null;return{orig:$.slice(0,J),neu:AZ($.slice(J+Z.length))}}function nu($,Z,J){if(Z.length===0&&$.endsWith("/")&&J.startsWith("/"))return $+J.slice(1);return $+Z+J}function JW0($){let Z=$.indexOf("{");if(Z>=0){let X=$.indexOf("}",Z),z=$.indexOf(" => ",Z);if(X>Z&&z>=0&&z<X){let G=$.slice(0,Z),W=$.slice(Z+1,z),q=$.slice(z+4,X),U=$.slice(X+1);return{path:nu(G,q,U),origPath:nu(G,W,U)}}}let J=au($," => ");if(J)return{path:J.neu,origPath:J.orig};return{path:AZ($)}}function lj($){let Z=[];for(let J of $.split(`
|
|
81
81
|
`)){let X=J.replace(/\r$/,"");if(X.length<4)continue;if(X.startsWith("##"))continue;let z=X[0],G=X[1];if(X[2]!==" ")continue;let W=X.slice(3);if(z==="R"||z==="C"||G==="R"||G==="C"){let q=au(W," -> ");if(q){Z.push({x:z,y:G,path:q.neu,origPath:q.orig});continue}}Z.push({x:z,y:G,path:AZ(W)})}return Z}function iu($){if($==="-")return null;let Z=Number.parseInt($,10);return Number.isNaN(Z)?null:Z}function ru($){let Z=[];for(let J of $.split(`
|
|
82
|
-
`)){let X=J.replace(/\r$/,"");if(X.length===0)continue;let z=X.indexOf("\t");if(z<0)continue;let G=X.indexOf("\t",z+1);if(G<0)continue;let W=X.slice(G+1);if(W.length===0)continue;let q=JW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:iu(X.slice(0,z)),deleted:iu(X.slice(z+1,G))})}return Z}var $W0,ZW0;var dj=c(()=>{$W0=new TextEncoder,ZW0=new TextDecoder});var su={};A$(su,{sameWorktreeChanges:()=>FF,readWorktreeChanges:()=>QW0,pickPushedChanges:()=>wT,parsePorcelain:()=>OH});import{spawnSync as XW0}from"child_process";function FF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function wT($,Z){if(!$)return null;return $.get(Z)??pj}function QW0($){if(!$)return pj;try{let Z=XW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return pj;return OH(Z.stdout)}catch{return pj}}function OH($){let Z=0,J=0;for(let{x:X,y:z}of lj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var pj;var jH=c(()=>{dJ();dj();pj={added:0,deleted:0}});var Zc={};A$(Zc,{resolveBaseRef:()=>eu,readBranchSignals:()=>YW0,parseShortstat:()=>$c});import{spawnSync as zW0}from"child_process";function nj($,Z){try{let J=zW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function eu($){let Z=nj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(nj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function $c($){let Z=(J)=>{let X=$.match(J);return X?Number.parseInt(X[1]??"0",10):0};return{files:Z(/(\d+) files? changed/),insertions:Z(/(\d+) insertions?\(\+\)/),deletions:Z(/(\d+) deletions?\(-\)/)}}function YW0($){if(!$)return tu;let Z=eu($);if(!Z)return tu;let J=nj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=nj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:$c(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var tu;var Jc=c(()=>{dJ();tu={baseRef:null,ahead:null,diff:null}});async function GW0($,Z,J){let X;try{X=await ZT()}catch(z){throw new K1(`failed to start PTY host for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}try{if($.tab&&$.tab!=="new"){let O=U2({command:$.command,vendor:$.vendor,effort:$.modelEffort})[0];return await QT(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?mu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=cQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);HH(G,Z);let B=qH({task:{id:$.id,kind:$.kind,vendor:G,repo:$.repo},worktreePath:Z,shell:process.env.SHELL?.trim()||"/bin/zsh",argv:q,promptIntent:$.newTask?{kind:"new-task",prompt:J,spawnerTaskId:(await zH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await XT(X.rpc,{id:$.id,engineBin:q[0]},Z,J,B,{forceNew:z!==void 0});if(M.started&&!M.engineReady)throw new K1(`failed to start hosted engine session for ${$.id}`,"SESSION_FAILED");if(M.started&&U)if(z)ku($.id,z,U);else DT($.id,U);else if(!z)DT($.id);return M}catch(z){if(z instanceof K1)throw z;throw new K1(`hosted engine session failed for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}finally{X.close()}}async function xT($,Z,J,X=WW0){let z=Z.worktreePath;if(!z)z=(await $.request("task.ensureWorktree",{taskId:Z.id})).worktreePath;if(!z)throw new K1(`task ${Z.id} has no worktree`,"NO_WORKTREE");let G=await X.deliverHosted(Z,z,J);if(!G)throw new K1(`failed to start hosted engine session for ${Z.id}`,"SESSION_FAILED");return G}var WW0,MF;var NF=c(()=>{q9();B7();Pj();Rj();Sj();YF();Bj();PT();$8();WW0={deliverHosted:GW0};MF={isTaskRunning:async($)=>(await MF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await XH();if(J)try{Z=await QH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (NZ(),tO)),B=Z.filter((M)=>M.alive&&typeof M.pid==="number"&&M.pid>0);if(B.length>0){let M=q(await U());X=new Map(B.map((O)=>[O.key,W(M,O.pid)?.vendor??null]))}}catch{}let z={};try{z=(await Promise.resolve().then(() => (uj(),TT))).readPtyExitRecords()}catch{}let G=yu($);return{tabs:gu(G,$,Z,z,X),running:vu(G,$,Z)}},deliverPrompt:($,Z,J)=>xT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (A4(),mq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (CZ(),du));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (jH(),su))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (Jc(),Zc))).readBranchSignals($),tearDownSession:async($)=>{let Z=await XH();if(Z)try{await zT(Z.rpc,$T(await QH(Z.rpc),$))}catch{}finally{Z.close()}}}});var ij;var Xc=c(()=>{ij={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.175",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://github.com/Sma1lboy/rove#readme",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react-task-dialogs":"KOBE_DEV=1 bun ./src/tui-react/component/mock-dialogs-host.tsx","dev:mock-react-filetree":"KOBE_DEV=1 bun ./src/tui-react/panes/filetree/mock-host.tsx","dev:mock-react-sidebar":"KOBE_DEV=1 bun ./src/tui-react/panes/sidebar/mock-host.tsx","dev:mock-react-terminal":"KOBE_DEV=1 bun ./src/tui-react/panes/terminal/mock-host.tsx","dev:mock-react-dialogs":"KOBE_DEV=1 bun ./src/tui-react/mock/dialogs-host.tsx","dev:mock-react-workspace":"KOBE_DEV=1 bun ./src/tui-react/workspace/mock-host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:with-web":"bun run build",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.14","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","kobe-web":"workspace:*","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]}});var zc={};A$(zc,{repoSlug:()=>oY,releasePageUrl:()=>kT,recommendedGlobalInstallCommand:()=>bT,isNewerSemver:()=>fT,fetchReleaseSummaries:()=>OF,fetchReleaseNotesRange:()=>vT,fetchReleaseNotes:()=>gT,compareSemver:()=>C3,checkLatestVersion:()=>aY,breakingVersionsCrossed:()=>LF,UPDATE_SCRIPT_URL:()=>oj,UPDATE_COMMAND:()=>DZ,PACKAGE_NAME:()=>yT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function oY(){let $=ij.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function bT(){return`npm install -g ${yT}@latest`}function LF($,Z,J=pJ){let[X,z]=C3($,Z)<=0?[$,Z]:[Z,$];return J.filter((G)=>C3(G,X)>0&&C3(G,z)<=0)}async function HW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),aj);try{let X=$.replace("/","%2F"),z=await fetch(`https://registry.npmjs.org/${X}/latest`,{signal:Z.signal,headers:{accept:"application/json"}});if(!z.ok)return null;let G=await z.json();if(typeof G.version!=="string")return null;return G.version}catch{return null}finally{clearTimeout(J)}}function fT($,Z){return C3($,Z)>0}function C3($,Z){let J=(G)=>G.split("-")[0]??G,X=J($).split(".").map((G)=>Number.parseInt(G,10)),z=J(Z).split(".").map((G)=>Number.parseInt(G,10));for(let G=0;G<3;G++){let W=X[G]??0,q=z[G]??0;if(Number.isNaN(W)||Number.isNaN(q))return 0;if(W>q)return 1;if(W<q)return-1}return 0}async function aY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:fT(Z,D$)};if(fq()&&!$.force)return null;let J=await HW0(yT);if(!J)return null;return{current:D$,latest:J,hasUpdate:fT(J,D$)}}function Qc($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function gT($){let Z=oY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases/tags/${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return null;let W=await G.json();if(typeof W.body!=="string"||typeof W.html_url!=="string")return null;return{body:W.body,url:W.html_url,version:$}}catch{return null}finally{clearTimeout(z)}}async function vT($){let Z=oY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return[];let W=await G.json();if(!Array.isArray(W))return[];return W.map((q)=>{let U=Qc(q.tag_name);if(!U||typeof q.html_url!=="string"||typeof q.body!=="string")return null;if(C3(U,$.current)<=0)return null;if(C3(U,$.latest)>0)return null;return{version:U,url:q.html_url,body:q.body}}).filter((q)=>q!==null)}catch{return[]}finally{clearTimeout(z)}}async function OF($=12){let Z=oY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),aj);try{let z=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${$}`,{signal:J.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!z.ok)return[];let G=await z.json();if(!Array.isArray(G))return[];return G.map((W)=>{let q=Qc(W.tag_name);if(!q||typeof W.html_url!=="string")return null;return{version:q,url:W.html_url}}).filter((W)=>W!==null)}catch{return[]}finally{clearTimeout(X)}}function kT($){let Z=oY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,yT,oj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",DZ,pJ,aj=3000;var c8=c(()=>{Xc();j5();D$=ij.version,yT=ij.name;DZ=`curl -fsSL ${oj} | sh`;pJ=[]});function i4($){if(!$.client)throw new K1("daemon required","BAD_DAEMON");return $.client}async function Z4($,Z,J){return i4($).request(Z,J)}async function Yc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (G9(),aR)),Promise.resolve().then(() => (T7(),pR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=c(()=>{$8()});async function UW0($){let Z=$.args.require("command"),J=lQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===uY?{generic:!0}:{}}}var Gc,Wc;var mT=c(()=>{q9();f2();B2();Gc={name:"engine-list",summary:"List every engine Rove can launch \u2014 built-ins and your registered presets \u2014 each with its RAW launch command, exactly as it runs. Copy one into `add --command` / `send --tab new --command` verbatim, or edit its flags first. `protocol` is the adapter Rove speaks to it (history, trust, delivery); `generic` = none, which still runs fine but loses transcript reads. Returns { engines }.",flags:[],offline:!0,handler:async()=>({engines:om()})};Wc={name:"set-command",summary:"Set a task's engine launch command (takes effect on the next session rebuild). The protocol Rove speaks to it is derived from the command \u2014 the result reports which one, `generic` when the command names no engine Rove knows.",flags:[$$.taskId(),{...$$.command(),required:!0}],handler:UW0}});function Bc($){let Z=$.args.str("precheck");if(Z===void 0)return{};if(Z.length===0)return{precheck:null};return{precheck:{command:Z,timeoutSeconds:$.args.int("precheck-timeout")??120}}}var qc,Hc,Uc,Kc;var Fc=c(()=>{f2();B2();qc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Hc=[{name:"precheck",type:"string",placeholder:"CMD",description:"Shell command run in the repo BEFORE the engine starts. Non-zero exit skips the run without spawning an agent \u2014 the cheap way to avoid burning a turn when nothing changed."},{name:"precheck-timeout",type:"int",placeholder:"SEC",description:"Seconds before the precheck is killed and the run skipped (default 120)."}],Uc={name:"grace",type:"int",placeholder:"MIN",description:"How late a missed occurrence may still run when the daemon was down (default 60). Only the most recent missed occurrence is ever run."};Kc=[{name:"routine-list",summary:"List scheduled routines with their next run time.",flags:[],handler:($)=>Z4($,"automation.list",{})},{name:"routine-create",summary:"Schedule a prompt. Each firing creates a fresh task (worktree + engine) and delivers it. An enabled routine keeps the daemon alive so it fires with no TUI attached.",flags:[$$.repo(),{name:"name",type:"string",required:!0,placeholder:"N",description:"Routine name."},$$.prompt(!0,"Text delivered as the new session's first message."),{...qc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Hc,Uc,{name:"disabled",type:"bool",description:"Create it paused instead of active."}],handler:($)=>Z4($,"automation.create",{repo:$.args.requirePath("repo"),name:$.args.require("name"),prompt:$.args.require("prompt"),schedule:$.args.require("schedule"),...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{},...$.args.bool("disabled")?{enabled:!1}:{}})},{name:"routine-update",summary:"Change a routine. A new --schedule re-anchors its next run; --precheck '' clears the precheck.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"name",type:"string",placeholder:"N",description:"New name."},$$.prompt(!1,"New prompt."),qc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Hc,Uc],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),...$.args.str("name")!==void 0?{name:$.args.str("name")}:{},...$.args.str("prompt")!==void 0?{prompt:$.args.str("prompt")}:{},...$.args.str("schedule")!==void 0?{schedule:$.args.str("schedule")}:{},...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")!==void 0?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{}})},{name:"routine-set-enabled",summary:"Pause or resume a routine. Disabling the last active one releases the daemon's keep-alive hold.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"enabled",type:"bool",required:!0,description:"true to resume, false to pause."}],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),enabled:$.args.bool("enabled")})},{name:"routine-delete",summary:"Delete a routine and its run history. Tasks it already created are untouched.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.delete",{id:$.args.require("id")})},{name:"routine-run-now",summary:"Run a routine immediately, skipping its precheck (asking for it IS the answer). Does not shift its schedule.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runNow",{id:$.args.require("id")})},{name:"routine-runs",summary:"Run history, newest first. Statuses: dispatched, skipped_precheck (nothing to do), skipped_missed, skipped_unavailable, dispatch_failed.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runs",{id:$.args.require("id")})}]});async function Mc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:lQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Nc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Lc($){let{args:Z,runtime:J}=$,X=await J.resolveRepoRoot(Z.requirePath("repo")),z=Z.int("count"),G=Z.str("agents");if(z!==void 0||G)return KW0($,X,z,G);return BW0($,X)}async function BW0($,Z){let J=i4($),{args:X}=$,z=await Mc($,Z),G={repo:Z,...await GT(),...Nc(z)},W=X.str("title");if(W)G.title=W;let q=X.str("branch");if(q)G.branch=q;let U=X.str("base-branch");if(U)G.baseRef=U;let B=await J.request("task.create",G),M=B.taskId;if(X.bool("activate"))await J.request("task.setActive",{taskId:M});let O=X.enumOf("status");if(O)await J.request("task.status",{taskId:M,status:O});let N=X.bool("pin");if(N!==void 0)await J.request("task.pin",{taskId:M,pinned:N});let j=B.task;if(O||N!==void 0)j=(await J.request("task.get",{taskId:M})).task;let D=X.str("prompt");if(!D)return{taskId:M,task:j,started:!1};let C=await $.runtime.deliverPrompt(J,{id:M,worktreePath:j.worktreePath,kind:j.kind,vendor:j.vendor,command:j.command,modelEffort:j.modelEffort,repo:j.repo,newTask:!0},D);if(j=(await J.request("task.get",{taskId:M})).task,!C.delivered)throw new K1(`task ${M} created but the prompt was not delivered (paste did not land)`,"NOT_DELIVERED",{taskId:M});return{taskId:M,task:j,started:C.started,engineReady:C.engineReady,session:C.session,delivered:C.delivered}}async function KW0($,Z,J,X){let z=i4($),{args:G}=$,W=G.str("prompt");if(!W)throw new K1("--count/--agents spawn parallel attempts of ONE prompt \u2014 pass --prompt","MISSING_FLAG",L3("add"));if(G.str("branch"))throw new K1("--branch names ONE branch and cannot be shared by parallel siblings \u2014 drop it (each sibling gets its own auto branch) or spawn them one at a time","BAD_FLAG",L3("add"));if(X){let E=J!==void 0?"--count":G.str("command")?"--command":null;if(E)throw new K1(`${E} conflicts with --agents, which already names each sibling's engine and how many \u2014 pass one or the other`,"BAD_FLAG",L3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Mc($,Z),M=X?Lj(X):Oj(J??1,B.vendor??"claude");if(M.length>OZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${OZ} \u2014 spawn in batches`,"BAD_FLAG");let O=KO(),N=[],j=null,D=await GT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Nc(w)};if(q)f.title=M.length>1?`${q} #${E+1}/${M.length}`:q;if(U)f.baseRef=U;try{let y=await z.request("task.create",f);N.push({taskId:y.taskId,vendor:T,task:y.task})}catch(y){let h=y instanceof K1?y.code:"CREATE_FAILED",p=y instanceof Error?y.message:String(y);j={vendor:T,error:{message:p,code:h}};break}}let C=await Promise.allSettled(N.map(({taskId:E,vendor:T,task:w})=>$.runtime.deliverPrompt(z,{id:E,worktreePath:w.worktreePath,kind:w.kind,vendor:T,command:w.command,modelEffort:w.modelEffort,repo:w.repo,newTask:!0},W))),_=[],g=[];if(C.forEach((E,T)=>{let{taskId:w,vendor:f}=N[T];if(E.status==="fulfilled"&&E.value.delivered){_.push({ok:!0,taskId:w,vendor:f,started:E.value.started,engineReady:E.value.engineReady,session:E.value.session});return}let y=E.status==="rejected"?E.reason:new K1(`prompt was not confirmed in ${w}'s engine`,"NOT_DELIVERED"),h=y instanceof K1?y.code:"DELIVER_FAILED",p=y instanceof Error?y.message:String(y);g.push({ok:!1,taskId:w,vendor:f,error:{message:p,code:h}})}),j)g.push({ok:!1,vendor:j.vendor,error:j.error});let I={count:N.length,requested:M.length,groupId:O,tasks:_,failures:g};if(g.length>0)throw new K1(`add delivered ${_.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Oc=c(()=>{q9();gP();YF();f2();B2();$8()});var rj;var hT=c(()=>{rj=["backlog","in_progress","in_review","done","canceled","error"]});var jc;var Vc=c(()=>{f2();Oc();hT();jc=[{name:"add",summary:`Create a task (shows in the sidebar immediately). With --prompt it also starts the engine and delivers it. PARALLEL ATTEMPTS: --count N spawns N sibling tasks of the SAME prompt, each in its own worktree/branch (--agents claude:2,codex:1 for a mixed fleet); capped at ${OZ}, prefer 3-4. Does NOT steal focus \u2014 pass --activate to make it the active task. Alias: spawn-task.`,flags:[$$.repo(),$$.title(),{name:"branch",type:"string",placeholder:"B",description:"Explicit branch name (else derived from the title in the repo's own style). Single task only."},{name:"base-branch",type:"string",placeholder:"B",description:"Base ref the worktree branches from."},$$.command(),{name:"count",type:"int",placeholder:"N",description:`Spawn N sibling tasks of one prompt (parallel attempts, cap ${OZ}). Requires --prompt.`},{name:"agents",type:"string",placeholder:"claude:2,codex:1",description:"Per-ENGINE counts for a mixed parallel round (alternative to --count). Engine ids only \u2014 see `engine-list`."},{name:"status",type:"enum",values:rj,default:"backlog",description:"Initial lifecycle status."},{name:"pin",type:"bool",description:"Pin the task to the top of the sidebar."},{name:"activate",type:"bool",default:"false",description:"Make this the active task (pulls every mounted TUI's Tasks-pane focus). Off by default."},$$.prompt(!1,"Optional first message \u2014 when set, materializes the worktree, starts the engine, and pastes it. Required with --count/--agents.")],handler:Lc}]});var _c,Cc;var Ac=c(()=>{hJ();f2();B2();NF();$8();_c={name:"pane-open",summary:"Open a terminal pane in a task's workspace: split the focused tab (default, or --tab's tab) or open a separate command tab, optionally running a command. Broadcast over the daemon's tab.open channel \u2014 an attached TUI showing the task performs the split. Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"tab",type:"string",placeholder:"TAB",description:"Host tab for the split (e.g. tab-3) instead of the focused tab (split placement only)."},{name:"command",type:"string",placeholder:"CMD",description:"Shell command the pane runs (via the login shell's `-ilc`, so pipes/args and your shell rc's PATH/exports work); the pane closes when it exits. Omit for an interactive shell."},{name:"direction",type:"enum",values:["right","down"],default:"right",description:"Split orientation relative to the active pane (split placement only)."},{name:"placement",type:"enum",values:["split","tab"],default:"split",description:"`split` joins the focused tab's split group; `tab` opens a separate command tab."},{name:"title",type:"string",placeholder:"TEXT",description:`Pane label (default: the command's first word, else "shell").`}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("command"),z=y2({fallback:"/bin/sh"}),G=X?[z,"-ilc",X]:[z,"-il"],W=$.args.str("title")??(X?X.trim().split(/\s+/)[0]??"shell":"shell"),q=$.args.str("tab");return Z4($,"tab.open",{taskId:J,argv:G,title:W,...q!==void 0?{tabId:q}:{},placement:$.args.str("placement")??"split",direction:$.args.str("direction")??"right"})}},Cc={name:"pane-close",summary:"Close panes opened by pane-open: every split pane / command tab in the task whose label matches --title. Broadcast over the daemon's tab.close channel \u2014 an attached TUI showing the task performs the close (headless no-op). Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Pane label to close \u2014 the --title the pane was opened with (engine panes are never closed)."},{name:"tab",type:"string",placeholder:"TAB",description:"Scope the title match to one tab (e.g. tab-3) instead of every tab of the task."}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("tab");return Z4($,"tab.close",{taskId:J,title:$.args.str("title"),...X!==void 0?{tabId:X}:{}})}}});var uT,jF,cT,lT="DIRTY_WORKTREE",dT,pT,FW0="TASK_DELETING",nQ,MW0="MAIN_CHECKOUT_DIRTY",nT,NW0="EMPTY_BRANCH",iT,sj="EMPTY_BRANCH_DIRTY_WORKTREE",oT,LW0="LAND_CONFLICT",tj;var nJ=c(()=>{uT=class uT extends Error{from;to;taskId;constructor($,Z,J){super(`illegal transition for task ${J}: ${$} -> ${Z}`);this.from=$;this.to=Z;this.taskId=J;this.name="IllegalTransitionError"}};jF=class jF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};cT=class cT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};dT=class dT extends Error{taskId;constructor($){super(`${lT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};pT=class pT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};nQ=class nQ extends Error{taskId;constructor($){super(`${FW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};nT=class nT extends Error{repo;dir;constructor($,Z){super(`${MW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};iT=class iT extends Error{branch;landedOn;constructor($,Z){super(`${NW0}: '${$}' has no commits ahead of '${Z}' \u2014 landing it would be a no-op (the worker may not have delivered anything)`);this.branch=$;this.landedOn=Z;this.name="EmptyBranchError"}};oT=class oT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${sj}: '${$}' has no commits ahead of '${Z}' but its worktree ${J} has uncommitted changes (${z}) \u2014 commit them in the worktree first, then land again`);this.branch=$;this.landedOn=Z;this.worktreePath=J;this.files=X;this.name="EmptyBranchDirtyWorktreeError"}};tj=class tj extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${LW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function OW0($,Z,J){let X=await zH(),z=X?.taskId;if(!z||z===Z)return J;let G=z;try{let U=await $.request("task.get",{taskId:z});G=U.task.title||U.task.branch||z}catch{}let W=V3(),q=`--task-id ${z} --tab ${X.tabId}`;return`[ROVE PEER] from "${G}" (task ${z} \u2014 load the Rove agent skill FIRST (registered as /rove; legacy /kobe installs still work), then reply: \`${W} send ${q} --prompt "<text>"\`; verb reference: \`${W} schema\`): ${J}`}async function Dc($){let Z=$.args.str("title"),J=$.args.str("body"),X=$.args.str("task");if(Z===void 0&&J===void 0&&X===void 0)throw new K1("issue-update requires --title, --body, and/or --task","MISSING_FLAG");let z=$.args.requirePath("repo"),G=$.args.int("id"),W;if(Z!==void 0||J!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:{type:"update",id:G,title:Z,body:J}});if(X!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:X==="none"?{type:"unlink",id:G}:{type:"link",id:G,taskId:X}});return W}async function Pc($){let Z=i4($),J=$.args.require("prompt"),X=$.args.str("tab");if(X&&X!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(X))throw new K1(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(X)})`,"BAD_TAB");let z=$.args.str("command");if(z&&X!=="new")throw new K1(`--command only applies to a new tab; pass --tab new (got --tab ${X??"<canonical>"})`,"BAD_FLAG",L3("send"));let G=z?lQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await um(Z);if(M){if(W=M.taskId,X===void 0)X=await cm($.runtime,M)}else{let O=await uJ(Z);if(!O)throw new K1("no --task-id given and no active task \u2014 open a task first or pass --task-id","MISSING_TARGET");W=O}}let q=await Z.request("task.get",{taskId:W}),U=$.args.bool("plain")?J:await OW0(Z,W,J),B=await $.runtime.deliverPrompt(Z,{id:W,worktreePath:q.task.worktreePath,kind:q.task.kind,vendor:q.task.vendor,command:q.task.command,modelEffort:z?void 0:q.task.modelEffort,repo:q.task.repo,tab:X,tabVendor:G,tabCommand:z},U);if(!B.delivered)throw new K1(`prompt was not confirmed in ${W}'s engine (paste did not land)`,"NOT_DELIVERED");return{ok:!0,taskId:W,session:B.session,started:B.started,engineReady:B.engineReady}}async function jW0($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("prompt"),z=$.args.str("tab"),G=await Z.request("session.deliver",{taskId:J,text:X,...z!==void 0?{tabId:z}:{},source:"dispatcher"});return{ok:!0,taskId:J,...z!==void 0?{tabId:z}:{},routed:"session.deliver",...G?.clients!==void 0?{clients:G.clients}:{}}}async function Tc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Sc($){let Z=i4($),J=$.args.require("task-id"),X=await Z.request("task.get",{taskId:J}),{tabs:z,running:G}=await $.runtime.taskTabs(J);return{task:X.task,running:G,tabs:z}}async function Ic($){return i4($).request("task.list")}async function Ec($){let Z=i4($),X=$.args.bool("none")?null:$.args.require("task-id");return await Z.request("task.setActive",{taskId:X}),{ok:!0,activeTaskId:X}}async function wc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("archived")??!0,z=await Z.request("task.archive",{taskId:J,archived:X});if(X)await $.runtime.tearDownSession(J);return z}async function xc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("force")??!1,z=$.args.bool("delete-branch")??!1,G=await Z.request("task.delete",{taskId:J,force:X,deleteBranch:z});return await $.runtime.tearDownSession(J),G}async function fc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.str("strategy")==="squash"?"squash":"merge",z=$.args.bool("remove-worktree")??!1,G;try{G=await Z.request("task.land",{taskId:J,strategy:X,deleteBranch:$.args.bool("delete-branch")??!1,archive:$.args.bool("then-archive")??!1,removeWorktree:z,...z?{callerCwd:process.cwd()}:{}})}catch(W){throw VW0(W,J)}return{ok:!0,taskId:J,...G.result}}function VW0($,Z){let J=M1($);if(!J.includes(sj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,sj,{hint:"the worker wrote files but never committed them \u2014 send it back to commit its own work, then land again",nextCommandArgs:["api","send","--task-id",Z,"--prompt",`your work is uncommitted on ${X} \u2014 commit it yourself with a proper message, then report back`]})}async function yc($){let Z=i4($),{args:J}=$,X={repo:J.requirePath("repo"),worktreePath:J.requirePath("worktree")},z=J.str("branch");if(z)X.branch=z;let G=J.str("command");if(G)X.command=G,X.vendor=lQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Rc;var VH=c(()=>{q9();B7();nJ();YF();f2();B2();NF();$8();Rc={name:"dispatch",summary:"Route text into a task's live session via the daemon's session.deliver channel. The dispatcher's messenger (docs/design/dispatcher.md); unlike `send`, it requires an already-hosted session.",flags:[$$.taskId(!0),$$.prompt(!0,"Text delivered into the task's engine session."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:"Deliver into exactly this tab (e.g. tab-3) instead of the canonical engine tab."}],handler:jW0}});var bc;var gc=c(()=>{f2();B2();Ac();VH();bc=[{name:"send",summary:"Paste a follow-up prompt into a task's running engine (one full turn). Without --task-id, a task spawned from another Rove session replies to its dispatcher's tab (then that task's live canonical engine; nothing alive = DISPATCHER_UNREACHABLE, never a silent spawn); otherwise the active task. Sent from inside another Rove task ($ROVE_TASK_ID), the prompt is prefixed with [ROVE PEER] provenance \u2014 who sent it and how to reply (tab-precise) \u2014 so agent-to-agent messaging needs no coordinator.",flags:[$$.taskId(!1),$$.prompt(!0,"Text pasted + submitted into the engine pane."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Tab addressing: "new" spawns the prompt in a fresh engine tab; "tab-N" delivers to that exact alive tab (error when dead/absent). Omitted = the canonical engine tab.'},{...$$.command(),description:"Engine launch command for a `--tab new` tab \u2014 the API twin of the TUI's ctrl+e pick. Lets one worktree run two agents on the same files (e.g. hand the stuck work to codex without leaving the branch). An engine id from `engine-list` or a full command line; pinned to that tab, so it survives restarts and a later set-command on the task. Only valid with --tab new."},{name:"plain",type:"bool",required:!1,description:"Deliver the prompt verbatim \u2014 skip the [ROVE PEER] provenance prefix."}],handler:Pc},Rc,{name:"note",summary:"File a one-line field note \u2014 a resolved, repo-level gotcha worth sharing. Appended to the repo's durable note store (every future session on this repo starts with it) and forwarded to the dispatcher session for live relay (docs/design/dispatcher.md).",flags:[$$.taskId(!0),{name:"text",type:"string",required:!0,placeholder:"TEXT",description:"One line: the verified conclusion another session could act on."}],handler:Tc},{name:"note-list",summary:"Read a repo's accumulated field notes, newest first. Returns { notes }.",flags:[$$.repo(!0)],handler:($)=>Z4($,"note.list",{repo:$.args.requirePath("repo")})},_c,Cc,{name:"notify",summary:"Show a toast in every attached Rove UI \u2014 broadcast over the daemon's notice.event channel. Agents/scripts use it to surface 'done / needs input / error' moments without touching the task's session.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Toast text (one line)."},{name:"kind",type:"string",default:"done",placeholder:"KIND",description:`Free-form kind tag. "done", "needs_input" and "error" get the TUI's severity styling/unread mark; any other value renders neutrally.`},$$.taskId(!1),{name:"source",type:"string",placeholder:"TAG",description:"Free-form origin tag (e.g. an agent name) recorded on the event."}],handler:async($)=>{return Z4($,"notice.send",{title:$.args.str("title"),kind:$.args.str("kind")??"done",taskId:$.args.str("task-id"),source:$.args.str("source")})}},{name:"prompt",summary:"Ask the human for a line of text through the attached TUI's input dialog (plugins' host-provided prompt). Blocks until answered, cancelled, or timed out; returns { value } or { cancelled, reason }.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Dialog title (shown verbatim)."},{name:"placeholder",type:"string",placeholder:"TEXT",description:"Input placeholder."},{name:"initial",type:"string",placeholder:"TEXT",description:"Pre-filled input value."},{name:"timeout",type:"string",placeholder:"MS",description:"Give up after this many milliseconds (default 120000, max 600000)."}],handler:async($)=>{let Z=$.args.str("timeout"),J=Z?Number.parseInt(Z,10):void 0;return Z4($,"ui.prompt",{title:$.args.str("title"),placeholder:$.args.str("placeholder"),initial:$.args.str("initial"),...J&&Number.isFinite(J)?{timeoutMs:J}:{}})}},{name:"set-active",summary:"Set the shared active task (the focus every Tasks pane highlights). Pass --none to clear.",flags:[$$.taskId(!1),{name:"none",type:"bool",description:"Clear the active task instead of setting one."}],handler:Ec}]});var vc;var kc=c(()=>{f2();B2();mT();hT();vc=[{name:"rename",summary:"Set a task's title.",flags:[$$.taskId(),{name:"title",type:"string",required:!0,placeholder:"T",description:"New title."}],handler:($)=>Z4($,"task.rename",{taskId:$.args.require("task-id"),title:$.args.require("title")})},{name:"set-branch",summary:"Rename a task's branch (git branch -m if materialized, else recorded).",flags:[$$.taskId(),{name:"branch",type:"string",required:!0,placeholder:"B",description:"New branch name."}],handler:($)=>Z4($,"task.setBranch",{taskId:$.args.require("task-id"),branch:$.args.require("branch")})},Wc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:rj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as _W0}from"child_process";function DW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function mc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function hc($,Z){let J=Z?.map((X)=>typeof X.message==="string"?X.message:null).filter((X)=>!!X);if(J&&J.length>0)return J.join("; ");return $.trim()||"GitHub CLI returned an empty response"}function uc($,Z,J){let X=["api","graphql","-f",`query=${$}`];for(let[U,B]of Object.entries(Z))X.push("-f",`${U}=${B}`);let z=J.spawn("gh",X,{encoding:"utf8"});if(z.error)throw Error(`failed to run gh: ${z.error.message}`);let G=typeof z.stdout==="string"?z.stdout:String(z.stdout??""),W=typeof z.stderr==="string"?z.stderr:String(z.stderr??""),q;try{q=JSON.parse(G)}catch{throw Error(`failed to parse gh response: ${hc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(hc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function PW0($){return`${$}
|
|
82
|
+
`)){let X=J.replace(/\r$/,"");if(X.length===0)continue;let z=X.indexOf("\t");if(z<0)continue;let G=X.indexOf("\t",z+1);if(G<0)continue;let W=X.slice(G+1);if(W.length===0)continue;let q=JW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:iu(X.slice(0,z)),deleted:iu(X.slice(z+1,G))})}return Z}var $W0,ZW0;var dj=c(()=>{$W0=new TextEncoder,ZW0=new TextDecoder});var su={};A$(su,{sameWorktreeChanges:()=>FF,readWorktreeChanges:()=>QW0,pickPushedChanges:()=>wT,parsePorcelain:()=>OH});import{spawnSync as XW0}from"child_process";function FF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function wT($,Z){if(!$)return null;return $.get(Z)??pj}function QW0($){if(!$)return pj;try{let Z=XW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return pj;return OH(Z.stdout)}catch{return pj}}function OH($){let Z=0,J=0;for(let{x:X,y:z}of lj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var pj;var jH=c(()=>{dJ();dj();pj={added:0,deleted:0}});var Zc={};A$(Zc,{resolveBaseRef:()=>eu,readBranchSignals:()=>YW0,parseShortstat:()=>$c});import{spawnSync as zW0}from"child_process";function nj($,Z){try{let J=zW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function eu($){let Z=nj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(nj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function $c($){let Z=(J)=>{let X=$.match(J);return X?Number.parseInt(X[1]??"0",10):0};return{files:Z(/(\d+) files? changed/),insertions:Z(/(\d+) insertions?\(\+\)/),deletions:Z(/(\d+) deletions?\(-\)/)}}function YW0($){if(!$)return tu;let Z=eu($);if(!Z)return tu;let J=nj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=nj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:$c(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var tu;var Jc=c(()=>{dJ();tu={baseRef:null,ahead:null,diff:null}});async function GW0($,Z,J){let X;try{X=await ZT()}catch(z){throw new K1(`failed to start PTY host for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}try{if($.tab&&$.tab!=="new"){let O=U2({command:$.command,vendor:$.vendor,effort:$.modelEffort})[0];return await QT(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?mu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=cQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);HH(G,Z);let B=qH({task:{id:$.id,kind:$.kind,vendor:G,repo:$.repo},worktreePath:Z,shell:process.env.SHELL?.trim()||"/bin/zsh",argv:q,promptIntent:$.newTask?{kind:"new-task",prompt:J,spawnerTaskId:(await zH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await XT(X.rpc,{id:$.id,engineBin:q[0]},Z,J,B,{forceNew:z!==void 0});if(M.started&&!M.engineReady)throw new K1(`failed to start hosted engine session for ${$.id}`,"SESSION_FAILED");if(M.started&&U)if(z)ku($.id,z,U);else DT($.id,U);else if(!z)DT($.id);return M}catch(z){if(z instanceof K1)throw z;throw new K1(`hosted engine session failed for ${$.id}: ${z instanceof Error?z.message:String(z)}`,"SESSION_FAILED")}finally{X.close()}}async function xT($,Z,J,X=WW0){let z=Z.worktreePath;if(!z)z=(await $.request("task.ensureWorktree",{taskId:Z.id})).worktreePath;if(!z)throw new K1(`task ${Z.id} has no worktree`,"NO_WORKTREE");let G=await X.deliverHosted(Z,z,J);if(!G)throw new K1(`failed to start hosted engine session for ${Z.id}`,"SESSION_FAILED");return G}var WW0,MF;var NF=c(()=>{q9();B7();Pj();Rj();Sj();YF();Bj();PT();$8();WW0={deliverHosted:GW0};MF={isTaskRunning:async($)=>(await MF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await XH();if(J)try{Z=await QH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (NZ(),tO)),B=Z.filter((M)=>M.alive&&typeof M.pid==="number"&&M.pid>0);if(B.length>0){let M=q(await U());X=new Map(B.map((O)=>[O.key,W(M,O.pid)?.vendor??null]))}}catch{}let z={};try{z=(await Promise.resolve().then(() => (uj(),TT))).readPtyExitRecords()}catch{}let G=yu($);return{tabs:gu(G,$,Z,z,X),running:vu(G,$,Z)}},deliverPrompt:($,Z,J)=>xT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (A4(),mq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (CZ(),du));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (jH(),su))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (Jc(),Zc))).readBranchSignals($),tearDownSession:async($)=>{let Z=await XH();if(Z)try{await zT(Z.rpc,$T(await QH(Z.rpc),$))}catch{}finally{Z.close()}}}});var ij;var Xc=c(()=>{ij={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.176",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://github.com/Sma1lboy/rove#readme",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react-task-dialogs":"KOBE_DEV=1 bun ./src/tui-react/component/mock-dialogs-host.tsx","dev:mock-react-filetree":"KOBE_DEV=1 bun ./src/tui-react/panes/filetree/mock-host.tsx","dev:mock-react-sidebar":"KOBE_DEV=1 bun ./src/tui-react/panes/sidebar/mock-host.tsx","dev:mock-react-terminal":"KOBE_DEV=1 bun ./src/tui-react/panes/terminal/mock-host.tsx","dev:mock-react-dialogs":"KOBE_DEV=1 bun ./src/tui-react/mock/dialogs-host.tsx","dev:mock-react-workspace":"KOBE_DEV=1 bun ./src/tui-react/workspace/mock-host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:with-web":"bun run build",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.14","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","kobe-web":"workspace:*","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]}});var zc={};A$(zc,{repoSlug:()=>oY,releasePageUrl:()=>kT,recommendedGlobalInstallCommand:()=>bT,isNewerSemver:()=>fT,fetchReleaseSummaries:()=>OF,fetchReleaseNotesRange:()=>vT,fetchReleaseNotes:()=>gT,compareSemver:()=>C3,checkLatestVersion:()=>aY,breakingVersionsCrossed:()=>LF,UPDATE_SCRIPT_URL:()=>oj,UPDATE_COMMAND:()=>DZ,PACKAGE_NAME:()=>yT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function oY(){let $=ij.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function bT(){return`npm install -g ${yT}@latest`}function LF($,Z,J=pJ){let[X,z]=C3($,Z)<=0?[$,Z]:[Z,$];return J.filter((G)=>C3(G,X)>0&&C3(G,z)<=0)}async function HW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),aj);try{let X=$.replace("/","%2F"),z=await fetch(`https://registry.npmjs.org/${X}/latest`,{signal:Z.signal,headers:{accept:"application/json"}});if(!z.ok)return null;let G=await z.json();if(typeof G.version!=="string")return null;return G.version}catch{return null}finally{clearTimeout(J)}}function fT($,Z){return C3($,Z)>0}function C3($,Z){let J=(G)=>G.split("-")[0]??G,X=J($).split(".").map((G)=>Number.parseInt(G,10)),z=J(Z).split(".").map((G)=>Number.parseInt(G,10));for(let G=0;G<3;G++){let W=X[G]??0,q=z[G]??0;if(Number.isNaN(W)||Number.isNaN(q))return 0;if(W>q)return 1;if(W<q)return-1}return 0}async function aY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:fT(Z,D$)};if(fq()&&!$.force)return null;let J=await HW0(yT);if(!J)return null;return{current:D$,latest:J,hasUpdate:fT(J,D$)}}function Qc($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function gT($){let Z=oY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases/tags/${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return null;let W=await G.json();if(typeof W.body!=="string"||typeof W.html_url!=="string")return null;return{body:W.body,url:W.html_url,version:$}}catch{return null}finally{clearTimeout(z)}}async function vT($){let Z=oY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),aj);try{let G=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!G.ok)return[];let W=await G.json();if(!Array.isArray(W))return[];return W.map((q)=>{let U=Qc(q.tag_name);if(!U||typeof q.html_url!=="string"||typeof q.body!=="string")return null;if(C3(U,$.current)<=0)return null;if(C3(U,$.latest)>0)return null;return{version:U,url:q.html_url,body:q.body}}).filter((q)=>q!==null)}catch{return[]}finally{clearTimeout(z)}}async function OF($=12){let Z=oY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),aj);try{let z=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${$}`,{signal:J.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!z.ok)return[];let G=await z.json();if(!Array.isArray(G))return[];return G.map((W)=>{let q=Qc(W.tag_name);if(!q||typeof W.html_url!=="string")return null;return{version:q,url:W.html_url}}).filter((W)=>W!==null)}catch{return[]}finally{clearTimeout(X)}}function kT($){let Z=oY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,yT,oj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",DZ,pJ,aj=3000;var c8=c(()=>{Xc();j5();D$=ij.version,yT=ij.name;DZ=`curl -fsSL ${oj} | sh`;pJ=[]});function i4($){if(!$.client)throw new K1("daemon required","BAD_DAEMON");return $.client}async function Z4($,Z,J){return i4($).request(Z,J)}async function Yc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (G9(),aR)),Promise.resolve().then(() => (T7(),pR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=c(()=>{$8()});async function UW0($){let Z=$.args.require("command"),J=lQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===uY?{generic:!0}:{}}}var Gc,Wc;var mT=c(()=>{q9();f2();B2();Gc={name:"engine-list",summary:"List every engine Rove can launch \u2014 built-ins and your registered presets \u2014 each with its RAW launch command, exactly as it runs. Copy one into `add --command` / `send --tab new --command` verbatim, or edit its flags first. `protocol` is the adapter Rove speaks to it (history, trust, delivery); `generic` = none, which still runs fine but loses transcript reads. Returns { engines }.",flags:[],offline:!0,handler:async()=>({engines:om()})};Wc={name:"set-command",summary:"Set a task's engine launch command (takes effect on the next session rebuild). The protocol Rove speaks to it is derived from the command \u2014 the result reports which one, `generic` when the command names no engine Rove knows.",flags:[$$.taskId(),{...$$.command(),required:!0}],handler:UW0}});function Bc($){let Z=$.args.str("precheck");if(Z===void 0)return{};if(Z.length===0)return{precheck:null};return{precheck:{command:Z,timeoutSeconds:$.args.int("precheck-timeout")??120}}}var qc,Hc,Uc,Kc;var Fc=c(()=>{f2();B2();qc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Hc=[{name:"precheck",type:"string",placeholder:"CMD",description:"Shell command run in the repo BEFORE the engine starts. Non-zero exit skips the run without spawning an agent \u2014 the cheap way to avoid burning a turn when nothing changed."},{name:"precheck-timeout",type:"int",placeholder:"SEC",description:"Seconds before the precheck is killed and the run skipped (default 120)."}],Uc={name:"grace",type:"int",placeholder:"MIN",description:"How late a missed occurrence may still run when the daemon was down (default 60). Only the most recent missed occurrence is ever run."};Kc=[{name:"routine-list",summary:"List scheduled routines with their next run time.",flags:[],handler:($)=>Z4($,"automation.list",{})},{name:"routine-create",summary:"Schedule a prompt. Each firing creates a fresh task (worktree + engine) and delivers it. An enabled routine keeps the daemon alive so it fires with no TUI attached.",flags:[$$.repo(),{name:"name",type:"string",required:!0,placeholder:"N",description:"Routine name."},$$.prompt(!0,"Text delivered as the new session's first message."),{...qc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Hc,Uc,{name:"disabled",type:"bool",description:"Create it paused instead of active."}],handler:($)=>Z4($,"automation.create",{repo:$.args.requirePath("repo"),name:$.args.require("name"),prompt:$.args.require("prompt"),schedule:$.args.require("schedule"),...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{},...$.args.bool("disabled")?{enabled:!1}:{}})},{name:"routine-update",summary:"Change a routine. A new --schedule re-anchors its next run; --precheck '' clears the precheck.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"name",type:"string",placeholder:"N",description:"New name."},$$.prompt(!1,"New prompt."),qc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Hc,Uc],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),...$.args.str("name")!==void 0?{name:$.args.str("name")}:{},...$.args.str("prompt")!==void 0?{prompt:$.args.str("prompt")}:{},...$.args.str("schedule")!==void 0?{schedule:$.args.str("schedule")}:{},...$.args.vendor()?{vendor:$.args.vendor()}:{},...$.args.str("base-branch")!==void 0?{baseRef:$.args.str("base-branch")}:{},...Bc($),...$.args.int("grace")!==void 0?{missedRunGraceMinutes:$.args.int("grace")}:{}})},{name:"routine-set-enabled",summary:"Pause or resume a routine. Disabling the last active one releases the daemon's keep-alive hold.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."},{name:"enabled",type:"bool",required:!0,description:"true to resume, false to pause."}],handler:($)=>Z4($,"automation.update",{id:$.args.require("id"),enabled:$.args.bool("enabled")})},{name:"routine-delete",summary:"Delete a routine and its run history. Tasks it already created are untouched.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.delete",{id:$.args.require("id")})},{name:"routine-run-now",summary:"Run a routine immediately, skipping its precheck (asking for it IS the answer). Does not shift its schedule.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runNow",{id:$.args.require("id")})},{name:"routine-runs",summary:"Run history, newest first. Statuses: dispatched, skipped_precheck (nothing to do), skipped_missed, skipped_unavailable, dispatch_failed.",flags:[{name:"id",type:"string",required:!0,placeholder:"ID",description:"Routine id."}],handler:($)=>Z4($,"automation.runs",{id:$.args.require("id")})}]});async function Mc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:lQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Nc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Lc($){let{args:Z,runtime:J}=$,X=await J.resolveRepoRoot(Z.requirePath("repo")),z=Z.int("count"),G=Z.str("agents");if(z!==void 0||G)return KW0($,X,z,G);return BW0($,X)}async function BW0($,Z){let J=i4($),{args:X}=$,z=await Mc($,Z),G={repo:Z,...await GT(),...Nc(z)},W=X.str("title");if(W)G.title=W;let q=X.str("branch");if(q)G.branch=q;let U=X.str("base-branch");if(U)G.baseRef=U;let B=await J.request("task.create",G),M=B.taskId;if(X.bool("activate"))await J.request("task.setActive",{taskId:M});let O=X.enumOf("status");if(O)await J.request("task.status",{taskId:M,status:O});let N=X.bool("pin");if(N!==void 0)await J.request("task.pin",{taskId:M,pinned:N});let j=B.task;if(O||N!==void 0)j=(await J.request("task.get",{taskId:M})).task;let D=X.str("prompt");if(!D)return{taskId:M,task:j,started:!1};let C=await $.runtime.deliverPrompt(J,{id:M,worktreePath:j.worktreePath,kind:j.kind,vendor:j.vendor,command:j.command,modelEffort:j.modelEffort,repo:j.repo,newTask:!0},D);if(j=(await J.request("task.get",{taskId:M})).task,!C.delivered)throw new K1(`task ${M} created but the prompt was not delivered (paste did not land)`,"NOT_DELIVERED",{taskId:M});return{taskId:M,task:j,started:C.started,engineReady:C.engineReady,session:C.session,delivered:C.delivered}}async function KW0($,Z,J,X){let z=i4($),{args:G}=$,W=G.str("prompt");if(!W)throw new K1("--count/--agents spawn parallel attempts of ONE prompt \u2014 pass --prompt","MISSING_FLAG",L3("add"));if(G.str("branch"))throw new K1("--branch names ONE branch and cannot be shared by parallel siblings \u2014 drop it (each sibling gets its own auto branch) or spawn them one at a time","BAD_FLAG",L3("add"));if(X){let E=J!==void 0?"--count":G.str("command")?"--command":null;if(E)throw new K1(`${E} conflicts with --agents, which already names each sibling's engine and how many \u2014 pass one or the other`,"BAD_FLAG",L3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Mc($,Z),M=X?Lj(X):Oj(J??1,B.vendor??"claude");if(M.length>OZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${OZ} \u2014 spawn in batches`,"BAD_FLAG");let O=KO(),N=[],j=null,D=await GT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Nc(w)};if(q)f.title=M.length>1?`${q} #${E+1}/${M.length}`:q;if(U)f.baseRef=U;try{let y=await z.request("task.create",f);N.push({taskId:y.taskId,vendor:T,task:y.task})}catch(y){let h=y instanceof K1?y.code:"CREATE_FAILED",p=y instanceof Error?y.message:String(y);j={vendor:T,error:{message:p,code:h}};break}}let C=await Promise.allSettled(N.map(({taskId:E,vendor:T,task:w})=>$.runtime.deliverPrompt(z,{id:E,worktreePath:w.worktreePath,kind:w.kind,vendor:T,command:w.command,modelEffort:w.modelEffort,repo:w.repo,newTask:!0},W))),_=[],g=[];if(C.forEach((E,T)=>{let{taskId:w,vendor:f}=N[T];if(E.status==="fulfilled"&&E.value.delivered){_.push({ok:!0,taskId:w,vendor:f,started:E.value.started,engineReady:E.value.engineReady,session:E.value.session});return}let y=E.status==="rejected"?E.reason:new K1(`prompt was not confirmed in ${w}'s engine`,"NOT_DELIVERED"),h=y instanceof K1?y.code:"DELIVER_FAILED",p=y instanceof Error?y.message:String(y);g.push({ok:!1,taskId:w,vendor:f,error:{message:p,code:h}})}),j)g.push({ok:!1,vendor:j.vendor,error:j.error});let I={count:N.length,requested:M.length,groupId:O,tasks:_,failures:g};if(g.length>0)throw new K1(`add delivered ${_.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Oc=c(()=>{q9();gP();YF();f2();B2();$8()});var rj;var hT=c(()=>{rj=["backlog","in_progress","in_review","done","canceled","error"]});var jc;var Vc=c(()=>{f2();Oc();hT();jc=[{name:"add",summary:`Create a task (shows in the sidebar immediately). With --prompt it also starts the engine and delivers it. PARALLEL ATTEMPTS: --count N spawns N sibling tasks of the SAME prompt, each in its own worktree/branch (--agents claude:2,codex:1 for a mixed fleet); capped at ${OZ}, prefer 3-4. Does NOT steal focus \u2014 pass --activate to make it the active task. Alias: spawn-task.`,flags:[$$.repo(),$$.title(),{name:"branch",type:"string",placeholder:"B",description:"Explicit branch name (else derived from the title in the repo's own style). Single task only."},{name:"base-branch",type:"string",placeholder:"B",description:"Base ref the worktree branches from."},$$.command(),{name:"count",type:"int",placeholder:"N",description:`Spawn N sibling tasks of one prompt (parallel attempts, cap ${OZ}). Requires --prompt.`},{name:"agents",type:"string",placeholder:"claude:2,codex:1",description:"Per-ENGINE counts for a mixed parallel round (alternative to --count). Engine ids only \u2014 see `engine-list`."},{name:"status",type:"enum",values:rj,default:"backlog",description:"Initial lifecycle status."},{name:"pin",type:"bool",description:"Pin the task to the top of the sidebar."},{name:"activate",type:"bool",default:"false",description:"Make this the active task (pulls every mounted TUI's Tasks-pane focus). Off by default."},$$.prompt(!1,"Optional first message \u2014 when set, materializes the worktree, starts the engine, and pastes it. Required with --count/--agents.")],handler:Lc}]});var _c,Cc;var Ac=c(()=>{hJ();f2();B2();NF();$8();_c={name:"pane-open",summary:"Open a terminal pane in a task's workspace: split the focused tab (default, or --tab's tab) or open a separate command tab, optionally running a command. Broadcast over the daemon's tab.open channel \u2014 an attached TUI showing the task performs the split. Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"tab",type:"string",placeholder:"TAB",description:"Host tab for the split (e.g. tab-3) instead of the focused tab (split placement only)."},{name:"command",type:"string",placeholder:"CMD",description:"Shell command the pane runs (via the login shell's `-ilc`, so pipes/args and your shell rc's PATH/exports work); the pane closes when it exits. Omit for an interactive shell."},{name:"direction",type:"enum",values:["right","down"],default:"right",description:"Split orientation relative to the active pane (split placement only)."},{name:"placement",type:"enum",values:["split","tab"],default:"split",description:"`split` joins the focused tab's split group; `tab` opens a separate command tab."},{name:"title",type:"string",placeholder:"TEXT",description:`Pane label (default: the command's first word, else "shell").`}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("command"),z=y2({fallback:"/bin/sh"}),G=X?[z,"-ilc",X]:[z,"-il"],W=$.args.str("title")??(X?X.trim().split(/\s+/)[0]??"shell":"shell"),q=$.args.str("tab");return Z4($,"tab.open",{taskId:J,argv:G,title:W,...q!==void 0?{tabId:q}:{},placement:$.args.str("placement")??"split",direction:$.args.str("direction")??"right"})}},Cc={name:"pane-close",summary:"Close panes opened by pane-open: every split pane / command tab in the task whose label matches --title. Broadcast over the daemon's tab.close channel \u2014 an attached TUI showing the task performs the close (headless no-op). Task defaults to $ROVE_TASK_ID, then the active task.",flags:[$$.taskId(!1),{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Pane label to close \u2014 the --title the pane was opened with (engine panes are never closed)."},{name:"tab",type:"string",placeholder:"TAB",description:"Scope the title match to one tab (e.g. tab-3) instead of every tab of the task."}],handler:async($)=>{let Z=i4($),J=$.args.str("task-id")??process.env.KOBE_TASK_ID??await uJ(Z);if(!J)throw new K1("no target task: pass --task-id (no $ROVE_TASK_ID, no active task)","TASK_NOT_FOUND");let X=$.args.str("tab");return Z4($,"tab.close",{taskId:J,title:$.args.str("title"),...X!==void 0?{tabId:X}:{}})}}});var uT,jF,cT,lT="DIRTY_WORKTREE",dT,pT,FW0="TASK_DELETING",nQ,MW0="MAIN_CHECKOUT_DIRTY",nT,NW0="EMPTY_BRANCH",iT,sj="EMPTY_BRANCH_DIRTY_WORKTREE",oT,LW0="LAND_CONFLICT",tj;var nJ=c(()=>{uT=class uT extends Error{from;to;taskId;constructor($,Z,J){super(`illegal transition for task ${J}: ${$} -> ${Z}`);this.from=$;this.to=Z;this.taskId=J;this.name="IllegalTransitionError"}};jF=class jF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};cT=class cT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};dT=class dT extends Error{taskId;constructor($){super(`${lT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};pT=class pT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};nQ=class nQ extends Error{taskId;constructor($){super(`${FW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};nT=class nT extends Error{repo;dir;constructor($,Z){super(`${MW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};iT=class iT extends Error{branch;landedOn;constructor($,Z){super(`${NW0}: '${$}' has no commits ahead of '${Z}' \u2014 landing it would be a no-op (the worker may not have delivered anything)`);this.branch=$;this.landedOn=Z;this.name="EmptyBranchError"}};oT=class oT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${sj}: '${$}' has no commits ahead of '${Z}' but its worktree ${J} has uncommitted changes (${z}) \u2014 commit them in the worktree first, then land again`);this.branch=$;this.landedOn=Z;this.worktreePath=J;this.files=X;this.name="EmptyBranchDirtyWorktreeError"}};tj=class tj extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${LW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function OW0($,Z,J){let X=await zH(),z=X?.taskId;if(!z||z===Z)return J;let G=z;try{let U=await $.request("task.get",{taskId:z});G=U.task.title||U.task.branch||z}catch{}let W=V3(),q=`--task-id ${z} --tab ${X.tabId}`;return`[ROVE PEER] from "${G}" (task ${z} \u2014 load the Rove agent skill FIRST (registered as /rove; legacy /kobe installs still work), then reply: \`${W} send ${q} --prompt "<text>"\`; verb reference: \`${W} schema\`): ${J}`}async function Dc($){let Z=$.args.str("title"),J=$.args.str("body"),X=$.args.str("task");if(Z===void 0&&J===void 0&&X===void 0)throw new K1("issue-update requires --title, --body, and/or --task","MISSING_FLAG");let z=$.args.requirePath("repo"),G=$.args.int("id"),W;if(Z!==void 0||J!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:{type:"update",id:G,title:Z,body:J}});if(X!==void 0)W=await Z4($,"issue.mutate",{repoRoot:z,op:X==="none"?{type:"unlink",id:G}:{type:"link",id:G,taskId:X}});return W}async function Pc($){let Z=i4($),J=$.args.require("prompt"),X=$.args.str("tab");if(X&&X!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(X))throw new K1(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(X)})`,"BAD_TAB");let z=$.args.str("command");if(z&&X!=="new")throw new K1(`--command only applies to a new tab; pass --tab new (got --tab ${X??"<canonical>"})`,"BAD_FLAG",L3("send"));let G=z?lQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await um(Z);if(M){if(W=M.taskId,X===void 0)X=await cm($.runtime,M)}else{let O=await uJ(Z);if(!O)throw new K1("no --task-id given and no active task \u2014 open a task first or pass --task-id","MISSING_TARGET");W=O}}let q=await Z.request("task.get",{taskId:W}),U=$.args.bool("plain")?J:await OW0(Z,W,J),B=await $.runtime.deliverPrompt(Z,{id:W,worktreePath:q.task.worktreePath,kind:q.task.kind,vendor:q.task.vendor,command:q.task.command,modelEffort:z?void 0:q.task.modelEffort,repo:q.task.repo,tab:X,tabVendor:G,tabCommand:z},U);if(!B.delivered)throw new K1(`prompt was not confirmed in ${W}'s engine (paste did not land)`,"NOT_DELIVERED");return{ok:!0,taskId:W,session:B.session,started:B.started,engineReady:B.engineReady}}async function jW0($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("prompt"),z=$.args.str("tab"),G=await Z.request("session.deliver",{taskId:J,text:X,...z!==void 0?{tabId:z}:{},source:"dispatcher"});return{ok:!0,taskId:J,...z!==void 0?{tabId:z}:{},routed:"session.deliver",...G?.clients!==void 0?{clients:G.clients}:{}}}async function Tc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Sc($){let Z=i4($),J=$.args.require("task-id"),X=await Z.request("task.get",{taskId:J}),{tabs:z,running:G}=await $.runtime.taskTabs(J);return{task:X.task,running:G,tabs:z}}async function Ic($){return i4($).request("task.list")}async function Ec($){let Z=i4($),X=$.args.bool("none")?null:$.args.require("task-id");return await Z.request("task.setActive",{taskId:X}),{ok:!0,activeTaskId:X}}async function wc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("archived")??!0,z=await Z.request("task.archive",{taskId:J,archived:X});if(X)await $.runtime.tearDownSession(J);return z}async function xc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.bool("force")??!1,z=$.args.bool("delete-branch")??!1,G=await Z.request("task.delete",{taskId:J,force:X,deleteBranch:z});return await $.runtime.tearDownSession(J),G}async function fc($){let Z=i4($),J=$.args.require("task-id"),X=$.args.str("strategy")==="squash"?"squash":"merge",z=$.args.bool("remove-worktree")??!1,G;try{G=await Z.request("task.land",{taskId:J,strategy:X,deleteBranch:$.args.bool("delete-branch")??!1,archive:$.args.bool("then-archive")??!1,removeWorktree:z,...z?{callerCwd:process.cwd()}:{}})}catch(W){throw VW0(W,J)}return{ok:!0,taskId:J,...G.result}}function VW0($,Z){let J=M1($);if(!J.includes(sj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,sj,{hint:"the worker wrote files but never committed them \u2014 send it back to commit its own work, then land again",nextCommandArgs:["api","send","--task-id",Z,"--prompt",`your work is uncommitted on ${X} \u2014 commit it yourself with a proper message, then report back`]})}async function yc($){let Z=i4($),{args:J}=$,X={repo:J.requirePath("repo"),worktreePath:J.requirePath("worktree")},z=J.str("branch");if(z)X.branch=z;let G=J.str("command");if(G)X.command=G,X.vendor=lQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Rc;var VH=c(()=>{q9();B7();nJ();YF();f2();B2();NF();$8();Rc={name:"dispatch",summary:"Route text into a task's live session via the daemon's session.deliver channel. The dispatcher's messenger (docs/design/dispatcher.md); unlike `send`, it requires an already-hosted session.",flags:[$$.taskId(!0),$$.prompt(!0,"Text delivered into the task's engine session."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:"Deliver into exactly this tab (e.g. tab-3) instead of the canonical engine tab."}],handler:jW0}});var bc;var gc=c(()=>{f2();B2();Ac();VH();bc=[{name:"send",summary:"Paste a follow-up prompt into a task's running engine (one full turn). Without --task-id, a task spawned from another Rove session replies to its dispatcher's tab (then that task's live canonical engine; nothing alive = DISPATCHER_UNREACHABLE, never a silent spawn); otherwise the active task. Sent from inside another Rove task ($ROVE_TASK_ID), the prompt is prefixed with [ROVE PEER] provenance \u2014 who sent it and how to reply (tab-precise) \u2014 so agent-to-agent messaging needs no coordinator.",flags:[$$.taskId(!1),$$.prompt(!0,"Text pasted + submitted into the engine pane."),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Tab addressing: "new" spawns the prompt in a fresh engine tab; "tab-N" delivers to that exact alive tab (error when dead/absent). Omitted = the canonical engine tab.'},{...$$.command(),description:"Engine launch command for a `--tab new` tab \u2014 the API twin of the TUI's ctrl+e pick. Lets one worktree run two agents on the same files (e.g. hand the stuck work to codex without leaving the branch). An engine id from `engine-list` or a full command line; pinned to that tab, so it survives restarts and a later set-command on the task. Only valid with --tab new."},{name:"plain",type:"bool",required:!1,description:"Deliver the prompt verbatim \u2014 skip the [ROVE PEER] provenance prefix."}],handler:Pc},Rc,{name:"note",summary:"File a one-line field note \u2014 a resolved, repo-level gotcha worth sharing. Appended to the repo's durable note store (every future session on this repo starts with it) and forwarded to the dispatcher session for live relay (docs/design/dispatcher.md).",flags:[$$.taskId(!0),{name:"text",type:"string",required:!0,placeholder:"TEXT",description:"One line: the verified conclusion another session could act on."}],handler:Tc},{name:"note-list",summary:"Read a repo's accumulated field notes, newest first. Returns { notes }.",flags:[$$.repo(!0)],handler:($)=>Z4($,"note.list",{repo:$.args.requirePath("repo")})},_c,Cc,{name:"notify",summary:"Show a toast in every attached Rove UI \u2014 broadcast over the daemon's notice.event channel. Agents/scripts use it to surface 'done / needs input / error' moments without touching the task's session.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Toast text (one line)."},{name:"kind",type:"string",default:"done",placeholder:"KIND",description:`Free-form kind tag. "done", "needs_input" and "error" get the TUI's severity styling/unread mark; any other value renders neutrally.`},$$.taskId(!1),{name:"source",type:"string",placeholder:"TAG",description:"Free-form origin tag (e.g. an agent name) recorded on the event."}],handler:async($)=>{return Z4($,"notice.send",{title:$.args.str("title"),kind:$.args.str("kind")??"done",taskId:$.args.str("task-id"),source:$.args.str("source")})}},{name:"prompt",summary:"Ask the human for a line of text through the attached TUI's input dialog (plugins' host-provided prompt). Blocks until answered, cancelled, or timed out; returns { value } or { cancelled, reason }.",flags:[{name:"title",type:"string",required:!0,placeholder:"TEXT",description:"Dialog title (shown verbatim)."},{name:"placeholder",type:"string",placeholder:"TEXT",description:"Input placeholder."},{name:"initial",type:"string",placeholder:"TEXT",description:"Pre-filled input value."},{name:"timeout",type:"string",placeholder:"MS",description:"Give up after this many milliseconds (default 120000, max 600000)."}],handler:async($)=>{let Z=$.args.str("timeout"),J=Z?Number.parseInt(Z,10):void 0;return Z4($,"ui.prompt",{title:$.args.str("title"),placeholder:$.args.str("placeholder"),initial:$.args.str("initial"),...J&&Number.isFinite(J)?{timeoutMs:J}:{}})}},{name:"set-active",summary:"Set the shared active task (the focus every Tasks pane highlights). Pass --none to clear.",flags:[$$.taskId(!1),{name:"none",type:"bool",description:"Clear the active task instead of setting one."}],handler:Ec}]});var vc;var kc=c(()=>{f2();B2();mT();hT();vc=[{name:"rename",summary:"Set a task's title.",flags:[$$.taskId(),{name:"title",type:"string",required:!0,placeholder:"T",description:"New title."}],handler:($)=>Z4($,"task.rename",{taskId:$.args.require("task-id"),title:$.args.require("title")})},{name:"set-branch",summary:"Rename a task's branch (git branch -m if materialized, else recorded).",flags:[$$.taskId(),{name:"branch",type:"string",required:!0,placeholder:"B",description:"New branch name."}],handler:($)=>Z4($,"task.setBranch",{taskId:$.args.require("task-id"),branch:$.args.require("branch")})},Wc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:rj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as _W0}from"child_process";function DW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function mc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function hc($,Z){let J=Z?.map((X)=>typeof X.message==="string"?X.message:null).filter((X)=>!!X);if(J&&J.length>0)return J.join("; ");return $.trim()||"GitHub CLI returned an empty response"}function uc($,Z,J){let X=["api","graphql","-f",`query=${$}`];for(let[U,B]of Object.entries(Z))X.push("-f",`${U}=${B}`);let z=J.spawn("gh",X,{encoding:"utf8"});if(z.error)throw Error(`failed to run gh: ${z.error.message}`);let G=typeof z.stdout==="string"?z.stdout:String(z.stdout??""),W=typeof z.stderr==="string"?z.stderr:String(z.stderr??""),q;try{q=JSON.parse(G)}catch{throw Error(`failed to parse gh response: ${hc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(hc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function PW0($){return`${$}
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
Submitted from Rove ${D$}.`}function _H($,Z={}){let J=mc($.title,"feedback title"),X=PW0(mc($.body,"feedback body")),z=(Z.repoSlug??oY)();if(!z)throw Error("package repository is not a GitHub repository");let{owner:G,name:W}=DW0(z),q=$.categorySlug?.trim()||aT,U={spawn:Z.spawn??_W0},M=uc(CW0,{owner:G,name:W},U).repository,O=M?.id;if(!O)throw Error(`GitHub repository not found: ${z}`);let N=M.discussionCategories?.nodes?.find((C)=>C.slug===q);if(!N)throw Error(`GitHub Discussion category not found: ${q}`);let D=uc(AW0,{repositoryId:O,categoryId:N.id,title:J,body:X},U).createDiscussion?.discussion;if(!D?.url||typeof D.number!=="number")throw Error("GitHub did not return the created Discussion");return{number:D.number,url:D.url}}var aT="feedback",CW0=`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@sma1lboy/kobe",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.176",
|
|
5
5
|
"description": "Rove — the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "bun@1.3.13",
|