@sma1lboy/kobe 0.8.170 → 0.8.171
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,oG0));while(J.length>0&&(J[J.length-1]??"").trim()==="")J.pop();return J.slice(-iG0)}function bu($=sO()){try{let Z=JSON.parse(dG0($,"utf8"));if(Z===null||typeof Z!=="object"||Array.isArray(Z))return{};return Z}catch{return{}}}function _T($,Z=sO()){if($.key.startsWith("::"))return;if($.exit.code===0&&$.exit.signal===null)return;let J=bu(Z);J[$.key]={key:$.key,pid:$.pid,code:$.exit.code,signal:$.exit.signal,at:$.exit.at,tail:yu($.tail)};let X=Object.values(J).sort((z,G)=>z.at<G.at?1:-1).slice(0,nG0);cG0(pG0(Z),{recursive:!0}),lG0(Z,JSON.stringify(Object.fromEntries(X.map((z)=>[z.key,z])),null,2),"utf8")}var nG0=50,iG0=40,oG0=500,aG0;var gj=d(()=>{P7();aG0=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[@-_]/g});var ku={};A$(ku,{setRepoLastActiveVendor:()=>dJ,setGlobalDefaultVendor:()=>DT,resolvePreferredVendor:()=>U9,getRepoLastActiveVendor:()=>vu,getGlobalDefaultVendor:()=>vj});function AT($,Z){let J=$?.trim();if(!J)return;if(d5(J)||Z.includes(J))return J;return}function vu($){return AT(E5(gu+$),w2())}function dJ($,Z){Z6(gu+$,Z)}function vj(){let $=w2();return AT(E5("defaultVendor"),$)??AT(E5("lastSelectedVendor"),$)}function DT($){Z6("defaultVendor",$)}function U9($){return($?vu($):void 0)??vj()??g4}var gu="lastActiveVendor.";var _Z=d(()=>{q2();l5();C4()});function z8($=process.env){return{...$,...PT}}var PT;var lJ=d(()=>{PT={GIT_OPTIONAL_LOCKS:"0"}});function mu($){return $>="0"&&$<="7"}function cu($,Z){let J=[],X="",z=()=>{if(X.length>0){for(let W of rG0.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(mu(q)){let U="",B=G+1;while(B<$.length&&U.length<3&&mu($[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:sG0.decode(new Uint8Array(J)),end:G}}function CZ($){if($.length===0||$[0]!=='"')return $;return cu($,0).value}function du($,Z){if($[0]==='"'){let X=cu($,0);if($.startsWith(Z,X.end))return{orig:X.value,neu:CZ($.slice(X.end+Z.length))};return null}let J=$.indexOf(Z);if(J<0)return null;return{orig:$.slice(0,J),neu:CZ($.slice(J+Z.length))}}function hu($,Z,J){if(Z.length===0&&$.endsWith("/")&&J.startsWith("/"))return $+J.slice(1);return $+Z+J}function tG0($){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:hu(G,q,U),origPath:hu(G,W,U)}}}let J=du($," => ");if(J)return{path:J.neu,origPath:J.orig};return{path:CZ($)}}function kj($){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=du(W," -> ");if(q){Z.push({x:z,y:G,path:q.neu,origPath:q.orig});continue}}Z.push({x:z,y:G,path:CZ(W)})}return Z}function uu($){if($==="-")return null;let Z=Number.parseInt($,10);return Number.isNaN(Z)?null:Z}function lu($){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=tG0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:uu(X.slice(0,z)),deleted:uu(X.slice(z+1,G))})}return Z}var rG0,sG0;var mj=d(()=>{rG0=new TextEncoder,sG0=new TextDecoder});var pu={};A$(pu,{sameWorktreeChanges:()=>BF,readWorktreeChanges:()=>$W0,pickPushedChanges:()=>RT,parsePorcelain:()=>NH});import{spawnSync as eG0}from"child_process";function BF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function RT($,Z){if(!$)return null;return $.get(Z)??hj}function $W0($){if(!$)return hj;try{let Z=eG0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return hj;return NH(Z.stdout)}catch{return hj}}function NH($){let Z=0,J=0;for(let{x:X,y:z}of kj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var hj;var OH=d(()=>{lJ();mj();hj={added:0,deleted:0}});var au={};A$(au,{resolveBaseRef:()=>iu,readBranchSignals:()=>JW0,parseShortstat:()=>ou});import{spawnSync as ZW0}from"child_process";function uj($,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 iu($){let Z=uj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(uj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function ou($){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 JW0($){if(!$)return nu;let Z=iu($);if(!Z)return nu;let J=uj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=uj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:ou(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var nu;var ru=d(()=>{lJ();nu={baseRef:null,ahead:null,diff:null}});async function XW0($,Z,J){let X;try{X=await rR()}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 eR(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?fu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=uQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);qH(G,Z);let B=WH({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 QH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await tR(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)xu($.id,z,U);else jT($.id,U);else if(!z)jT($.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 TT($,Z,J,X=QW0){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 QW0,KF;var FF=d(()=>{W9();B7();Vj();_j();Aj();QF();Gj();VT();$8();QW0={deliverHosted:XW0};KF={isTaskRunning:async($)=>(await KF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await JH();if(J)try{Z=await XH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (MZ(),iO)),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(() => (gj(),CT))).readPtyExitRecords()}catch{}let G=Su($);return{tabs:Eu(G,$,Z,z,X),running:wu(G,$,Z)}},deliverPrompt:($,Z,J)=>TT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (C4(),kq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (_Z(),ku));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (OH(),pu))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (ru(),au))).readBranchSignals($),tearDownSession:async($)=>{let Z=await JH();if(Z)try{await $T(Z.rpc,aR(await XH(Z.rpc),$))}catch{}finally{Z.close()}}}});var cj;var su=d(()=>{cj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.170",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 eu={};A$(eu,{repoSlug:()=>nY,releasePageUrl:()=>fT,recommendedGlobalInstallCommand:()=>ET,isNewerSemver:()=>ST,fetchReleaseSummaries:()=>LF,fetchReleaseNotesRange:()=>xT,fetchReleaseNotes:()=>wT,compareSemver:()=>C3,checkLatestVersion:()=>iY,breakingVersionsCrossed:()=>MF,UPDATE_SCRIPT_URL:()=>dj,UPDATE_COMMAND:()=>AZ,PACKAGE_NAME:()=>IT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function nY(){let $=cj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function ET(){return`npm install -g ${IT}@latest`}function MF($,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 YW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),lj);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 ST($,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 iY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:ST(Z,D$)};if(xq()&&!$.force)return null;let J=await YW0(IT);if(!J)return null;return{current:D$,latest:J,hasUpdate:ST(J,D$)}}function tu($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function wT($){let Z=nY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),lj);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 xT($){let Z=nY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),lj);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=tu(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 LF($=12){let Z=nY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),lj);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=tu(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 fT($){let Z=nY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,IT,dj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",AZ,pJ,lj=3000;var u8=d(()=>{su();j5();D$=cj.version,IT=cj.name;AZ=`curl -fsSL ${dj} | 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 $c(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (Y9(),lR)),Promise.resolve().then(() => (P7(),hR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=d(()=>{$8()});async function GW0($){let Z=$.args.require("command"),J=cQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===mY?{generic:!0}:{}}}var Zc,Jc;var yT=d(()=>{W9();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:cm()})};Jc={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:GW0}});function Yc($){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 Xc,Qc,zc,Gc;var Wc=d(()=>{f2();B2();Xc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Qc=[{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)."}],zc={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."};Gc=[{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."),{...Xc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Qc,zc,{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")}:{},...Yc($),...$.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."),Xc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Qc,zc],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")}:{},...Yc($),...$.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 qc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:cQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Hc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Uc($){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 qW0($,X,z,G);return WW0($,X)}async function WW0($,Z){let J=i4($),{args:X}=$,z=await qc($,Z),G={repo:Z,...await JT(),...Hc(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 L=X.bool("pin");if(L!==void 0)await J.request("task.pin",{taskId:M,pinned:L});let j=B.task;if(O||L!==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 _=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,!_.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:_.started,engineReady:_.engineReady,session:_.session,delivered:_.delivered}}async function qW0($,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",N3("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",N3("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",N3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await qc($,Z),M=X?Bj(X):Kj(J??1,B.vendor??"claude");if(M.length>NZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${NZ} \u2014 spawn in batches`,"BAD_FLAG");let O=WO(),L=[],j=null,D=await JT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Hc(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);L.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 _=await Promise.allSettled(L.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))),C=[],g=[];if(_.forEach((E,T)=>{let{taskId:w,vendor:f}=L[T];if(E.status==="fulfilled"&&E.value.delivered){C.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:L.length,requested:M.length,groupId:O,tasks:C,failures:g};if(g.length>0)throw new K1(`add delivered ${C.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Bc=d(()=>{W9();wP();QF();f2();B2();$8()});var pj;var bT=d(()=>{pj=["backlog","in_progress","in_review","done","canceled","error"]});var Kc;var Fc=d(()=>{f2();Bc();bT();Kc=[{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 ${NZ}, 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 ${NZ}). 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:pj,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:Uc}]});var Mc,Lc;var Nc=d(()=>{hJ();f2();B2();FF();$8();Mc={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"})}},Lc={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 gT,NF,vT,kT="DIRTY_WORKTREE",mT,hT,HW0="TASK_DELETING",pQ,UW0="MAIN_CHECKOUT_DIRTY",uT,BW0="EMPTY_BRANCH",cT,nj="EMPTY_BRANCH_DIRTY_WORKTREE",dT,KW0="LAND_CONFLICT",ij;var nJ=d(()=>{gT=class gT 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"}};NF=class NF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};vT=class vT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};mT=class mT extends Error{taskId;constructor($){super(`${kT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};hT=class hT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};pQ=class pQ extends Error{taskId;constructor($){super(`${HW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};uT=class uT extends Error{repo;dir;constructor($,Z){super(`${UW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};cT=class cT extends Error{branch;landedOn;constructor($,Z){super(`${BW0}: '${$}' 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"}};dT=class dT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${nj}: '${$}' 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"}};ij=class ij extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${KW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function FW0($,Z,J){let X=await QH(),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 Oc($){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 jc($){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",N3("send"));let G=z?cQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await bm(Z);if(M){if(W=M.taskId,X===void 0)X=await gm($.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 FW0(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 MW0($){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 _c($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Cc($){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 Ac($){return i4($).request("task.list")}async function Dc($){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 Pc($){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 Rc($){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 Tc($){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(nj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,nj,{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 Sc($){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=cQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Vc;var jH=d(()=>{W9();B7();nJ();QF();f2();B2();FF();$8();Vc={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:MW0}});var Ic;var Ec=d(()=>{f2();B2();Nc();jH();Ic=[{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:jc},Vc,{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:_c},{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")})},Mc,Lc,{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:Dc}]});var wc;var xc=d(()=>{f2();B2();yT();bT();wc=[{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")})},Jc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:pj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as NW0}from"child_process";function VW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function fc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function yc($,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 bc($,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: ${yc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(yc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function _W0($){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=tG0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:uu(X.slice(0,z)),deleted:uu(X.slice(z+1,G))})}return Z}var rG0,sG0;var mj=d(()=>{rG0=new TextEncoder,sG0=new TextDecoder});var pu={};A$(pu,{sameWorktreeChanges:()=>BF,readWorktreeChanges:()=>$W0,pickPushedChanges:()=>RT,parsePorcelain:()=>NH});import{spawnSync as eG0}from"child_process";function BF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function RT($,Z){if(!$)return null;return $.get(Z)??hj}function $W0($){if(!$)return hj;try{let Z=eG0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return hj;return NH(Z.stdout)}catch{return hj}}function NH($){let Z=0,J=0;for(let{x:X,y:z}of kj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var hj;var OH=d(()=>{lJ();mj();hj={added:0,deleted:0}});var au={};A$(au,{resolveBaseRef:()=>iu,readBranchSignals:()=>JW0,parseShortstat:()=>ou});import{spawnSync as ZW0}from"child_process";function uj($,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 iu($){let Z=uj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(uj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function ou($){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 JW0($){if(!$)return nu;let Z=iu($);if(!Z)return nu;let J=uj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=uj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:ou(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var nu;var ru=d(()=>{lJ();nu={baseRef:null,ahead:null,diff:null}});async function XW0($,Z,J){let X;try{X=await rR()}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 eR(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?fu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=uQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);qH(G,Z);let B=WH({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 QH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await tR(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)xu($.id,z,U);else jT($.id,U);else if(!z)jT($.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 TT($,Z,J,X=QW0){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 QW0,KF;var FF=d(()=>{W9();B7();Vj();_j();Aj();QF();Gj();VT();$8();QW0={deliverHosted:XW0};KF={isTaskRunning:async($)=>(await KF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await JH();if(J)try{Z=await XH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (MZ(),iO)),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(() => (gj(),CT))).readPtyExitRecords()}catch{}let G=Su($);return{tabs:Eu(G,$,Z,z,X),running:wu(G,$,Z)}},deliverPrompt:($,Z,J)=>TT($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (C4(),kq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (_Z(),ku));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (OH(),pu))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (ru(),au))).readBranchSignals($),tearDownSession:async($)=>{let Z=await JH();if(Z)try{await $T(Z.rpc,aR(await XH(Z.rpc),$))}catch{}finally{Z.close()}}}});var cj;var su=d(()=>{cj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.171",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 eu={};A$(eu,{repoSlug:()=>nY,releasePageUrl:()=>fT,recommendedGlobalInstallCommand:()=>ET,isNewerSemver:()=>ST,fetchReleaseSummaries:()=>LF,fetchReleaseNotesRange:()=>xT,fetchReleaseNotes:()=>wT,compareSemver:()=>C3,checkLatestVersion:()=>iY,breakingVersionsCrossed:()=>MF,UPDATE_SCRIPT_URL:()=>dj,UPDATE_COMMAND:()=>AZ,PACKAGE_NAME:()=>IT,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function nY(){let $=cj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function ET(){return`npm install -g ${IT}@latest`}function MF($,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 YW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),lj);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 ST($,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 iY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:ST(Z,D$)};if(xq()&&!$.force)return null;let J=await YW0(IT);if(!J)return null;return{current:D$,latest:J,hasUpdate:ST(J,D$)}}function tu($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function wT($){let Z=nY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),lj);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 xT($){let Z=nY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),lj);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=tu(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 LF($=12){let Z=nY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),lj);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=tu(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 fT($){let Z=nY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,IT,dj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",AZ,pJ,lj=3000;var u8=d(()=>{su();j5();D$=cj.version,IT=cj.name;AZ=`curl -fsSL ${dj} | 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 $c(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (Y9(),lR)),Promise.resolve().then(() => (P7(),hR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=d(()=>{$8()});async function GW0($){let Z=$.args.require("command"),J=cQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===mY?{generic:!0}:{}}}var Zc,Jc;var yT=d(()=>{W9();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:cm()})};Jc={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:GW0}});function Yc($){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 Xc,Qc,zc,Gc;var Wc=d(()=>{f2();B2();Xc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Qc=[{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)."}],zc={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."};Gc=[{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."),{...Xc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Qc,zc,{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")}:{},...Yc($),...$.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."),Xc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Qc,zc],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")}:{},...Yc($),...$.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 qc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:cQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Hc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Uc($){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 qW0($,X,z,G);return WW0($,X)}async function WW0($,Z){let J=i4($),{args:X}=$,z=await qc($,Z),G={repo:Z,...await JT(),...Hc(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 L=X.bool("pin");if(L!==void 0)await J.request("task.pin",{taskId:M,pinned:L});let j=B.task;if(O||L!==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 _=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,!_.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:_.started,engineReady:_.engineReady,session:_.session,delivered:_.delivered}}async function qW0($,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",N3("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",N3("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",N3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await qc($,Z),M=X?Bj(X):Kj(J??1,B.vendor??"claude");if(M.length>NZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${NZ} \u2014 spawn in batches`,"BAD_FLAG");let O=WO(),L=[],j=null,D=await JT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Hc(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);L.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 _=await Promise.allSettled(L.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))),C=[],g=[];if(_.forEach((E,T)=>{let{taskId:w,vendor:f}=L[T];if(E.status==="fulfilled"&&E.value.delivered){C.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:L.length,requested:M.length,groupId:O,tasks:C,failures:g};if(g.length>0)throw new K1(`add delivered ${C.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Bc=d(()=>{W9();wP();QF();f2();B2();$8()});var pj;var bT=d(()=>{pj=["backlog","in_progress","in_review","done","canceled","error"]});var Kc;var Fc=d(()=>{f2();Bc();bT();Kc=[{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 ${NZ}, 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 ${NZ}). 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:pj,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:Uc}]});var Mc,Lc;var Nc=d(()=>{hJ();f2();B2();FF();$8();Mc={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"})}},Lc={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 gT,NF,vT,kT="DIRTY_WORKTREE",mT,hT,HW0="TASK_DELETING",pQ,UW0="MAIN_CHECKOUT_DIRTY",uT,BW0="EMPTY_BRANCH",cT,nj="EMPTY_BRANCH_DIRTY_WORKTREE",dT,KW0="LAND_CONFLICT",ij;var nJ=d(()=>{gT=class gT 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"}};NF=class NF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};vT=class vT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};mT=class mT extends Error{taskId;constructor($){super(`${kT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};hT=class hT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};pQ=class pQ extends Error{taskId;constructor($){super(`${HW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};uT=class uT extends Error{repo;dir;constructor($,Z){super(`${UW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};cT=class cT extends Error{branch;landedOn;constructor($,Z){super(`${BW0}: '${$}' 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"}};dT=class dT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${nj}: '${$}' 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"}};ij=class ij extends Error{taskId;branch;files;constructor($,Z,J){let X=J.length>0?J.join(", "):"(none reported)";super(`${KW0}: merging '${Z}' hit conflicts, merge aborted \u2014 conflicted files: ${X}`);this.taskId=$;this.branch=Z;this.files=J;this.name="LandConflictError"}}});async function FW0($,Z,J){let X=await QH(),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 Oc($){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 jc($){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",N3("send"));let G=z?cQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await bm(Z);if(M){if(W=M.taskId,X===void 0)X=await gm($.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 FW0(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 MW0($){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 _c($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Cc($){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 Ac($){return i4($).request("task.list")}async function Dc($){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 Pc($){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 Rc($){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 Tc($){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(nj))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,nj,{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 Sc($){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=cQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Vc;var jH=d(()=>{W9();B7();nJ();QF();f2();B2();FF();$8();Vc={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:MW0}});var Ic;var Ec=d(()=>{f2();B2();Nc();jH();Ic=[{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:jc},Vc,{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:_c},{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")})},Mc,Lc,{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:Dc}]});var wc;var xc=d(()=>{f2();B2();yT();bT();wc=[{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")})},Jc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:pj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as NW0}from"child_process";function VW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function fc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function yc($,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 bc($,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: ${yc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(yc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function _W0($){return`${$}
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
Submitted from Rove ${D$}.`}function VH($,Z={}){let J=fc($.title,"feedback title"),X=_W0(fc($.body,"feedback body")),z=(Z.repoSlug??nY)();if(!z)throw Error("package repository is not a GitHub repository");let{owner:G,name:W}=VW0(z),q=$.categorySlug?.trim()||lT,U={spawn:Z.spawn??NW0},M=bc(OW0,{owner:G,name:W},U).repository,O=M?.id;if(!O)throw Error(`GitHub repository not found: ${z}`);let L=M.discussionCategories?.nodes?.find((_)=>_.slug===q);if(!L)throw Error(`GitHub Discussion category not found: ${q}`);let D=bc(jW0,{repositoryId:O,categoryId:L.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 lT="feedback",OW0=`
|
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,sG0));while(J.length>0&&(J[J.length-1]??"").trim()==="")J.pop();return J.slice(-rG0)}function vu($=tO()){try{let Z=JSON.parse(nG0($,"utf8"));if(Z===null||typeof Z!=="object"||Array.isArray(Z))return{};return Z}catch{return{}}}function CT($,Z=tO()){if($.key.startsWith("::"))return;if($.exit.code===0&&$.exit.signal===null)return;let J=vu(Z);J[$.key]={key:$.key,pid:$.pid,code:$.exit.code,signal:$.exit.signal,at:$.exit.at,tail:gu($.tail)};let X=Object.values(J).sort((z,G)=>z.at<G.at?1:-1).slice(0,aG0);pG0(oG0(Z),{recursive:!0}),iG0(Z,JSON.stringify(Object.fromEntries(X.map((z)=>[z.key,z])),null,2),"utf8")}var aG0=50,rG0=40,sG0=500,tG0;var vj=d(()=>{P7();tG0=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[@-_]/g});var hu={};A$(hu,{setRepoLastActiveVendor:()=>dJ,setGlobalDefaultVendor:()=>PT,resolvePreferredVendor:()=>U9,getRepoLastActiveVendor:()=>mu,getGlobalDefaultVendor:()=>kj});function DT($,Z){let J=$?.trim();if(!J)return;if(d5(J)||Z.includes(J))return J;return}function mu($){return DT(E5(ku+$),w2())}function dJ($,Z){Z6(ku+$,Z)}function kj(){let $=w2();return DT(E5("defaultVendor"),$)??DT(E5("lastSelectedVendor"),$)}function PT($){Z6("defaultVendor",$)}function U9($){return($?mu($):void 0)??kj()??g4}var ku="lastActiveVendor.";var _Z=d(()=>{q2();l5();C4()});function z8($=process.env){return{...$,...RT}}var RT;var lJ=d(()=>{RT={GIT_OPTIONAL_LOCKS:"0"}});function uu($){return $>="0"&&$<="7"}function lu($,Z){let J=[],X="",z=()=>{if(X.length>0){for(let W of eG0.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(uu(q)){let U="",B=G+1;while(B<$.length&&U.length<3&&uu($[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:$W0.decode(new Uint8Array(J)),end:G}}function CZ($){if($.length===0||$[0]!=='"')return $;return lu($,0).value}function pu($,Z){if($[0]==='"'){let X=lu($,0);if($.startsWith(Z,X.end))return{orig:X.value,neu:CZ($.slice(X.end+Z.length))};return null}let J=$.indexOf(Z);if(J<0)return null;return{orig:$.slice(0,J),neu:CZ($.slice(J+Z.length))}}function cu($,Z,J){if(Z.length===0&&$.endsWith("/")&&J.startsWith("/"))return $+J.slice(1);return $+Z+J}function ZW0($){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:cu(G,q,U),origPath:cu(G,W,U)}}}let J=pu($," => ");if(J)return{path:J.neu,origPath:J.orig};return{path:CZ($)}}function mj($){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=pu(W," -> ");if(q){Z.push({x:z,y:G,path:q.neu,origPath:q.orig});continue}}Z.push({x:z,y:G,path:CZ(W)})}return Z}function du($){if($==="-")return null;let Z=Number.parseInt($,10);return Number.isNaN(Z)?null:Z}function nu($){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=ZW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:du(X.slice(0,z)),deleted:du(X.slice(z+1,G))})}return Z}var eG0,$W0;var hj=d(()=>{eG0=new TextEncoder,$W0=new TextDecoder});var iu={};A$(iu,{sameWorktreeChanges:()=>BF,readWorktreeChanges:()=>XW0,pickPushedChanges:()=>TT,parsePorcelain:()=>NH});import{spawnSync as JW0}from"child_process";function BF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function TT($,Z){if(!$)return null;return $.get(Z)??uj}function XW0($){if(!$)return uj;try{let Z=JW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return uj;return NH(Z.stdout)}catch{return uj}}function NH($){let Z=0,J=0;for(let{x:X,y:z}of mj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var uj;var OH=d(()=>{lJ();hj();uj={added:0,deleted:0}});var su={};A$(su,{resolveBaseRef:()=>au,readBranchSignals:()=>zW0,parseShortstat:()=>ru});import{spawnSync as QW0}from"child_process";function cj($,Z){try{let J=QW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function au($){let Z=cj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(cj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function ru($){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 zW0($){if(!$)return ou;let Z=au($);if(!Z)return ou;let J=cj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=cj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:ru(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var ou;var tu=d(()=>{lJ();ou={baseRef:null,ahead:null,diff:null}});async function YW0($,Z,J){let X;try{X=await sR()}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 $T(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?bu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=uQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);qH(G,Z);let B=WH({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 QH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await eR(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)yu($.id,z,U);else VT($.id,U);else if(!z)VT($.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 ST($,Z,J,X=GW0){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 GW0,KF;var FF=d(()=>{W9();B7();_j();Cj();Dj();QF();Wj();_T();$8();GW0={deliverHosted:YW0};KF={isTaskRunning:async($)=>(await KF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await JH();if(J)try{Z=await XH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (MZ(),oO)),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(() => (vj(),AT))).readPtyExitRecords()}catch{}let G=Eu($);return{tabs:xu(G,$,Z,z,X),running:fu(G,$,Z)}},deliverPrompt:($,Z,J)=>ST($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (C4(),kq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (_Z(),hu));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (OH(),iu))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (tu(),su))).readBranchSignals($),tearDownSession:async($)=>{let Z=await JH();if(Z)try{await ZT(Z.rpc,rR(await XH(Z.rpc),$))}catch{}finally{Z.close()}}}});var dj;var eu=d(()=>{dj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.170",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:()=>nY,releasePageUrl:()=>yT,recommendedGlobalInstallCommand:()=>wT,isNewerSemver:()=>IT,fetchReleaseSummaries:()=>LF,fetchReleaseNotesRange:()=>fT,fetchReleaseNotes:()=>xT,compareSemver:()=>C3,checkLatestVersion:()=>iY,breakingVersionsCrossed:()=>MF,UPDATE_SCRIPT_URL:()=>lj,UPDATE_COMMAND:()=>AZ,PACKAGE_NAME:()=>ET,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function nY(){let $=dj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function wT(){return`npm install -g ${ET}@latest`}function MF($,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 qW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),pj);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 IT($,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 iY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:IT(Z,D$)};if(xq()&&!$.force)return null;let J=await qW0(ET);if(!J)return null;return{current:D$,latest:J,hasUpdate:IT(J,D$)}}function $c($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function xT($){let Z=nY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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 fT($){let Z=nY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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=$c(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 LF($=12){let Z=nY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),pj);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=$c(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 yT($){let Z=nY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,ET,lj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",AZ,pJ,pj=3000;var u8=d(()=>{eu();j5();D$=dj.version,ET=dj.name;AZ=`curl -fsSL ${lj} | 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 Jc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (Y9(),pR)),Promise.resolve().then(() => (P7(),uR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=d(()=>{$8()});async function HW0($){let Z=$.args.require("command"),J=cQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===mY?{generic:!0}:{}}}var Xc,Qc;var bT=d(()=>{W9();f2();B2();Xc={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:lm()})};Qc={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:HW0}});function Wc($){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 zc,Yc,Gc,qc;var Hc=d(()=>{f2();B2();zc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Yc=[{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)."}],Gc={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."};qc=[{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."),{...zc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Yc,Gc,{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")}:{},...Wc($),...$.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."),zc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Yc,Gc],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")}:{},...Wc($),...$.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 Uc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:cQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Bc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Kc($){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 BW0($,X,z,G);return UW0($,X)}async function UW0($,Z){let J=i4($),{args:X}=$,z=await Uc($,Z),G={repo:Z,...await XT(),...Bc(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 L=X.bool("pin");if(L!==void 0)await J.request("task.pin",{taskId:M,pinned:L});let j=B.task;if(O||L!==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 _=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,!_.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:_.started,engineReady:_.engineReady,session:_.session,delivered:_.delivered}}async function BW0($,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",N3("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",N3("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",N3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Uc($,Z),M=X?Kj(X):Fj(J??1,B.vendor??"claude");if(M.length>NZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${NZ} \u2014 spawn in batches`,"BAD_FLAG");let O=qO(),L=[],j=null,D=await XT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Bc(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);L.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 _=await Promise.allSettled(L.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))),C=[],g=[];if(_.forEach((E,T)=>{let{taskId:w,vendor:f}=L[T];if(E.status==="fulfilled"&&E.value.delivered){C.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:L.length,requested:M.length,groupId:O,tasks:C,failures:g};if(g.length>0)throw new K1(`add delivered ${C.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Fc=d(()=>{W9();xP();QF();f2();B2();$8()});var nj;var gT=d(()=>{nj=["backlog","in_progress","in_review","done","canceled","error"]});var Mc;var Lc=d(()=>{f2();Fc();gT();Mc=[{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 ${NZ}, 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 ${NZ}). 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:nj,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:Kc}]});var Nc,Oc;var jc=d(()=>{hJ();f2();B2();FF();$8();Nc={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"})}},Oc={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 vT,NF,kT,mT="DIRTY_WORKTREE",hT,uT,KW0="TASK_DELETING",pQ,FW0="MAIN_CHECKOUT_DIRTY",cT,MW0="EMPTY_BRANCH",dT,ij="EMPTY_BRANCH_DIRTY_WORKTREE",lT,LW0="LAND_CONFLICT",oj;var nJ=d(()=>{vT=class vT 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"}};NF=class NF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};kT=class kT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};hT=class hT extends Error{taskId;constructor($){super(`${mT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};uT=class uT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};pQ=class pQ extends Error{taskId;constructor($){super(`${KW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};cT=class cT extends Error{repo;dir;constructor($,Z){super(`${FW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};dT=class dT extends Error{branch;landedOn;constructor($,Z){super(`${MW0}: '${$}' 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"}};lT=class lT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${ij}: '${$}' 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"}};oj=class oj 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 NW0($,Z,J){let X=await QH(),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 Vc($){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 _c($){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",N3("send"));let G=z?cQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await vm(Z);if(M){if(W=M.taskId,X===void 0)X=await km($.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 NW0(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 OW0($){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 Ac($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Dc($){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 Pc($){return i4($).request("task.list")}async function Rc($){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 Tc($){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 Sc($){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 Ic($){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 jW0(W,J)}return{ok:!0,taskId:J,...G.result}}function jW0($,Z){let J=M1($);if(!J.includes(ij))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,ij,{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 Ec($){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=cQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Cc;var jH=d(()=>{W9();B7();nJ();QF();f2();B2();FF();$8();Cc={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:OW0}});var wc;var xc=d(()=>{f2();B2();jc();jH();wc=[{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:_c},Cc,{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:Ac},{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")})},Nc,Oc,{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:Rc}]});var fc;var yc=d(()=>{f2();B2();bT();gT();fc=[{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")})},Qc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:nj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as VW0}from"child_process";function AW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function bc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function gc($,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 vc($,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: ${gc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(gc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function DW0($){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=ZW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:du(X.slice(0,z)),deleted:du(X.slice(z+1,G))})}return Z}var eG0,$W0;var hj=d(()=>{eG0=new TextEncoder,$W0=new TextDecoder});var iu={};A$(iu,{sameWorktreeChanges:()=>BF,readWorktreeChanges:()=>XW0,pickPushedChanges:()=>TT,parsePorcelain:()=>NH});import{spawnSync as JW0}from"child_process";function BF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function TT($,Z){if(!$)return null;return $.get(Z)??uj}function XW0($){if(!$)return uj;try{let Z=JW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return uj;return NH(Z.stdout)}catch{return uj}}function NH($){let Z=0,J=0;for(let{x:X,y:z}of mj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var uj;var OH=d(()=>{lJ();hj();uj={added:0,deleted:0}});var su={};A$(su,{resolveBaseRef:()=>au,readBranchSignals:()=>zW0,parseShortstat:()=>ru});import{spawnSync as QW0}from"child_process";function cj($,Z){try{let J=QW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function au($){let Z=cj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(cj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function ru($){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 zW0($){if(!$)return ou;let Z=au($);if(!Z)return ou;let J=cj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=cj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:ru(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var ou;var tu=d(()=>{lJ();ou={baseRef:null,ahead:null,diff:null}});async function YW0($,Z,J){let X;try{X=await sR()}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 $T(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?bu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=uQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);qH(G,Z);let B=WH({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 QH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await eR(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)yu($.id,z,U);else VT($.id,U);else if(!z)VT($.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 ST($,Z,J,X=GW0){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 GW0,KF;var FF=d(()=>{W9();B7();_j();Cj();Dj();QF();Wj();_T();$8();GW0={deliverHosted:YW0};KF={isTaskRunning:async($)=>(await KF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await JH();if(J)try{Z=await XH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (MZ(),oO)),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(() => (vj(),AT))).readPtyExitRecords()}catch{}let G=Eu($);return{tabs:xu(G,$,Z,z,X),running:fu(G,$,Z)}},deliverPrompt:($,Z,J)=>ST($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (C4(),kq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (_Z(),hu));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (OH(),iu))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (tu(),su))).readBranchSignals($),tearDownSession:async($)=>{let Z=await JH();if(Z)try{await ZT(Z.rpc,rR(await XH(Z.rpc),$))}catch{}finally{Z.close()}}}});var dj;var eu=d(()=>{dj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.171",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:()=>nY,releasePageUrl:()=>yT,recommendedGlobalInstallCommand:()=>wT,isNewerSemver:()=>IT,fetchReleaseSummaries:()=>LF,fetchReleaseNotesRange:()=>fT,fetchReleaseNotes:()=>xT,compareSemver:()=>C3,checkLatestVersion:()=>iY,breakingVersionsCrossed:()=>MF,UPDATE_SCRIPT_URL:()=>lj,UPDATE_COMMAND:()=>AZ,PACKAGE_NAME:()=>ET,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function nY(){let $=dj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function wT(){return`npm install -g ${ET}@latest`}function MF($,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 qW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),pj);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 IT($,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 iY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:IT(Z,D$)};if(xq()&&!$.force)return null;let J=await qW0(ET);if(!J)return null;return{current:D$,latest:J,hasUpdate:IT(J,D$)}}function $c($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function xT($){let Z=nY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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 fT($){let Z=nY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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=$c(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 LF($=12){let Z=nY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),pj);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=$c(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 yT($){let Z=nY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,ET,lj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",AZ,pJ,pj=3000;var u8=d(()=>{eu();j5();D$=dj.version,ET=dj.name;AZ=`curl -fsSL ${lj} | 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 Jc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (Y9(),pR)),Promise.resolve().then(() => (P7(),uR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=d(()=>{$8()});async function HW0($){let Z=$.args.require("command"),J=cQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===mY?{generic:!0}:{}}}var Xc,Qc;var bT=d(()=>{W9();f2();B2();Xc={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:lm()})};Qc={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:HW0}});function Wc($){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 zc,Yc,Gc,qc;var Hc=d(()=>{f2();B2();zc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Yc=[{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)."}],Gc={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."};qc=[{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."),{...zc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Yc,Gc,{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")}:{},...Wc($),...$.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."),zc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Yc,Gc],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")}:{},...Wc($),...$.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 Uc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:cQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Bc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Kc($){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 BW0($,X,z,G);return UW0($,X)}async function UW0($,Z){let J=i4($),{args:X}=$,z=await Uc($,Z),G={repo:Z,...await XT(),...Bc(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 L=X.bool("pin");if(L!==void 0)await J.request("task.pin",{taskId:M,pinned:L});let j=B.task;if(O||L!==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 _=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,!_.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:_.started,engineReady:_.engineReady,session:_.session,delivered:_.delivered}}async function BW0($,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",N3("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",N3("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",N3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Uc($,Z),M=X?Kj(X):Fj(J??1,B.vendor??"claude");if(M.length>NZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${NZ} \u2014 spawn in batches`,"BAD_FLAG");let O=qO(),L=[],j=null,D=await XT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Bc(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);L.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 _=await Promise.allSettled(L.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))),C=[],g=[];if(_.forEach((E,T)=>{let{taskId:w,vendor:f}=L[T];if(E.status==="fulfilled"&&E.value.delivered){C.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:L.length,requested:M.length,groupId:O,tasks:C,failures:g};if(g.length>0)throw new K1(`add delivered ${C.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Fc=d(()=>{W9();xP();QF();f2();B2();$8()});var nj;var gT=d(()=>{nj=["backlog","in_progress","in_review","done","canceled","error"]});var Mc;var Lc=d(()=>{f2();Fc();gT();Mc=[{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 ${NZ}, 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 ${NZ}). 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:nj,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:Kc}]});var Nc,Oc;var jc=d(()=>{hJ();f2();B2();FF();$8();Nc={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"})}},Oc={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 vT,NF,kT,mT="DIRTY_WORKTREE",hT,uT,KW0="TASK_DELETING",pQ,FW0="MAIN_CHECKOUT_DIRTY",cT,MW0="EMPTY_BRANCH",dT,ij="EMPTY_BRANCH_DIRTY_WORKTREE",lT,LW0="LAND_CONFLICT",oj;var nJ=d(()=>{vT=class vT 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"}};NF=class NF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};kT=class kT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};hT=class hT extends Error{taskId;constructor($){super(`${mT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};uT=class uT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};pQ=class pQ extends Error{taskId;constructor($){super(`${KW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};cT=class cT extends Error{repo;dir;constructor($,Z){super(`${FW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};dT=class dT extends Error{branch;landedOn;constructor($,Z){super(`${MW0}: '${$}' 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"}};lT=class lT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${ij}: '${$}' 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"}};oj=class oj 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 NW0($,Z,J){let X=await QH(),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 Vc($){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 _c($){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",N3("send"));let G=z?cQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await vm(Z);if(M){if(W=M.taskId,X===void 0)X=await km($.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 NW0(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 OW0($){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 Ac($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Dc($){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 Pc($){return i4($).request("task.list")}async function Rc($){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 Tc($){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 Sc($){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 Ic($){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 jW0(W,J)}return{ok:!0,taskId:J,...G.result}}function jW0($,Z){let J=M1($);if(!J.includes(ij))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,ij,{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 Ec($){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=cQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Cc;var jH=d(()=>{W9();B7();nJ();QF();f2();B2();FF();$8();Cc={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:OW0}});var wc;var xc=d(()=>{f2();B2();jc();jH();wc=[{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:_c},Cc,{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:Ac},{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")})},Nc,Oc,{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:Rc}]});var fc;var yc=d(()=>{f2();B2();bT();gT();fc=[{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")})},Qc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:nj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as VW0}from"child_process";function AW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function bc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function gc($,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 vc($,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: ${gc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(gc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function DW0($){return`${$}
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
Submitted from Rove ${D$}.`}function VH($,Z={}){let J=bc($.title,"feedback title"),X=DW0(bc($.body,"feedback body")),z=(Z.repoSlug??nY)();if(!z)throw Error("package repository is not a GitHub repository");let{owner:G,name:W}=AW0(z),q=$.categorySlug?.trim()||pT,U={spawn:Z.spawn??VW0},M=vc(_W0,{owner:G,name:W},U).repository,O=M?.id;if(!O)throw Error(`GitHub repository not found: ${z}`);let L=M.discussionCategories?.nodes?.find((_)=>_.slug===q);if(!L)throw Error(`GitHub Discussion category not found: ${q}`);let D=vc(CW0,{repositoryId:O,categoryId:L.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 pT="feedback",_W0=`
|
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,sG0));while(J.length>0&&(J[J.length-1]??"").trim()==="")J.pop();return J.slice(-rG0)}function vu($=tO()){try{let Z=JSON.parse(nG0($,"utf8"));if(Z===null||typeof Z!=="object"||Array.isArray(Z))return{};return Z}catch{return{}}}function CT($,Z=tO()){if($.key.startsWith("::"))return;if($.exit.code===0&&$.exit.signal===null)return;let J=vu(Z);J[$.key]={key:$.key,pid:$.pid,code:$.exit.code,signal:$.exit.signal,at:$.exit.at,tail:gu($.tail)};let X=Object.values(J).sort((z,G)=>z.at<G.at?1:-1).slice(0,aG0);pG0(oG0(Z),{recursive:!0}),iG0(Z,JSON.stringify(Object.fromEntries(X.map((z)=>[z.key,z])),null,2),"utf8")}var aG0=50,rG0=40,sG0=500,tG0;var vj=d(()=>{P7();tG0=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[@-_]/g});var hu={};A$(hu,{setRepoLastActiveVendor:()=>dJ,setGlobalDefaultVendor:()=>PT,resolvePreferredVendor:()=>U9,getRepoLastActiveVendor:()=>mu,getGlobalDefaultVendor:()=>kj});function DT($,Z){let J=$?.trim();if(!J)return;if(d5(J)||Z.includes(J))return J;return}function mu($){return DT(E5(ku+$),w2())}function dJ($,Z){Z6(ku+$,Z)}function kj(){let $=w2();return DT(E5("defaultVendor"),$)??DT(E5("lastSelectedVendor"),$)}function PT($){Z6("defaultVendor",$)}function U9($){return($?mu($):void 0)??kj()??g4}var ku="lastActiveVendor.";var _Z=d(()=>{q2();l5();C4()});function z8($=process.env){return{...$,...RT}}var RT;var lJ=d(()=>{RT={GIT_OPTIONAL_LOCKS:"0"}});function uu($){return $>="0"&&$<="7"}function lu($,Z){let J=[],X="",z=()=>{if(X.length>0){for(let W of eG0.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(uu(q)){let U="",B=G+1;while(B<$.length&&U.length<3&&uu($[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:$W0.decode(new Uint8Array(J)),end:G}}function CZ($){if($.length===0||$[0]!=='"')return $;return lu($,0).value}function pu($,Z){if($[0]==='"'){let X=lu($,0);if($.startsWith(Z,X.end))return{orig:X.value,neu:CZ($.slice(X.end+Z.length))};return null}let J=$.indexOf(Z);if(J<0)return null;return{orig:$.slice(0,J),neu:CZ($.slice(J+Z.length))}}function cu($,Z,J){if(Z.length===0&&$.endsWith("/")&&J.startsWith("/"))return $+J.slice(1);return $+Z+J}function ZW0($){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:cu(G,q,U),origPath:cu(G,W,U)}}}let J=pu($," => ");if(J)return{path:J.neu,origPath:J.orig};return{path:CZ($)}}function mj($){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=pu(W," -> ");if(q){Z.push({x:z,y:G,path:q.neu,origPath:q.orig});continue}}Z.push({x:z,y:G,path:CZ(W)})}return Z}function du($){if($==="-")return null;let Z=Number.parseInt($,10);return Number.isNaN(Z)?null:Z}function nu($){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=ZW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:du(X.slice(0,z)),deleted:du(X.slice(z+1,G))})}return Z}var eG0,$W0;var hj=d(()=>{eG0=new TextEncoder,$W0=new TextDecoder});var iu={};A$(iu,{sameWorktreeChanges:()=>BF,readWorktreeChanges:()=>XW0,pickPushedChanges:()=>TT,parsePorcelain:()=>NH});import{spawnSync as JW0}from"child_process";function BF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function TT($,Z){if(!$)return null;return $.get(Z)??uj}function XW0($){if(!$)return uj;try{let Z=JW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return uj;return NH(Z.stdout)}catch{return uj}}function NH($){let Z=0,J=0;for(let{x:X,y:z}of mj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var uj;var OH=d(()=>{lJ();hj();uj={added:0,deleted:0}});var su={};A$(su,{resolveBaseRef:()=>au,readBranchSignals:()=>zW0,parseShortstat:()=>ru});import{spawnSync as QW0}from"child_process";function cj($,Z){try{let J=QW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function au($){let Z=cj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(cj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function ru($){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 zW0($){if(!$)return ou;let Z=au($);if(!Z)return ou;let J=cj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=cj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:ru(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var ou;var tu=d(()=>{lJ();ou={baseRef:null,ahead:null,diff:null}});async function YW0($,Z,J){let X;try{X=await sR()}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 $T(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?bu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=uQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);qH(G,Z);let B=WH({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 QH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await eR(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)yu($.id,z,U);else VT($.id,U);else if(!z)VT($.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 ST($,Z,J,X=GW0){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 GW0,KF;var FF=d(()=>{W9();B7();_j();Cj();Dj();QF();Wj();_T();$8();GW0={deliverHosted:YW0};KF={isTaskRunning:async($)=>(await KF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await JH();if(J)try{Z=await XH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (MZ(),oO)),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(() => (vj(),AT))).readPtyExitRecords()}catch{}let G=Eu($);return{tabs:xu(G,$,Z,z,X),running:fu(G,$,Z)}},deliverPrompt:($,Z,J)=>ST($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (C4(),kq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (_Z(),hu));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (OH(),iu))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (tu(),su))).readBranchSignals($),tearDownSession:async($)=>{let Z=await JH();if(Z)try{await ZT(Z.rpc,rR(await XH(Z.rpc),$))}catch{}finally{Z.close()}}}});var dj;var eu=d(()=>{dj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.170",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:()=>nY,releasePageUrl:()=>yT,recommendedGlobalInstallCommand:()=>wT,isNewerSemver:()=>IT,fetchReleaseSummaries:()=>LF,fetchReleaseNotesRange:()=>fT,fetchReleaseNotes:()=>xT,compareSemver:()=>C3,checkLatestVersion:()=>iY,breakingVersionsCrossed:()=>MF,UPDATE_SCRIPT_URL:()=>lj,UPDATE_COMMAND:()=>AZ,PACKAGE_NAME:()=>ET,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function nY(){let $=dj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function wT(){return`npm install -g ${ET}@latest`}function MF($,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 qW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),pj);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 IT($,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 iY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:IT(Z,D$)};if(xq()&&!$.force)return null;let J=await qW0(ET);if(!J)return null;return{current:D$,latest:J,hasUpdate:IT(J,D$)}}function $c($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function xT($){let Z=nY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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 fT($){let Z=nY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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=$c(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 LF($=12){let Z=nY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),pj);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=$c(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 yT($){let Z=nY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,ET,lj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",AZ,pJ,pj=3000;var u8=d(()=>{eu();j5();D$=dj.version,ET=dj.name;AZ=`curl -fsSL ${lj} | 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 Jc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (Y9(),pR)),Promise.resolve().then(() => (P7(),uR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=d(()=>{$8()});async function HW0($){let Z=$.args.require("command"),J=cQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===mY?{generic:!0}:{}}}var Xc,Qc;var bT=d(()=>{W9();f2();B2();Xc={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:lm()})};Qc={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:HW0}});function Wc($){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 zc,Yc,Gc,qc;var Hc=d(()=>{f2();B2();zc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Yc=[{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)."}],Gc={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."};qc=[{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."),{...zc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Yc,Gc,{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")}:{},...Wc($),...$.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."),zc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Yc,Gc],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")}:{},...Wc($),...$.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 Uc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:cQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Bc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Kc($){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 BW0($,X,z,G);return UW0($,X)}async function UW0($,Z){let J=i4($),{args:X}=$,z=await Uc($,Z),G={repo:Z,...await XT(),...Bc(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 L=X.bool("pin");if(L!==void 0)await J.request("task.pin",{taskId:M,pinned:L});let j=B.task;if(O||L!==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 _=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,!_.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:_.started,engineReady:_.engineReady,session:_.session,delivered:_.delivered}}async function BW0($,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",N3("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",N3("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",N3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Uc($,Z),M=X?Kj(X):Fj(J??1,B.vendor??"claude");if(M.length>NZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${NZ} \u2014 spawn in batches`,"BAD_FLAG");let O=qO(),L=[],j=null,D=await XT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Bc(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);L.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 _=await Promise.allSettled(L.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))),C=[],g=[];if(_.forEach((E,T)=>{let{taskId:w,vendor:f}=L[T];if(E.status==="fulfilled"&&E.value.delivered){C.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:L.length,requested:M.length,groupId:O,tasks:C,failures:g};if(g.length>0)throw new K1(`add delivered ${C.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Fc=d(()=>{W9();xP();QF();f2();B2();$8()});var nj;var gT=d(()=>{nj=["backlog","in_progress","in_review","done","canceled","error"]});var Mc;var Lc=d(()=>{f2();Fc();gT();Mc=[{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 ${NZ}, 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 ${NZ}). 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:nj,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:Kc}]});var Nc,Oc;var jc=d(()=>{hJ();f2();B2();FF();$8();Nc={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"})}},Oc={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 vT,NF,kT,mT="DIRTY_WORKTREE",hT,uT,KW0="TASK_DELETING",pQ,FW0="MAIN_CHECKOUT_DIRTY",cT,MW0="EMPTY_BRANCH",dT,ij="EMPTY_BRANCH_DIRTY_WORKTREE",lT,LW0="LAND_CONFLICT",oj;var nJ=d(()=>{vT=class vT 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"}};NF=class NF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};kT=class kT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};hT=class hT extends Error{taskId;constructor($){super(`${mT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};uT=class uT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};pQ=class pQ extends Error{taskId;constructor($){super(`${KW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};cT=class cT extends Error{repo;dir;constructor($,Z){super(`${FW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};dT=class dT extends Error{branch;landedOn;constructor($,Z){super(`${MW0}: '${$}' 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"}};lT=class lT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${ij}: '${$}' 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"}};oj=class oj 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 NW0($,Z,J){let X=await QH(),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 Vc($){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 _c($){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",N3("send"));let G=z?cQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await vm(Z);if(M){if(W=M.taskId,X===void 0)X=await km($.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 NW0(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 OW0($){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 Ac($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Dc($){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 Pc($){return i4($).request("task.list")}async function Rc($){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 Tc($){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 Sc($){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 Ic($){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 jW0(W,J)}return{ok:!0,taskId:J,...G.result}}function jW0($,Z){let J=M1($);if(!J.includes(ij))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,ij,{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 Ec($){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=cQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Cc;var jH=d(()=>{W9();B7();nJ();QF();f2();B2();FF();$8();Cc={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:OW0}});var wc;var xc=d(()=>{f2();B2();jc();jH();wc=[{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:_c},Cc,{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:Ac},{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")})},Nc,Oc,{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:Rc}]});var fc;var yc=d(()=>{f2();B2();bT();gT();fc=[{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")})},Qc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:nj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as VW0}from"child_process";function AW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function bc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function gc($,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 vc($,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: ${gc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(gc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function DW0($){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=ZW0(W);if(q.path.length===0)continue;Z.push({path:q.path,...q.origPath!==void 0?{origPath:q.origPath}:{},added:du(X.slice(0,z)),deleted:du(X.slice(z+1,G))})}return Z}var eG0,$W0;var hj=d(()=>{eG0=new TextEncoder,$W0=new TextDecoder});var iu={};A$(iu,{sameWorktreeChanges:()=>BF,readWorktreeChanges:()=>XW0,pickPushedChanges:()=>TT,parsePorcelain:()=>NH});import{spawnSync as JW0}from"child_process";function BF($,Z){return $.added===Z.added&&$.deleted===Z.deleted}function TT($,Z){if(!$)return null;return $.get(Z)??uj}function XW0($){if(!$)return uj;try{let Z=JW0("git",["status","--porcelain=v1"],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});if(Z.status!==0||!Z.stdout)return uj;return NH(Z.stdout)}catch{return uj}}function NH($){let Z=0,J=0;for(let{x:X,y:z}of mj($))if(X==="D"||z==="D")J+=1;else Z+=1;return{added:Z,deleted:J}}var uj;var OH=d(()=>{lJ();hj();uj={added:0,deleted:0}});var su={};A$(su,{resolveBaseRef:()=>au,readBranchSignals:()=>zW0,parseShortstat:()=>ru});import{spawnSync as QW0}from"child_process";function cj($,Z){try{let J=QW0("git",[...Z],{cwd:$,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:z8()});return J.status===0?J.stdout.trim():null}catch{return null}}function au($){let Z=cj($,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(Z)return Z;for(let J of["origin/main","origin/master","main","master"])if(cj($,["rev-parse","--verify","--quiet",J])!==null)return J;return null}function ru($){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 zW0($){if(!$)return ou;let Z=au($);if(!Z)return ou;let J=cj($,["rev-list","--count",`${Z}..HEAD`]),X=J===null?null:Number.parseInt(J,10),z=cj($,["diff","--shortstat",`${Z}...HEAD`]),G=z===null?null:ru(z);return{baseRef:Z,ahead:X!==null&&Number.isNaN(X)?null:X,diff:G}}var ou;var tu=d(()=>{lJ();ou={baseRef:null,ahead:null,diff:null}});async function YW0($,Z,J){let X;try{X=await sR()}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 $T(X.rpc,$.id,$.tab,Z,J,{engineBin:O})}let z=$.tab==="new"?bu($.id,$.tabVendor,$.tabCommand):void 0,G=$.tabVendor??$.vendor,W=$.tabCommand??($.tabVendor?void 0:$.command),{argv:q,sessionId:U}=uQ(U2({command:W,vendor:G,effort:$.modelEffort}),G);qH(G,Z);let B=WH({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 QH())?.taskId}:{kind:"explicit",prompt:J},tabId:z}),M=await eR(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)yu($.id,z,U);else VT($.id,U);else if(!z)VT($.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 ST($,Z,J,X=GW0){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 GW0,KF;var FF=d(()=>{W9();B7();_j();Cj();Dj();QF();Wj();_T();$8();GW0={deliverHosted:YW0};KF={isTaskRunning:async($)=>(await KF.taskTabs($)).running,taskTabs:async($)=>{let Z=[],J=await JH();if(J)try{Z=await XH(J.rpc)}finally{J.close()}let X;try{let{foregroundEngineIn:W,parsePsSnapshot:q,psSnapshot:U}=await Promise.resolve().then(() => (MZ(),oO)),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(() => (vj(),AT))).readPtyExitRecords()}catch{}let G=Eu($);return{tabs:xu(G,$,Z,z,X),running:fu(G,$,Z)}},deliverPrompt:($,Z,J)=>ST($,Z,J),resolveRepoRoot:async($)=>(await Promise.resolve().then(() => (C4(),kq))).resolveMainRepoRoot($),defaultVendor:async($)=>{let{getGlobalDefaultVendor:Z,getRepoLastActiveVendor:J}=await Promise.resolve().then(() => (_Z(),hu));return($?J($):void 0)??Z()},readWorktreeChanges:async($)=>(await Promise.resolve().then(() => (OH(),iu))).readWorktreeChanges($),readBranchSignals:async($)=>(await Promise.resolve().then(() => (tu(),su))).readBranchSignals($),tearDownSession:async($)=>{let Z=await JH();if(Z)try{await ZT(Z.rpc,rR(await XH(Z.rpc),$))}catch{}finally{Z.close()}}}});var dj;var eu=d(()=>{dj={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.8.171",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:()=>nY,releasePageUrl:()=>yT,recommendedGlobalInstallCommand:()=>wT,isNewerSemver:()=>IT,fetchReleaseSummaries:()=>LF,fetchReleaseNotesRange:()=>fT,fetchReleaseNotes:()=>xT,compareSemver:()=>C3,checkLatestVersion:()=>iY,breakingVersionsCrossed:()=>MF,UPDATE_SCRIPT_URL:()=>lj,UPDATE_COMMAND:()=>AZ,PACKAGE_NAME:()=>ET,CURRENT_VERSION:()=>D$,BREAKING_VERSIONS:()=>pJ});function nY(){let $=dj.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function wT(){return`npm install -g ${ET}@latest`}function MF($,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 qW0($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),pj);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 IT($,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 iY($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:D$,latest:Z,hasUpdate:IT(Z,D$)};if(xq()&&!$.force)return null;let J=await qW0(ET);if(!J)return null;return{current:D$,latest:J,hasUpdate:IT(J,D$)}}function $c($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function xT($){let Z=nY();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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 fT($){let Z=nY();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),pj);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=$c(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 LF($=12){let Z=nY();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),pj);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=$c(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 yT($){let Z=nY();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var D$,ET,lj="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",AZ,pJ,pj=3000;var u8=d(()=>{eu();j5();D$=dj.version,ET=dj.name;AZ=`curl -fsSL ${lj} | 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 Jc(){let[{KobeDaemonClient:$},{defaultPtyHostSocketPath:Z}]=await Promise.all([Promise.resolve().then(() => (Y9(),pR)),Promise.resolve().then(() => (P7(),uR))]),J=new $(Z());try{return await J.connect(),await J.request("pty.list",{})}catch{return{sessions:[]}}finally{J.close()}}var B2=d(()=>{$8()});async function HW0($){let Z=$.args.require("command"),J=cQ(Z);return await Z4($,"task.setCommand",{taskId:$.args.require("task-id"),command:Z,vendor:J}),{ok:!0,command:Z,protocol:J,...J===mY?{generic:!0}:{}}}var Xc,Qc;var bT=d(()=>{W9();f2();B2();Xc={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:lm()})};Qc={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:HW0}});function Wc($){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 zc,Yc,Gc,qc;var Hc=d(()=>{f2();B2();zc={name:"schedule",type:"string",placeholder:"CRON",description:"Five-field cron in the daemon host's local time, e.g. '0 9 * * MON-FRI'."},Yc=[{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)."}],Gc={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."};qc=[{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."),{...zc,required:!0},$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"Base ref each run's worktree branches from."},...Yc,Gc,{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")}:{},...Wc($),...$.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."),zc,$$.vendor(),{name:"base-branch",type:"string",placeholder:"B",description:"New base ref ('' to clear)."},...Yc,Gc],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")}:{},...Wc($),...$.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 Uc($,Z){let J=$.args.str("command");if(J)return{command:J,vendor:cQ(J)};let X=await $.runtime.defaultVendor(Z);return X?{command:X,vendor:X}:{}}function Bc($){return{...$.command?{command:$.command}:{},...$.vendor?{vendor:$.vendor}:{}}}async function Kc($){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 BW0($,X,z,G);return UW0($,X)}async function UW0($,Z){let J=i4($),{args:X}=$,z=await Uc($,Z),G={repo:Z,...await XT(),...Bc(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 L=X.bool("pin");if(L!==void 0)await J.request("task.pin",{taskId:M,pinned:L});let j=B.task;if(O||L!==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 _=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,!_.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:_.started,engineReady:_.engineReady,session:_.session,delivered:_.delivered}}async function BW0($,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",N3("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",N3("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",N3("add"))}let q=G.str("title"),U=G.str("base-branch"),B=await Uc($,Z),M=X?Kj(X):Fj(J??1,B.vendor??"claude");if(M.length>NZ)throw new K1(`a parallel round of ${M.length} exceeds the cap of ${NZ} \u2014 spawn in batches`,"BAD_FLAG");let O=qO(),L=[],j=null,D=await XT();for(let[E,T]of M.entries()){let w=X?{command:T,vendor:T}:{...B,vendor:T},f={repo:Z,groupId:O,...D,...Bc(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);L.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 _=await Promise.allSettled(L.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))),C=[],g=[];if(_.forEach((E,T)=>{let{taskId:w,vendor:f}=L[T];if(E.status==="fulfilled"&&E.value.delivered){C.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:L.length,requested:M.length,groupId:O,tasks:C,failures:g};if(g.length>0)throw new K1(`add delivered ${C.length}/${M.length}`,"PARTIAL_FANOUT",I);return I}var Fc=d(()=>{W9();xP();QF();f2();B2();$8()});var nj;var gT=d(()=>{nj=["backlog","in_progress","in_review","done","canceled","error"]});var Mc;var Lc=d(()=>{f2();Fc();gT();Mc=[{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 ${NZ}, 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 ${NZ}). 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:nj,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:Kc}]});var Nc,Oc;var jc=d(()=>{hJ();f2();B2();FF();$8();Nc={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"})}},Oc={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 vT,NF,kT,mT="DIRTY_WORKTREE",hT,uT,KW0="TASK_DELETING",pQ,FW0="MAIN_CHECKOUT_DIRTY",cT,MW0="EMPTY_BRANCH",dT,ij="EMPTY_BRANCH_DIRTY_WORKTREE",lT,LW0="LAND_CONFLICT",oj;var nJ=d(()=>{vT=class vT 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"}};NF=class NF extends Error{constructor($){super(`task not found: ${$}`);this.name="TaskNotFoundError"}};kT=class kT extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}};hT=class hT extends Error{taskId;constructor($){super(`${mT}: task ${$} worktree has uncommitted or untracked changes`);this.taskId=$;this.name="DirtyWorktreeError"}};uT=class uT extends Error{taskId;cause;constructor($,Z){super(`failed to remove worktree for task ${$}: ${M1(Z)}`);this.taskId=$;this.cause=Z;this.name="WorktreeRemoveFailedError"}};pQ=class pQ extends Error{taskId;constructor($){super(`${KW0}: task ${$} is being deleted`);this.taskId=$;this.name="TaskDeletingError"}};cT=class cT extends Error{repo;dir;constructor($,Z){super(`${FW0}: base checkout at ${Z} has uncommitted changes; commit or stash them before landing`);this.repo=$;this.dir=Z;this.name="MainCheckoutDirtyError"}};dT=class dT extends Error{branch;landedOn;constructor($,Z){super(`${MW0}: '${$}' 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"}};lT=class lT extends Error{branch;landedOn;worktreePath;files;constructor($,Z,J,X){let z=X.length>0?X.join(", "):"(none reported)";super(`${ij}: '${$}' 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"}};oj=class oj 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 NW0($,Z,J){let X=await QH(),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 Vc($){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 _c($){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",N3("send"));let G=z?cQ(z):void 0,W=$.args.str("task-id");if(!W){let M=await vm(Z);if(M){if(W=M.taskId,X===void 0)X=await km($.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 NW0(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 OW0($){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 Ac($){let Z=i4($),J=$.args.require("task-id"),X=$.args.require("text");return await Z.request("note.file",{taskId:J,text:X})}async function Dc($){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 Pc($){return i4($).request("task.list")}async function Rc($){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 Tc($){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 Sc($){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 Ic($){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 jW0(W,J)}return{ok:!0,taskId:J,...G.result}}function jW0($,Z){let J=M1($);if(!J.includes(ij))return $;let X=/EMPTY_BRANCH_DIRTY_WORKTREE: '([^']+)'/.exec(J)?.[1]??"your task branch";return new K1(J,ij,{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 Ec($){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=cQ(G);let W=J.str("title");if(W)X.title=W;return Z.request("worktree.adopt",X)}var Cc;var jH=d(()=>{W9();B7();nJ();QF();f2();B2();FF();$8();Cc={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:OW0}});var wc;var xc=d(()=>{f2();B2();jc();jH();wc=[{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:_c},Cc,{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:Ac},{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")})},Nc,Oc,{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:Rc}]});var fc;var yc=d(()=>{f2();B2();bT();gT();fc=[{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")})},Qc,{name:"set-status",summary:"Set a task's lifecycle status.",flags:[$$.taskId(),{name:"status",type:"enum",required:!0,values:nj,description:"New status."}],handler:($)=>Z4($,"task.status",{taskId:$.args.require("task-id"),status:$.args.requireEnum("status")})}]});import{spawnSync as VW0}from"child_process";function AW0($){let[Z,J]=$.split("/");if(!Z||!J)throw Error(`invalid GitHub repository slug: ${$}`);return{owner:Z,name:J}}function bc($,Z){let J=$.trim();if(!J)throw Error(`${Z} is required`);return J}function gc($,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 vc($,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: ${gc(W,void 0)}`)}if((z.status??0)!==0||q.errors?.length)throw Error(gc(W,q.errors));if(!q.data)throw Error("GitHub CLI response did not include data");return q.data}function DW0($){return`${$}
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
Submitted from Rove ${D$}.`}function VH($,Z={}){let J=bc($.title,"feedback title"),X=DW0(bc($.body,"feedback body")),z=(Z.repoSlug??nY)();if(!z)throw Error("package repository is not a GitHub repository");let{owner:G,name:W}=AW0(z),q=$.categorySlug?.trim()||pT,U={spawn:Z.spawn??VW0},M=vc(_W0,{owner:G,name:W},U).repository,O=M?.id;if(!O)throw Error(`GitHub repository not found: ${z}`);let L=M.discussionCategories?.nodes?.find((_)=>_.slug===q);if(!L)throw Error(`GitHub Discussion category not found: ${q}`);let D=vc(CW0,{repositoryId:O,categoryId:L.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 pT="feedback",_W0=`
|
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.171",
|
|
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",
|