@sma1lboy/rove 0.9.149 → 0.9.151

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/cli/chunk-15k6hqzx.js +2 -0
  2. package/dist/cli/chunk-1cjd7h8p.js +6 -0
  3. package/dist/cli/chunk-1vhbnf49.js +2 -0
  4. package/dist/cli/chunk-2cyzv75r.js +3 -0
  5. package/dist/cli/{chunk-7m4s0xfa.js → chunk-3zf7mr7r.js} +1 -1
  6. package/dist/cli/chunk-4d5bph3p.js +2 -0
  7. package/dist/cli/chunk-4nm1axc3.js +2 -0
  8. package/dist/cli/{chunk-g1ybdgad.js → chunk-579zz8df.js} +2 -2
  9. package/dist/cli/{chunk-f9p1gze7.js → chunk-5mr9j201.js} +3 -3
  10. package/dist/cli/{chunk-q6579rbz.js → chunk-5wzap7r2.js} +1 -1
  11. package/dist/cli/chunk-6kz81dkc.js +17 -0
  12. package/dist/cli/{chunk-f6zsej8e.js → chunk-6sp2ags8.js} +1 -1
  13. package/dist/cli/chunk-7jkf3tvr.js +3 -0
  14. package/dist/cli/{chunk-v90k9ppb.js → chunk-7tfqaet5.js} +1 -1
  15. package/dist/cli/chunk-7zmrn4gn.js +3 -0
  16. package/dist/cli/{chunk-nm6adny4.js → chunk-86bjqmg1.js} +1 -1
  17. package/dist/cli/{chunk-k3ksts6g.js → chunk-87y9qjcm.js} +1 -1
  18. package/dist/cli/chunk-8rxg6hs2.js +2 -0
  19. package/dist/cli/chunk-95e0ks8n.js +2 -0
  20. package/dist/cli/chunk-98thhbm5.js +9 -0
  21. package/dist/cli/chunk-9nbg0nzh.js +3 -0
  22. package/dist/cli/chunk-a3a9gdc4.js +3 -0
  23. package/dist/cli/{chunk-mrwee8sj.js → chunk-aeq5xmtq.js} +1 -1
  24. package/dist/cli/chunk-akckb9kw.js +3 -0
  25. package/dist/cli/chunk-ayagydjk.js +2 -0
  26. package/dist/cli/chunk-cexxmfva.js +2 -0
  27. package/dist/cli/chunk-d393z1mj.js +4 -0
  28. package/dist/cli/{chunk-khfc4rjt.js → chunk-d89r6eqm.js} +1 -1
  29. package/dist/cli/chunk-dmdqnet6.js +3 -0
  30. package/dist/cli/chunk-e7t4xpr9.js +36 -0
  31. package/dist/cli/chunk-e8493db0.js +4 -0
  32. package/dist/cli/{chunk-66kp3cr1.js → chunk-emm50f4q.js} +1 -1
  33. package/dist/cli/{chunk-etnxfpx5.js → chunk-fm4q306m.js} +1 -1
  34. package/dist/cli/{chunk-nceh1q3d.js → chunk-fpjcrjna.js} +1 -1
  35. package/dist/cli/chunk-fyf7xgaa.js +2 -0
  36. package/dist/cli/{chunk-e1g9mvww.js → chunk-g47vt3k5.js} +1 -1
  37. package/dist/cli/chunk-gtkejmxx.js +3 -0
  38. package/dist/cli/chunk-gzf4dfg6.js +3 -0
  39. package/dist/cli/chunk-j5r92gh9.js +2 -0
  40. package/dist/cli/chunk-jfkw009v.js +2 -0
  41. package/dist/cli/{chunk-zgx27dnc.js → chunk-jq5vp0f7.js} +1 -1
  42. package/dist/cli/{chunk-me77sx3d.js → chunk-jv5nqjnv.js} +1 -1
  43. package/dist/cli/chunk-jwv06n3d.js +8 -0
  44. package/dist/cli/{chunk-5x8ckw1a.js → chunk-jy6nd23p.js} +1 -1
  45. package/dist/cli/{chunk-zqwksfqh.js → chunk-k1sjc72d.js} +8 -8
  46. package/dist/cli/chunk-k9skkhzs.js +2 -0
  47. package/dist/cli/chunk-ktmvmskn.js +4 -0
  48. package/dist/cli/{chunk-xyy4f9ek.js → chunk-m2xasved.js} +2 -2
  49. package/dist/cli/chunk-m370e00b.js +4 -0
  50. package/dist/cli/{chunk-mcqzk9cg.js → chunk-m4my5wna.js} +3 -3
  51. package/dist/cli/chunk-m57cv76y.js +3 -0
  52. package/dist/cli/chunk-n4dmwkfa.js +4 -0
  53. package/dist/cli/chunk-nw91q4x3.js +2 -0
  54. package/dist/cli/{chunk-me7kkwp7.js → chunk-p9vkwnb8.js} +2 -2
  55. package/dist/cli/{chunk-856hq7jz.js → chunk-pmt3agbd.js} +1 -1
  56. package/dist/cli/{chunk-9m1nqceb.js → chunk-q0f6rhex.js} +2 -2
  57. package/dist/cli/chunk-q4ry13v3.js +2 -0
  58. package/dist/cli/chunk-r1p9bwja.js +7 -0
  59. package/dist/cli/{chunk-hg5x2wr0.js → chunk-r2pztgm6.js} +2 -2
  60. package/dist/cli/chunk-rf2m6f3h.js +5 -0
  61. package/dist/cli/{chunk-vapjtyv9.js → chunk-rgh49bm3.js} +1 -1
  62. package/dist/cli/{chunk-8nnmpnxb.js → chunk-rz8247zr.js} +2 -2
  63. package/dist/cli/chunk-rz8zs7j8.js +3 -0
  64. package/dist/cli/{chunk-zb56ck5f.js → chunk-s433recg.js} +1 -1
  65. package/dist/cli/{chunk-a4a4qaa2.js → chunk-s8xyh1bt.js} +1 -1
  66. package/dist/cli/chunk-sexavazm.js +3 -0
  67. package/dist/cli/chunk-ssepbf68.js +2 -0
  68. package/dist/cli/{chunk-jvpzy378.js → chunk-t05pnk6y.js} +1 -1
  69. package/dist/cli/{chunk-dkxhmj9k.js → chunk-tgxe9ae1.js} +2 -2
  70. package/dist/cli/{chunk-6zwg6me2.js → chunk-tk8p54f7.js} +1 -1
  71. package/dist/cli/chunk-tz9e598v.js +2 -0
  72. package/dist/cli/{chunk-jyv82gf0.js → chunk-w7zv47mp.js} +3 -4
  73. package/dist/cli/{chunk-mqbjqw85.js → chunk-wc1kk5c0.js} +1 -1
  74. package/dist/cli/{chunk-cytn2byt.js → chunk-wzyh3fgx.js} +1 -1
  75. package/dist/cli/{chunk-np07kccr.js → chunk-x39pv7rx.js} +1 -1
  76. package/dist/cli/{chunk-gbasmvsc.js → chunk-x3gch5nw.js} +1 -1
  77. package/dist/cli/{chunk-kd1anc9y.js → chunk-x8m1vmyd.js} +1 -1
  78. package/dist/cli/{chunk-jsss3ze7.js → chunk-xe62kmhp.js} +2 -2
  79. package/dist/cli/{chunk-adez6hq4.js → chunk-xnr8dga2.js} +3 -3
  80. package/dist/cli/chunk-xtr7ks02.js +3 -0
  81. package/dist/cli/{chunk-y2yq6zca.js → chunk-y5hnrx8d.js} +1 -1
  82. package/dist/cli/{chunk-13s8rnk5.js → chunk-y9ksfpbp.js} +1 -1
  83. package/dist/cli/{chunk-p7kztgsd.js → chunk-ybsdy2w8.js} +1 -1
  84. package/dist/cli/{chunk-bj59a9mg.js → chunk-yfg503fr.js} +1 -1
  85. package/dist/cli/{chunk-b8d162tf.js → chunk-zaxdx0wd.js} +1 -1
  86. package/dist/cli/index.js +7 -7
  87. package/dist/cli/kobe.js +1 -1
  88. package/dist/cli/pty-host-node.mjs +25 -2
  89. package/dist/cli/rove.js +1 -1
  90. package/package.json +3 -2
  91. package/dist/cli/chunk-003tvywc.js +0 -3
  92. package/dist/cli/chunk-02y7hdy3.js +0 -3
  93. package/dist/cli/chunk-0kn7xxqm.js +0 -6
  94. package/dist/cli/chunk-20pt9yqh.js +0 -4
  95. package/dist/cli/chunk-2jxdzw4r.js +0 -3
  96. package/dist/cli/chunk-2pqqvse3.js +0 -2
  97. package/dist/cli/chunk-49s2zc0h.js +0 -8
  98. package/dist/cli/chunk-5hhvrvgm.js +0 -8
  99. package/dist/cli/chunk-7nhdvr5v.js +0 -4
  100. package/dist/cli/chunk-8g456mmt.js +0 -3
  101. package/dist/cli/chunk-99devyxr.js +0 -2
  102. package/dist/cli/chunk-9mbvexw2.js +0 -2
  103. package/dist/cli/chunk-awsawfrm.js +0 -2
  104. package/dist/cli/chunk-bzz4ta7g.js +0 -17
  105. package/dist/cli/chunk-cxb93h7m.js +0 -2
  106. package/dist/cli/chunk-df7qe9y7.js +0 -4
  107. package/dist/cli/chunk-gjf604bb.js +0 -3
  108. package/dist/cli/chunk-gm3vj0fv.js +0 -5
  109. package/dist/cli/chunk-h356efbh.js +0 -2
  110. package/dist/cli/chunk-h5j8b87f.js +0 -2
  111. package/dist/cli/chunk-h79zfebh.js +0 -7
  112. package/dist/cli/chunk-ksd57jm6.js +0 -2
  113. package/dist/cli/chunk-m6pvaxm7.js +0 -2
  114. package/dist/cli/chunk-mfqjdpd8.js +0 -2
  115. package/dist/cli/chunk-ncsgawg7.js +0 -2
  116. package/dist/cli/chunk-pbqwegjy.js +0 -2
  117. package/dist/cli/chunk-q7dr9eh6.js +0 -3
  118. package/dist/cli/chunk-qtke4x42.js +0 -3
  119. package/dist/cli/chunk-seyk0v2m.js +0 -2
  120. package/dist/cli/chunk-v5893dx3.js +0 -2
  121. package/dist/cli/chunk-vwjec3m6.js +0 -3
  122. package/dist/cli/chunk-vws0j65e.js +0 -4
  123. package/dist/cli/chunk-w5xy83ze.js +0 -2
  124. package/dist/cli/chunk-xbc3gcry.js +0 -2
  125. package/dist/cli/chunk-yhcz2d2r.js +0 -34
  126. package/dist/cli/chunk-ykvk2546.js +0 -3
@@ -0,0 +1,9 @@
1
+ // @bun
2
+ import{canonicalize,isKobeManagedPath,isUnderManagedWorktreesRoot,managedWorktreeRootForPath,remoteManagedRootForPath,remoteWorktreePathFor,requireAbsolute,worktreePathFor}from"./chunk-2cyzv75r.js";import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{execHostForRepo,execHostForWorktreePath}from"./chunk-7zmrn4gn.js";import{getRemoteRepoConfig}from"./chunk-87y9qjcm.js";import path3 from"path";var defaultExecDeps={execForRepo:execHostForRepo,execForPath:execHostForWorktreePath,remoteBasePath(repoKey){return getRemoteRepoConfig(repoKey)?.basePath??null}};class GitCommandError extends Error{args;cwd;exitCode;stdout;stderr;constructor(args,cwd,result){super(`git ${args.join(" ")} (cwd=${cwd}) exited with code ${result.exitCode}: ${result.stderr.trim()||result.stdout.trim()}`);this.name="GitCommandError",this.args=args,this.cwd=cwd,this.exitCode=result.exitCode,this.stdout=result.stdout,this.stderr=result.stderr}}var MAX_IGNORED_ENTRY_KB=65536;function parseIgnoredPaths(stdoutZ){return stdoutZ.split("\x00").filter((entry)=>entry.startsWith("!! ")).map((entry)=>entry.slice(3)).filter((p)=>p.length>0)}var DU_ARGV_BUDGET_BYTES=98304;function parseDuKb(stdout){let sizes=new Map;for(let line of stdout.split(`
3
+ `)){let m=/^(\d+)\s+(.+)$/.exec(line.trim());if(m?.[1]&&m[2])sizes.set(m[2],Number.parseInt(m[1],10))}return sizes}async function duKb(exec,worktreePath,paths){let sizes=new Map,batch=[],bytes=0,flush=async()=>{if(batch.length===0)return;let du=await exec.run(["du","-sk","--",...batch],{cwd:worktreePath});for(let[p,kb]of parseDuKb(du.stdout))sizes.set(p,kb);batch.length=0,bytes=0};for(let p of paths){if(p.includes(`
4
+ `)){let one=await exec.run(["du","-sk","--",p],{cwd:worktreePath}),kb=/^\s*(\d+)/.exec(one.stdout)?.[1];if(one.exitCode===0&&kb)sizes.set(p,Number.parseInt(kb,10));continue}if(bytes+p.length+1>DU_ARGV_BUDGET_BYTES)await flush();batch.push(p),bytes+=p.length+1}return await flush(),sizes}async function smallIgnoredPaths(exec,worktreePath){try{let status=await exec.run(["git","status","--porcelain","-z","--ignored"],{cwd:worktreePath,env:READ_ONLY_GIT_ENV});if(status.exitCode!==0)return[];let paths=parseIgnoredPaths(status.stdout);if(paths.length===0)return[];let sizes=await duKb(exec,worktreePath,paths);return paths.filter((p)=>{let kb=sizes.get(p);return kb!==void 0&&kb<=MAX_IGNORED_ENTRY_KB})}catch{return[]}}async function gitlinkPaths(git,tree){let out=await git(["ls-tree","-r",tree]);if(out.exitCode!==0)return[];return out.stdout.split(`
5
+ `).filter((line)=>line.startsWith("160000 ")).map((line)=>line.slice(line.indexOf("\t")+1)).filter((p)=>p.length>0)}function branchRefSlug(branch){return(branch??"").replace(/[\u0000-\u0020\u007f~^:?*[\\/]+/g,"-").replace(/@\{/g,"-").replace(/\.{2,}/g,"-").replace(/^[-.]+|[-.]+$/g,"")||"detached"}function salvageRef(branch,now){let stamp=now.toISOString().replace(/[-:]/g,"").replace(/\.\d+Z$/,"Z");return`refs/rove/salvage/${branchRefSlug(branch)}-${stamp}`}async function createSalvageRef(git,preferred,commit){for(let attempt=1;attempt<=50;attempt++){let ref=attempt===1?preferred:`${preferred}-${attempt}`;if((await git(["update-ref",ref,commit,""])).exitCode===0)return ref}return null}async function salvageWorktree(deps,exec,worktreePath,now=new Date){let git=(args)=>deps.runGit(exec,args,{cwd:worktreePath,allowFail:!0});try{let status=await git(["status","--porcelain"]);if(status.exitCode!==0)return null;let ignored=await smallIgnoredPaths(exec,worktreePath);if(status.stdout.trim().length===0&&ignored.length===0)return null;let indexPath=(await git(["rev-parse","--git-path","rove-salvage-index"])).stdout.trim();if(!indexPath)return null;let withIndex=(args)=>deps.runGit(exec,args,{cwd:worktreePath,allowFail:!0,env:{GIT_INDEX_FILE:indexPath}}),head=(await git(["rev-parse","HEAD"])).stdout.trim(),branch=(await git(["rev-parse","--abbrev-ref","HEAD"])).stdout.trim();try{if(head&&(await withIndex(["read-tree",head])).exitCode!==0)return null;if((await withIndex(["add","-A"])).exitCode!==0)return null;if(ignored.length>0)await withIndex(["add","-f","--",...ignored]);let tree=(await withIndex(["write-tree"])).stdout.trim();if(!tree)return null;let message=`rove salvage: force-removed worktree ${worktreePath}`,commit=(await withIndex(head?["commit-tree",tree,"-p",head,"-m",message]:["commit-tree",tree,"-m",message])).stdout.trim();if(!commit)return null;let ref=await createSalvageRef(git,salvageRef(branch&&branch!=="HEAD"?branch:null,now),commit);if(!ref)return null;return{ref,commit,uncaptured:await gitlinkPaths(git,tree)}}finally{await exec.run(["rm","-f",indexPath],{cwd:worktreePath}).catch(()=>{return})}}catch{return null}}async function anchorBranchTip(deps,exec,repo,branch,now=new Date){if(!branch||branch==="HEAD")return null;let git=(args)=>deps.runGit(exec,args,{cwd:repo,allowFail:!0});try{let tipOut=await git(["rev-parse","--verify",`refs/heads/${branch}`]),tip=tipOut.stdout.trim();if(tipOut.exitCode!==0||!tip)return null;let holders=await git(["for-each-ref","--contains",tip,"--format=%(refname)"]);if(holders.exitCode===0){if(holders.stdout.split(`
6
+ `).map((l)=>l.trim()).filter((l)=>l.length>0&&l!==`refs/heads/${branch}`).length>0)return null}let ref=salvageRef(branch,now);if((await git(["update-ref",ref,tip])).exitCode!==0)return null;return{ref,commit:tip,uncaptured:[]}}catch{return null}}async function branchExists(deps,ctx,branch){return(await deps.runGit(ctx.exec,["show-ref","--verify","--quiet",`refs/heads/${branch}`],{cwd:ctx.dir,allowFail:!0,readOnly:!0})).exitCode===0}async function deleteBranchIn(deps,exec,repo,branch,force){if(!branch||branch==="HEAD")return;await deps.runGit(exec,["branch",force?"-D":"-d",branch],{cwd:repo,allowFail:!0})}async function deleteBranchAnchored(deps,exec,repo,branch,opts){if(opts.force)opts.onAnchor?.(await anchorBranchTip(deps,exec,repo,branch));await deleteBranchIn(deps,exec,repo,branch,opts.force)}async function branchHasUpstream(deps,worktreePath,branch){return(await deps.runGit(deps.execAt(worktreePath),["for-each-ref","--format=%(upstream)",`refs/heads/${branch}`],{cwd:worktreePath,readOnly:!0})).stdout.trim().length>0}async function hasLocalBranch(deps,worktreePath,branch){return(await deps.runGit(deps.execAt(worktreePath),["show-ref","--verify","--quiet",`refs/heads/${branch}`],{cwd:worktreePath,allowFail:!0,readOnly:!0})).exitCode===0}async function renameBranch(deps,worktreePath,from,to){let exec=deps.execAt(worktreePath);if(from===to)return;let repo=await deps.findRepoFor(exec,worktreePath);if(!repo)throw Error(`renameBranch(): ${worktreePath} is not a git worktree`);let out=await deps.runGit(exec,["branch","-m",from,to],{cwd:repo,allowFail:!0});if(out.exitCode===0)return;let ctx={exec,dir:repo,remote:exec.isRemote};if(!await branchExists(deps,ctx,from)&&await branchExists(deps,ctx,to))return;throw new GitCommandError(["branch","-m",from,to],repo,out)}import fs from"fs";import path from"path";async function mapWithLimit(items,limit,fn){let results=Array(items.length),next=0,worker=async()=>{for(;;){let i=next++;if(i>=items.length)return;results[i]=await fn(items[i])}},width=Math.max(1,Math.min(limit,items.length));return await Promise.all(Array.from({length:width},worker)),results}var PROBE_CONCURRENCY=6;function parseWorktreeListPorcelain(out){let records=[],current=null;for(let rawLine of out.split(`
7
+ `)){let line=rawLine.replace(/\r$/,"");if(line===""){if(current)records.push(current);current=null;continue}if(!current)current={};if(line.startsWith("worktree "))current.path=line.slice(9);else if(line.startsWith("HEAD "))current.head=line.slice(5);else if(line.startsWith("branch ")){let ref=line.slice(7);current.branch=ref.startsWith("refs/heads/")?ref.slice(11):ref}else if(line==="detached")current.detached=!0;else if(line==="bare")current.bare=!0}if(current)records.push(current);return records}async function lastActivityMs(deps,ctx,worktreePath){try{let stdout=await deps.runGitStdoutAt(ctx,worktreePath,["log","-1","--format=%ct"]),secs=Number.parseInt(stdout.trim(),10);if(Number.isFinite(secs)&&secs>0)return secs*1000}catch{}if(!ctx.exec.isRemote)try{return fs.statSync(worktreePath).mtimeMs}catch{}return 0}async function listBranchNames(deps,repo){let ctx=deps.ctxFor(repo);requireAbsolute("repo",ctx.dir);let stdout;try{stdout=await deps.runGitStdout(ctx,["for-each-ref","--format=%(refname:short)","refs/heads","refs/remotes/origin"])}catch{return[]}let names=new Set;for(let line of stdout.split(`
8
+ `)){let name=line.trim().replace(/^origin\//,"");if(name&&name!=="HEAD")names.add(name)}return[...names]}async function listManaged(deps,repo){let ctx=deps.ctxFor(repo);requireAbsolute("repo",ctx.dir);let all=parseWorktreeListPorcelain(await deps.runGitStdout(ctx,["worktree","list","--porcelain"])),kept=[];for(let entry of all){if(!entry.path)continue;let callerRoot=ctx.remote?remoteManagedRootForPath(ctx.dir,entry.path):managedWorktreeRootForPath(repo,entry.path);if(!callerRoot)continue;if(!entry.branch||entry.detached)continue;let rel=path.relative(canonicalize(callerRoot),canonicalize(entry.path));kept.push({callerPath:path.join(callerRoot,rel),probePath:entry.path,branch:entry.branch,head:entry.head??""})}return mapWithLimit(kept,PROBE_CONCURRENCY,async(e)=>({path:e.callerPath,branch:e.branch,head:e.head,dirty:await deps.isDirty(e.probePath).catch(()=>null)}))}async function listAllAdoptable(deps,repo){let ctx=deps.ctxFor(repo),adoptable=await adoptablePaths(deps,ctx),infos=await mapWithLimit(adoptable,PROBE_CONCURRENCY,async(entry)=>{let[dirty,activityMs]=await Promise.all([deps.isDirty(entry.path).catch(()=>null),lastActivityMs(deps,ctx,entry.path)]);return{path:entry.path,branch:entry.branch,head:entry.head,dirty,kobeManaged:ctx.remote?remoteManagedRootForPath(ctx.dir,entry.path)!==null:isKobeManagedPath(repo,entry.path),lastActivityMs:activityMs}});return infos.sort((a,b)=>b.lastActivityMs-a.lastActivityMs),infos}async function adoptablePaths(deps,ctx){requireAbsolute("repo",ctx.dir);let all=parseWorktreeListPorcelain(await deps.runGitStdout(ctx,["worktree","list","--porcelain"])),canon=(p)=>ctx.remote?p:canonicalize(p),canonRepo=canon(ctx.dir),canonMain=all.find((entry)=>entry.path)?.path,canonMainPath=canonMain?canon(canonMain):null,kept=[];for(let entry of all){if(!entry.path)continue;if(entry.bare)continue;if(!entry.branch||entry.detached)continue;let canonEntry=canon(entry.path);if(canonMainPath!==null&&canonEntry===canonMainPath)continue;if(canonEntry===canonRepo)continue;kept.push({path:entry.path,branch:entry.branch,head:entry.head??""})}return kept}async function unreadableWorktreeNames(deps,ctx){if(ctx.remote)return[];requireAbsolute("repo",ctx.dir);let adminRoot;try{let common=(await deps.runGitStdout(ctx,["rev-parse","--git-common-dir"])).trim();if(!common)return[];adminRoot=path.join(path.resolve(ctx.dir,common),"worktrees")}catch{return[]}let names;try{names=fs.readdirSync(adminRoot,{withFileTypes:!0}).filter((entry)=>entry.isDirectory()).map((entry)=>entry.name)}catch{return[]}if(names.length===0)return[];let listed;try{listed=await deps.runGitStdout(ctx,["worktree","list","--porcelain"])}catch{return[]}let reported=new Set(parseWorktreeListPorcelain(listed).filter((entry)=>entry.path).map((entry)=>canonicalize(entry.path))),missing=[];for(let name of names){let gitdir;try{gitdir=fs.readFileSync(path.join(adminRoot,name,"gitdir"),"utf8").trim()}catch{missing.push(name);continue}if(gitdir&&!reported.has(canonicalize(path.dirname(gitdir))))missing.push(name)}return missing}import path2 from"path";async function isRegisteredWorktree(deps,exec,repo,worktreePath){let out=await deps.runGit(exec,["worktree","list","--porcelain"],{cwd:repo,allowFail:!0,readOnly:!0});if(out.exitCode!==0)return!1;let same=(a,b)=>exec.isRemote?a===b:canonicalize(a)===canonicalize(b);return parseWorktreeListPorcelain(out.stdout).some((e)=>e.path!==void 0&&same(e.path,worktreePath))}async function deregisteredWorktreeResidue(exec,worktreePath){let pointer=(await exec.readFile(`${worktreePath}/.git`))?.trim().match(/^gitdir:\s*(.+)$/)?.[1]?.trim();if(!pointer)return!1;let marker="/worktrees/",at=pointer.lastIndexOf(marker);if(at<0)return!1;return await exec.exists(pointer.slice(0,at))}async function removeWorktree(deps,worktreePath,opts){requireAbsolute("path",worktreePath);let exec=deps.execForPath(worktreePath),force=opts?.force===!0;if(!await exec.exists(worktreePath)){let goneRepo=opts?.repo??await deps.findRepoFor(exec,path2.dirname(worktreePath));if(goneRepo){if(await deps.runGit(exec,["worktree","prune"],{cwd:goneRepo,allowFail:!0}),opts?.deleteBranch===!0&&opts.branch)await deleteBranchAnchored(deps.branchDeps(),exec,goneRepo,opts.branch,{force})}return}let repo=await deps.findRepoFor(exec,worktreePath);if(repo===null||!await isRegisteredWorktree(deps,exec,repo,worktreePath)){if(await deregisteredWorktreeResidue(exec,worktreePath)){opts?.onResidue?.({path:worktreePath,reason:"a previous removal deregistered the worktree"});return}if(repo){opts?.onResidue?.({path:worktreePath,reason:"a previous removal deregistered the worktree"});return}if(!force)throw Error(`remove(): ${worktreePath} is not a git worktree`);if(!isUnderManagedWorktreesRoot(worktreePath,opts?.repo))throw Error(`remove(): ${worktreePath} has no reachable git repo and is not under a Rove worktrees root; refusing to delete it`);if(opts?.onSalvage?.(null),await exec.run(["rm","-rf",worktreePath]),await exec.exists(worktreePath))opts?.onResidue?.({path:worktreePath,reason:"the directory could not be deleted"});return}let branch=opts?.deleteBranch?await deps.currentBranch(worktreePath).catch(()=>null)??opts.branch??null:null;if(force){let salvaged=await salvageWorktree({runGit:(e,a,o)=>deps.runGit(e,a,o)},exec,worktreePath);opts?.onSalvage?.(salvaged)}else{if(await deps.isDirty(worktreePath))throw Error(`remove(): refusing to remove dirty worktree at ${worktreePath} (pass { force: true } to override)`);let ignored=await deps.ignoredWork(worktreePath).catch(()=>[]);if(ignored.length>0)throw Error(`remove(): refusing to remove worktree at ${worktreePath} \u2014 it holds gitignored work git status cannot see: ${ignored.join(", ")} (pass { force: true } to override)`)}let args=force?["worktree","remove","--force",worktreePath]:["worktree","remove",worktreePath],result=await deps.runGit(exec,args,{cwd:repo,allowFail:!0});if(result.exitCode!==0){if(await isRegisteredWorktree(deps,exec,repo,worktreePath))throw new GitCommandError(args,repo,result);opts?.onResidue?.({path:worktreePath,reason:result.stderr.trim()||result.stdout.trim()||"unknown"})}if(await deps.runGit(exec,["worktree","prune"],{cwd:repo,allowFail:!0}),branch)await deleteBranchAnchored(deps.branchDeps(),exec,repo,branch,{force})}class GitWorktreeManager{execDeps;constructor(execDeps=defaultExecDeps){this.execDeps=execDeps}ctxFor(repoKey){let basePath=this.execDeps.remoteBasePath(repoKey);return basePath?{exec:this.execDeps.execForRepo(repoKey),dir:basePath,remote:!0}:{exec:this.execDeps.execForRepo(repoKey),dir:repoKey,remote:!1}}async runGit(exec,args,opts){if(!opts.cwd)throw Error("runGit(): cwd is required; refusing to inherit from process.cwd()");let env=opts.readOnly?{...opts.env,...READ_ONLY_GIT_ENV}:opts.env,r=await exec.run(["git",...args],{cwd:opts.cwd,env}),result={stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode};if(result.exitCode!==0&&!opts.allowFail)throw new GitCommandError(args,opts.cwd,result);return result}async create(repo,branch,worktreePath,baseRef){let ctx=this.ctxFor(repo);if(requireAbsolute("repo",ctx.dir),requireAbsolute("path",worktreePath),!branch)throw Error("create(): branch must be a non-empty string");if(await ctx.exec.exists(worktreePath)){let existing=await this.tryDescribe(ctx,worktreePath);if(existing){if(existing.branch!==branch)throw Error(`worktree at ${worktreePath} is on branch '${existing.branch}', refusing to hijack to '${branch}'`);return existing}throw Error(`create(): ${worktreePath} exists but is not a registered git worktree`)}await ctx.exec.mkdirp(path3.dirname(worktreePath));let args=await branchExists(this.branchDeps(),ctx,branch)?["worktree","add",worktreePath,branch]:baseRef?["worktree","add","-b",branch,worktreePath,baseRef]:["worktree","add","-b",branch,worktreePath];await this.runGit(ctx.exec,args,{cwd:ctx.dir});let info=await this.tryDescribe(ctx,worktreePath);if(!info)throw Error(`create(): git reported success but ${worktreePath} is not a worktree`);if(info.branch!==branch)throw Error(`create(): post-condition failed \u2014 expected branch '${branch}' at ${worktreePath}, got '${info.branch}'`);return info}async createForTask(args){let basePath=this.execDeps.remoteBasePath(args.repo),target=basePath?remoteWorktreePathFor(basePath,args.slug):worktreePathFor(args.repo,args.slug);return this.create(args.repo,args.branch,target,args.baseRef)}async remove(worktreePath,opts){await removeWorktree({runGit:(exec,args,runOpts)=>this.runGit(exec,args,runOpts),execForPath:(p)=>this.execDeps.execForPath(p),findRepoFor:(exec,p)=>this.findRepoFor(exec,p),currentBranch:(p)=>this.currentBranch(p),isDirty:(p)=>this.isDirty(p),ignoredWork:(p)=>this.ignoredWork(p),branchDeps:()=>this.branchDeps()},worktreePath,opts)}async deleteBranch(repo,branch,opts){let ctx=this.ctxFor(repo);requireAbsolute("repo",ctx.dir),await deleteBranchAnchored(this.branchDeps(),ctx.exec,ctx.dir,branch,{force:opts?.force===!0,onAnchor:opts?.onAnchor})}execAt(worktreePath){return requireAbsolute("path",worktreePath),this.execDeps.execForPath(worktreePath)}branchDeps(){return{runGit:(exec,args,opts)=>this.runGit(exec,args,opts),execAt:(worktreePath)=>this.execAt(worktreePath),findRepoFor:(exec,worktreePath)=>this.findRepoFor(exec,worktreePath)}}listDeps(){return{ctxFor:(repoKey)=>this.ctxFor(repoKey),runGitStdout:async(ctx,args)=>(await this.runGit(ctx.exec,args,{cwd:ctx.dir,readOnly:!0})).stdout,runGitStdoutAt:async(ctx,cwd,args)=>(await this.runGit(ctx.exec,args,{cwd,readOnly:!0})).stdout,isDirty:(worktreePath)=>this.isDirty(worktreePath)}}list(repo){return listManaged(this.listDeps(),repo)}listAll(repo){return listAllAdoptable(this.listDeps(),repo)}listAdoptablePaths(repo){return adoptablePaths(this.listDeps(),this.ctxFor(repo))}listUnreadableWorktrees(repo){return unreadableWorktreeNames(this.listDeps(),this.ctxFor(repo))}listBranchNames(repo){return listBranchNames(this.listDeps(),repo)}async pathExists(worktreePath){return this.execAt(worktreePath).exists(worktreePath)}async pruneWorktrees(repo){let ctx=this.ctxFor(repo);requireAbsolute("repo",ctx.dir),await this.runGit(ctx.exec,["worktree","prune"],{cwd:ctx.dir,allowFail:!0})}async isDirty(worktreePath){return(await this.runGit(this.execAt(worktreePath),["status","--porcelain"],{cwd:worktreePath,readOnly:!0})).stdout.length>0}async ignoredWork(worktreePath){return smallIgnoredPaths(this.execAt(worktreePath),worktreePath)}async currentBranch(worktreePath){let name=(await this.runGit(this.execAt(worktreePath),["rev-parse","--abbrev-ref","HEAD"],{cwd:worktreePath,readOnly:!0})).stdout.trim();if(!name||name==="HEAD")throw Error(`currentBranch(): ${worktreePath} is in detached-HEAD state`);return name}branchHasUpstream(worktreePath,branch){return branchHasUpstream(this.branchDeps(),worktreePath,branch)}hasLocalBranch(worktreePath,branch){return hasLocalBranch(this.branchDeps(),worktreePath,branch)}renameBranch(worktreePath,from,to){return renameBranch(this.branchDeps(),worktreePath,from,to)}async tryDescribe(ctx,worktreePath){let out=await this.runGit(ctx.exec,["worktree","list","--porcelain"],{cwd:ctx.dir,readOnly:!0}),entries=parseWorktreeListPorcelain(out.stdout),norm=(p)=>ctx.remote?p:canonicalize(p),target=norm(worktreePath),match=entries.find((e)=>e.path&&norm(e.path)===target);if(!match||!match.path||!match.branch||match.detached)return null;return{path:worktreePath,branch:match.branch,head:match.head??"",dirty:await this.isDirty(match.path)}}async findRepoFor(exec,worktreePath){try{let out=await this.runGit(exec,["rev-parse","--git-common-dir"],{cwd:worktreePath,allowFail:!0,readOnly:!0});if(out.exitCode!==0)return null;let gitDir=out.stdout.trim();if(!gitDir)return null;let absolute=path3.isAbsolute(gitDir)?gitDir:path3.resolve(worktreePath,gitDir);return path3.basename(absolute)===".git"?path3.dirname(absolute):absolute}catch(err){if(err instanceof GitCommandError)return null;throw err}}}
9
+ export{defaultExecDeps,GitWorktreeManager};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{loadPluginRegistry,readPluginManifest}from"./chunk-d393z1mj.js";import{CONTRIB_ENGINE_IDS,clearPluginEngines,registerPluginEngine,resetAvailableVendorsCache}from"./chunk-n4dmwkfa.js";import{getCustomEngineIds}from"./chunk-87y9qjcm.js";function loadPluginEngines(homeDir){let registered=[];try{for(let entry of loadPluginRegistry(homeDir).plugins){if(!entry.enabled)continue;try{let{manifest}=readPluginManifest(entry.root);for(let engine of manifest.engines){let identity={vendorId:engine.id,shortName:engine.identity?.shortName??engine.name};if(registerPluginEngine(engine.id,{displayName:engine.name,defaultCommand:engine.command,...engine.processNames?{processNames:engine.processNames}:{},screenManifest:{rules:engine.rules},identity,...engine.firstMessageDelivery?{firstMessageDelivery:engine.firstMessageDelivery}:{}}))registered.push(engine.id);else console.warn(`[rove] plugin ${entry.id}: engine id \`${engine.id}\` shadows a built-in or shipped engine \u2014 skipped`)}}catch{}}}catch{}return registered}function reloadPluginEngines(homeDir){clearPluginEngines();let registered=loadPluginEngines(homeDir);return loadedOnce=registered,resetAvailableVendorsCache(),registered}var loadedOnce;function ensurePluginEnginesLoaded(){return loadedOnce??=loadPluginEngines(),loadedOnce}function registeredEngineIds(){return[...new Set([...CONTRIB_ENGINE_IDS,...getCustomEngineIds(),...ensurePluginEnginesLoaded()])]}
3
+ export{loadPluginEngines,reloadPluginEngines,ensurePluginEnginesLoaded,registeredEngineIds};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{randomBytes}from"crypto";import{linkSync,mkdirSync,readFileSync,unlinkSync,writeFileSync}from"fs";import{link,mkdir,readFile,unlink,writeFile}from"fs/promises";import{dirname}from"path";function isProcessAlive(pid){if(!Number.isInteger(pid)||pid<=0)return!1;try{return process.kill(pid,0),!0}catch(err){if(err.code==="ESRCH")return!1;return!0}}class LockfileError extends Error{heldByPid;constructor(message,heldByPid){super(message);this.name="LockfileError",this.heldByPid=heldByPid}}async function acquire(lockPath,opts={}){await mkdir(dirname(lockPath),{recursive:!0});let token=`${process.pid}:${randomBytes(8).toString("hex")}`,sidecar=`${lockPath}.${token.replace(":","-")}`;for(;;){await writeFile(sidecar,token);try{return await link(sidecar,lockPath),token}catch(err){if(err.code!=="EEXIST")throw err}finally{await unlink(sidecar).catch(()=>{})}let holder;try{holder=(await readFile(lockPath,"utf8")).trim()}catch(err){if(err.code!=="ENOENT")throw err;continue}let holderPid=Number.parseInt(holder,10),alive=Number.isFinite(holderPid)&&holderPid>0&&isProcessAlive(holderPid);if(alive&&!opts.forceTakeover)throw new LockfileError(`task index is locked by another Rove instance (pid ${holderPid})`,holderPid);console.warn(`[rove] removing stale lockfile at ${lockPath} (was held by pid ${holderPid}${alive?", forced":", process gone"})`),releaseSync(lockPath,holder)}}async function release(lockPath,token){let current;try{current=(await readFile(lockPath,"utf8")).trim()}catch(err){if(err.code==="ENOENT")return;throw err}if(current!==token)return;try{await unlink(lockPath)}catch(err){if(err.code==="ENOENT")return;throw err}}function sleepSync(ms){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,ms)}function acquireSync(lockPath,timeoutMs=5000){mkdirSync(dirname(lockPath),{recursive:!0});let token=`${process.pid}:${randomBytes(8).toString("hex")}`,sidecar=`${lockPath}.${token.replace(":","-")}`,deadline=Date.now()+timeoutMs;for(;;){writeFileSync(sidecar,token);try{return linkSync(sidecar,lockPath),token}catch(err){if(err.code!=="EEXIST")throw err}finally{try{unlinkSync(sidecar)}catch{}}let holder;try{holder=readFileSync(lockPath,"utf8").trim()}catch(err){if(err.code!=="ENOENT")throw err;continue}let holderPid=Number.parseInt(holder,10);if(Number.isFinite(holderPid)&&holderPid>0&&isProcessAlive(holderPid)){if(Date.now()>=deadline)throw new LockfileError(`${lockPath} is locked by another Rove instance (pid ${holderPid})`,holderPid);sleepSync(25);continue}console.warn(`[rove] removing stale lockfile at ${lockPath} (was held by pid ${holderPid}, process gone)`),releaseSync(lockPath,holder)}}function releaseSync(lockPath,token){try{if(readFileSync(lockPath,"utf8").trim()!==token)return;unlinkSync(lockPath)}catch(err){if(err.code!=="ENOENT")throw err}}
3
+ export{isProcessAlive,LockfileError,acquire,release,acquireSync,releaseSync};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{loadPluginRegistry,pluginConfigDir,pluginDataDir,pluginLogPath,pluginRegistryPath,pluginStateDir,pluginsRootDir}from"./chunk-jyv82gf0.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE}from"./chunk-4wwx51m5.js";import{chmodSync}from"fs";function tighten(path,mode){try{chmodSync(path,mode)}catch{}}function tightenPluginPermissions(id,homeDir){tighten(pluginDataDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginConfigDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginStateDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(`${pluginConfigDir(id,homeDir)}/.env`,OWNER_ONLY_FILE_MODE),tighten(pluginLogPath(id,homeDir),OWNER_ONLY_FILE_MODE)}function tightenInstalledPluginPermissions(homeDir){tighten(pluginsRootDir(homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginRegistryPath(homeDir),OWNER_ONLY_FILE_MODE);for(let entry of loadPluginRegistry(homeDir).plugins)tightenPluginPermissions(entry.id,homeDir)}var MONTH_NAMES=new Map([["JAN",1],["FEB",2],["MAR",3],["APR",4],["MAY",5],["JUN",6],["JUL",7],["AUG",8],["SEP",9],["OCT",10],["NOV",11],["DEC",12]]),DAY_NAMES=new Map([["SUN",0],["MON",1],["TUE",2],["WED",3],["THU",4],["FRI",5],["SAT",6]]);function fieldNumber(raw,names,field){let token=raw.toUpperCase(),named=names?.get(token);if(named!==void 0)return named;if(!/^\d+$/.test(token))throw Error(`invalid cron ${field}: ${raw}`);return Number(token)}function parseField(args){let out=new Set;for(let part of args.value.split(",")){if(part.length===0)throw Error(`invalid cron ${args.field}: ${args.value}`);let[spec,stepRaw,...extra]=part.split("/");if(extra.length>0||spec===void 0)throw Error(`invalid cron ${args.field}: ${part}`);let step=1;if(stepRaw!==void 0){if(!/^\d+$/.test(stepRaw))throw Error(`invalid cron ${args.field} step: ${part}`);if(step=Number(stepRaw),step<1)throw Error(`invalid cron ${args.field} step: ${part}`)}let lo,hi;if(spec==="*")lo=args.min,hi=args.max;else if(spec.includes("-")){let[loRaw,hiRaw,...rest]=spec.split("-");if(rest.length>0||loRaw===void 0||hiRaw===void 0)throw Error(`invalid cron ${args.field} range: ${part}`);lo=fieldNumber(loRaw,args.names,args.field),hi=fieldNumber(hiRaw,args.names,args.field)}else lo=fieldNumber(spec,args.names,args.field),hi=stepRaw===void 0?lo:args.max;if(lo<args.min||hi>args.max||lo>hi)throw Error(`cron ${args.field} out of range: ${part}`);for(let v=lo;v<=hi;v+=step)out.add(args.normalize?args.normalize(v):v)}return out}function parseCron(expression){if(expression.length>256)throw Error("cron expression is too long");let fields=expression.trim().split(/\s+/).filter(Boolean);if(fields.length!==5)throw Error(`cron expression needs 5 fields (minute hour day month weekday), got ${fields.length}`);let[minute,hour,dayOfMonth,month,dayOfWeek]=fields;return{minutes:parseField({value:minute,min:0,max:59,field:"minute"}),hours:parseField({value:hour,min:0,max:23,field:"hour"}),daysOfMonth:parseField({value:dayOfMonth,min:1,max:31,field:"day-of-month"}),months:parseField({value:month,min:1,max:12,field:"month",names:MONTH_NAMES}),daysOfWeek:parseField({value:dayOfWeek,min:0,max:7,field:"weekday",names:DAY_NAMES,normalize:(v)=>v%7}),dayOfMonthRestricted:dayOfMonth!=="*",dayOfWeekRestricted:dayOfWeek!=="*"}}function isValidCron(expression){try{return parseCron(expression),!0}catch{return!1}}function instantOf(d,hour,minute){return new Date(d.year,d.month-1,d.day,hour,minute,0,0).getTime()}function localDayOf(ms){let d=new Date(ms);return{year:d.getFullYear(),month:d.getMonth()+1,day:d.getDate()}}function shiftDay(d,delta){return localDayOf(new Date(d.year,d.month-1,d.day+delta,12,0,0,0).getTime())}function dayMatches(rule,d){if(!rule.months.has(d.month))return!1;let domMatch=rule.daysOfMonth.has(d.day),dowMatch=rule.daysOfWeek.has(new Date(d.year,d.month-1,d.day).getDay());if(rule.dayOfMonthRestricted&&rule.dayOfWeekRestricted)return domMatch||dowMatch;if(rule.dayOfMonthRestricted)return domMatch;if(rule.dayOfWeekRestricted)return dowMatch;return!0}function floorToMinute(ms){return ms-ms%60000}function sorted(values,direction){return[...values].sort((a,b)=>(a-b)*direction)}function nextCronAfter(expression,afterMs){let rule=parseCron(expression),hours=sorted(rule.hours,1),minutes=sorted(rule.minutes,1),from=new Date(floorToMinute(afterMs)+60000),day=localDayOf(from.getTime()),fromHour=from.getHours(),fromMinute=from.getMinutes();for(let i=0;i<3294;i++){if(dayMatches(rule,day))for(let hour of hours){if(hour<fromHour)continue;for(let minute of minutes){if(hour===fromHour&&minute<fromMinute)continue;let at=instantOf(day,hour,minute);if(at>afterMs)return at}}day=shiftDay(day,1),fromHour=0,fromMinute=0}throw Error(`cron expression never matches: ${expression}`)}function latestCronAtOrBefore(expression,nowMs,notBeforeMs){if(nowMs<notBeforeMs)return null;let rule=parseCron(expression),hours=sorted(rule.hours,-1),minutes=sorted(rule.minutes,-1),from=new Date(floorToMinute(nowMs)),day=localDayOf(from.getTime()),fromHour=from.getHours(),fromMinute=from.getMinutes();for(let i=0;i<3294;i++){if(instantOf(day,23,59)<notBeforeMs)return null;if(dayMatches(rule,day))for(let hour of hours){if(hour>fromHour)continue;for(let minute of minutes){if(hour===fromHour&&minute>fromMinute)continue;let at=instantOf(day,hour,minute);if(at>nowMs)continue;return at>=notBeforeMs?at:null}}day=shiftDay(day,-1),fromHour=23,fromMinute=59}return null}function countCronBetween(expression,fromMs,beforeMs,cap=500){if(!(fromMs<beforeMs))return 0;let count=0,cursor=fromMs-1;while(count<cap){let at;try{at=nextCronAfter(expression,cursor)}catch{return count}if(at>=beforeMs)return count;count+=1,cursor=at}return count}
2
+ import{loadPluginRegistry,pluginConfigDir,pluginDataDir,pluginLogPath,pluginRegistryPath,pluginStateDir,pluginsRootDir}from"./chunk-d393z1mj.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE}from"./chunk-4wwx51m5.js";import{chmodSync}from"fs";function tighten(path,mode){try{chmodSync(path,mode)}catch{}}function tightenPluginPermissions(id,homeDir){tighten(pluginDataDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginConfigDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginStateDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(`${pluginConfigDir(id,homeDir)}/.env`,OWNER_ONLY_FILE_MODE),tighten(pluginLogPath(id,homeDir),OWNER_ONLY_FILE_MODE)}function tightenInstalledPluginPermissions(homeDir){tighten(pluginsRootDir(homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginRegistryPath(homeDir),OWNER_ONLY_FILE_MODE);for(let entry of loadPluginRegistry(homeDir).plugins)tightenPluginPermissions(entry.id,homeDir)}var MONTH_NAMES=new Map([["JAN",1],["FEB",2],["MAR",3],["APR",4],["MAY",5],["JUN",6],["JUL",7],["AUG",8],["SEP",9],["OCT",10],["NOV",11],["DEC",12]]),DAY_NAMES=new Map([["SUN",0],["MON",1],["TUE",2],["WED",3],["THU",4],["FRI",5],["SAT",6]]);function fieldNumber(raw,names,field){let token=raw.toUpperCase(),named=names?.get(token);if(named!==void 0)return named;if(!/^\d+$/.test(token))throw Error(`invalid cron ${field}: ${raw}`);return Number(token)}function parseField(args){let out=new Set;for(let part of args.value.split(",")){if(part.length===0)throw Error(`invalid cron ${args.field}: ${args.value}`);let[spec,stepRaw,...extra]=part.split("/");if(extra.length>0||spec===void 0)throw Error(`invalid cron ${args.field}: ${part}`);let step=1;if(stepRaw!==void 0){if(!/^\d+$/.test(stepRaw))throw Error(`invalid cron ${args.field} step: ${part}`);if(step=Number(stepRaw),step<1)throw Error(`invalid cron ${args.field} step: ${part}`)}let lo,hi;if(spec==="*")lo=args.min,hi=args.max;else if(spec.includes("-")){let[loRaw,hiRaw,...rest]=spec.split("-");if(rest.length>0||loRaw===void 0||hiRaw===void 0)throw Error(`invalid cron ${args.field} range: ${part}`);lo=fieldNumber(loRaw,args.names,args.field),hi=fieldNumber(hiRaw,args.names,args.field)}else lo=fieldNumber(spec,args.names,args.field),hi=stepRaw===void 0?lo:args.max;if(lo<args.min||hi>args.max||lo>hi)throw Error(`cron ${args.field} out of range: ${part}`);for(let v=lo;v<=hi;v+=step)out.add(args.normalize?args.normalize(v):v)}return out}function parseCron(expression){if(expression.length>256)throw Error("cron expression is too long");let fields=expression.trim().split(/\s+/).filter(Boolean);if(fields.length!==5)throw Error(`cron expression needs 5 fields (minute hour day month weekday), got ${fields.length}`);let[minute,hour,dayOfMonth,month,dayOfWeek]=fields;return{minutes:parseField({value:minute,min:0,max:59,field:"minute"}),hours:parseField({value:hour,min:0,max:23,field:"hour"}),daysOfMonth:parseField({value:dayOfMonth,min:1,max:31,field:"day-of-month"}),months:parseField({value:month,min:1,max:12,field:"month",names:MONTH_NAMES}),daysOfWeek:parseField({value:dayOfWeek,min:0,max:7,field:"weekday",names:DAY_NAMES,normalize:(v)=>v%7}),dayOfMonthRestricted:dayOfMonth!=="*",dayOfWeekRestricted:dayOfWeek!=="*"}}function isValidCron(expression){try{return parseCron(expression),!0}catch{return!1}}function instantOf(d,hour,minute){return new Date(d.year,d.month-1,d.day,hour,minute,0,0).getTime()}function localDayOf(ms){let d=new Date(ms);return{year:d.getFullYear(),month:d.getMonth()+1,day:d.getDate()}}function shiftDay(d,delta){return localDayOf(new Date(d.year,d.month-1,d.day+delta,12,0,0,0).getTime())}function dayMatches(rule,d){if(!rule.months.has(d.month))return!1;let domMatch=rule.daysOfMonth.has(d.day),dowMatch=rule.daysOfWeek.has(new Date(d.year,d.month-1,d.day).getDay());if(rule.dayOfMonthRestricted&&rule.dayOfWeekRestricted)return domMatch||dowMatch;if(rule.dayOfMonthRestricted)return domMatch;if(rule.dayOfWeekRestricted)return dowMatch;return!0}function floorToMinute(ms){return ms-ms%60000}function sorted(values,direction){return[...values].sort((a,b)=>(a-b)*direction)}function nextCronAfter(expression,afterMs){let rule=parseCron(expression),hours=sorted(rule.hours,1),minutes=sorted(rule.minutes,1),from=new Date(floorToMinute(afterMs)+60000),day=localDayOf(from.getTime()),fromHour=from.getHours(),fromMinute=from.getMinutes();for(let i=0;i<3294;i++){if(dayMatches(rule,day))for(let hour of hours){if(hour<fromHour)continue;for(let minute of minutes){if(hour===fromHour&&minute<fromMinute)continue;let at=instantOf(day,hour,minute);if(at>afterMs)return at}}day=shiftDay(day,1),fromHour=0,fromMinute=0}throw Error(`cron expression never matches: ${expression}`)}function latestCronAtOrBefore(expression,nowMs,notBeforeMs){if(nowMs<notBeforeMs)return null;let rule=parseCron(expression),hours=sorted(rule.hours,-1),minutes=sorted(rule.minutes,-1),from=new Date(floorToMinute(nowMs)),day=localDayOf(from.getTime()),fromHour=from.getHours(),fromMinute=from.getMinutes();for(let i=0;i<3294;i++){if(instantOf(day,23,59)<notBeforeMs)return null;if(dayMatches(rule,day))for(let hour of hours){if(hour>fromHour)continue;for(let minute of minutes){if(hour===fromHour&&minute>fromMinute)continue;let at=instantOf(day,hour,minute);if(at>nowMs)continue;return at>=notBeforeMs?at:null}}day=shiftDay(day,-1),fromHour=23,fromMinute=59}return null}function countCronBetween(expression,fromMs,beforeMs,cap=500){if(!(fromMs<beforeMs))return 0;let count=0,cursor=fromMs-1;while(count<cap){let at;try{at=nextCronAfter(expression,cursor)}catch{return count}if(at>=beforeMs)return count;count+=1,cursor=at}return count}
3
3
  export{tightenPluginPermissions,tightenInstalledPluginPermissions,isValidCron,nextCronAfter,latestCronAtOrBefore,countCronBetween};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{canonicalize}from"./chunk-2cyzv75r.js";import{applyJitter,exponentialBackoff}from"./chunk-gwcneg6c.js";import{getRemoteRepoConfig,isRemoteRepoKey,resolveRepoRoot}from"./chunk-87y9qjcm.js";var canonPath=canonicalize;function randomDirTaskSuffix(){return Math.random().toString(36).slice(2,6).padEnd(4,"0")}function titleFromRepo(repo){let segs=repo.split(/[/\\]/).filter(Boolean);return segs.length>0?segs[segs.length-1]??repo:repo}function normalizeMainRepo(repo){let normalized=resolveRepoRoot(repo);return{repo:normalized,key:isRemoteRepoKey(normalized)?normalized:canonPath(normalized)}}function repoWorkingDir(repo){return getRemoteRepoConfig(repo)?.basePath??repo}var GH_PR_VIEW_FIELDS="number,url,title,state,baseRefName,headRefName,reviewDecision,mergeable,statusCheckRollup";function lifecycleFromState(state,reviewDecision){switch((state??"").toUpperCase()){case"MERGED":return"merged";case"CLOSED":return"closed";case"OPEN":return(reviewDecision??"").toUpperCase()==="APPROVED"?"ready_to_merge":"open";default:return"unknown"}}function entryCheckState(entry){let status=(entry.status??"").toUpperCase(),conclusion=(entry.conclusion??"").toUpperCase(),contextState=(entry.state??"").toUpperCase();if(status&&status!=="COMPLETED")return"pending";if(conclusion){if(conclusion==="SUCCESS"||conclusion==="NEUTRAL"||conclusion==="SKIPPED")return"passing";return"failing"}if(contextState==="SUCCESS")return"passing";if(contextState==="PENDING"||contextState==="EXPECTED")return"pending";if(contextState==="FAILURE"||contextState==="ERROR")return"failing";return"unknown"}function checkStateFromRollup(rollup){if(!rollup||rollup.length===0)return"none";let sawPending=!1,sawPassing=!1;for(let entry of rollup){let s=entryCheckState(entry);if(s==="failing")return"failing";if(s==="pending")sawPending=!0;else if(s==="passing")sawPassing=!0}if(sawPending)return"pending";if(sawPassing)return"passing";return"unknown"}function mapGhPrView(view,at){if(!view||typeof view.number!=="number")return null;return{provider:"github",lifecycle:lifecycleFromState(view.state,view.reviewDecision),checkState:checkStateFromRollup(view.statusCheckRollup),number:view.number,url:view.url,title:view.title,baseRef:view.baseRefName,headRef:view.headRefName,reviewDecision:view.reviewDecision||void 0,mergeable:view.mergeable||void 0,lastCheckedAt:at}}function samePrStatus(a,b){if(a===b)return!0;if(!a||!b)return!1;return a.provider===b.provider&&a.lifecycle===b.lifecycle&&a.checkState===b.checkState&&a.number===b.number&&a.url===b.url&&a.title===b.title&&a.baseRef===b.baseRef&&a.headRef===b.headRef&&a.reviewDecision===b.reviewDecision&&a.mergeable===b.mergeable}var NO_REMOTE_PATTERNS=["none of the git remotes","no git remote","to use github cli in a github repository","not a github repository"],AUTH_PATTERNS=["gh auth login","authentication required","not logged in","http 401","bad credentials","requires authentication"],NETWORK_PATTERNS=["could not resolve host","no such host","dial tcp","connection refused","connection reset","network is unreachable","i/o timeout","timeout","tls handshake","http 5","rate limit","try again"];function matchesAny(haystack,needles){return needles.some((n)=>haystack.includes(n))}function classifyGhFailure(s){if(s.parseError)return{kind:"error",error:"parse"};if(s.timedOut)return{kind:"error",error:"timeout"};if(s.spawnError)return{kind:"error",error:"missing-binary"};let err=(s.stderr??"").toLowerCase();if(matchesAny(err,NO_REMOTE_PATTERNS))return{kind:"error",error:"no-remote"};if(matchesAny(err,AUTH_PATTERNS))return{kind:"error",error:"auth"};if(matchesAny(err,NETWORK_PATTERNS))return{kind:"error",error:"network"};return{kind:"error",error:"unknown"}}function nextPrPoll(outcome,prevFailures,now,cfg,rand=Math.random){let at=(delay)=>now+applyJitter(delay,cfg.jitterRatio,rand);if(outcome.kind==="pr")return{nextAllowedAt:at(outcome.settled?cfg.settledMs:cfg.tickMs),failures:0};if(outcome.kind==="empty")return{nextAllowedAt:at(cfg.noPrMs),failures:0};if(outcome.error==="no-remote")return{nextAllowedAt:at(cfg.noRemoteMs),failures:0};let failures=prevFailures+1;return{nextAllowedAt:at(exponentialBackoff(cfg.failureBaseMs,failures-1,cfg.failureCapMs)),failures}}function checkResolutionNotify(prev,next){if(prev!=="pending")return null;if(next==="passing"||next==="failing")return next;return null}
3
+ export{GH_PR_VIEW_FIELDS,mapGhPrView,samePrStatus,classifyGhFailure,nextPrPoll,checkResolutionNotify,canonPath,randomDirTaskSuffix,titleFromRepo,normalizeMainRepo,repoWorkingDir};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{getGlobalDefaultVendor,getRepoLastActiveVendor,resolvePreferredVendor,setGlobalDefaultVendor,setRepoLastActiveVendor}from"./chunk-6sp2ags8.js";import"./chunk-87y9qjcm.js";import"./chunk-m57cv76y.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-9c1e5z6a.js";import"./chunk-6dn6h640.js";import"./chunk-h82kzdsn.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{setRepoLastActiveVendor,setGlobalDefaultVendor,resolvePreferredVendor,getRepoLastActiveVendor,getGlobalDefaultVendor};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{ensurePluginEnginesLoaded,loadPluginEngines,registeredEngineIds,reloadPluginEngines}from"./chunk-9nbg0nzh.js";import"./chunk-d393z1mj.js";import"./chunk-kwe61yx7.js";import"./chunk-n4dmwkfa.js";import"./chunk-w7zv47mp.js";import"./chunk-7jkf3tvr.js";import"./chunk-87y9qjcm.js";import"./chunk-m57cv76y.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import"./chunk-6dn6h640.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{reloadPluginEngines,registeredEngineIds,loadPluginEngines,ensurePluginEnginesLoaded};
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{PLUGIN_EVENT_NAMES}from"./chunk-kwe61yx7.js";import{parse}from"./chunk-w7zv47mp.js";import{COMPAT_STATE_DIR_BASENAME,ROVE_STATE_DIR_BASENAME,readRoveHomeDirEnv}from"./chunk-3bfm4hrs.js";import{existsSync,readFileSync}from"fs";import{basename,join}from"path";var PLUGIN_PLATFORMS=["macos","linux","windows"];class ManifestError extends Error{}function fail(message){throw new ManifestError(`rove-plugin.toml: ${message}`)}function asString(value,field){if(typeof value!=="string"||value.length===0)fail(`\`${field}\` must be a non-empty string`);return value}function asSettingDefault(value,field){if(value===void 0||value===!1)return;if(value===!0)return"1";if(typeof value==="number"&&Number.isFinite(value))return String(value);return asString(value,field)}var TIMEOUT_MIN_MS=100,TIMEOUT_MAX_MS=600000;function asTimeoutMs(value,field){if(value===void 0)return;if(typeof value!=="number"||!Number.isInteger(value)||value<TIMEOUT_MIN_MS||value>TIMEOUT_MAX_MS)fail(`\`${field}\` must be a whole number of milliseconds between ${TIMEOUT_MIN_MS} and ${TIMEOUT_MAX_MS}`);return value}function asCommand(value,field){if(!Array.isArray(value)||value.length===0||!value.every((v)=>typeof v==="string"&&v.length>0))fail(`\`${field}\` must be a non-empty array of strings (argv form)`);return value}function asPlatforms(value,field){if(value===void 0)return;if(!Array.isArray(value)||!value.every((v)=>PLUGIN_PLATFORMS.includes(v)))fail(`\`${field}\` must be an array drawn from ${PLUGIN_PLATFORMS.join(", ")}`);return value}function asTableArray(value,field){if(value===void 0)return[];if(!Array.isArray(value)||!value.every((v)=>typeof v==="object"&&v!==null&&!Array.isArray(v)))fail(`\`[[${field}]]\` must be an array of tables`);return value}function asStringArray(value,field){if(value===void 0)return;if(!Array.isArray(value)||!value.every((v)=>typeof v==="string"&&v.length>0))fail(`\`${field}\` must be a non-empty array of strings`);return value}var SETTING_KEY_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,RESERVED_SETTING_KEYS=["PATH","HOME","SHELL","IFS","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","NODE_OPTIONS","BUN_INSPECT","PYTHONPATH","PYTHONSTARTUP","PERL5OPT","PERL5LIB","RUBYOPT","BASH_ENV","ENV","GIT_SSH_COMMAND","GIT_SSH","GIT_EXTERNAL_DIFF","GIT_PAGER","PAGER","EDITOR","VISUAL"];function settingKeyRejection(key){if(!SETTING_KEY_RE.test(key))return`\`${key}\` is not a valid env var name (${SETTING_KEY_RE.source})`;if(RESERVED_SETTING_KEYS.includes(key))return`\`${key}\` is reserved; it steers how the plugin's own process runs`;return null}var PLUGIN_MANIFEST_FILENAME="rove-plugin.toml",LEGACY_PLUGIN_MANIFEST_FILENAME="kobe-plugin.toml",PLUGIN_MANIFEST_FILENAMES=[PLUGIN_MANIFEST_FILENAME,LEGACY_PLUGIN_MANIFEST_FILENAME],RESERVED_ENGINE_IDS=["claude","codex","copilot","kimi","gemini","opencode","cursor","grok","droid","amp"];function pluginManifestPath(root){for(let filename of PLUGIN_MANIFEST_FILENAMES){let path=join(root,filename);if(existsSync(path))return path}return null}function readPluginManifest(root){let path=pluginManifestPath(root);if(!path)throw new ManifestError(`no ${PLUGIN_MANIFEST_FILENAMES.join(" or ")} found at ${root}`);return parsePluginManifest(readFileSync(path,"utf8"),basename(path))}var PLUGIN_ID_RE=/^[A-Za-z0-9][A-Za-z0-9._:-]*$/,LOCAL_ID_RE=/^[A-Za-z0-9][A-Za-z0-9_:-]*$/;function qualifiedActionId(pluginId,actionId){return`${pluginId}.${actionId}`}function currentPluginPlatform(platform=process.platform){if(platform==="darwin")return"macos";if(platform==="linux")return"linux";if(platform==="win32")return"windows";return}function supportsPlatform(item,manifest,platform){let declared=item.platforms??manifest.platforms;if(!declared)return!0;return platform!==void 0&&declared.includes(platform)}function parsePluginManifest(text,filename=PLUGIN_MANIFEST_FILENAME){try{return parseCanonicalPluginManifest(text)}catch(err){if(filename!==PLUGIN_MANIFEST_FILENAME&&err instanceof ManifestError)throw new ManifestError(err.message.replace(/^rove-plugin\.toml:/,`${filename}:`));throw err}}function parseCanonicalPluginManifest(text){let raw;try{raw=parse(text)}catch(err){fail(`invalid TOML \u2014 ${err instanceof Error?err.message:String(err)}`)}let warnings=[],id=asString(raw.id,"id");if(!PLUGIN_ID_RE.test(id))fail(`plugin id \`${id}\` may use ASCII letters, digits, dot, colon, underscore, hyphen`);let name=asString(raw.name,"name"),version=asString(raw.version,"version"),rawMinVersion=raw.min_rove_version??raw.min_kobe_version,minKobeVersion=asString(rawMinVersion,"min_rove_version"),description=raw.description===void 0?void 0:asString(raw.description,"description"),platforms=asPlatforms(raw.platforms,"platforms");if(!platforms)warnings.push("no top-level `platforms` declared; assuming the plugin runs everywhere");if(raw.min_rove_version!==void 0&&raw.min_kobe_version!==void 0&&raw.min_rove_version!==raw.min_kobe_version)warnings.push("both `min_rove_version` and legacy `min_kobe_version` are set; using `min_rove_version`");let build=asTableArray(raw.build,"build").map((t,i)=>({command:asCommand(t.command,`build[${i}].command`),platforms:asPlatforms(t.platforms,`build[${i}].platforms`)})),startup=asTableArray(raw.startup,"startup").map((t,i)=>({command:asCommand(t.command,`startup[${i}].command`),platforms:asPlatforms(t.platforms,`startup[${i}].platforms`),timeoutMs:asTimeoutMs(t.timeout_ms,`startup[${i}].timeout_ms`)})),shutdown=asTableArray(raw.shutdown,"shutdown").map((t,i)=>({command:asCommand(t.command,`shutdown[${i}].command`),platforms:asPlatforms(t.platforms,`shutdown[${i}].platforms`),timeoutMs:asTimeoutMs(t.timeout_ms,`shutdown[${i}].timeout_ms`)})),actions=asTableArray(raw.actions,"actions").map((t,i)=>{let actionId=asString(t.id,`actions[${i}].id`);if(t.timeout_ms!==void 0)warnings.push(`actions[${i}] declares \`timeout_ms\`; actions are user-invoked and are never killed on a deadline`);if(!LOCAL_ID_RE.test(actionId))fail(`action id \`${actionId}\` may not contain dots`);return{id:actionId,title:asString(t.title,`actions[${i}].title`),command:asCommand(t.command,`actions[${i}].command`),platforms:asPlatforms(t.platforms,`actions[${i}].platforms`)}}),seen=new Set;for(let a of actions){if(seen.has(a.id))fail(`duplicate action id \`${a.id}\``);seen.add(a.id)}let panes=asTableArray(raw.panes,"panes").map((t,i)=>{let paneId=asString(t.id,`panes[${i}].id`);if(!LOCAL_ID_RE.test(paneId))fail(`pane id \`${paneId}\` may not contain dots`);if(t.timeout_ms!==void 0)warnings.push(`panes[${i}] declares \`timeout_ms\`; a pane is a terminal the user closes, not a bounded hook`);if(t.placement!==void 0&&t.placement!=="tab"&&t.placement!=="split")warnings.push(`pane \`${paneId}\` placement \`${String(t.placement)}\` is not supported yet; opening as a split`);return{id:paneId,title:asString(t.title,`panes[${i}].title`),placement:t.placement==="tab"?"tab":"split",command:asCommand(t.command,`panes[${i}].command`),platforms:asPlatforms(t.platforms,`panes[${i}].platforms`)}}),paneSeen=new Set;for(let p of panes){if(paneSeen.has(p.id))fail(`duplicate pane id \`${p.id}\``);paneSeen.add(p.id)}let events=asTableArray(raw.events,"events").flatMap((t,i)=>{let on=asString(t.on,`events[${i}].on`),hook={on,command:asCommand(t.command,`events[${i}].command`),platforms:asPlatforms(t.platforms,`events[${i}].platforms`),timeoutMs:asTimeoutMs(t.timeout_ms,`events[${i}].timeout_ms`)};if(!PLUGIN_EVENT_NAMES.includes(on))warnings.push(`unknown event \`${on}\`; this hook will never fire on this Rove version`);return[hook]}),settings=asTableArray(raw.settings,"settings").map((t,i)=>{let type=asString(t.type,`settings[${i}].type`);if(type!=="string"&&type!=="number"&&type!=="boolean"&&type!=="enum"&&type!=="secret")fail(`settings[${i}].type must be string | number | boolean | enum | secret`);let options=t.options===void 0?void 0:Array.isArray(t.options)&&t.options.every((o)=>typeof o==="string"&&o.length>0)?t.options:fail(`settings[${i}].options must be an array of strings`);if(type==="enum"&&(!options||options.length===0))fail(`settings[${i}] enum needs \`options\``);let settingDefault=asSettingDefault(t.default,`settings[${i}].default`),key=asString(t.key,`settings[${i}].key`),rejection=settingKeyRejection(key);if(rejection)fail(`settings[${i}].key ${rejection}`);return{key,label:asString(t.label,`settings[${i}].label`),type,...options?{options}:{},...settingDefault===void 0?{}:{default:settingDefault}}}),fileHandlers=asTableArray(raw.file_handlers,"file_handlers").map((t,i)=>{let pattern=asString(t.pattern,`file_handlers[${i}].pattern`);try{new RegExp(pattern)}catch{fail(`file_handlers[${i}].pattern is not a valid regex`)}let action=asString(t.action,`file_handlers[${i}].action`);if(!actions.some((a)=>a.id===action))fail(`file_handlers[${i}] names unknown action \`${action}\``);return{pattern,action}}),engines=asTableArray(raw.engines,"engines").map((t,i)=>{let engineId=asString(t.id,`engines[${i}].id`);if(!LOCAL_ID_RE.test(engineId))fail(`engine id \`${engineId}\` may not contain dots`);if(RESERVED_ENGINE_IDS.includes(engineId))fail(`engine id \`${engineId}\` shadows a built-in or shipped engine`);let rules=asTableArray(t.rules,`engines[${i}].rules`).map((r,j)=>{let state=asString(r.state,`engines[${i}].rules[${j}].state`);if(state!=="working"&&state!=="blocked"&&state!=="idle")fail(`engines[${i}].rules[${j}].state must be working | blocked | idle`);let lineRegex=asStringArray(r.line_regex,`engines[${i}].rules[${j}].line_regex`);for(let re of lineRegex??[])try{new RegExp(re)}catch{fail(`engines[${i}].rules[${j}].line_regex \`${re}\` is not a valid regex`)}let all=asStringArray(r.all,`engines[${i}].rules[${j}].all`),any=asStringArray(r.any,`engines[${i}].rules[${j}].any`);if(!all&&!any&&!lineRegex)fail(`engines[${i}].rules[${j}] needs at least one of all/any/line_regex`);return{state,...typeof r.bottom_lines==="number"?{bottomLines:r.bottom_lines}:{},...all?{all}:{},...any?{any}:{},...lineRegex?{lineRegex}:{}}}),identityRaw=t.identity,identity;if(identityRaw!==void 0){if(typeof identityRaw!=="object"||identityRaw===null||Array.isArray(identityRaw))fail(`engines[${i}].identity must be a table`);let idt=identityRaw,shortName=((key)=>idt[key]===void 0?void 0:asString(idt[key],`engines[${i}].identity.${key}`))("short_name");identity={...shortName!==void 0?{shortName}:{}}}let firstMessageDelivery;if(t.first_message_delivery!==void 0){let raw2=asString(t.first_message_delivery,`engines[${i}].first_message_delivery`);if(raw2!=="argv"&&raw2!=="paste")fail(`engines[${i}].first_message_delivery must be argv | paste`);firstMessageDelivery=raw2}return{id:engineId,name:asString(t.name,`engines[${i}].name`),command:asCommand(t.command,`engines[${i}].command`),...t.process_names===void 0?{}:{processNames:asCommand(t.process_names,`engines[${i}].process_names`)},rules,...identity?{identity}:{},...firstMessageDelivery?{firstMessageDelivery}:{}}}),engineSeen=new Set;for(let e of engines){if(engineSeen.has(e.id))fail(`duplicate engine id \`${e.id}\``);engineSeen.add(e.id)}return{manifest:{id,name,version,minKobeVersion,description,platforms,build,startup,shutdown,actions,events,panes,settings,fileHandlers,engines},warnings}}import{existsSync as existsSync2}from"fs";import{homedir}from"os";import{join as join2}from"path";function stateRoot(homeDir){let home=homeDir??readRoveHomeDirEnv()??homedir(),canonical=join2(home,ROVE_STATE_DIR_BASENAME);if(existsSync2(join2(canonical,"plugins.json")))return canonical;let legacy=join2(home,COMPAT_STATE_DIR_BASENAME);return existsSync2(join2(legacy,"plugins.json"))?legacy:canonical}function pluginRegistryPath(homeDir){return join2(stateRoot(homeDir),"plugins.json")}function pluginsRootDir(homeDir){return join2(stateRoot(homeDir),"plugins")}function legacyPluginsRootDir(homeDir){let home=homeDir??readRoveHomeDirEnv()??homedir();return join2(home,COMPAT_STATE_DIR_BASENAME,"plugins")}function pluginDataDir(id,homeDir){return join2(pluginsRootDir(homeDir),id)}function pluginCheckoutDir(id,homeDir){return join2(pluginDataDir(id,homeDir),"checkout")}function pluginConfigDir(id,homeDir){return join2(pluginDataDir(id,homeDir),"config")}function pluginStateDir(id,homeDir){return join2(pluginDataDir(id,homeDir),"state")}function pluginLogPath(id,homeDir){return join2(pluginDataDir(id,homeDir),"log.jsonl")}function pluginsOutdatedCachePath(homeDir){return join2(stateRoot(homeDir),"plugins-outdated.json")}import{mkdirSync,readFileSync as readFileSync2,writeFileSync}from"fs";import{dirname,join as join3,relative}from"path";var EMPTY={plugins:[]};function loadPluginRegistry(homeDir){let text;try{text=readFileSync2(pluginRegistryPath(homeDir),"utf8")}catch{return EMPTY}try{let raw=JSON.parse(text);if(!Array.isArray(raw.plugins))return EMPTY;return{plugins:raw.plugins.filter(isEntry).map((entry)=>withCanonicalRoot(entry,homeDir))}}catch{return EMPTY}}function withCanonicalRoot(entry,homeDir){if(entry.source.kind!=="github")return entry;let legacy=legacyPluginsRootDir(homeDir),canonical=pluginsRootDir(homeDir);if(legacy===canonical)return entry;let inside=relative(legacy,entry.root);if(inside===""||inside.startsWith("..")||inside.startsWith("/"))return entry;return{...entry,root:join3(canonical,inside)}}function isEntry(v){if(typeof v!=="object"||v===null)return!1;let e=v,source=e.source;return typeof e.id==="string"&&typeof e.root==="string"&&typeof e.enabled==="boolean"&&typeof e.version==="string"&&typeof e.installedAt==="number"&&typeof source==="object"&&source!==null&&(source.kind==="link"||source.kind==="github"&&typeof source.spec==="string")}function savePluginRegistry(registry,homeDir){let path=pluginRegistryPath(homeDir);mkdirSync(dirname(path),{recursive:!0}),writeFileSync(path,`${JSON.stringify(registry,null,2)}
3
+ `,{mode:384})}function upsertPluginEntry(registry,entry){return{plugins:[...registry.plugins.filter((p)=>p.id!==entry.id),entry]}}function removePluginEntry(registry,id){return{plugins:registry.plugins.filter((p)=>p.id!==id)}}
4
+ export{PLUGIN_MANIFEST_FILENAMES,pluginManifestPath,readPluginManifest,qualifiedActionId,currentPluginPlatform,supportsPlatform,parsePluginManifest,pluginRegistryPath,pluginsRootDir,pluginDataDir,pluginCheckoutDir,pluginConfigDir,pluginStateDir,pluginLogPath,pluginsOutdatedCachePath,loadPluginRegistry,savePluginRegistry,upsertPluginEntry,removePluginEntry};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{CURRENT_VERSION,repoSlug}from"./chunk-02y7hdy3.js";import{spawnSync}from"child_process";var DEFAULT_FEEDBACK_CATEGORY_SLUG="feedback",DISCUSSION_CATEGORY_QUERY=`
2
+ import{CURRENT_VERSION,repoSlug}from"./chunk-gtkejmxx.js";import{spawnSync}from"child_process";var DEFAULT_FEEDBACK_CATEGORY_SLUG="feedback",DISCUSSION_CATEGORY_QUERY=`
3
3
  query($owner: String!, $name: String!) {
4
4
  repository(owner: $owner, name: $name) {
5
5
  id
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{toTaskId}from"./chunk-xy8be792.js";import{LockfileError,acquire}from"./chunk-a3a9gdc4.js";import{coerceVendorId}from"./chunk-h82kzdsn.js";import{DAEMON_MIGRATION_MARKER}from"./chunk-8ddjfc2v.js";import{logClient}from"./chunk-grh6dvfv.js";import{defaultClientLogPath}from"./chunk-x760j10f.js";import{existsSync}from"fs";import{copyFile,readFile}from"fs/promises";import{dirname,join}from"path";function coerceTask(value){if(!value||typeof value!=="object")return null;let v=value;if(typeof v.id!=="string"||typeof v.title!=="string"||typeof v.repo!=="string"||typeof v.branch!=="string"||typeof v.worktreePath!=="string"||typeof v.status!=="string"||typeof v.createdAt!=="string"||typeof v.updatedAt!=="string")return null;if(!isTaskStatus(v.status))return null;let kind=v.kind==="main"?"main":v.kind==="dir"?"dir":"task",scratch=kind==="dir"&&v.scratch===!0,healedStatus=kind==="main"&&(v.status==="in_progress"||v.status==="done")?"backlog":v.status,deletion=coerceDeletion(v.deletion),quotaResume=coerceQuotaResume(v.quotaResume),linkedWorkItem=coerceLinkedWorkItem(v.linkedWorkItem),dispatcher=coerceDispatcher(v.dispatcher),routine=coerceRoutine(v.routine);return{id:toTaskId(v.id),title:v.title,repo:v.repo,branch:v.branch,worktreePath:v.worktreePath,status:healedStatus,pinned:typeof v.pinned==="boolean"?v.pinned:!1,kind,...scratch?{scratch:!0}:{},...routine?{routine}:{},vendor:coerceVendorId(typeof v.vendor==="string"?v.vendor:void 0),...typeof v.command==="string"&&v.command.trim().length>0?{command:v.command}:{},prStatus:coercePRStatus(v.prStatus),...typeof v.modelEffort==="string"&&v.modelEffort.length>0?{modelEffort:v.modelEffort}:{},...typeof v.groupId==="string"&&v.groupId.length>0?{groupId:v.groupId}:{},...v.observedLanguage==="zh"||v.observedLanguage==="en"?{observedLanguage:v.observedLanguage}:{},...deletion?{deletion}:{},...quotaResume?{quotaResume}:{},...linkedWorkItem?{linkedWorkItem}:{},...dispatcher?{dispatcher}:{},...typeof v.prompt==="string"&&v.prompt.length>0?{prompt:v.prompt}:{},...typeof v.baseRef==="string"&&v.baseRef.trim().length>0?{baseRef:v.baseRef}:{},createdAt:v.createdAt,updatedAt:v.updatedAt}}function coerceDispatcher(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(typeof v.taskId!=="string"||v.taskId.length===0)return;if(typeof v.tabId!=="string"||v.tabId.length===0)return;return{taskId:v.taskId,tabId:v.tabId}}function coerceRoutine(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(typeof v.automationId!=="string"||v.automationId.length===0)return;return{automationId:v.automationId}}function coerceQuotaResume(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(typeof v.resumeAt!=="string"||v.resumeAt.length===0)return;if(typeof v.requestedAt!=="string"||v.requestedAt.length===0)return;return{resumeAt:v.resumeAt,requestedAt:v.requestedAt}}function coerceLinkedWorkItem(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(v.provider!=="github")return;if(v.type!=="issue"&&v.type!=="pr")return;if(typeof v.number!=="number"||!Number.isFinite(v.number))return;if(typeof v.title!=="string"||typeof v.url!=="string"||v.url.length===0)return;return{provider:v.provider,type:v.type,number:v.number,title:v.title,url:v.url}}function coerceDeletion(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(v.phase!=="queued"&&v.phase!=="running"&&v.phase!=="error"||typeof v.force!=="boolean"||typeof v.requestedAt!=="string"||v.requestedAt.length===0||v.error!==void 0&&typeof v.error!=="string")return;return{phase:v.phase,force:v.force,...typeof v.deleteBranch==="boolean"?{deleteBranch:v.deleteBranch}:{},requestedAt:v.requestedAt,...typeof v.error==="string"?{error:v.error}:{}}}function coercePRStatus(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(!isPRProviderId(v.provider)||!isPRLifecycleState(v.lifecycle)||!isPRCheckState(v.checkState))return;return{provider:v.provider,lifecycle:v.lifecycle,checkState:v.checkState,...typeof v.number==="number"&&Number.isFinite(v.number)?{number:v.number}:{},...typeof v.url==="string"?{url:v.url}:{},...typeof v.title==="string"?{title:v.title}:{},...typeof v.baseRef==="string"?{baseRef:v.baseRef}:{},...typeof v.headRef==="string"?{headRef:v.headRef}:{},...typeof v.reviewDecision==="string"?{reviewDecision:v.reviewDecision}:{},...typeof v.mergeable==="string"?{mergeable:v.mergeable}:{},...typeof v.lastCheckedAt==="string"?{lastCheckedAt:v.lastCheckedAt}:{},...typeof v.lastError==="string"?{lastError:v.lastError}:{}}}function isPRProviderId(v){return v==="github"||v==="gitlab"||v==="bitbucket"||v==="unknown"}function isPRLifecycleState(v){return v==="creating"||v==="open"||v==="ready_to_merge"||v==="merged"||v==="closed"||v==="unknown"}function isPRCheckState(v){return v==="none"||v==="pending"||v==="passing"||v==="failing"||v==="unknown"}function isTaskStatus(s){return s==="backlog"||s==="in_progress"||s==="in_review"||s==="done"||s==="canceled"||s==="error"}var sleep=(ms)=>new Promise((resolve)=>setTimeout(resolve,ms)),LOCK_RETRY_DELAY_MS=25,LOCK_MAX_WAIT_MS=5000;async function acquireWithRetry(lockPath){let deadline=Date.now()+LOCK_MAX_WAIT_MS;for(;;)try{return await acquire(lockPath)}catch(err){if(!(err instanceof LockfileError)||Date.now()>=deadline)throw err;await sleep(LOCK_RETRY_DELAY_MS)}}var CURRENT_VERSION=3;async function backupCorruptManifest(path,now=()=>new Date){let backupPath=`${path}.corrupt-${now().toISOString().replaceAll(":","-")}`;try{return await copyFile(path,backupPath),backupPath}catch{return null}}var SUPPORTED_VERSIONS=new Set([1,2,3]);function warnManifestRecovery(message,manifestPath){console.warn(message),logClient("tasks-index",message,manifestPath?defaultClientLogPath(dirname(dirname(manifestPath))):void 0)}async function recoverUnsupportedVersion(parsed,sourcePath){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return!1;let version=parsed.version;if(version===void 0||SUPPORTED_VERSIONS.has(version))return!1;let backup=await backupCorruptManifest(sourcePath);return warnManifestRecovery(`[rove] tasks.json at ${sourcePath} has unsupported version=${String(version)}; recovering with empty index.${backup?` Original bytes backed up to ${backup}.`:" Backup copy failed; the stale file is left in place."}`,sourcePath),!0}function normalizeIndex(parsed,source){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return warnManifestRecovery(`[rove] tasks.json at ${source} is not an object; recovering with empty index.`,source),{version:CURRENT_VERSION,tasks:[]};let obj=parsed,version=obj.version;if(version!==void 0&&!SUPPORTED_VERSIONS.has(version))return warnManifestRecovery(`[rove] tasks.json at ${source} has unsupported version=${String(version)}; recovering with empty index.`,source),{version:CURRENT_VERSION,tasks:[]};let rawTasks=Array.isArray(obj.tasks)?obj.tasks:[],tasks=[];for(let entry of rawTasks){let task=coerceTask(entry);if(task)tasks.push(task);else console.warn(`[rove] dropping malformed task entry from ${source}: ${JSON.stringify(entry)}`)}return{version:CURRENT_VERSION,tasks}}var TOMBSTONE_TTL_MS=2592000000;function readableLegacyIndexPath(canonicalPath,legacyPath){return existsSync(join(dirname(canonicalPath),DAEMON_MIGRATION_MARKER))?void 0:legacyPath}async function readDiskIndex(path,legacyPath){let raw,sourcePath=path;try{raw=await readFile(sourcePath,"utf8")}catch(err){if(err.code!=="ENOENT")throw err;let legacy=readableLegacyIndexPath(path,legacyPath);if(!legacy)return{tasks:[],removed:[]};sourcePath=legacy;try{raw=await readFile(sourcePath,"utf8")}catch(legacyErr){if(legacyErr.code==="ENOENT")return{tasks:[],removed:[]};throw legacyErr}}let parsed;try{parsed=JSON.parse(raw)}catch{return await backupCorruptManifest(sourcePath),{tasks:[],removed:[]}}if(await recoverUnsupportedVersion(parsed,sourcePath))return{tasks:[],removed:[]};return{tasks:normalizeIndex(parsed,sourcePath).tasks,removed:coerceTombstones(parsed)}}function coerceTombstones(parsed){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return[];let raw=parsed.removed;if(!Array.isArray(raw))return[];let out=[];for(let entry of raw){if(!entry||typeof entry!=="object")continue;let v=entry;if(typeof v.id==="string"&&v.id.length>0&&typeof v.at==="string")out.push({id:v.id,at:v.at})}return out}function mergeTasksWithDisk(cacheTasks,diskTasks,dirty,removed,diskRemoved=[],now=Date.now()){let tombstones=new Map;for(let t of diskRemoved){let at=Date.parse(t.at);if(!Number.isFinite(at)||now-at>TOMBSTONE_TTL_MS)continue;tombstones.set(t.id,t.at)}for(let[id,at]of removed)tombstones.set(id,at);let diskById=new Map(diskTasks.map((t)=>[t.id,t])),result=[],included=new Set;for(let task of cacheTasks){if(tombstones.has(task.id))continue;if(dirty.has(task.id))result.push(task);else{let onDisk=diskById.get(task.id);if(onDisk===void 0)continue;result.push(onDisk)}included.add(task.id)}for(let task of diskTasks){if(included.has(task.id)||tombstones.has(task.id))continue;result.push(task),included.add(task.id)}return{tasks:result,removed:[...tombstones].map(([id,at])=>({id,at}))}}async function recoverIndexFromDisk(path,legacyPath){let raw,sourcePath=path;try{raw=await readFile(path,"utf8")}catch(err){if(err.code!=="ENOENT")throw err;let legacy=readableLegacyIndexPath(path,legacyPath),legacyRaw;if(legacy)try{legacyRaw=await readFile(legacy,"utf8"),sourcePath=legacy}catch(legacyErr){if(legacyErr.code!=="ENOENT")throw legacyErr}if(legacyRaw===void 0)return{version:CURRENT_VERSION,tasks:[]};raw=legacyRaw}let parsed;try{parsed=JSON.parse(raw)}catch(err){let backup=await backupCorruptManifest(sourcePath);return warnManifestRecovery(`[rove] tasks.json at ${sourcePath} is corrupted (${err.message}); recovering with empty index.${backup?` Original bytes backed up to ${backup}.`:" Backup copy failed; the stale file is left in place."}`,sourcePath),{version:CURRENT_VERSION,tasks:[]}}if(await recoverUnsupportedVersion(parsed,sourcePath))return{version:CURRENT_VERSION,tasks:[]};return normalizeIndex(parsed,sourcePath)}
3
+ export{acquireWithRetry,readableLegacyIndexPath,readDiskIndex,mergeTasksWithDisk,recoverIndexFromDisk};
@@ -0,0 +1,36 @@
1
+ // @bun
2
+ import{CONTRIB_ENGINE_IDS,contribEngineEntry,detectClaudeAccount,detectCodexAccount,detectCopilotAccount,detectKimiAccount,isContribEngine,pluginEngineIds}from"./chunk-n4dmwkfa.js";import{TomlError,parse}from"./chunk-w7zv47mp.js";import{spawnCapture}from"./chunk-gwcneg6c.js";import{ClaudeHookAdapter,GATED_TOOL_VERBS,JsonHookAdapter,isObject,kobeHookInvocation,readSharedConfigSync,updateSharedJsonSync}from"./chunk-m370e00b.js";import{claudeGlobalConfigPath,copilotConfigPath,isJsonlLineWithinBound,readFirstLineBounded,readTextFileBounded,readTextFileIfRegular,vendorConfigHome,vendorWriteHomeDeps}from"./chunk-7jkf3tvr.js";import{quoteShellArgv}from"./chunk-2fypr41w.js";import{BUILTIN_VENDORS,isBuiltinVendor}from"./chunk-h82kzdsn.js";var claudeCapabilities={},claudeIdentity={vendorId:"claude",shortName:"Claude"};import{homedir,userInfo}from"os";import path from"path";var OAUTH_USAGE_URL="https://api.anthropic.com/api/oauth/usage",OAUTH_BETA_HEADER="oauth-2025-04-20",OAUTH_USER_AGENT="claude-cli/2.1.198 (external, cli)",USAGE_TIMEOUT_MS=1e4,KEYCHAIN_SERVICE="Claude Code-credentials";function parseResetsAtMs(value){if(value==null)return null;let numeric=typeof value==="number"?value:/^\d+(?:\.\d+)?$/.test(value.trim())?Number(value):null;if(numeric!=null){if(!Number.isFinite(numeric)||numeric<=0)return null;return numeric<1000000000000?numeric*1000:numeric}let parsed=Date.parse(String(value));return Number.isNaN(parsed)?null:parsed}var clampPercent=(value)=>Math.min(100,Math.max(0,Math.round(value)));function windowLabel(kind,scopeModel){if(kind==="weekly_scoped"&&scopeModel)return scopeModel;return kind.startsWith("weekly")||kind.startsWith("seven_day")?"7d":"5h"}function usageFromClaudePayload(payload,capturedAt){let windows=[];if(payload.limits?.length)for(let limit of payload.limits){if(typeof limit.kind!=="string"||typeof limit.percent!=="number")continue;windows.push({kind:limit.kind,label:windowLabel(limit.kind,limit.scope?.model?.display_name),percent:clampPercent(limit.percent),resetsAt:parseResetsAtMs(limit.resets_at)})}else{if(typeof payload.five_hour?.utilization==="number")windows.push({kind:"session",label:"5h",percent:clampPercent(payload.five_hour.utilization),resetsAt:parseResetsAtMs(payload.five_hour.resets_at)});if(typeof payload.seven_day?.utilization==="number")windows.push({kind:"weekly_all",label:"7d",percent:clampPercent(payload.seven_day.utilization),resetsAt:parseResetsAtMs(payload.seven_day.resets_at)})}return{windows,capturedAt}}function parseCredentials(raw){try{let oauth=JSON.parse(raw)?.claudeAiOauth;if(!oauth||typeof oauth.accessToken!=="string"||!oauth.accessToken)return null;return{accessToken:oauth.accessToken,...typeof oauth.expiresAt==="number"&&Number.isFinite(oauth.expiresAt)?{expiresAt:oauth.expiresAt}:{}}}catch{return null}}var isFresh=(c)=>c.expiresAt===void 0||c.expiresAt>Date.now();async function readFileCredentials(dir){try{return parseCredentials(await readTextFileBounded(path.join(dir,".credentials.json")))}catch{return null}}async function readKeychainCredentials(){if(process.platform!=="darwin")return null;let controller=new AbortController,timeout=setTimeout(()=>controller.abort(),3000);try{let result=await spawnCapture("security",["find-generic-password","-a",userInfo().username,"-w","-s",KEYCHAIN_SERVICE],{cwd:homedir(),signal:controller.signal});return result.status===0?parseCredentials(result.stdout.trim()):null}finally{clearTimeout(timeout)}}async function readAccessToken(){let configDir=process.env.CLAUDE_CONFIG_DIR?.trim();if(configDir){let fromFile=await readFileCredentials(configDir);return fromFile&&isFresh(fromFile)?fromFile.accessToken:null}return[await readKeychainCredentials(),await readFileCredentials(vendorConfigHome("claude"))].find((c)=>c!=null&&isFresh(c))?.accessToken??null}async function fetchClaudeQuotaUsage(now=Date.now){let token=await readAccessToken().catch(()=>null);if(!token)return null;let controller=new AbortController,timeout=setTimeout(()=>controller.abort(),USAGE_TIMEOUT_MS);try{let response=await fetch(OAUTH_USAGE_URL,{headers:{Authorization:`Bearer ${token}`,"Content-Type":"application/json","User-Agent":OAUTH_USER_AGENT,"anthropic-beta":OAUTH_BETA_HEADER},signal:controller.signal});if(!response.ok)return null;return usageFromClaudePayload(await response.json(),now())}catch{return null}finally{clearTimeout(timeout)}}var CLAUDE_SCREEN_MANIFEST={rules:[],composerEmpty:[{bottomLines:6,all:["\u276F"],lineRegex:["^\\s*\u276F\\s*(?:[\xB7\u2022]\\s*(?:\u2190[^\\n]*)?)?$"]}]};function trustClaudeWorktree(worktreePath,home){let deps=vendorWriteHomeDeps(home);updateSharedJsonSync(claudeGlobalConfigPath(deps.env,deps.home()),(raw)=>{if(raw===void 0)return{};let doc=JSON.parse(raw);if(!isObject(doc))throw Error("Claude trust config must be a JSON object");return doc},(doc)=>{if(doc.projects!==void 0&&!isObject(doc.projects))throw Error("Claude trust projects must be an object");let projects={...doc.projects},existing=Object.hasOwn(projects,worktreePath)?projects[worktreePath]:{};if(!isObject(existing))throw Error("Claude trust project must be an object");if(existing.hasTrustDialogAccepted===!0)return;return projects[worktreePath]={...existing,hasTrustDialogAccepted:!0,hasCompletedProjectOnboarding:!0},JSON.stringify({...doc,projects},null,2)})}function isSyntheticClaudeRecord(record){return record.isMeta===!0||record.isCompactSummary===!0}function isClaudeCommandBreadcrumb(blocks){if(blocks.length===0)return!1;for(let b of blocks){if(b.type!=="text")return!1;let t=b.text.trim();if(!t.startsWith("<command-name>")&&!t.startsWith("<command-message>")&&!t.startsWith("<local-command"))return!1}return!0}function isObject2(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}function opensTurn(content){if(typeof content==="string")return content.trim().length>0;if(!Array.isArray(content))return!1;return content.some((b)=>!isObject2(b)||b.type!=="tool_result")}function num(v){return typeof v==="number"&&Number.isFinite(v)?v:0}function readUsage(v){if(!isObject2(v))return;return{input_tokens:num(v.input_tokens),output_tokens:num(v.output_tokens),cache_read_input_tokens:num(v.cache_read_input_tokens),cache_creation_input_tokens:num(v.cache_creation_input_tokens)}}function finish(draft){if(!draft.id)return null;let totals={input_tokens:0,output_tokens:0,cache_read_input_tokens:0,cache_creation_input_tokens:0};for(let u of draft.usageByMessage.values())totals.input_tokens+=u.input_tokens,totals.output_tokens+=u.output_tokens,totals.cache_read_input_tokens+=u.cache_read_input_tokens,totals.cache_creation_input_tokens+=u.cache_creation_input_tokens;return{id:draft.id,sessionId:draft.sessionId,...draft.model?{model:draft.model}:{},startedAt:draft.startedAt,endedAt:draft.endedAt,...draft.usageByMessage.size>0?{usage:totals}:{}}}function parseClaudeTurns(raw,fallbackSessionId=""){let out=[],draft=null;for(let line of raw.split(`
3
+ `)){let trimmed=line.trim();if(!trimmed||!isJsonlLineWithinBound(trimmed))continue;let record;try{record=JSON.parse(trimmed)}catch{continue}if(!isObject2(record)||isSyntheticClaudeRecord(record))continue;let inner=isObject2(record.message)?record.message:record,at=typeof record.timestamp==="string"?Date.parse(record.timestamp):Number.NaN;if(!Number.isFinite(at))continue;let sessionId=typeof record.sessionId==="string"?record.sessionId:fallbackSessionId;if(inner.role==="user"){if(!opensTurn(inner.content))continue;if(draft){let done=finish(draft);if(done)out.push(done)}draft={id:"",sessionId,startedAt:at,endedAt:at,usageByMessage:new Map};continue}if(inner.role!=="assistant"||!draft)continue;if(draft.endedAt=at,typeof inner.model==="string")draft.model=inner.model;let messageId=typeof inner.id==="string"?inner.id:"";if(messageId)draft.id=messageId;let usage=readUsage(inner.usage);if(usage&&messageId)draft.usageByMessage.set(messageId,usage)}if(draft){let done=finish(draft);if(done)out.push(done)}return out}async function readClaudeTurns(transcriptPath){try{let raw=await readTextFileBounded(transcriptPath);return parseClaudeTurns(raw)}catch{return[]}}var HEX_RE=/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;function parseHex(value){let match=HEX_RE.exec(value);if(!match)return[0,0,0];return[Number.parseInt(match[1],16),Number.parseInt(match[2],16),Number.parseInt(match[3],16)]}function luminance([red,green,blue]){return(red*0.2126+green*0.7152+blue*0.0722)/255}function blend(from,to,amount){return[Math.round(from[0]+(to[0]-from[0])*amount),Math.round(from[1]+(to[1]-from[1])*amount),Math.round(from[2]+(to[2]-from[2])*amount)]}function codexUserMessageBackground(background){return luminance(background)>0.5?blend(background,[0,0,0],0.04):blend(background,[255,255,255],0.12)}function transcriptRewrite(palette){let foreground=parseHex(palette.foreground),background=parseHex(palette.background),backgroundIsLight=luminance(background)>0.5;return{matchBackground:codexUserMessageBackground(background),foreground:backgroundIsLight?foreground:background,background:backgroundIsLight?background:foreground}}var codexTerminalPresentation={alternateScreenStyleRewrites:(palette)=>[transcriptRewrite(palette)]};var codexCapabilities={terminalPresentation:codexTerminalPresentation},codexIdentity={vendorId:"codex",shortName:"Codex"};import{join}from"path";var EVENT_MAP=[{event:"SessionStart",verb:"session-start"},{event:"UserPromptSubmit",verb:"turn-start"},{event:"Stop",verb:"turn-complete"},{event:"PreCompact",verb:"pre-compact"},{event:"PostCompact",verb:"post-compact"},{event:"PreToolUse",verb:"tool-pre"},{event:"PostToolUse",verb:"tool-post"}],KOBE_CODEX_HOOK_EVENTS=EVENT_MAP.map((e)=>e.event);function codexHooksPath(){return join(vendorConfigHome("codex"),"hooks.json")}class CodexHookAdapter extends JsonHookAdapter{vendor="codex";eventMap=EVENT_MAP;globalSettingsPath(){return codexHooksPath()}activityDetailFromPayload(kind,payload){if(kind==="tool-pre"||kind==="tool-post")return{tool:{...typeof payload.tool_name==="string"?{name:payload.tool_name}:{}}};if(kind==="pre-compact"||kind==="post-compact")return{compact:{trigger:payload.trigger==="manual"?"manual":"auto"}};return}sessionFromPayload(payload){if(typeof payload.session_id!=="string"||!payload.session_id)return;return{sessionId:payload.session_id,...typeof payload.transcript_path==="string"&&payload.transcript_path?{transcriptPath:payload.transcript_path}:{}}}}import{createHash}from"crypto";function createAppendParseCache(opts){let maxFiles=opts.maxFiles??8,cache=new Map;function remember(filePath,entry){if(cache.delete(filePath),cache.set(filePath,entry),cache.size>maxFiles){let oldest=cache.keys().next().value;if(oldest!==void 0)cache.delete(oldest)}}return function(filePath,raw,ctx){let stableLength=raw.lastIndexOf(`
4
+ `)+1,entry=cache.get(filePath),verifiedLength=Math.min(entry?.prefixLength??0,stableLength),hash=createHash("sha256").update(raw.slice(0,verifiedLength)),unchanged=entry!==void 0&&Object.is(entry.context,ctx)&&entry.prefixLength<=stableLength&&hash.copy().digest("hex")===entry.prefixHash,prefixState;if(unchanged)prefixState=entry.prefixLength<stableLength?opts.parseChunk(raw.slice(entry.prefixLength,stableLength),entry.state,ctx):entry.state;else prefixState=opts.parseChunk(raw.slice(0,stableLength),opts.initial(ctx),ctx);if(!unchanged||entry.prefixLength!==stableLength||entry.state!==prefixState)remember(filePath,{context:ctx,prefixLength:stableLength,prefixHash:hash.update(raw.slice(verifiedLength,stableLength)).digest("hex"),state:prefixState});let tail=raw.slice(stableLength);return tail.trim().length>0?opts.parseChunk(tail,prefixState,ctx):prefixState}}var sortedMessages=new WeakMap;function sortByTimestamp(messages){let hit=sortedMessages.get(messages);if(hit)return hit;let sorted=[...messages].sort((a,b)=>a.timestamp<b.timestamp?-1:a.timestamp>b.timestamp?1:0);return sortedMessages.set(messages,sorted),sorted}function normalizeCodexContent(raw){if(typeof raw==="string")return raw.length>0?[{type:"text",text:raw}]:[];if(!Array.isArray(raw))return[];let blocks=[];for(let item of raw){if(typeof item==="string"){if(item.length>0)blocks.push({type:"text",text:item});continue}if(!isObject3(item))continue;let t=typeof item.type==="string"?item.type:void 0;if(t==="input_text"||t==="output_text"){let text=typeof item.text==="string"?item.text:"";if(text.length>0)blocks.push({type:"text",text});continue}if(t)blocks.push({type:"text",text:`[codex: ${t}]`})}return blocks}function isObject3(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}function isSyntheticCodexUserRow(blocks){if(blocks.length===0)return!1;for(let b of blocks){if(b.type!=="text")return!1;let t=(b.text??"").trim();if(!isTagEnvelope(t)&&!isInstructionsEnvelope(t))return!1}return!0}var ENVELOPE_TAGS=["environment_context","recommended_plugins","user_instructions"];function isTagEnvelope(text){return ENVELOPE_TAGS.some((tag)=>text.startsWith(`<${tag}>`)&&text.endsWith(`</${tag}>`))}function isInstructionsEnvelope(text){return text.startsWith("# AGENTS.md instructions")&&text.includes("<INSTRUCTIONS>")}function codexUsageToSnapshot(usage,opts={}){let totalInput=numberOr(usage.input_tokens,0),cachedInput=numberOr(usage.cached_input_tokens,0),output=numberOr(usage.output_tokens,0),nonCachedInput=Math.max(0,totalInput-cachedInput);if(totalInput<=0&&output<=0&&cachedInput<=0)return;return{input_tokens:nonCachedInput,output_tokens:output,...cachedInput>0?{cache_read_input_tokens:cachedInput}:{},...validPositive(opts.contextWindowTokens)?{context_window_tokens:opts.contextWindowTokens}:{}}}function numberOr(v,fallback){return typeof v==="number"&&Number.isFinite(v)?v:fallback}function validPositive(v){return typeof v==="number"&&Number.isFinite(v)&&v>0}var emptyState={messages:[],latestUsage:void 0,latestUsageTimestampMs:null},cache=createAppendParseCache({initial:()=>emptyState,parseChunk:foldRolloutChunk});function parseRolloutRaw(filePath,raw,sessionId){let state=cache(filePath,raw,sessionId);return{messages:sortByTimestamp(state.messages),...state.latestUsage?{usageMetrics:state.latestUsage}:{}}}function foldRolloutChunk(chunk,prev,sessionId){let updatedMessages,writableMessages=()=>{return updatedMessages??=[...prev.messages],updatedMessages},latestUsage=prev.latestUsage,latestUsageTimestampMs=prev.latestUsageTimestampMs;for(let line of chunk.split(`
5
+ `)){let trimmed=line.trim();if(!trimmed)continue;if(!isJsonlLineWithinBound(trimmed))continue;let parsed;try{parsed=JSON.parse(trimmed)}catch{continue}if(!isObject4(parsed))continue;if(parsed.type==="response_item"){let payload=isObject4(parsed.payload)?parsed.payload:void 0;if(!payload)continue;let ts=typeof parsed.timestamp==="string"?parsed.timestamp:new Date().toISOString(),msg=normalizeCodexResponseItem(payload,ts,sessionId);if(msg)writableMessages().push(msg);continue}let usageFields=codexUsageFields(parsed);if(!usageFields)continue;let base=codexUsageToSnapshot(usageFields.usage,{contextWindowTokens:usageFields.contextWindow});if(!base)continue;let lastPrompt=usageFields.lastUsage?numberOr2(usageFields.lastUsage.input_tokens):0,snapshot={...base,...lastPrompt>0?{context_tokens:lastPrompt}:{}},lastUsage=usageFields.lastUsage&&codexLastUsageToMessageUsage(usageFields.lastUsage);if(lastUsage){let messages=updatedMessages??prev.messages,index=messages.findLastIndex((message2)=>message2.role==="assistant"),message=messages[index];if(message)writableMessages()[index]={...message,usage:lastUsage}}let timestampMs=typeof parsed.timestamp==="string"?parseTimestampMs(parsed.timestamp):null;if(timestampMs!==null&&(latestUsageTimestampMs===null||timestampMs>latestUsageTimestampMs))latestUsageTimestampMs=timestampMs,latestUsage=snapshot;else if(latestUsageTimestampMs===null)latestUsage=snapshot}return{messages:updatedMessages??prev.messages,latestUsage,latestUsageTimestampMs}}function codexUsageFields(parsed){if(parsed.type==="event_msg"){let payload=isObject4(parsed.payload)?parsed.payload:void 0;if(payload?.type!=="token_count")return;let info=isObject4(payload.info)?payload.info:void 0,usage=info&&isObject4(info.total_token_usage)?info.total_token_usage:void 0;if(!usage)return;let lastUsage=info&&isObject4(info.last_token_usage)?info.last_token_usage:void 0,contextWindow=typeof info?.model_context_window==="number"?info.model_context_window:void 0;return{usage,lastUsage,contextWindow}}if(parsed.type==="turn.completed"){let usage=isObject4(parsed.usage)?parsed.usage:void 0;return usage?{usage,lastUsage:usage,contextWindow:void 0}:void 0}return}function codexLastUsageToMessageUsage(usage){let totalInput=numberOr2(usage.input_tokens),cachedInput=numberOr2(usage.cached_input_tokens),output=numberOr2(usage.output_tokens);if(totalInput<=0&&output<=0&&cachedInput<=0)return;return{input_tokens:Math.max(0,totalInput-cachedInput),output_tokens:output,...cachedInput>0?{cache_read_input_tokens:cachedInput}:{}}}function numberOr2(v){return typeof v==="number"&&Number.isFinite(v)?v:0}function normalizeCodexResponseItem(payload,timestamp,sessionId){if(payload.type==="message"){let role=payload.role;if(role!=="user"&&role!=="assistant"&&role!=="system")return;let blocks=normalizeCodexContent(payload.content);if(role==="user"&&isSyntheticCodexUserRow(blocks))return;return{role,blocks,timestamp,sessionId}}if(payload.type==="reasoning")return normalizeCodexReasoning(payload,timestamp,sessionId);if(payload.type==="function_call")return normalizeCodexToolCall(payload,timestamp,sessionId,{name:stringOr(payload.name,"function_call"),input:parseMaybeJson(payload.arguments)});if(payload.type==="custom_tool_call")return normalizeCodexToolCall(payload,timestamp,sessionId,{name:stringOr(payload.name,"custom_tool_call"),input:parseMaybeJson(payload.input)});if(payload.type==="tool_search_call")return normalizeCodexToolCall(payload,timestamp,sessionId,{name:"tool_search_call",input:stripPayload(payload,["type","call_id","status"])});if(payload.type==="function_call_output"||payload.type==="custom_tool_call_output")return normalizeCodexToolResult(payload,timestamp,sessionId,parseMaybeJson(payload.output));if(payload.type==="tool_search_output")return normalizeCodexToolResult(payload,timestamp,sessionId,stripPayload(payload,["type","call_id"]));if(payload.type==="web_search_call"||payload.type==="image_generation_call"||payload.type==="local_shell_call")return normalizeSingleRecordTool(payload,timestamp,sessionId);return}function normalizeCodexReasoning(payload,timestamp,sessionId){let text=reasoningTextFromItem(payload);if(text.length===0)return;return{role:"assistant",blocks:[{type:"thinking",text}],timestamp,sessionId}}function normalizeCodexToolCall(payload,timestamp,sessionId,args){let callId=typeof payload.call_id==="string"?payload.call_id:void 0;if(!callId)return;return{role:"assistant",blocks:[{type:"tool_call",callId,name:args.name,input:args.input}],timestamp,sessionId}}function normalizeCodexToolResult(payload,timestamp,sessionId,output){let callId=typeof payload.call_id==="string"?payload.call_id:void 0;if(!callId)return;return{role:"user",blocks:[{type:"tool_result",callId,output,isError:!1}],timestamp,sessionId}}function normalizeSingleRecordTool(payload,timestamp,sessionId){let type=typeof payload.type==="string"?payload.type:"tool",callId=typeof payload.call_id==="string"&&payload.call_id.length>0?payload.call_id:`${type}:${timestamp}`,name=stringOr(payload.name,type),input=stripPayload(payload,["type","call_id","status"]),output=stripPayload(payload,["type","call_id"]);return{role:"assistant",timestamp,sessionId,blocks:[{type:"tool_call",callId,name,input},{type:"tool_result",callId,output,isError:!1}]}}function reasoningTextFromItem(item){let content=textFromReasoningValue(item.content);if(content.length>0)return content;let text=typeof item.text==="string"?item.text:"";if(text.length>0)return text;return textFromReasoningValue(item.summary)}function textFromReasoningValue(value){if(typeof value==="string")return value;if(!Array.isArray(value))return"";let parts=[];for(let entry of value){if(typeof entry==="string"){parts.push(entry);continue}if(!isObject4(entry))continue;let text=typeof entry.text==="string"?entry.text:"";if(text.length>0)parts.push(text)}return parts.join("")}function stripPayload(payload,keys){let out={};for(let[key,value]of Object.entries(payload))if(!keys.includes(key))out[key]=value;return out}function stringOr(value,fallback){return typeof value==="string"&&value.length>0?value:fallback}function parseMaybeJson(value){if(typeof value!=="string")return value;try{return JSON.parse(value)}catch{return value}}function parseTimestampMs(value){let ms=new Date(value).getTime();return Number.isFinite(ms)?ms:null}function isObject4(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}import{readdir,stat}from"fs/promises";import path2 from"path";var defaultHistoryDeps={sessionsDir:()=>path2.join(vendorConfigHome("codex"),"sessions"),readdir:(p)=>readdir(p),readFile:readTextFileBounded,readHead:readFirstLineBounded,stat},UUID_AT_END=/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i,FULL_UUID=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,IO_CONCURRENCY=8;function sameStamp(a,b){return a.mtimeMs===b.mtimeMs&&a.size===b.size&&a.ctimeMs===b.ctimeMs&&a.ino===b.ino&&a.dev===b.dev}function rolloutCwd(raw){for(let line of raw.split(`
6
+ `)){if(!isJsonlLineWithinBound(line))return"";if(!line.trim())continue;try{let record=JSON.parse(line);if(typeof record!=="object"||record===null||!("type"in record)||record.type!=="session_meta")return"";if(!("payload"in record)||typeof record.payload!=="object"||record.payload===null)return"";return"cwd"in record.payload&&typeof record.payload.cwd==="string"?record.payload.cwd:""}catch{return""}}return""}class RolloutCatalog{root;deps;directories=new Map;metadata=new Map;located=new Map;refreshing;constructor(root,deps){this.root=root;this.deps=deps}async names(dir){let stamp=await this.deps.stat(dir).catch(()=>null),hit=this.directories.get(dir);if(!stamp)return this.directories.delete(dir),[];if(stamp?.ctimeMs!==void 0&&hit&&sameStamp(hit.stamp,stamp))return hit.names;let names;try{names=(await this.deps.readdir(dir)).sort().reverse()}catch{return hit?.names??[]}if(stamp)this.directories.set(dir,{stamp,names});return names}async*files(){let visited=new Set([this.root]);for(let year of await this.names(this.root)){if(!/^\d{4}$/.test(year))continue;let yp=path2.join(this.root,year);visited.add(yp);for(let month of await this.names(yp)){if(!/^(0[1-9]|1[0-2])$/.test(month))continue;let mp=path2.join(yp,month);visited.add(mp);for(let day of await this.names(mp)){if(!/^(0[1-9]|[12]\d|3[01])$/.test(day))continue;let dp=path2.join(mp,day);visited.add(dp);for(let name of await this.names(dp))if(name.startsWith("rollout-")&&name.endsWith(".jsonl"))yield path2.join(dp,name)}}}for(let dir of this.directories.keys())if(!visited.has(dir))this.directories.delete(dir)}async locate(sessionId){if(!FULL_UUID.test(sessionId))return;let id=sessionId.toLowerCase(),hit=this.located.get(id);if(hit&&await this.isFile(hit))return hit;this.located.delete(id);for await(let file of this.files()){if(path2.basename(file).match(UUID_AT_END)?.[1]?.toLowerCase()!==id||!await this.isFile(file))continue;if(this.located.size>=256){let oldest=this.located.keys().next().value;if(oldest!==void 0)this.located.delete(oldest)}return this.located.set(id,file),file}return}async isFile(file){let info=await this.deps.stat(file).catch(()=>null);return info!==null&&(info.isFile?.()??!0)}sessions(){if(!this.refreshing)this.refreshing=this.refresh().finally(()=>{this.refreshing=void 0});return this.refreshing}async refresh(){let next=new Map,files=[];for await(let file of this.files())files.push(file);let cursor=0,readNext=async()=>{while(cursor<files.length){let file=files[cursor++];if(file===void 0)break;let stamp=await this.deps.stat(file).catch(()=>null);if(!stamp)continue;let hit=this.metadata.get(file);if(hit&&sameStamp(hit.stamp,stamp)){next.set(file,hit);continue}let raw=await(this.deps.readHead??this.deps.readFile)(file).catch(()=>""),cwd=rolloutCwd(raw),sessionId=path2.basename(file).match(UUID_AT_END)?.[1];if(cwd&&sessionId)next.set(file,{path:file,sessionId,cwd,stamp})}};return await Promise.all(Array.from({length:Math.min(IO_CONCURRENCY,files.length)},readNext)),this.metadata=next,files.flatMap((file)=>{let entry=next.get(file);return entry?[entry]:[]})}}var catalogs=new WeakMap;function catalog(deps){let root=deps.sessionsDir(),current=catalogs.get(deps);if(!current||current.root!==root)current=new RolloutCatalog(root,deps),catalogs.set(deps,current);return current}async function listRolloutFiles(deps=defaultHistoryDeps){let files=[];for await(let file of catalog(deps).files())files.push(file);return files}function findRolloutFile(sessionId,deps=defaultHistoryDeps){return catalog(deps).locate(sessionId)}async function listSessionIdsForWorktree(worktree,deps=defaultHistoryDeps){if(!worktree)return[];return(await catalog(deps).sessions()).filter((file)=>file.cwd===worktree).map((file)=>file.sessionId).reverse()}async function findLatestRolloutForWorktree(worktree,deps=defaultHistoryDeps){if(!worktree)return null;let best=null;for(let file of await catalog(deps).sessions())if(file.cwd===worktree&&(!best||file.stamp.mtimeMs>best.mtimeMs))best={path:file.path,mtimeMs:file.stamp.mtimeMs};return best}async function latestTranscriptMtimeForWorktree(worktree,deps=defaultHistoryDeps){return(await findLatestRolloutForWorktree(worktree,deps))?.mtimeMs??0}async function readHistory(sessionId,deps=defaultHistoryDeps){return(await readHistoryWithMetrics(sessionId,deps)).messages}async function readHistoryWithMetrics(sessionId,deps=defaultHistoryDeps){let file=await findRolloutFile(sessionId,deps);if(!file)return{messages:[]};let raw;try{raw=await deps.readFile(file)}catch{return{messages:[]}}return parseRolloutRaw(file,raw,sessionId)}var MAX_ROLLOUTS_SCANNED=5;function windowLabel2(minutes){if(minutes%1440===0)return`${minutes/1440}d`;if(minutes%60===0)return`${minutes/60}h`;return`${minutes}m`}function toWindow(kind,raw,nowMs){if(!raw||typeof raw.used_percent!=="number"||typeof raw.window_minutes!=="number")return null;let resetsAt=typeof raw.resets_at==="number"&&raw.resets_at>0?raw.resets_at*1000:null;if(resetsAt==null||resetsAt<=nowMs)return null;return{kind,label:windowLabel2(raw.window_minutes),percent:Math.min(100,Math.max(0,Math.round(raw.used_percent))),resetsAt}}function usageFromRolloutRaw(raw,nowMs){let lines=raw.split(`
7
+ `);for(let i=lines.length-1;i>=0;i--){let line=lines[i];if(!line||!isJsonlLineWithinBound(line)||!line.includes('"rate_limits"'))continue;let limits;try{limits=JSON.parse(line).payload?.rate_limits}catch{continue}if(!limits)continue;let windows=[toWindow("primary",limits.primary,nowMs),toWindow("secondary",limits.secondary,nowMs)].filter((w)=>w!=null);if(windows.length)return{windows,capturedAt:nowMs}}return null}async function fetchCodexQuotaUsage(now=Date.now,deps=defaultHistoryDeps){try{let files=(await listRolloutFiles(deps)).slice(0,MAX_ROLLOUTS_SCANNED);for(let file of files){let usage=usageFromRolloutRaw(await deps.readFile(file),now());if(usage)return usage}}catch{}return null}var CODEX_SCREEN_MANIFEST={rules:[],composerEmpty:[{bottomLines:2,all:["\u203A"],lineRegex:["^\\s*\u203A\\s*$"]},{bottomLines:2,all:["\u203A"],lineRegex:["^\\s*\u203A\\s+Ask Codex to do anything\\s*$"],dimmed:["Ask Codex to do anything"]}]};var CODEX_THREAD_ID=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function codexSessionIdFromTitle(title){let trimmed=title.trim();return CODEX_THREAD_ID.test(trimmed)?trimmed.toLowerCase():null}import{appendFileSync,closeSync,mkdirSync,openSync,unlinkSync,writeFileSync}from"fs";import path3 from"path";var TRUST_LINE='trust_level = "trusted"',LOCK_NAME="config.toml.rove.lock",LOCK_TIMEOUT_MS=5000,LOCK_POLL_MS=10,MAX_DUPLICATE_REPAIRS=5;function trustCodexWorktree(worktreePath,home){let dir=vendorConfigHome("codex",vendorWriteHomeDeps(home)),file=path3.join(dir,"config.toml"),header=`[projects.${JSON.stringify(worktreePath)}]`;mkdirSync(dir,{recursive:!0}),withConfigLock(path3.join(dir,LOCK_NAME),()=>{let before=readSharedConfigSync(file)??"",{text,doc}=parseTrustConfig(before),exists=isObject(doc.projects)&&Object.hasOwn(doc.projects,worktreePath),lead=text.length>0&&!text.endsWith(`
8
+ `)?`
9
+ `:"",addition=exists?"":`${lead}
10
+ ${header}
11
+ ${TRUST_LINE}
12
+ `;try{parse(text+addition)}catch{throw Error("Cannot add Codex trust without changing existing TOML")}if(text!==before)writeFileSync(file,text+addition,{mode:384});else if(addition)appendFileSync(file,addition,{mode:384})})}function parseTrustConfig(original){let text=original;for(let repairs=0;;repairs++)try{return{text,doc:parse(text)}}catch(error){if(!(error instanceof TomlError)||repairs>=MAX_DUPLICATE_REPAIRS)break;let lines=text.split(`
13
+ `),index=error.line-1,header=lines[index];if(!header||!/^\[projects\."(?:[^"\\]|\\.)*"\]$/.test(header)||lines[index+1]!==TRUST_LINE)break;let next=index+2;while(next<lines.length&&lines[next].trim()==="")next++;if(next<lines.length&&!lines[next].startsWith("["))break;try{let prior=parse(lines.slice(0,index).join(`
14
+ `)),duplicate=parse(`${header}
15
+ ${TRUST_LINE}`);if(!isObject(prior.projects)||!isObject(duplicate.projects))break;let project=Object.keys(duplicate.projects)[0];if(!project||!Object.hasOwn(prior.projects,project))break;let trusted=prior.projects[project];if(!isObject(trusted)||Object.keys(trusted).length!==1||trusted.trust_level!=="trusted")break}catch{break}lines.splice(index,2),text=lines.join(`
16
+ `)}throw Error("Codex trust config is invalid; leaving it unchanged")}function withConfigLock(lockPath,fn){let fd,deadline=Date.now()+LOCK_TIMEOUT_MS,sleeper=new Int32Array(new SharedArrayBuffer(4));for(;;)try{fd=openSync(lockPath,"wx");break}catch(error){if(!(error instanceof Error&&("code"in error)&&error.code==="EEXIST"))throw error;if(Date.now()>=deadline)throw Error("Timed out waiting for Codex config lock");Atomics.wait(sleeper,0,0,LOCK_POLL_MS)}try{writeFileSync(fd,String(process.pid)),fn()}finally{closeSync(fd);try{unlinkSync(lockPath)}catch{}}}function isObject5(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}function num2(v){return typeof v==="number"&&Number.isFinite(v)?v:0}function parseCodexTurns(raw,fallbackSessionId=""){let out=[],drafts=new Map,sessionId=fallbackSessionId,openTurnId="";for(let line of raw.split(`
17
+ `)){let trimmed=line.trim();if(!trimmed||!isJsonlLineWithinBound(trimmed))continue;let record;try{record=JSON.parse(trimmed)}catch{continue}if(!isObject5(record))continue;let payload=isObject5(record.payload)?record.payload:void 0;if(!payload)continue;let at=typeof record.timestamp==="string"?Date.parse(record.timestamp):Number.NaN;if(record.type==="session_meta"){let id=payload.session_id??payload.id;if(typeof id==="string"&&id)sessionId=id;continue}if(record.type==="turn_context"){let turnId2=typeof payload.turn_id==="string"?payload.turn_id:"",model=typeof payload.model==="string"?payload.model:"";if(!turnId2||!model)continue;let draft2=drafts.get(turnId2);if(draft2)draft2.model=model;else drafts.set(turnId2,{...emptyDraft(turnId2,Number.NaN),model});continue}if(record.type!=="event_msg")continue;if(payload.type==="task_started"){let turnId2=typeof payload.turn_id==="string"?payload.turn_id:"";if(!turnId2)continue;let model=drafts.get(turnId2)?.model,startedAt=Number.isFinite(at)?at:num2(payload.started_at)*1000;drafts.set(turnId2,{...emptyDraft(turnId2,startedAt),...model?{model}:{},...typeof payload.model_context_window==="number"?{contextWindow:payload.model_context_window}:{}}),openTurnId=turnId2;continue}if(payload.type==="token_count"){let draft2=drafts.get(openTurnId);if(!draft2)continue;let info=isObject5(payload.info)?payload.info:void 0,last=info&&isObject5(info.last_token_usage)?info.last_token_usage:void 0;if(!last)continue;if(draft2.input+=num2(last.input_tokens),draft2.cachedInput+=num2(last.cached_input_tokens),draft2.output+=num2(last.output_tokens),draft2.sawUsage=!0,draft2.contextWindow===void 0&&typeof info?.model_context_window==="number")draft2.contextWindow=info.model_context_window;continue}if(payload.type!=="task_complete")continue;let turnId=typeof payload.turn_id==="string"?payload.turn_id:"",draft=turnId?drafts.get(turnId):void 0;if(!draft||!Number.isFinite(draft.startedAt))continue;if(drafts.delete(turnId),openTurnId===turnId)openTurnId="";let endedAt=Number.isFinite(at)?at:num2(payload.completed_at)*1000,usage=draft.sawUsage?codexUsageToSnapshot({input_tokens:draft.input,cached_input_tokens:draft.cachedInput,output_tokens:draft.output},draft.contextWindow!==void 0?{contextWindowTokens:draft.contextWindow}:{}):void 0;out.push({id:draft.turnId,sessionId,...draft.model?{model:draft.model}:{},startedAt:draft.startedAt,endedAt,...usage?{usage}:{}})}return out}function emptyDraft(turnId,startedAt){return{turnId,startedAt,input:0,cachedInput:0,output:0,sawUsage:!1}}async function readCodexTurns(transcriptPath){try{let raw=await readTextFileBounded(transcriptPath);return parseCodexTurns(raw)}catch{return[]}}var COPILOT_SCREEN_MANIFEST={rules:[{state:"blocked",any:["enter to select","enter to confirm","enter to submit","enter accept"],all:["esc"]},{state:"working",any:["esc to cancel","esc cancel","esc again to cancel","esc interrupt"]}]};import{homedir as homedir2}from"os";function splitJsoncHeader(raw){let lines=raw.split(`
18
+ `),i=0;while(i<lines.length&&(lines[i].trim().startsWith("//")||lines[i].trim()===""))i++;return{header:lines.slice(0,i).join(`
19
+ `),body:lines.slice(i).join(`
20
+ `)}}function trustCopilotWorktree(worktreePath,home=homedir2()){let carriedHeader="";updateSharedJsonSync(copilotConfigPath((name)=>process.env[name],home),(raw)=>{if(carriedHeader="",raw===void 0)return{};let{header,body}=splitJsoncHeader(raw);carriedHeader=header;try{return JSON.parse(body)}catch{return{}}},(doc)=>{let existing=Array.isArray(doc.trustedFolders)?doc.trustedFolders:[];if(existing.some((entry)=>entry===worktreePath))return;let merged={...doc,trustedFolders:[...existing,worktreePath]},body=JSON.stringify(merged,null,2);return carriedHeader?`${carriedHeader}
21
+ ${body}
22
+ `:`${body}
23
+ `})}import path7 from"path";import{appendFile,mkdir,readdir as readdir2,stat as stat2,unlink}from"fs/promises";import path4 from"path";function normalizeClaudeContent(content){if(typeof content==="string")return content.length>0?[{type:"text",text:content}]:[];if(!Array.isArray(content))return[];let out=[];for(let block of content){if(typeof block==="string"){if(block.length>0)out.push({type:"text",text:block});continue}if(!block||typeof block!=="object")continue;let b=block;if(b.type==="text"&&typeof b.text==="string"){out.push({type:"text",text:b.text});continue}if(b.type==="tool_use"){out.push({type:"tool_call",callId:typeof b.id==="string"?b.id:"",name:typeof b.name==="string"?b.name:"",input:b.input});continue}if(b.type==="tool_result"){out.push({type:"tool_result",callId:typeof b.tool_use_id==="string"?b.tool_use_id:"",output:b.content,isError:b.is_error===!0});continue}if(b.type==="thinking"&&typeof b.thinking==="string")out.push({type:"thinking",text:b.thinking})}return out}var cache2=createAppendParseCache({initial:()=>[],parseChunk:(chunk,prev,sessionId)=>{let added=parseJsonl2(chunk,sessionId);return added.length?prev.concat(added):prev}});function parseSessionRaw(filePath,raw,sessionId){return sortByTimestamp(cache2(filePath,raw,sessionId))}function parseJsonl2(raw,sessionId){let out=[];for(let line of raw.split(`
24
+ `)){let trimmed=line.trim();if(!trimmed)continue;if(!isJsonlLineWithinBound(trimmed))continue;let parsed;try{parsed=JSON.parse(trimmed)}catch{continue}if(!isObject6(parsed))continue;let msg=extractMessage(parsed,sessionId);if(msg)out.push(msg)}return out}function extractMessage(record,fallbackSessionId){if(isSyntheticClaudeRecord(record))return null;let inner=isObject6(record.message)?record.message:record,role=inner.role;if(role!=="user"&&role!=="assistant"&&role!=="system")return null;if(!("content"in inner))return null;let blocks=normalizeClaudeContent(inner.content);if(role==="user"&&isClaudeCommandBreadcrumb(blocks))return null;let ts=typeof record.timestamp==="string"?record.timestamp:new Date().toISOString(),sid=typeof record.sessionId==="string"?record.sessionId:fallbackSessionId,usage=extractUsage(inner.usage);return usage?{role,blocks,timestamp:ts,sessionId:sid,usage}:{role,blocks,timestamp:ts,sessionId:sid}}function extractUsage(v){if(!isObject6(v))return;let inTok=typeof v.input_tokens==="number"?v.input_tokens:void 0,outTok=typeof v.output_tokens==="number"?v.output_tokens:void 0;if(inTok===void 0||outTok===void 0)return;let cacheRead=typeof v.cache_read_input_tokens==="number"?v.cache_read_input_tokens:void 0,cacheCreate=typeof v.cache_creation_input_tokens==="number"?v.cache_creation_input_tokens:void 0;return{input_tokens:inTok,output_tokens:outTok,...cacheRead!==void 0?{cache_read_input_tokens:cacheRead}:{},...cacheCreate!==void 0?{cache_creation_input_tokens:cacheCreate}:{}}}function isObject6(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}var defaultDeps={projectsDir(){return path4.join(vendorConfigHome("claude"),"projects")},async readdir(p){try{return await readdir2(p)}catch{return[]}},async readFile(p){return await readTextFileBounded(p)},async pathExists(p){try{return await readdir2(p),!0}catch{return!1}}};function encodeCwd(cwd){return cwd.replace(/[^a-zA-Z0-9]/g,"-")}async function listSessionFilesForWorktree(worktree){if(!worktree)return[];let dir=path4.join(vendorConfigHome("claude"),"projects",encodeCwd(worktree)),entries;try{entries=await readdir2(dir)}catch{return[]}let out=[];for(let entry of entries){if(!entry.endsWith(".jsonl"))continue;let full=path4.join(dir,entry),mtimeMs=0;try{mtimeMs=(await stat2(full)).mtimeMs}catch{}out.push({sessionId:entry.slice(0,-6),path:full,mtimeMs})}return out.sort((a,b)=>b.mtimeMs-a.mtimeMs),out}async function latestTranscriptMtimeForWorktree2(worktree){return(await listSessionFilesForWorktree(worktree))[0]?.mtimeMs??0}async function readHistory2(sessionId,deps=defaultDeps){let root=deps.projectsDir(),projectDirs=await deps.readdir(root);for(let dir of projectDirs){let candidate=path4.join(root,dir,`${sessionId}.jsonl`),raw;try{raw=await deps.readFile(candidate)}catch{continue}return parseSessionRaw(candidate,raw,sessionId)}return[]}async function readUsageSnapshot(sessionId,deps=defaultDeps){let messages=await readHistory2(sessionId,deps),input=0,output=0,cacheRead=0,cacheCreate=0,lastContext=0;for(let message of messages){let usage=message.usage;if(!usage)continue;input+=usage.input_tokens,output+=usage.output_tokens;let read=usage.cache_read_input_tokens??0,create=usage.cache_creation_input_tokens??0;cacheRead+=read,cacheCreate+=create,lastContext=usage.input_tokens+read+create}if(input===0&&output===0)return;return{input_tokens:input,output_tokens:output,...cacheRead>0?{cache_read_input_tokens:cacheRead}:{},...cacheCreate>0?{cache_creation_input_tokens:cacheCreate}:{},...lastContext>0?{context_tokens:lastContext,context_tokens_approximate:!0}:{}}}import{readdir as readdir3,rm,stat as stat3}from"fs/promises";import path5 from"path";function copilotUsageToSnapshot(value){if(!isObject7(value))return;let modelMetrics=isObject7(value.modelMetrics)?value.modelMetrics:void 0;if(!modelMetrics)return;let input=0,output=0,cached=0;for(let metrics of Object.values(modelMetrics)){if(!isObject7(metrics)||!isObject7(metrics.usage))continue;input+=numberOr3(metrics.usage.inputTokens,0),output+=numberOr3(metrics.usage.outputTokens,0),cached+=numberOr3(metrics.usage.cacheReadTokens,0)}let context=numberOr3(value.currentTokens,0);if(input===0&&output===0&&cached===0&&context===0)return;return{input_tokens:input,output_tokens:output,...cached>0?{cache_read_input_tokens:cached}:{},...context>0?{context_tokens:context}:{}}}function isObject7(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}function numberOr3(value,fallback){return typeof value==="number"&&Number.isFinite(value)?value:fallback}var defaultDeps2={copilotDir(){return vendorConfigHome("copilot")},async readdir(p){try{return await readdir3(p)}catch{return[]}},async readFile(p){return await readTextFileBounded(p)},stat:stat3,async rm(p){await rm(p,{recursive:!0,force:!0})}};async function listSessionDirs(deps=defaultDeps2){let root=path5.join(deps.copilotDir(),"session-state");return(await deps.readdir(root)).map((name)=>path5.join(root,name))}async function listSessionIdsForWorktree2(worktree,deps=defaultDeps2){let matches=[];for(let dir of await listSessionDirs(deps)){let workspace=await readWorkspace(dir,deps);if(workspace.cwd!==worktree)continue;matches.push({id:workspace.id??path5.basename(dir),updatedAt:workspace.updatedAt??""})}return matches.sort((a,b)=>a.updatedAt.localeCompare(b.updatedAt)).map((m)=>m.id)}async function latestTranscriptMtimeForWorktree3(worktree,deps=defaultDeps2){if(!worktree)return 0;let newest=0;for(let dir of await listSessionDirs(deps)){if((await readWorkspace(dir,deps)).cwd!==worktree)continue;try{let{mtimeMs}=await deps.stat(path5.join(dir,"events.jsonl"));if(mtimeMs>newest)newest=mtimeMs}catch{}}return newest}async function readHistoryWithMetrics2(sessionId,deps=defaultDeps2){let dir=await findSessionDir(sessionId,deps);if(!dir)return{messages:[]};let file=path5.join(dir,"events.jsonl"),raw=await deps.readFile(file).catch(()=>""),state=eventsCache(file,raw,sessionId);return{messages:state.messages,...state.usageMetrics?{usageMetrics:state.usageMetrics}:{}}}async function readHistory3(sessionId,deps=defaultDeps2){return(await readHistoryWithMetrics2(sessionId,deps)).messages}async function findSessionDir(sessionId,deps=defaultDeps2){for(let dir of await listSessionDirs(deps)){if(path5.basename(dir)===sessionId)return dir;let workspace=await readWorkspace(dir,deps);if(workspace.id===sessionId||workspace.name?.toLowerCase()===sessionId.toLowerCase())return dir}return}async function readWorkspace(dir,deps=defaultDeps2){let raw=await deps.readFile(path5.join(dir,"workspace.yaml")).catch(()=>"");return parseWorkspaceYaml(raw)}function parseWorkspaceYaml(raw){let out={};for(let rawLine of raw.split(`
25
+ `)){let match=rawLine.replace(/\r$/,"").match(/^([A-Za-z_]+):\s*(.*)$/);if(!match)continue;let key=match[1],value=match[2]??"";if(value.startsWith('"')&&value.endsWith('"'))value=value.slice(1,-1).replace(/\\"/g,'"');out[key]=value}return{id:out.id,cwd:out.cwd,name:out.name,updatedAt:out.updated_at,createdAt:out.created_at}}function initialParseState(fallbackSessionId){return{messages:[],sessionId:fallbackSessionId,usageMetrics:void 0,firstUserMessage:null}}var eventsCache=createAppendParseCache({initial:initialParseState,parseChunk:(chunk,prev)=>foldEvents(chunk,prev)});function foldEvents(raw,prev){let updatedMessages,appendMessage=(message)=>{updatedMessages??=[...prev.messages],updatedMessages.push(message)},sessionId=prev.sessionId,usageMetrics=prev.usageMetrics,firstUserMessage=prev.firstUserMessage;for(let line of raw.split(`
26
+ `)){let trimmed=line.trim();if(!trimmed)continue;if(!isJsonlLineWithinBound(trimmed))continue;let record;try{record=JSON.parse(trimmed)}catch{continue}if(!isObject8(record)||typeof record.type!=="string")continue;let timestamp=typeof record.timestamp==="string"?record.timestamp:new Date().toISOString(),data=isObject8(record.data)?record.data:{};if(record.type==="session.start"){let sid=typeof data.sessionId==="string"?data.sessionId:void 0;if(sid)sessionId=sid;continue}if(record.type==="user.message"){let text=typeof data.content==="string"?data.content:"";if(!text)continue;if(!firstUserMessage)firstUserMessage=Buffer.from(text.slice(0,PREVIEW_CHAR_CAP),"utf8").toString("utf8");appendMessage({role:"user",blocks:[{type:"text",text}],timestamp,sessionId});continue}if(record.type==="assistant.message"){let blocks=[],text=typeof data.content==="string"?data.content:"";if(text)blocks.push({type:"text",text});let toolRequests=Array.isArray(data.toolRequests)?data.toolRequests:[];for(let req of toolRequests){if(!isObject8(req))continue;let callId=typeof req.id==="string"?req.id:typeof req.toolCallId==="string"?req.toolCallId:"tool",name=typeof req.name==="string"?req.name:typeof req.toolName==="string"?req.toolName:"tool";blocks.push({type:"tool_call",callId,name,input:req.arguments??{}})}if(blocks.length>0)appendMessage({role:"assistant",blocks,timestamp,sessionId});continue}if(record.type==="tool.execution_complete"){let callId=typeof data.toolCallId==="string"?data.toolCallId:void 0;if(!callId)continue;let output=data.result??(data.success===!1?{success:!1}:void 0);appendMessage({role:"assistant",blocks:[{type:"tool_result",callId,output,isError:data.success===!1}],timestamp,sessionId});continue}if(record.type==="session.shutdown")usageMetrics=copilotUsageToSnapshot(data)}return{messages:updatedMessages??prev.messages,sessionId,usageMetrics,firstUserMessage}}var PREVIEW_CHAR_CAP=200;function isObject8(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}import{stat as stat4}from"fs/promises";import path6 from"path";var defaultDeps3={kimiDir(){return vendorConfigHome("kimi")},async readFile(p){return await readTextFileBounded(p)},stat:stat4};function parseSessionIndex(raw){let out=[];for(let line of raw.split(`
27
+ `)){if(!isJsonlLineWithinBound(line)||!line.trim())continue;try{let record=JSON.parse(line);if(typeof record!=="object"||record===null)continue;if(!("sessionId"in record)||!("sessionDir"in record)||!("workDir"in record))continue;let{sessionId,sessionDir,workDir}=record;if(typeof sessionId==="string"&&sessionId&&typeof sessionDir==="string"&&sessionDir&&typeof workDir==="string"&&workDir)out.push({sessionId,sessionDir,workDir})}catch{}}return out}async function sessionIndex(deps){let raw=await deps.readFile(path6.join(deps.kimiDir(),"session_index.jsonl")).catch(()=>"");return parseSessionIndex(raw)}function wirePath(sessionDir){return path6.join(sessionDir,"agents","main","wire.jsonl")}async function worktreeSessionFiles(worktree,deps){if(!worktree)return[];let matches=[];for(let entry of await sessionIndex(deps)){if(entry.workDir!==worktree)continue;let file=wirePath(entry.sessionDir),info=await deps.stat(file).catch(()=>null);if(info)matches.push({id:entry.sessionId,mtimeMs:info.mtimeMs})}return matches.sort((a,b)=>a.mtimeMs-b.mtimeMs)}async function listSessionIdsForWorktree3(worktree,deps=defaultDeps3){return(await worktreeSessionFiles(worktree,deps)).map((file)=>file.id)}async function latestTranscriptMtimeForWorktree4(worktree,deps=defaultDeps3){return(await worktreeSessionFiles(worktree,deps)).at(-1)?.mtimeMs??0}async function transcriptPath(sessionId,deps=defaultDeps3){if(!sessionId)return null;let entry=(await sessionIndex(deps)).find((e)=>e.sessionId===sessionId);if(!entry)return null;let file=wirePath(entry.sessionDir);return await deps.stat(file).then(()=>file).catch(()=>null)}var EMPTY_HISTORY={async listSessionIdsForWorktree(){return[]},async readHistory(){return[]},async transcriptPath(){return null},async latestTranscriptMtimeForWorktree(){return 0}},claudeHistoryReader={async listSessionIdsForWorktree(worktree){return[...await listSessionFilesForWorktree(worktree)].sort((a,b)=>a.mtimeMs-b.mtimeMs).map((f)=>f.sessionId)},readHistory:(sessionId)=>readHistory2(sessionId),readUsageSnapshot:(sessionId)=>readUsageSnapshot(sessionId),async transcriptPath(sessionId,worktree){return(await listSessionFilesForWorktree(worktree)).find((f)=>f.sessionId===sessionId)?.path??null},latestTranscriptMtimeForWorktree:(worktree)=>latestTranscriptMtimeForWorktree2(worktree)},codexHistoryReader={listSessionIdsForWorktree:(worktree)=>listSessionIdsForWorktree(worktree),readHistory:(sessionId)=>readHistory(sessionId),readUsageSnapshot:async(sessionId)=>(await readHistoryWithMetrics(sessionId)).usageMetrics,transcriptPath:async(sessionId)=>await findRolloutFile(sessionId)??null,latestTranscriptMtimeForWorktree:(worktree)=>latestTranscriptMtimeForWorktree(worktree)},copilotHistoryReader={listSessionIdsForWorktree:(worktree)=>listSessionIdsForWorktree2(worktree),readHistory:(sessionId)=>readHistory3(sessionId),readUsageSnapshot:async(sessionId)=>(await readHistoryWithMetrics2(sessionId)).usageMetrics,async transcriptPath(sessionId){let dir=await findSessionDir(sessionId);return dir?path7.join(dir,"events.jsonl"):null},latestTranscriptMtimeForWorktree:(worktree)=>latestTranscriptMtimeForWorktree3(worktree)},kimiHistoryReader={listSessionIdsForWorktree:(worktree)=>listSessionIdsForWorktree3(worktree),readHistory:EMPTY_HISTORY.readHistory,transcriptPath:(sessionId)=>transcriptPath(sessionId),latestTranscriptMtimeForWorktree:(worktree)=>latestTranscriptMtimeForWorktree4(worktree)};import{existsSync}from"fs";import{mkdir as mkdir2,readFile,writeFile}from"fs/promises";import{homedir as homedir3}from"os";import{dirname,join as join2}from"path";var KIMI_HOOK_EVENT_MAP=[{event:"SessionStart",verb:"session-start"},{event:"UserPromptSubmit",verb:"turn-start"},{event:"Stop",verb:"turn-complete"},{event:"StopFailure",verb:"turn-failed"},{event:"Interrupt",verb:"turn-interrupted"},{event:"PermissionRequest",verb:"awaiting-input"},{event:"SessionEnd",verb:"session-end"},{event:"PreCompact",verb:"pre-compact"},{event:"PostCompact",verb:"post-compact"},{event:"SubagentStart",verb:"subagent-start"},{event:"SubagentStop",verb:"subagent-stop"},{event:"PreToolUse",verb:"tool-pre"},{event:"PostToolUse",verb:"tool-post"},{event:"PostToolUseFailure",verb:"tool-failed"}],KOBE_KIMI_HOOK_EVENTS=[...new Set(KIMI_HOOK_EVENT_MAP.map((e)=>e.event))],BLOCK_BEGIN="# >>> rove hooks",BLOCK_END="# <<< rove hooks",HOOK_TIMEOUT_SECONDS=10;function kimiConfigPath(home=homedir3()){return join2(vendorConfigHome("kimi",{env:(k)=>process.env[k],home:()=>home}),"config.toml")}function renderKimiHookBlock(inv=kobeHookInvocation(),opts={}){let lines=[BLOCK_BEGIN];for(let spec of KIMI_HOOK_EVENT_MAP){if(!opts.toolEvents&&GATED_TOOL_VERBS.has(spec.verb))continue;let command=quoteShellArgv([...inv,"hook",spec.verb,"--engine","kimi"]);if(lines.push("[[hooks]]"),lines.push(`event = ${JSON.stringify(spec.event)}`),spec.matcher)lines.push(`matcher = ${JSON.stringify(spec.matcher)}`);lines.push(`command = ${JSON.stringify(command)}`),lines.push(`timeout = ${HOOK_TIMEOUT_SECONDS}`),lines.push("")}return lines.push(BLOCK_END),lines.join(`
28
+ `)}function removeKimiHookBlock(content){let lines=content.split(`
29
+ `),out=[],inBlock=!1;for(let line of lines){if(line.trim()===BLOCK_BEGIN){if(inBlock=!0,out.length>0&&out[out.length-1]==="")out.pop();continue}if(inBlock){if(line.trim()===BLOCK_END)inBlock=!1;continue}out.push(line)}return out.join(`
30
+ `)}function mergeKimiHooks(content,install,inv=kobeHookInvocation(),opts={}){let base=removeKimiHookBlock(content);if(!install)return base;let trimmed=base.replace(/\n+$/,"");return`${trimmed.length>0?`${trimmed}
31
+
32
+ `:""}${renderKimiHookBlock(inv,opts)}
33
+ `}function kimiFailureDetail(payload){let type=typeof payload.error_type==="string"?payload.error_type:"",message=typeof payload.error_message==="string"?payload.error_message:"",note=type||void 0;return{failure:(()=>{if(type==="APIProviderRateLimitError"||message.includes("provider.rate_limit"))return"rate_limit";if(type==="APIProviderQuotaExhaustedError")return"rate_limit";if(message.includes("provider.auth_error"))return"billing";return"other"})(),...note?{note}:{}}}class KimiHookAdapter{vendor="kimi";supportsHooks(){return!0}globalSettingsPath(){return kimiConfigPath()}activityDetailFromPayload(kind,payload){if(kind==="turn-failed")return kimiFailureDetail(payload);if(kind==="awaiting-input")return{waiting:"permission"};if(kind==="tool-pre"||kind==="tool-post"||kind==="tool-failed")return{tool:{...typeof payload.tool_name==="string"?{name:payload.tool_name}:{}}};return}sessionFromPayload(payload){if(typeof payload.session_id!=="string"||!payload.session_id)return;return{sessionId:payload.session_id}}async installActivityHooks(settingsFilePath,opts={}){if(!existsSync(dirname(settingsFilePath)))return;await editTomlConfig(settingsFilePath,(cur)=>mergeKimiHooks(cur,!0,void 0,opts))}async removeActivityHooks(settingsFilePath){if(!existsSync(settingsFilePath))return;await editTomlConfig(settingsFilePath,(cur)=>mergeKimiHooks(cur,!1))}supportsWorktreeSync(){return!1}async removeWorktreeSyncHook(){}async removeWorktreeWatchHook(){}}async function editTomlConfig(path8,transform){try{let current="";try{current=await readFile(path8,"utf8")}catch(error){if(!(error&&typeof error==="object"&&("code"in error)&&error.code==="ENOENT"))return}let next=transform(current);if(next===current)return;await mkdir2(dirname(path8),{recursive:!0}),await writeFile(path8,next)}catch{}}var KIMI_SCREEN_MANIFEST={rules:[{state:"blocked",all:["\u21B5 confirm"],any:["approve","reject","revise"]},{state:"blocked",all:["\u2191\u2193 navigate","esc exit"]},{state:"blocked",all:["\u2191\u2193 select","esc cancel"]},{state:"working",lineRegex:["^\\s*(\uD83C\uDF15|\uD83C\uDF16|\uD83C\uDF17|\uD83C\uDF18|\uD83C\uDF11|\uD83C\uDF12|\uD83C\uDF13|\uD83C\uDF14)","^\\s*[\\u2800-\\u28FF]+\\s*(thinking|working|using )"]}],composerEmpty:[{bottomLines:2,all:[">"],lineRegex:["^\\s*\u2502?\\s*>\\s*[\u2026]?\\s*\u2502?\\s*$"]}]};import{createHash as createHash2}from"crypto";import{mkdirSync as mkdirSync2,realpathSync,writeFileSync as writeFileSync2}from"fs";import path8 from"path";function resolvedWorktree(worktreePath){try{return realpathSync(worktreePath)}catch{return worktreePath}}function kimiTrustFilePath(worktreePath,home){let resolved=resolvedWorktree(worktreePath),hash=createHash2("sha256").update(resolved).digest("hex").slice(0,12),dir=path8.basename(resolved).toLowerCase();return path8.join(vendorConfigHome("kimi",vendorWriteHomeDeps(home)),"workspace-trust",`wd_${dir}_${hash}`)}function trustKimiWorktree(worktreePath,home){let file=kimiTrustFilePath(worktreePath,home);mkdirSync2(path8.dirname(file),{recursive:!0,mode:448});try{writeFileSync2(file,JSON.stringify({root:resolvedWorktree(worktreePath),trustedAt:Date.now()}),{mode:384,flag:"wx"})}catch(error){if(!(error instanceof Error&&("code"in error)&&error.code==="EEXIST"))throw error}}import{stat as stat5}from"fs/promises";class EngineTurnDetector{supportsCompletionMarkers(){return!0}async latestCompletion(worktree){return(await this.latestActivity(worktree)).marker}async latestActivityInFile(_transcriptPath){return null}}function createEngineTurnDetector(vendor){return engineEntry(vendor).createTurnDetector()}var statFile=(path9)=>stat5(path9).catch(()=>null);function completionReader(deps,parse2){let cache3=new Map;return async(path9,knownMtime)=>{let info=deps.statFile?await deps.statFile(path9):null;if(deps.statFile&&!info)return null;let mtimeMs=info?.mtimeMs??knownMtime??await(deps.statMtimeMs??(async(p)=>(await statFile(p))?.mtimeMs??0))(path9);if(!info&&knownMtime===void 0&&mtimeMs===0)return null;let key=info?`${info.dev}:${info.ino}:${info.size}:${info.mtimeMs}:${info.ctimeMs}`:String(mtimeMs),hit=cache3.get(path9);if(mtimeMs>0&&hit?.key===key)return hit.scan;let raw;try{raw=await deps.readFile(path9)}catch{return cache3.delete(path9),null}if(raw===null)return cache3.delete(path9),null;let scan={marker:parse2(raw,path9,mtimeMs),mtimeMs};if(cache3.delete(path9),cache3.set(path9,{key,scan}),cache3.size>8){let oldest=cache3.keys().next().value;if(oldest!==void 0)cache3.delete(oldest)}return scan}}var defaultClaudeDeps={listSessionFiles:(worktree)=>listSessionFilesForWorktree(worktree),readFile:readTextFileIfRegular,statFile};class ClaudeTurnDetector extends EngineTurnDetector{deps;vendor="claude";readCompletion;constructor(deps=defaultClaudeDeps){super();this.deps=deps;this.readCompletion=completionReader(deps,latestClaudeCompletionMarkerFromJsonl)}async latestActivity(worktree){let files=await this.deps.listSessionFiles(worktree),mtimeMs=files[0]?.mtimeMs??0,latest=null;for(let file of files.slice(0,4)){let marker=(await this.readCompletion(file.path,file.mtimeMs))?.marker;if(marker&&(!latest||marker.timestampMs>latest.timestampMs))latest=marker}return{marker:latest,mtimeMs}}latestActivityInFile(transcriptPath2){return this.readCompletion(transcriptPath2)}}var defaultCodexDeps={findLatestRollout:(worktree)=>findLatestRolloutForWorktree(worktree),readFile:readTextFileIfRegular,statFile};class CodexTurnDetector extends EngineTurnDetector{deps;vendor="codex";readCompletion;constructor(deps=defaultCodexDeps){super();this.deps=deps;this.readCompletion=completionReader(deps,latestCodexCompletionMarkerFromJsonl)}latestActivityInFile(transcriptPath2){return this.readCompletion(transcriptPath2)}async latestActivity(worktree){if(!worktree)return{marker:null,mtimeMs:0};let found=await this.deps.findLatestRollout(worktree);return found?await this.readCompletion(found.path,found.mtimeMs)??{marker:null,mtimeMs:0}:{marker:null,mtimeMs:0}}}class UnknownTurnDetector extends EngineTurnDetector{vendor;constructor(vendor){super();this.vendor=vendor}supportsCompletionMarkers(){return!1}async latestActivity(){return{marker:null,mtimeMs:0}}}var CLAUDE_TURN_END_STOP_REASONS=new Set(["end_turn","stop_sequence","max_tokens","refusal"]);function latestClaudeCompletionMarkerFromJsonl(raw,sourceId="claude",fallbackMtimeMs=0){let latest=null,lineNo=0;for(let line of raw.split(`
34
+ `)){lineNo++;let record=parseJsonLine(line);if(!record)continue;let inner=isObject9(record.message)?record.message:record;if(inner.role!=="assistant")continue;if(typeof inner.stop_reason!=="string")continue;if(!CLAUDE_TURN_END_STOP_REASONS.has(inner.stop_reason))continue;let timestampMs=timestampFromRecord(record,fallbackMtimeMs),marker={id:`claude:${sourceId}:${timestampMs}:${lineNo}`,timestampMs,source:"claude"};if(!latest||marker.timestampMs>=latest.timestampMs)latest=marker}return latest}var CODEX_ROLLOUT_DONE_EVENTS=new Set(["task_complete","turn_complete","turn_aborted"]);function isCodexCompletionRecord(record){if(record.type==="turn.completed")return!0;if(record.type!=="event_msg")return!1;let payload=isObject9(record.payload)?record.payload:void 0;return typeof payload?.type==="string"&&CODEX_ROLLOUT_DONE_EVENTS.has(payload.type)}function latestCodexCompletionMarkerFromJsonl(raw,sourceId="codex"){let latest=null,lineNo=0;for(let line of raw.split(`
35
+ `)){lineNo++;let record=parseJsonLine(line);if(!record||!isCodexCompletionRecord(record))continue;let timestampMs=timestampFromRecord(record,0),marker={id:`codex:${sourceId}:${timestampMs}:${lineNo}`,timestampMs,source:"codex"};if(!latest||marker.timestampMs>=latest.timestampMs)latest=marker}return latest}function parseJsonLine(line){if(!isJsonlLineWithinBound(line))return null;let trimmed=line.trim();if(!trimmed)return null;try{let parsed=JSON.parse(trimmed);return isObject9(parsed)?parsed:null}catch{return null}}function timestampFromRecord(record,fallback){let ts=typeof record.timestamp==="string"?Date.parse(record.timestamp):Number.NaN;return Number.isFinite(ts)?ts:fallback}function isObject9(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}var BUILTIN_ENGINES={claude:{vendor:"claude",builtin:!0,displayName:claudeIdentity.shortName,defaultCommand:["claude"],history:claudeHistoryReader,detectAccount:(deps)=>detectClaudeAccount(deps),createHookAdapter:()=>new ClaudeHookAdapter,createTurnDetector:()=>new ClaudeTurnDetector,capabilities:claudeCapabilities,identity:claudeIdentity,trustWorktree:trustClaudeWorktree,terminalTitle:{ownsStatus:!0,statusPrefixes:["\u2733","\u2802","\u2810","\u25D0","\u25D1"],workingPrefixes:["\u2802","\u2810","\u25D0","\u25D1"]},sessionIdentity:{pinFlag:"--session-id",sessionControlFlags:["--session-id","--resume","-r","--continue","-c","--from-pr"],resumeArgv:(base,id)=>[...base,"--resume",id],forkArgv:(base,sourceId,newId)=>{let forked=[...base,"--resume",sourceId,"--fork-session"];return newId?[...forked,"--session-id",newId]:forked}},quotaUsage:()=>fetchClaudeQuotaUsage(),readTurns:readClaudeTurns,screenManifest:CLAUDE_SCREEN_MANIFEST},codex:{vendor:"codex",builtin:!0,displayName:codexIdentity.shortName,defaultCommand:["codex"],effortLevels:["none","low","medium","high","xhigh","max"],effortArgv:(base,level)=>[...base,"-c",`model_reasoning_effort=${level}`],history:codexHistoryReader,detectAccount:(deps)=>detectCodexAccount(deps),createHookAdapter:()=>new CodexHookAdapter,createTurnDetector:()=>new CodexTurnDetector,capabilities:codexCapabilities,identity:codexIdentity,trustWorktree:trustCodexWorktree,readTurns:readCodexTurns,screenManifest:CODEX_SCREEN_MANIFEST,terminalTitle:{ownsStatus:!0,launchArgs:["-c",'tui.terminal_title=["activity","thread-title"]'],statusPrefixes:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],workingPrefixes:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],sessionIdFromTitle:codexSessionIdFromTitle},sessionIdentity:{resumeArgv:(base,id)=>{let[bin,...rest]=base;return bin?[bin,"resume",...rest,id]:base},forkArgv:(base,sourceId)=>{let[bin,...rest]=base;return bin?[bin,"fork",...rest,sourceId]:null}},quotaUsage:()=>fetchCodexQuotaUsage()},copilot:{vendor:"copilot",builtin:!0,displayName:"Copilot",defaultCommand:["copilot"],history:copilotHistoryReader,detectAccount:(deps)=>detectCopilotAccount(deps),createHookAdapter:()=>new NoopHookAdapter("copilot"),createTurnDetector:()=>new UnknownTurnDetector("copilot"),trustWorktree:trustCopilotWorktree,screenManifest:COPILOT_SCREEN_MANIFEST},kimi:{vendor:"kimi",builtin:!0,displayName:"Kimi",defaultCommand:["kimi"],firstMessageDelivery:"paste",processNames:["kimi-co"],trustWorktree:trustKimiWorktree,history:kimiHistoryReader,detectAccount:(deps)=>detectKimiAccount(deps),createHookAdapter:()=>new KimiHookAdapter,createTurnDetector:()=>new UnknownTurnDetector("kimi"),sessionIdentity:{sessionControlFlags:["-S","--session","-c","--continue"],resumeArgv:(base,id)=>[...base,"-S",id]},screenManifest:KIMI_SCREEN_MANIFEST}};function stripStatusPrefix(title,prefixes){for(let prefix of[...prefixes].sort((a,b)=>b.length-a.length)){if(!title.startsWith(prefix))continue;let rest=title.slice(prefix.length).trimStart();if(rest.length===0)return title;return rest}return title}function titleTurnHint(config,title){let working=config?.workingPrefixes;if(config?.ownsStatus!==!0||!working||working.length===0)return null;let trimmed=title.trim();if(trimmed.length===0)return null;return working.some((prefix)=>trimmed.startsWith(prefix))?"working":"rest"}function titleSessionId(config,title){let trimmed=title.trim();if(!trimmed)return null;return config?.sessionIdFromTitle?.(trimmed)??null}function titleIsPlaceholder(config,title){return titleSessionId(config,title)!==null}function customEngineEntry(vendor){return{vendor,builtin:!1,displayName:vendor,defaultCommand:[vendor],history:EMPTY_HISTORY,createHookAdapter:()=>new NoopHookAdapter(vendor),createTurnDetector:()=>new UnknownTurnDetector(vendor)}}function engineEntry(vendor){if(isBuiltinVendor(vendor))return BUILTIN_ENGINES[vendor];let custom=customEngineEntry(vendor);return isContribEngine(vendor)?contribEngineEntry(vendor,custom):custom}function identifiableEngineIds(){return[...BUILTIN_VENDORS,...CONTRIB_ENGINE_IDS,...pluginEngineIds()]}function supportsStructuredHistory(vendor){return engineEntry(vendor).history.readHistory!==EMPTY_HISTORY.readHistory}var ALL_STATUS_PREFIXES=[...new Set(Object.values(BUILTIN_ENGINES).flatMap((entry)=>entry.terminalTitle?.statusPrefixes??[]))];function engineStatusPrefixes(vendor){let declared=engineEntry(vendor).terminalTitle?.statusPrefixes;return declared&&declared.length>0?declared:ALL_STATUS_PREFIXES}function stripEngineStatusPrefix(title,vendor){return stripStatusPrefix(title,vendor?engineStatusPrefixes(vendor):ALL_STATUS_PREFIXES)}function engineTitleTurnHint(vendor,title){return titleTurnHint(engineEntry(vendor).terminalTitle,title)}function engineSessionIdFromTitle(vendor,title){return titleSessionId(engineEntry(vendor).terminalTitle,title)}function isEnginePlaceholderTitle(title,vendor){return titleIsPlaceholder(engineEntry(vendor).terminalTitle,title)}function getCapabilities(vendor){return engineEntry(vendor).capabilities}function vendorsWithQuotaProbe(){return Object.values(BUILTIN_ENGINES).filter((entry)=>entry.quotaUsage).map((entry)=>entry.vendor)}function vendorsWithTurnReader(){return Object.values(BUILTIN_ENGINES).filter((entry)=>entry.readTurns).map((entry)=>entry.vendor)}function createEngineHookAdapter(vendor){return engineEntry(vendor).createHookAdapter()}class NoopHookAdapter{vendor;constructor(vendor){this.vendor=vendor}supportsHooks(){return!1}globalSettingsPath(){return""}activityDetailFromPayload(){return}sessionFromPayload(){return}async installActivityHooks(){}async removeActivityHooks(){}supportsWorktreeSync(){return!1}async removeWorktreeSyncHook(){}async removeWorktreeWatchHook(){}}
36
+ export{createEngineHookAdapter,createEngineTurnDetector,engineEntry,identifiableEngineIds,supportsStructuredHistory,engineStatusPrefixes,stripEngineStatusPrefix,engineTitleTurnHint,engineSessionIdFromTitle,isEnginePlaceholderTitle,getCapabilities,vendorsWithQuotaProbe,vendorsWithTurnReader};
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{logDaemonInfo}from"./chunk-1cjd7h8p.js";import{resolveKobeSpawn,spawnDetachedDaemon,testDaemonResponds}from"./chunk-5bn91n19.js";import{isProcessAlive,stopDaemonProcess}from"./chunk-pdh5w4ht.js";import{readPidFile}from"./chunk-4wwx51m5.js";import{KobeDaemonClient}from"./chunk-79gqh5p2.js";import{defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-x760j10f.js";import{spawn}from"child_process";import{existsSync}from"fs";import{rename,rm}from"fs/promises";import{basename,delimiter,dirname,join,resolve}from"path";import{fileURLToPath}from"url";var PTY_HOST_START_ARGS=["pty-host"],PTY_HOST_NODE_BUNDLE="pty-host-node.mjs",PTY_HOST_NODE_DEV_CACHE="../../.cache/pty-host-node.mjs",PTY_HOST_NODE_ENTRY="../daemon/pty-host-node-entry.ts";function resolveNodeBinary(env=process.env,exists=existsSync,platform=process.platform){let dirs=(env.PATH??env.Path??"").split(delimiter).filter((dir)=>dir.length>0),suffixes=platform==="win32"?(env.PATHEXT??".EXE;.CMD;.BAT").split(";").filter((ext)=>ext.length>0):[""];for(let dir of dirs)for(let suffix of suffixes){let candidate=join(dir,`node${suffix}`);if(exists(candidate))return candidate}return null}async function bundleWithBun(entry,outFile,io){let{build,rename:move,discard}=io??{build:(config)=>Bun.build(config),rename,discard:(path)=>rm(path,{force:!0})},staging=`${outFile}.${process.pid}.tmp`,built=await build({entrypoints:[entry],outdir:dirname(staging),target:"node",format:"esm",naming:basename(staging),external:["node-pty"]});if(!built.success)return await discard(staging).catch(()=>{}),built;return await move(staging,outFile),built}async function resolveNodePtyHostSpawn(deps={}){let platform=deps.platform??process.platform;if(platform!=="win32")return null;let here=deps.moduleDir??dirname(fileURLToPath(import.meta.url)),exists=deps.exists??existsSync,bundle=deps.bundle??bundleWithBun,node=resolveNodeBinary(deps.env??process.env,exists,platform);if(!node)throw Error("Rove: the Windows PTY host runs under node, but no node was found on PATH. "+"Install Node.js (https://nodejs.org) and restart Rove \u2014 engine and terminal sessions cannot start without it.");let packaged=resolve(here,PTY_HOST_NODE_BUNDLE);if(exists(packaged))return[node,packaged];let entry=resolve(here,PTY_HOST_NODE_ENTRY);if(!exists(entry))throw Error(`Rove: no Windows PTY host found (looked for ${packaged} and ${entry})`);let cache=resolve(here,PTY_HOST_NODE_DEV_CACHE),built=await bundle(entry,cache);if(!built.success)throw Error(`Rove: could not build the Windows PTY host \u2014 ${built.logs.map(String).join("; ")}`);return[node,cache]}var BUSY_PTY_HOST_GRACE_MS=15000;async function liveChildCount(pid){try{let proc=spawn("/bin/ps",["-A","-o","ppid="],{stdio:["ignore","pipe","ignore"]});return(await new Promise((done)=>{let out="";proc.stdout.on("data",(chunk)=>{out+=String(chunk)}),proc.on("close",()=>done(out)),proc.on("error",()=>done(""))})).split(`
3
+ `).filter((row)=>Number(row.trim())===pid).length}catch{return 0}}async function ensurePtyHostReachable(){let socketPath=defaultPtyHostSocketPath();if(await testDaemonResponds(socketPath))return socketPath;let hostPid=await readPidFile(defaultPtyHostPidPath());if(hostPid!==null&&hostPid!==process.pid&&isProcessAlive(hostPid)){let deadline2=Date.now()+BUSY_PTY_HOST_GRACE_MS;while(Date.now()<deadline2){if(await new Promise((resolveTimer)=>setTimeout(resolveTimer,250)),await testDaemonResponds(socketPath))return socketPath;if(!isProcessAlive(hostPid))break}if(isProcessAlive(hostPid)){let sessions=await liveChildCount(hostPid);if(sessions>0)throw Error(`rove: the pty host (pid ${hostPid}) is not answering but still holds ${sessions} live session(s) \u2014 refusing to restart it, which would kill every engine running in them. Inspect it with \`rove api pty-list\`, or kill ${hostPid} yourself once you have accepted losing those sessions.`)}}await stopDaemonProcess(socketPath,defaultPtyHostPidPath()).catch(()=>{});let[command,...args]=await resolveNodePtyHostSpawn()??resolveKobeSpawn(PTY_HOST_START_ARGS);spawnDetachedDaemon(command??"",args,process.env,defaultPtyHostLogPath());let deadline=Date.now()+5000;while(Date.now()<deadline){if(await testDaemonResponds(socketPath))return socketPath;await new Promise((resolveTimer)=>setTimeout(resolveTimer,100))}throw Error(`rove: pty host did not start (or stayed wedged) at ${socketPath}`)}async function sweepPtyHostSessions(liveTaskIds,homeDir){let client=new KobeDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let{sessions}=await client.request("pty.list"),currentTasks;for(let session of sessions){if(!currentTasks){let ids=liveTaskIds();if(ids===null)return;currentTasks=new Set(ids)}if(currentTasks.has(session.key.split("::")[0]??session.key))continue;if(!session.generation){logDaemonInfo("pty-sweep",`skipped ${session.key}: host has no session generation; restart it when sessions can be interrupted`);continue}await client.request("pty.kill",{key:session.key,expectedGeneration:session.generation}),currentTasks=void 0}}catch{}finally{client.close()}}async function ptyHostHasLiveSessions(homeDir){let client=new KobeDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let result=await client.request("pty.list");if(!Array.isArray(result.sessions)||result.sessions.some((s)=>typeof s.alive!=="boolean"))return null;return result.sessions.some((s)=>s.alive)}catch(err){if(err instanceof Error&&"code"in err&&(err.code==="ENOENT"||err.code==="ECONNREFUSED")){let pid=await readPidFile(defaultPtyHostPidPath(homeDir));return pid!==null&&isProcessAlive(pid)?null:!1}return null}finally{client.close()}}
4
+ export{resolveNodeBinary,ensurePtyHostReachable,sweepPtyHostSessions,ptyHostHasLiveSessions};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{formatBytes}from"./chunk-my20q579.js";import{applyFixes,daemonRestartFix,defaultFixRuntime,engineTabsManualFix,humanOnlyFix,killOrphansManualFix,noEngineFix,probeEngines,probeGit,reinstallManualFix,resetManualFix,skillInstallFix,spawnHelperFix}from"./chunk-bj59a9mg.js";import"./chunk-np07kccr.js";import"./chunk-bzz4ta7g.js";import"./chunk-mrwee8sj.js";import"./chunk-q6579rbz.js";import"./chunk-hg5x2wr0.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-dqndd97s.js";import"./chunk-0kn7xxqm.js";import{kobeSkillState,skillInstallCommand}from"./chunk-g1ybdgad.js";import"./chunk-vyb5a2rh.js";import"./chunk-jyv82gf0.js";import{CURRENT_VERSION,package_default}from"./chunk-02y7hdy3.js";import{resolveNodeBinary}from"./chunk-20pt9yqh.js";import"./chunk-q7dr9eh6.js";import"./chunk-jvxh93nz.js";import"./chunk-b99tf0jr.js";import{t}from"./chunk-b8d162tf.js";import"./chunk-8g456mmt.js";import"./chunk-sdyzxayr.js";import{isStaleInstallError,resolveKobeSpawn}from"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import{readPidFile}from"./chunk-4wwx51m5.js";import{KobeDaemonClient}from"./chunk-79gqh5p2.js";import{isForeignDaemonHome}from"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-gbasmvsc.js";import"./chunk-yhcz2d2r.js";import"./chunk-df7qe9y7.js";import"./chunk-gwcneg6c.js";import"./chunk-7nhdvr5v.js";import"./chunk-2fypr41w.js";import"./chunk-k3ksts6g.js";import"./chunk-gjf604bb.js";import{readableLegacyIndexPath}from"./chunk-qtke4x42.js";import"./chunk-xy8be792.js";import"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import{homeDir,kvStatePath,roveStateDir}from"./chunk-6dn6h640.js";import"./chunk-h82kzdsn.js";import{activeCliName}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import{LEGACY_KOBE_STATE_DIR_BASENAME}from"./chunk-cb2fpajx.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-yk2ha5yj.js";import"./chunk-rxvbm4vt.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import{__require}from"./chunk-wqfp8d9w.js";import{existsSync,readFileSync as readFileSync2,statSync as statSync2}from"fs";import{join as join2}from"path";var MIN_BUN_VERSION=package_default.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0";function parseBunVersion(raw){return raw.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function isBunAtLeast(raw,minimum=MIN_BUN_VERSION){let found=parseBunVersion(raw),floor=parseBunVersion(minimum);if(!found||!floor)return!0;let a=found.split(".").map(Number),b=floor.split(".").map(Number);for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(av!==bv)return av>bv}return!0}function classifyHookChannel(input){let total=0,hooked=0;for(let tabs of Object.values(input.tabs))for(let entry of Object.values(tabs))if(total++,entry.source==="hook")hooked++;if(total===0)return{kind:"no-tabs"};if(hooked===0)return{kind:"down",totalTabs:total};return{kind:"live",hookTabs:hooked,totalTabs:total}}function hookChannelDoctorLines(verdict,input,cliName){if(verdict.kind==="no-tabs")return["hooks: \u2014 no engine tabs yet (nothing to check)"];if(verdict.kind==="live")return[`hooks: \u2713 engine hook channel live (${verdict.hookTabs}/${verdict.totalTabs} tab(s) hook-sourced)`];let out=[`hooks: \u2717 NO hook events reaching the daemon (0/${verdict.totalTabs} tab(s) hook-sourced)`," badges fall back to a ~10s poll, so activity looks seconds late",` daemon socket: ${input.socketPath}`];return out.push(' \u2192 compare with an engine tab\'s own path: `ps eww -p <engine-pid> | tr " " "\\n" | grep DAEMON_SOCKET_PATH`',` \u2192 restart the engine tabs (they may hold a stale socket path), or run \`${cliName} daemon restart\``,` \u2192 debug one hook directly: \`KOBE_HOOK_DEBUG=1 echo '{}' | ${cliName} hook turn-start --engine claude\``),out}import{readdirSync,statSync}from"fs";import{createRequire}from"module";import{dirname,join}from"path";function installedSpawnHelpers(){let pkg;try{pkg=dirname(createRequire(import.meta.url).resolve("node-pty/package.json"))}catch{return[]}let prebuilds=join(pkg,"prebuilds"),arches;try{arches=readdirSync(prebuilds).filter((name)=>name.startsWith("darwin-"))}catch{return[]}let helpers=[];for(let arch of arches){let path=join(prebuilds,arch,"spawn-helper");try{helpers.push({path,executable:(statSync(path).mode&64)!==0})}catch{}}return helpers}function spawnHelperDoctorLines(helpers){let broken=helpers.filter((helper)=>!helper.executable).map((helper)=>helper.path);if(helpers.length===0)return{lines:["node-pty: ? no darwin spawn-helper found next to node-pty"],broken};if(broken.length===0)return{lines:[`node-pty: \u2713 spawn-helper executable (${helpers.length} arch)`],broken};return{lines:["node-pty: \u2717 spawn-helper is not executable \u2014 every node-pty PTY spawn fails",...broken.map((path)=>` ${path}`),` \u2192 chmod 755 ${broken.join(" ")}`],broken}}import{readFileSync}from"fs";var PTY_MARKER="KOBE_TERMINAL_PTY=1";async function run(argv){try{let proc=Bun.spawn([...argv],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),[stdout,code]=await Promise.all([new Response(proc.stdout).text().catch(()=>""),proc.exited]);return{code,stdout}}catch{return{code:127,stdout:""}}}function parsePsRows(output){let rows=[];for(let line of output.split(`
2
+ import{formatBytes}from"./chunk-my20q579.js";import{applyFixes,daemonRestartFix,defaultFixRuntime,engineTabsManualFix,humanOnlyFix,killOrphansManualFix,noEngineFix,probeEngines,probeGit,reinstallManualFix,resetManualFix,skillInstallFix,spawnHelperFix}from"./chunk-yfg503fr.js";import"./chunk-x39pv7rx.js";import"./chunk-6kz81dkc.js";import"./chunk-aeq5xmtq.js";import"./chunk-5wzap7r2.js";import"./chunk-r2pztgm6.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-dqndd97s.js";import"./chunk-rz8zs7j8.js";import{kobeSkillState,skillInstallCommand}from"./chunk-579zz8df.js";import"./chunk-vyb5a2rh.js";import"./chunk-d393z1mj.js";import{CURRENT_VERSION,package_default}from"./chunk-gtkejmxx.js";import{resolveNodeBinary}from"./chunk-e8493db0.js";import"./chunk-gzf4dfg6.js";import"./chunk-jvxh93nz.js";import"./chunk-1cjd7h8p.js";import"./chunk-b99tf0jr.js";import{t}from"./chunk-zaxdx0wd.js";import"./chunk-sexavazm.js";import"./chunk-sdyzxayr.js";import{isStaleInstallError,resolveKobeSpawn}from"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import{readPidFile}from"./chunk-4wwx51m5.js";import{KobeDaemonClient}from"./chunk-79gqh5p2.js";import{isForeignDaemonHome}from"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-x3gch5nw.js";import"./chunk-e7t4xpr9.js";import"./chunk-n4dmwkfa.js";import"./chunk-w7zv47mp.js";import"./chunk-gwcneg6c.js";import"./chunk-m370e00b.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-87y9qjcm.js";import"./chunk-m57cv76y.js";import{readableLegacyIndexPath}from"./chunk-dmdqnet6.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import{homeDir,kvStatePath,roveStateDir}from"./chunk-6dn6h640.js";import"./chunk-h82kzdsn.js";import{activeCliName}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import{LEGACY_KOBE_STATE_DIR_BASENAME}from"./chunk-cb2fpajx.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-yk2ha5yj.js";import"./chunk-rxvbm4vt.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import{__require}from"./chunk-wqfp8d9w.js";import{existsSync,readFileSync as readFileSync2,statSync as statSync2}from"fs";import{join as join2}from"path";var MIN_BUN_VERSION=package_default.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0";function parseBunVersion(raw){return raw.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function isBunAtLeast(raw,minimum=MIN_BUN_VERSION){let found=parseBunVersion(raw),floor=parseBunVersion(minimum);if(!found||!floor)return!0;let a=found.split(".").map(Number),b=floor.split(".").map(Number);for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(av!==bv)return av>bv}return!0}function classifyHookChannel(input){let total=0,hooked=0;for(let tabs of Object.values(input.tabs))for(let entry of Object.values(tabs))if(total++,entry.source==="hook")hooked++;if(total===0)return{kind:"no-tabs"};if(hooked===0)return{kind:"down",totalTabs:total};return{kind:"live",hookTabs:hooked,totalTabs:total}}function hookChannelDoctorLines(verdict,input,cliName){if(verdict.kind==="no-tabs")return["hooks: \u2014 no engine tabs yet (nothing to check)"];if(verdict.kind==="live")return[`hooks: \u2713 engine hook channel live (${verdict.hookTabs}/${verdict.totalTabs} tab(s) hook-sourced)`];let out=[`hooks: \u2717 NO hook events reaching the daemon (0/${verdict.totalTabs} tab(s) hook-sourced)`," badges fall back to a ~10s poll, so activity looks seconds late",` daemon socket: ${input.socketPath}`];return out.push(' \u2192 compare with an engine tab\'s own path: `ps eww -p <engine-pid> | tr " " "\\n" | grep DAEMON_SOCKET_PATH`',` \u2192 restart the engine tabs (they may hold a stale socket path), or run \`${cliName} daemon restart\``,` \u2192 debug one hook directly: \`KOBE_HOOK_DEBUG=1 echo '{}' | ${cliName} hook turn-start --engine claude\``),out}import{readdirSync,statSync}from"fs";import{createRequire}from"module";import{dirname,join}from"path";function installedSpawnHelpers(){let pkg;try{pkg=dirname(createRequire(import.meta.url).resolve("node-pty/package.json"))}catch{return[]}let prebuilds=join(pkg,"prebuilds"),arches;try{arches=readdirSync(prebuilds).filter((name)=>name.startsWith("darwin-"))}catch{return[]}let helpers=[];for(let arch of arches){let path=join(prebuilds,arch,"spawn-helper");try{helpers.push({path,executable:(statSync(path).mode&64)!==0})}catch{}}return helpers}function spawnHelperDoctorLines(helpers){let broken=helpers.filter((helper)=>!helper.executable).map((helper)=>helper.path);if(helpers.length===0)return{lines:["node-pty: ? no darwin spawn-helper found next to node-pty"],broken};if(broken.length===0)return{lines:[`node-pty: \u2713 spawn-helper executable (${helpers.length} arch)`],broken};return{lines:["node-pty: \u2717 spawn-helper is not executable \u2014 every node-pty PTY spawn fails",...broken.map((path)=>` ${path}`),` \u2192 chmod 755 ${broken.join(" ")}`],broken}}import{readFileSync}from"fs";var PTY_MARKER="KOBE_TERMINAL_PTY=1";async function run(argv){try{let proc=Bun.spawn([...argv],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),[stdout,code]=await Promise.all([new Response(proc.stdout).text().catch(()=>""),proc.exited]);return{code,stdout}}catch{return{code:127,stdout:""}}}function parsePsRows(output){let rows=[];for(let line of output.split(`
3
3
  `)){let parts=line.trim().split(/\s+/);if(parts.length<6)continue;let[pid,ppid,pgid]=[parts[0],parts[1],parts[2]].map((value)=>Number.parseInt(value??"",10)),rssKb=Number.parseInt(parts[4]??"",10);if(!Number.isFinite(pid)||!Number.isFinite(ppid)||!Number.isFinite(pgid)||!Number.isFinite(rssKb))continue;rows.push({pid,ppid,pgid,etime:parts[3]??"",rssKb,command:parts.slice(5).join(" ")})}return rows}function pidAlive(pid,rows){return rows.some((row)=>row.pid===pid)}function orphanCandidates(rows,selfPgid,liveSessionPids){return rows.filter((row)=>row.ppid===1&&row.pgid!==selfPgid&&!liveSessionPids.has(row.pgid)&&!pidAlive(row.pgid,rows))}async function markedPids(pids){let marked=new Set;if(pids.length===0)return marked;if(process.platform==="linux"){for(let pid of pids)try{if(readFileSync(`/proc/${pid}/environ`,"utf8").split("\x00").includes(PTY_MARKER))marked.add(pid)}catch{}return marked}let result=await run(["ps","eww","-o","pid=,command=","-p",pids.join(",")]),marker=new RegExp(`(^|\\s)${PTY_MARKER}(\\s|$)`);for(let line of result.stdout.split(`
4
4
  `)){let pid=Number.parseInt(line.trim().split(/\s+/)[0]??"",10);if(Number.isFinite(pid)&&marker.test(line))marked.add(pid)}return marked}async function ownPgid(){let result=await run(["ps","-o","pgid=","-p",String(process.pid)]),pgid=Number.parseInt(result.stdout.trim(),10);return Number.isFinite(pgid)?pgid:-1}async function collectOrphans(liveSessionPids){if(process.platform==="win32")return{orphans:[],error:null};let ps=await run(["ps","-A","-o","pid=,ppid=,pgid=,etime=,rss=,command="]);if(ps.code!==0)return{orphans:[],error:`ps exited ${ps.code}`};let rows=parsePsRows(ps.stdout),candidates=orphanCandidates(rows,await ownPgid(),liveSessionPids),marked=await markedPids(candidates.map((row)=>row.pid));return{orphans:candidates.filter((row)=>marked.has(row.pid)),error:null}}function formatMb(rssKb){return`${(rssKb/1024).toFixed(0)} MB`}function orphanDoctorLines(orphans,error,cliName,killing=!1){if(error)return[`orphans: \u2717 could not inspect the process table \u2014 ${error}`];if(orphans.length===0)return["orphans: \u2713 none \u2014 no processes left behind by a dead PTY session"];let totalMb=orphans.reduce((sum,row)=>sum+row.rssKb,0)/1024,lines=[`orphans: \u26A0 ${orphans.length} process(es) outlived the PTY session that spawned them (${totalMb.toFixed(0)} MB RSS)`," each is reparented to init, carries Rove's PTY marker, and its process"," group leader is gone \u2014 no live task owns them"];for(let row of[...orphans].sort((a,b)=>b.rssKb-a.rssKb))lines.push(` pid ${row.pid} (group ${row.pgid}) up ${row.etime}, ${formatMb(row.rssKb)}: ${row.command.slice(0,90)}`);if(!killing)lines.push(` \u2192 \`${cliName} doctor --kill-orphans\` ends those process groups (SIGTERM, then SIGKILL)`," read the list first: something you backgrounded from a Rove terminal and then"," closed the tab on looks exactly like a leak, and doctor cannot tell them apart");return lines}var GROUP_EXIT_GRACE_MS=2000,GROUP_POLL_MS=100;function groupAlive(pgid){try{return process.kill(-pgid,0),!0}catch(err){return err.code!=="ESRCH"}}async function killOrphanGroups(orphans){let groups=[...new Set(orphans.map((row)=>row.pgid))];for(let pgid of groups)try{process.kill(-pgid,"SIGTERM")}catch{}let deadline=Date.now()+GROUP_EXIT_GRACE_MS,survivors=groups.filter(groupAlive);while(survivors.length>0&&Date.now()<deadline)await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),survivors=survivors.filter(groupAlive);for(let pgid of survivors)try{process.kill(-pgid,"SIGKILL")}catch{}return await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),{groups,survivors:survivors.filter(groupAlive)}}function multiplexerLabel(env){if(env.TMUX)return"tmux";if(env.ZELLIJ)return"zellij";if(env.STY)return"screen";return"no"}function terminalEnvLines(env){let show=(v)=>v&&v.length>0?v:"(unset)",program=env.TERM_PROGRAM?`${env.TERM_PROGRAM}${env.TERM_PROGRAM_VERSION?` v${env.TERM_PROGRAM_VERSION}`:""}`:"(unset)";return[`terminal: TERM=${show(env.TERM)} TERM_PROGRAM=${program} COLORTERM=${show(env.COLORTERM)}`,` running inside a multiplexer: ${multiplexerLabel(env)}`]}function parseKittyProbeReply(data){let kitty=data.match(/\x1b\[\?(\d+)u/);if(kitty?.[1]!==void 0)return{kind:"supported",flags:Number.parseInt(kitty[1],10)};if(/\x1b\[\?[\d;]*c/.test(data))return{kind:"unsupported"};return null}function kittyProbeLine(result){switch(result.kind){case"supported":return` kitty keyboard protocol: \u2713 answered (flags=${result.flags})`;case"unsupported":return[" kitty keyboard protocol: \u2717 not supported \u2014 legacy key path"," (ctrl+h/ctrl+j arrive as C0 backspace/linefeed bytes; the"," split chords ctrl+\\ and ctrl+= cannot be encoded at all)"].join(`
5
5
  `);case"no-response":return" kitty keyboard protocol: ? no reply (terminal ignored both the kitty query and DA1)";case"skipped":return` kitty keyboard protocol: skipped (${result.reason})`}}async function probeKittyKeyboard(timeoutMs=300){let stdin=process.stdin;if(!stdin.isTTY||!process.stdout.isTTY)return{kind:"skipped",reason:"not an interactive terminal"};let wasRaw=stdin.isRaw===!0,buffer="";return await new Promise((resolve)=>{let done=!1,finish=(result)=>{if(done)return;if(done=!0,clearTimeout(timer),stdin.off("data",onData),stdin.pause(),!wasRaw)stdin.setRawMode(!1);resolve(result)},onData=(chunk)=>{buffer+=chunk.toString("latin1");let decided=parseKittyProbeReply(buffer);if(decided)finish(decided)},timer=setTimeout(()=>finish({kind:"no-response"}),timeoutMs);stdin.setRawMode(!0),stdin.resume(),stdin.on("data",onData),process.stdout.write("\x1B[?u\x1B[c")})}async function terminalDoctorLines(){return[...terminalEnvLines(process.env),kittyProbeLine(await probeKittyKeyboard())]}var CLI_NAME=activeCliName();function isProcessAlive(pid){try{return process.kill(pid,0),!0}catch(err){return err.code==="EPERM"}}async function requestIfReachable(socketPath,name){let client=new KobeDaemonClient(socketPath);try{return await client.request(name,{})}catch{return null}finally{client.close()}}function fmtDuration(ms){let seconds=Math.floor(ms/1000);if(seconds<60)return`${seconds}s`;let minutes=Math.floor(seconds/60);if(minutes<60)return`${minutes}m ${seconds%60}s`;return`${Math.floor(minutes/60)}h ${minutes%60}m`}function describeFile(path){try{let stat=statSync2(path);return`present (${formatBytes(stat.size)}, modified ${stat.mtime.toISOString()})`}catch{return"absent"}}function taskCount(path){try{let parsed=JSON.parse(readFileSync2(path,"utf8"));return Array.isArray(parsed.tasks)?parsed.tasks.length:null}catch{return null}}function tailFile(path,count){try{return readFileSync2(path,"utf8").split(`
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{PLUGIN_MANIFEST_FILENAMES,currentPluginPlatform,loadPluginRegistry,parsePluginManifest,pluginCheckoutDir,pluginConfigDir,pluginManifestPath,pluginStateDir,pluginsRootDir,savePluginRegistry,supportsPlatform,upsertPluginEntry}from"./chunk-jyv82gf0.js";import{CURRENT_VERSION,compareSemver}from"./chunk-02y7hdy3.js";import{spawnSync}from"child_process";import{cpSync,existsSync,mkdirSync,readFileSync,renameSync,rmSync}from"fs";import{mkdtempSync}from"fs";import{basename,join,resolve}from"path";import{createInterface}from"readline/promises";var GITHUB_SPEC_RE=/^([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)(\/.+)?$/;class PluginCliError extends Error{}function fail(message){throw new PluginCliError(message)}function readManifestAt(root){let path=pluginManifestPath(root);if(!path)fail(`no ${PLUGIN_MANIFEST_FILENAMES.join(" or ")} found at ${root}`);let source=readFileSync(path,"utf8");return{...parsePluginManifest(source,basename(path)),manifestPath:path,manifestSource:source}}function checkVersionGate(parsed){let min=parsed.manifest.minKobeVersion;if(compareSemver(CURRENT_VERSION,min)<0)fail(`plugin requires Rove >= ${min} (this is ${CURRENT_VERSION}); update Rove first`)}function printPreview(parsed,source){let m=parsed.manifest;console.log(`
2
+ import{PLUGIN_MANIFEST_FILENAMES,currentPluginPlatform,loadPluginRegistry,parsePluginManifest,pluginCheckoutDir,pluginConfigDir,pluginManifestPath,pluginStateDir,pluginsRootDir,savePluginRegistry,supportsPlatform,upsertPluginEntry}from"./chunk-d393z1mj.js";import{CURRENT_VERSION,compareSemver}from"./chunk-gtkejmxx.js";import{spawnSync}from"child_process";import{cpSync,existsSync,mkdirSync,readFileSync,renameSync,rmSync}from"fs";import{mkdtempSync}from"fs";import{basename,join,resolve}from"path";import{createInterface}from"readline/promises";var GITHUB_SPEC_RE=/^([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)(\/.+)?$/;class PluginCliError extends Error{}function fail(message){throw new PluginCliError(message)}function readManifestAt(root){let path=pluginManifestPath(root);if(!path)fail(`no ${PLUGIN_MANIFEST_FILENAMES.join(" or ")} found at ${root}`);let source=readFileSync(path,"utf8");return{...parsePluginManifest(source,basename(path)),manifestPath:path,manifestSource:source}}function checkVersionGate(parsed){let min=parsed.manifest.minKobeVersion;if(compareSemver(CURRENT_VERSION,min)<0)fail(`plugin requires Rove >= ${min} (this is ${CURRENT_VERSION}); update Rove first`)}function printPreview(parsed,source){let m=parsed.manifest;console.log(`
3
3
  ${m.name} (${m.id}) v${m.version} \u2014 ${m.description??"no description"}`),console.log(`source: ${source}`);let show=(label,commands)=>{for(let c of commands)console.log(` ${label}: ${c.command.join(" ")}`)};show("build",m.build),show("startup",m.startup);for(let a of m.actions)console.log(` action ${a.id}: ${a.command.join(" ")}`);for(let e of m.events)console.log(` on ${e.on}: ${e.command.join(" ")}`);for(let w of parsed.warnings)console.log(` warning: ${w}`);console.log("")}async function confirmOrBail(yes){if(yes)return;if(!process.stdin.isTTY)fail("refusing to install without confirmation in a non-interactive terminal; pass --yes");let rl=createInterface({input:process.stdin,output:process.stdout}),answer=(await rl.question("Install this plugin and run its build commands? [y/N] ")).trim().toLowerCase();if(rl.close(),answer!=="y"&&answer!=="yes")fail("aborted")}function git(args,cwd){if(spawnSync("git",args,{cwd,stdio:["ignore","inherit","inherit"]}).status!==0)fail(`git ${args[0]} failed`)}function runBuildCommands(parsed,root){let platform=currentPluginPlatform();for(let[i,step]of parsed.manifest.build.entries()){if(!supportsPlatform(step,parsed.manifest,platform))continue;let[cmd,...args]=step.command;console.log(`build[${i}]: ${step.command.join(" ")}`);let res=spawnSync(cmd,args,{cwd:root,stdio:["ignore","inherit","inherit"]});if(res.status!==0)fail(`build[${i}] failed (exit ${res.status??"spawn error"}); plugin not registered`)}}function makeStagingDir(){let root=pluginsRootDir();return mkdirSync(root,{recursive:!0}),mkdtempSync(join(root,".staging-"))}function movePluginTree(from,to){try{renameSync(from,to)}catch(err){if(err.code!=="EXDEV")throw err;cpSync(from,to,{recursive:!0,verbatimSymlinks:!0}),rmSync(from,{recursive:!0,force:!0})}}function register(entry){savePluginRegistry(upsertPluginEntry(loadPluginRegistry(),entry)),mkdirSync(pluginConfigDir(entry.id),{recursive:!0,mode:448}),mkdirSync(pluginStateDir(entry.id),{recursive:!0,mode:448})}async function installPlugin(spec,opts){let match=spec.match(GITHUB_SPEC_RE);if(!match)fail(`install takes GitHub shorthand (owner/repo[/subdir]), got \`${spec}\``);let[,owner,repo,subdirRaw]=match,subdir=subdirRaw?.replace(/^\//,""),tmp=makeStagingDir();try{let url=`https://github.com/${owner}/${repo}.git`;if(console.log(`cloning ${url}${opts.ref?` @ ${opts.ref}`:""}`),opts.ref)git(["clone","--quiet",url,tmp]),git(["checkout","--quiet",opts.ref],tmp);else git(["clone","--quiet","--depth","1",url,tmp]);let rootInClone=subdir?join(tmp,subdir):tmp,parsed=readManifestAt(rootInClone);checkVersionGate(parsed);let id=parsed.manifest.id,existing=loadPluginRegistry().plugins.find((p)=>p.id===id);if(existing?.source.kind==="link")fail(`\`${id}\` is locally linked at ${existing.root}; unlink it first`);if(!supportsPlatform({},parsed.manifest,currentPluginPlatform()))fail(`plugin declares platforms [${parsed.manifest.platforms?.join(", ")}]; this machine is unsupported`);printPreview(parsed,`github.com/${owner}/${repo}${subdir?`/${subdir}`:""}`),await confirmOrBail(opts.yes),runBuildCommands(parsed,rootInClone);let manifestPath=pluginManifestPath(rootInClone);if(!manifestPath)fail("manifest disappeared during build; aborting");if(manifestPath!==parsed.manifestPath)fail("manifest changed during build; aborting");if(readFileSync(manifestPath,"utf8")!==parsed.manifestSource)fail("manifest changed during build; aborting");let checkout=pluginCheckoutDir(id);return rmSync(checkout,{recursive:!0,force:!0}),mkdirSync(join(checkout,".."),{recursive:!0}),movePluginTree(tmp,checkout),register({id,source:{kind:"github",spec},root:subdir?join(checkout,subdir):checkout,enabled:!0,version:parsed.manifest.version,installedAt:Date.now()}),console.log(`installed ${id} v${parsed.manifest.version}`),id}finally{rmSync(tmp,{recursive:!0,force:!0})}}function linkPlugin(dir){let root=resolve(dir);if(!existsSync(root))fail(`no such directory: ${root}`);let parsed=readManifestAt(root);checkVersionGate(parsed);let id=parsed.manifest.id;if(loadPluginRegistry().plugins.find((p)=>p.id===id)?.source.kind==="github")fail(`\`${id}\` is installed from GitHub; uninstall it before linking a local copy`);for(let w of parsed.warnings)console.log(`warning: ${w}`);if(!supportsPlatform({},parsed.manifest,currentPluginPlatform()))console.log(`warning: declares platforms [${parsed.manifest.platforms?.join(", ")}]; nothing will run on this machine`);register({id,source:{kind:"link"},root,enabled:!0,version:parsed.manifest.version,installedAt:Date.now()}),console.log(`linked ${id} v${parsed.manifest.version} \u2192 ${root}`)}
4
4
  export{PluginCliError,installPlugin,linkPlugin};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{RemoteExecHost,getKeychainPassword,isKeychainSupported,remoteKeychainRef,setKeychainPassword}from"./chunk-1kktfmtg.js";import"./chunk-2fypr41w.js";import{addRemoteRepo,isRemoteProjectsEnabled}from"./chunk-k3ksts6g.js";import"./chunk-gjf604bb.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import{remoteControlSocketPath}from"./chunk-6dn6h640.js";import{activeCliName}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";import{createInterface}from"readline";var CLI_NAME=activeCliName(),USAGE=`Usage: ${CLI_NAME} add --remote --host <host> --user <user> --path <basePath>
2
+ import{RemoteExecHost,getKeychainPassword,isKeychainSupported,remoteKeychainRef,setKeychainPassword}from"./chunk-1kktfmtg.js";import"./chunk-2fypr41w.js";import{addRemoteRepo,isRemoteProjectsEnabled}from"./chunk-87y9qjcm.js";import"./chunk-m57cv76y.js";import"./chunk-a3a9gdc4.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import{remoteControlSocketPath}from"./chunk-6dn6h640.js";import{activeCliName}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";import{createInterface}from"readline";var CLI_NAME=activeCliName(),USAGE=`Usage: ${CLI_NAME} add --remote --host <host> --user <user> --path <basePath>
3
3
  [--port N] [--key [path] | --password]
4
4
 
5
5
  Register an experimental SSH-backed project. Worktrees are created on <host>
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{applyOnboardingChoices,detectShell,envReadyForTasks,installCompletions,maybeRunOnboarding}from"./chunk-p9vkwnb8.js";import"./chunk-yfg503fr.js";import"./chunk-x39pv7rx.js";import"./chunk-jy6nd23p.js";import"./chunk-579zz8df.js";import"./chunk-gtkejmxx.js";import"./chunk-gzf4dfg6.js";import"./chunk-jvxh93nz.js";import"./chunk-zaxdx0wd.js";import"./chunk-sexavazm.js";import"./chunk-sdyzxayr.js";import"./chunk-x3gch5nw.js";import"./chunk-e7t4xpr9.js";import"./chunk-n4dmwkfa.js";import"./chunk-w7zv47mp.js";import"./chunk-gwcneg6c.js";import"./chunk-m370e00b.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-87y9qjcm.js";import"./chunk-m57cv76y.js";import"./chunk-dmdqnet6.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import"./chunk-6dn6h640.js";import"./chunk-h82kzdsn.js";import"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{maybeRunOnboarding,installCompletions,envReadyForTasks,detectShell,applyOnboardingChoices};
@@ -6,6 +6,6 @@ ${EXPORT_USAGE}
6
6
  `),process.exit(2)}function parseFormat(args){let format="json";for(let i=0;i<args.length;i++){let a=args[i];if(a==="--json")format="json";else if(a==="--csv")format="csv";else if(a==="--format"){let v=args[++i];if(v===void 0)usageError("--format requires a value (json, csv, or table)");format=coerceFormat(v)}else if(a.startsWith("--format="))format=coerceFormat(a.slice(9));else usageError(`unexpected argument "${a}"`)}return format}function coerceFormat(value){if(value==="json"||value==="csv"||value==="table")return value;usageError(`unknown format "${value}" (expected json, csv, or table)`)}function csvCell(value){if(/[",\r\n]/.test(value))return`"${value.replace(/"/g,'""')}"`;return value}function renderCsv(rows){let lines=[COLUMNS.join(",")];for(let row of rows)lines.push(COLUMNS.map((c)=>csvCell(row[c])).join(","));return lines.join(`
7
7
  `)}function padCell(cell,width){return cell+" ".repeat(Math.max(0,width-displayWidth(cell)))}function renderTable(rows){let widths={};for(let c of COLUMNS)widths[c]=Math.max(displayWidth(c),...rows.map((r)=>displayWidth(r[c])));let line=(cells)=>COLUMNS.map((c)=>padCell(cells[c],widths[c])).join(" ").trimEnd(),header={};for(let c of COLUMNS)header[c]=c;return[line(header),...rows.map(line)].join(`
8
8
  `)}function renderExport(tasks,format){let rows=tasks.map(toRow);if(format==="json")return JSON.stringify(rows,null,2);if(format==="csv")return renderCsv(rows);return renderTable(rows)}async function runExportSubcommand(args){if(args.includes("--help")||args.includes("-h")||args.includes("help")){process.stdout.write(`${EXPORT_USAGE}
9
- `);return}let format=parseFormat(args),{TaskIndexStore}=await import("./chunk-ncsgawg7.js"),store=new TaskIndexStore;await store.load();let tasks=store.list();if(tasks.length===0&&format==="table"){process.stdout.write(`no tasks
9
+ `);return}let format=parseFormat(args),{TaskIndexStore}=await import("./chunk-k9skkhzs.js"),store=new TaskIndexStore;await store.load();let tasks=store.list();if(tasks.length===0&&format==="table"){process.stdout.write(`no tasks
10
10
  `);return}process.stdout.write(`${renderExport(tasks,format)}
11
11
  `)}export{runExportSubcommand,renderExport};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{isDev}from"./chunk-6dn6h640.js";import{fileURLToPath}from"url";var package_default={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.151",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",keywords:["terminal","tui","cli","multiplexer","ai-agents","coding-agent","ai-coding-assistant","agentic-ai","parallel-agents","git-worktree","claude-code","codex","llm","developer-tools"],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://rove.run",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:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts",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","plugin-sandbox":"bun run scripts/plugin-sandbox.ts"},"//":"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","smol-toml":"^1.7.1",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.19","@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","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]};var CURRENT_VERSION=package_default.version,PACKAGE_NAME=package_default.name;function repoSlug(){let url=package_default.repository?.url;if(!url)return null;let m=url.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!m||!m[1]||!m[2])return null;return`${m[1]}/${m[2]}`}var UPDATE_SCRIPT_URL="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",UPDATE_COMMAND=`curl -fsSL ${UPDATE_SCRIPT_URL} | sh`;function owningNpmPrefix(modulePath=fileURLToPath(import.meta.url)){let at=modulePath.indexOf("/lib/node_modules/");if(at<=0)return null;return modulePath.slice(0,at)}function recommendedGlobalInstallCommand(prefix=owningNpmPrefix()){let target=`${PACKAGE_NAME}@latest`;return prefix===null?`npm install -g ${target}`:`npm install -g --prefix ${prefix} ${target}`}var BREAKING_VERSIONS=[];function breakingVersionsCrossed(from,to,breaking=BREAKING_VERSIONS){let[lo,hi]=compareSemver(from,to)<=0?[from,to]:[to,from];return breaking.filter((b)=>compareSemver(b,lo)>0&&compareSemver(b,hi)<=0)}var FETCH_TIMEOUT_MS=3000,RELEASE_CHANNELS=["latest","nightly"],DEFAULT_RELEASE_CHANNEL="latest";function channelOf(version=CURRENT_VERSION){return prereleaseOf(version)?.split(".")[0]==="nightly"?"nightly":DEFAULT_RELEASE_CHANNEL}async function fetchLatestFromRegistry(packageName,channel){let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let encoded=packageName.replace("/","%2F"),res=await fetch(`https://registry.npmjs.org/${encoded}/${channel}`,{signal:ctrl.signal,headers:{accept:"application/json"}});if(!res.ok)return null;let body=await res.json();if(typeof body.version!=="string")return null;return body.version}catch{return null}finally{clearTimeout(timer)}}function isNewerSemver(latest,current){let core=compareSemver(latest,current);if(core!==0)return core>0;return comparePrerelease(prereleaseOf(latest),prereleaseOf(current))>0}function prereleaseOf(version){let dash=version.indexOf("-");return dash===-1?void 0:version.slice(dash+1)||void 0}function comparePrerelease(a,b){if(a===b)return 0;if(a===void 0)return 1;if(b===void 0)return-1;let aParts=a.split("."),bParts=b.split(".");for(let i=0;i<Math.max(aParts.length,bParts.length);i++){let av=aParts[i],bv=bParts[i];if(av===void 0)return-1;if(bv===void 0)return 1;if(av===bv)continue;let an=/^\d+$/.test(av)?Number.parseInt(av,10):null,bn=/^\d+$/.test(bv)?Number.parseInt(bv,10):null;if(an!==null&&bn!==null)return an>bn?1:-1;if(an!==null)return-1;if(bn!==null)return 1;return av>bv?1:-1}return 0}function compareSemver(aVersion,bVersion){let norm=(v)=>v.split("-")[0]??v,a=norm(aVersion).split(".").map((s)=>Number.parseInt(s,10)),b=norm(bVersion).split(".").map((s)=>Number.parseInt(s,10));for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(Number.isNaN(av)||Number.isNaN(bv))return 0;if(av>bv)return 1;if(av<bv)return-1}return 0}async function checkLatestVersion(opts={}){let channel=opts.channel??channelOf(),fake=process.env.KOBE_FAKE_UPDATE;if(fake)return{current:CURRENT_VERSION,latest:fake,hasUpdate:isNewerSemver(fake,CURRENT_VERSION),channel};if(isDev()&&!opts.force)return null;let latest=await fetchLatestFromRegistry(PACKAGE_NAME,channel);if(!latest)return null;return{current:CURRENT_VERSION,latest,hasUpdate:isNewerSemver(latest,CURRENT_VERSION),channel}}function versionFromTagName(tagName){if(typeof tagName!=="string")return null;return tagName.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function fetchReleaseNotes(version){let slug=repoSlug();if(!slug)return null;let tag=`v${version}`,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases/tags/${tag}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return null;let body=await res.json();if(typeof body.body!=="string"||typeof body.html_url!=="string")return null;return{body:body.body,url:body.html_url,version}}catch{return null}finally{clearTimeout(timer)}}async function fetchReleaseNotesRange(args){let slug=repoSlug();if(!slug)return[];let limit=args.limit??100,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string"||typeof release.body!=="string")return null;if(compareSemver(version,args.current)<=0)return null;if(compareSemver(version,args.latest)>0)return null;return{version,url:release.html_url,body:release.body}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}async function fetchReleaseSummaries(limit=12){let slug=repoSlug();if(!slug)return[];let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string")return null;return{version,url:release.html_url}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}function releasePageUrl(version){let slug=repoSlug();if(!slug)return null;return`https://github.com/${slug}/releases/tag/v${version}`}
3
+ export{package_default,CURRENT_VERSION,PACKAGE_NAME,repoSlug,UPDATE_SCRIPT_URL,UPDATE_COMMAND,owningNpmPrefix,recommendedGlobalInstallCommand,BREAKING_VERSIONS,breakingVersionsCrossed,RELEASE_CHANNELS,DEFAULT_RELEASE_CHANNEL,channelOf,isNewerSemver,compareSemver,checkLatestVersion,fetchReleaseNotes,fetchReleaseNotesRange,fetchReleaseSummaries,releasePageUrl};