@sma1lboy/rove 0.9.153 → 0.9.155

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 (139) hide show
  1. package/dist/cli/{chunk-pdh5w4ht.js → chunk-0dqdymwa.js} +1 -1
  2. package/dist/cli/{chunk-ybv02fyn.js → chunk-0ehnq0kz.js} +10 -9
  3. package/dist/cli/{chunk-2kvvykg1.js → chunk-0pfrfrd1.js} +1 -1
  4. package/dist/cli/chunk-116dnbbd.js +2 -0
  5. package/dist/cli/{chunk-86bjqmg1.js → chunk-1760hrgn.js} +1 -1
  6. package/dist/cli/chunk-1re31mma.js +2 -0
  7. package/dist/cli/{chunk-9zb2wkfr.js → chunk-25hxhtdr.js} +1 -1
  8. package/dist/cli/chunk-2nadch8n.js +2 -0
  9. package/dist/cli/{chunk-5bn91n19.js → chunk-2vgmx7rh.js} +1 -1
  10. package/dist/cli/{chunk-73qrq7bg.js → chunk-32h9htyh.js} +1 -1
  11. package/dist/cli/{chunk-aeq5xmtq.js → chunk-3ntf6q51.js} +1 -1
  12. package/dist/cli/{chunk-s8eh3cf1.js → chunk-3wj69b0a.js} +1 -1
  13. package/dist/cli/{chunk-q2p5cnse.js → chunk-3xh813fz.js} +1 -1
  14. package/dist/cli/{chunk-7z9cqycv.js → chunk-4gjr08g0.js} +1 -1
  15. package/dist/cli/chunk-4pmd0mxp.js +4 -0
  16. package/dist/cli/chunk-4q1mkrp4.js +10 -0
  17. package/dist/cli/chunk-4rfdprnn.js +2 -0
  18. package/dist/cli/{chunk-qdp0w20h.js → chunk-53c27xa8.js} +1 -1
  19. package/dist/cli/{chunk-ke95ebrz.js → chunk-5f80ggc3.js} +1 -1
  20. package/dist/cli/{chunk-tw2t78nk.js → chunk-5hc2959x.js} +2 -2
  21. package/dist/cli/{chunk-rsqx358z.js → chunk-5v893waj.js} +1 -1
  22. package/dist/cli/{chunk-7gy0rnrs.js → chunk-5w9s18qb.js} +1 -1
  23. package/dist/cli/{chunk-6s6pne9d.js → chunk-5x7bqhp7.js} +1 -1
  24. package/dist/cli/{chunk-8gsqypg8.js → chunk-6123622n.js} +2 -2
  25. package/dist/cli/chunk-624j6yb8.js +2 -0
  26. package/dist/cli/{chunk-3gvqnsty.js → chunk-6aa78w6b.js} +3 -3
  27. package/dist/cli/{chunk-5snrwe65.js → chunk-6pt23vas.js} +1 -1
  28. package/dist/cli/{chunk-81cysjk5.js → chunk-85t004k4.js} +1 -1
  29. package/dist/cli/chunk-8kaqpb7t.js +2 -0
  30. package/dist/cli/{chunk-efdphna5.js → chunk-92yjtx23.js} +2 -2
  31. package/dist/cli/{chunk-gc25wht3.js → chunk-aak5ttgt.js} +1 -1
  32. package/dist/cli/{chunk-7s82zpcv.js → chunk-acz5t040.js} +1 -1
  33. package/dist/cli/{chunk-nywh3yb9.js → chunk-axfn4f28.js} +1 -1
  34. package/dist/cli/chunk-b0b0ej4m.js +2 -0
  35. package/dist/cli/{chunk-8r1pnch1.js → chunk-bwyskwer.js} +1 -1
  36. package/dist/cli/{chunk-51y7sjhe.js → chunk-c43g3qcb.js} +1 -1
  37. package/dist/cli/{chunk-xtr7ks02.js → chunk-c9zxw37m.js} +1 -1
  38. package/dist/cli/{chunk-56m4hk0p.js → chunk-cad0kv20.js} +1 -1
  39. package/dist/cli/chunk-caqpt09m.js +3 -0
  40. package/dist/cli/{chunk-07k2njwk.js → chunk-ch9b1d5y.js} +1 -1
  41. package/dist/cli/chunk-d17zkmw9.js +4 -0
  42. package/dist/cli/{chunk-dv7rxr77.js → chunk-dd93y7gx.js} +1 -1
  43. package/dist/cli/{chunk-2z90jxcn.js → chunk-de751t37.js} +1 -1
  44. package/dist/cli/chunk-de7wzktx.js +2 -0
  45. package/dist/cli/{chunk-37gnmm2m.js → chunk-ds9qf1w1.js} +1 -1
  46. package/dist/cli/{chunk-svpn3av1.js → chunk-e17gszac.js} +1 -1
  47. package/dist/cli/{chunk-nm802jgt.js → chunk-e18sn615.js} +1 -1
  48. package/dist/cli/chunk-ekgcpkcs.js +3 -0
  49. package/dist/cli/{chunk-8ad0ba2n.js → chunk-esk240e5.js} +2 -2
  50. package/dist/cli/{chunk-yshnare4.js → chunk-exggdhpt.js} +1 -1
  51. package/dist/cli/{chunk-cb2fpajx.js → chunk-g56kvet6.js} +1 -1
  52. package/dist/cli/{chunk-z83wxkg6.js → chunk-g90z5s39.js} +2 -2
  53. package/dist/cli/{chunk-9gz7jmgq.js → chunk-gkfd073t.js} +1 -1
  54. package/dist/cli/{chunk-z2aqaabp.js → chunk-h82956f7.js} +1 -1
  55. package/dist/cli/{chunk-ap5bjaq8.js → chunk-j1fvzjc1.js} +1 -1
  56. package/dist/cli/{chunk-grh6dvfv.js → chunk-k2ckx8zw.js} +1 -1
  57. package/dist/cli/chunk-k3mjej0g.js +2 -0
  58. package/dist/cli/{chunk-90wcrcj5.js → chunk-k9ev77fp.js} +2 -2
  59. package/dist/cli/{chunk-c6mthex1.js → chunk-ksbvcxc3.js} +1 -1
  60. package/dist/cli/{chunk-deejtpcr.js → chunk-kt1ppyje.js} +1 -1
  61. package/dist/cli/{chunk-v9p6gxm0.js → chunk-m8v407e1.js} +1 -1
  62. package/dist/cli/{chunk-vpzvcxc1.js → chunk-max057d8.js} +1 -1
  63. package/dist/cli/chunk-mcdv19rs.js +3 -0
  64. package/dist/cli/{chunk-dgsrf048.js → chunk-mh0nwzma.js} +4 -4
  65. package/dist/cli/chunk-mhs6yywx.js +2 -0
  66. package/dist/cli/{chunk-z4c6bmw0.js → chunk-mkkp4c5t.js} +2 -2
  67. package/dist/cli/{chunk-d809qqsk.js → chunk-mp8v5gn8.js} +1 -1
  68. package/dist/cli/{chunk-4wwx51m5.js → chunk-mqqnk8w7.js} +1 -1
  69. package/dist/cli/chunk-mr790xv9.js +2 -0
  70. package/dist/cli/{chunk-4tzgma89.js → chunk-msr1xtay.js} +1 -1
  71. package/dist/cli/chunk-mw8mjcg3.js +2 -0
  72. package/dist/cli/{chunk-g5nz190n.js → chunk-n7n12868.js} +1 -1
  73. package/dist/cli/{chunk-31crt0e4.js → chunk-nhexcv3a.js} +1 -1
  74. package/dist/cli/{chunk-mb5m7ex7.js → chunk-nhpfz161.js} +1 -1
  75. package/dist/cli/{chunk-ed1y1wtm.js → chunk-nqqtnvf7.js} +3 -3
  76. package/dist/cli/{chunk-e8493db0.js → chunk-nt525m04.js} +1 -1
  77. package/dist/cli/{chunk-kd870mfy.js → chunk-nt7zs4wd.js} +1 -1
  78. package/dist/cli/chunk-nx7ahbsg.js +2 -0
  79. package/dist/cli/{chunk-yk2ha5yj.js → chunk-nyv7a76k.js} +1 -1
  80. package/dist/cli/{chunk-ef11h2am.js → chunk-p7s4xwgx.js} +1 -1
  81. package/dist/cli/{chunk-rkt1qjec.js → chunk-ptjc5mtc.js} +1 -1
  82. package/dist/cli/{chunk-dwfv6dxg.js → chunk-q2tfsp59.js} +1 -1
  83. package/dist/cli/{chunk-y9ksfpbp.js → chunk-qed3p2s0.js} +1 -1
  84. package/dist/cli/{chunk-zaxdx0wd.js → chunk-qgd78nwt.js} +1 -1
  85. package/dist/cli/{chunk-4c220qpj.js → chunk-qv64n4v7.js} +4 -4
  86. package/dist/cli/chunk-r05r01nv.js +3 -0
  87. package/dist/cli/{chunk-x7ssay77.js → chunk-r3ev6gtj.js} +2 -2
  88. package/dist/cli/{chunk-3bfm4hrs.js → chunk-r3k9rbwm.js} +1 -1
  89. package/dist/cli/chunk-r639wna1.js +2 -0
  90. package/dist/cli/chunk-rc668r26.js +2 -0
  91. package/dist/cli/{chunk-fd7swjnq.js → chunk-s1ngmmg3.js} +1 -1
  92. package/dist/cli/{chunk-5wzap7r2.js → chunk-s83t3w1e.js} +1 -1
  93. package/dist/cli/{chunk-45j1qqdf.js → chunk-s9ts2h6w.js} +1 -1
  94. package/dist/cli/{chunk-ea1r26pa.js → chunk-sfv15era.js} +1 -1
  95. package/dist/cli/{chunk-z1e1bsv5.js → chunk-t27t2x9b.js} +1 -1
  96. package/dist/cli/{chunk-c1xp9qx6.js → chunk-t3z4etp5.js} +1 -1
  97. package/dist/cli/{chunk-mmd7zehs.js → chunk-t7xhb2jx.js} +1 -1
  98. package/dist/cli/{chunk-1a7ctg07.js → chunk-t9w68ha3.js} +1 -1
  99. package/dist/cli/{chunk-a4h476hv.js → chunk-vj2vdx3w.js} +1 -1
  100. package/dist/cli/chunk-wn2d39a2.js +2 -0
  101. package/dist/cli/{chunk-xjskp76m.js → chunk-xkg5kbgm.js} +1 -1
  102. package/dist/cli/{chunk-d393z1mj.js → chunk-xt3wcpsd.js} +1 -1
  103. package/dist/cli/{chunk-79gqh5p2.js → chunk-xxn3m0z5.js} +1 -1
  104. package/dist/cli/{chunk-h5jhdjv7.js → chunk-yfy6031g.js} +1 -1
  105. package/dist/cli/{chunk-ewdhz3dv.js → chunk-yhwb91e4.js} +1 -1
  106. package/dist/cli/{chunk-pxtx1gcf.js → chunk-yts6vqd3.js} +1 -1
  107. package/dist/cli/{chunk-5c3d1y0r.js → chunk-zd3wmj4d.js} +1 -1
  108. package/dist/cli/{chunk-b9h2ywc7.js → chunk-zqfbyq0a.js} +1 -1
  109. package/dist/cli/{chunk-2wdnqzbf.js → chunk-ztkmwsn3.js} +4 -4
  110. package/dist/cli/index.js +7 -7
  111. package/dist/cli/kobe-run.js +1 -1
  112. package/dist/cli/kobe.js +6 -6
  113. package/dist/cli/pty-host-node.mjs +6 -6
  114. package/dist/cli/rove-run.js +1 -1
  115. package/dist/cli/rove.js +6 -6
  116. package/package.json +1 -1
  117. package/dist/cli/chunk-4gaqhq8t.js +0 -2
  118. package/dist/cli/chunk-55s4zykj.js +0 -2
  119. package/dist/cli/chunk-5hjs0374.js +0 -2
  120. package/dist/cli/chunk-6t2zhxmq.js +0 -2
  121. package/dist/cli/chunk-7h7tqran.js +0 -2
  122. package/dist/cli/chunk-81h96pha.js +0 -2
  123. package/dist/cli/chunk-8ddjfc2v.js +0 -4
  124. package/dist/cli/chunk-9j7507ap.js +0 -2
  125. package/dist/cli/chunk-aq912vvw.js +0 -3
  126. package/dist/cli/chunk-arf294te.js +0 -2
  127. package/dist/cli/chunk-evmfa4v5.js +0 -2
  128. package/dist/cli/chunk-fna6sxe4.js +0 -5
  129. package/dist/cli/chunk-j1a890dg.js +0 -2
  130. package/dist/cli/chunk-j2j1kq3m.js +0 -2
  131. package/dist/cli/chunk-kpf3yaj9.js +0 -3
  132. package/dist/cli/chunk-m6n0mkye.js +0 -2
  133. package/dist/cli/chunk-makzf3q1.js +0 -9
  134. package/dist/cli/chunk-nzy3yafz.js +0 -2
  135. package/dist/cli/chunk-p8hzr9m6.js +0 -2
  136. package/dist/cli/chunk-r94jdy8g.js +0 -2
  137. package/dist/cli/chunk-sexavazm.js +0 -3
  138. package/dist/cli/chunk-x760j10f.js +0 -3
  139. package/dist/cli/chunk-xve4g8ct.js +0 -2
package/dist/cli/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- import{matchPathGlob}from"./chunk-kg11c1py.js";import{CURRENT_VERSION}from"./chunk-dv7rxr77.js";import{expandTilde}from"./chunk-4tzgma89.js";import{argvHasFlag}from"./chunk-jvxh93nz.js";import{connectIfRunning}from"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{rejectionReason}from"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import{coerceVendorId}from"./chunk-bq3fyc0p.js";import{activeCliName,prepareCliEnvironment}from"./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{__require}from"./chunk-wqfp8d9w.js";import{resolve as resolve2}from"path";function debugEnabled(env){return env.KOBE_DEBUG==="1"||env.ROVE_DEBUG==="1"}function failureSubject(cliName,argv){let verb=argv[2];return verb&&!verb.startsWith("-")&&!verb.includes("/")?`${cliName} ${verb}`:cliName}function summarizeCliGitError(message,cwd){if(!/not a git repository/i.test(message))return null;return`${cwd} is not a git repository \u2014 run this inside one, or pass a repo path.`}function formatCliFailure(err,opts){let subject=failureSubject(opts.cliName,opts.argv);if(debugEnabled(opts.env))return`${subject}: ${String(err instanceof Error?err.stack??err:err)}`;let raw=errorMessage(err);return`${subject}: ${summarizeCliGitError(raw,opts.cwd)??raw}`}var DYNAMIC_COMMANDS=new Map([["completions",async(args)=>{let{runCompletionsSubcommand}=await import("./chunk-7s82zpcv.js");await runCompletionsSubcommand(args)}],["export",async(args)=>{let{runExportSubcommand}=await import("./chunk-8gsqypg8.js");await runExportSubcommand(args)}],["repo",async(args)=>{let{runRepoSubcommand}=await import("./chunk-8ad0ba2n.js");await runRepoSubcommand(args)}],["api",async(args)=>{let{runApiSubcommand}=await import("./chunk-45j1qqdf.js");await runApiSubcommand(args)}],["update",async(args)=>{let{runUpdateSubcommand}=await import("./chunk-90wcrcj5.js");await runUpdateSubcommand(args)}],["theme",async(args)=>{let{runThemeSubcommand}=await import("./chunk-9gz7jmgq.js");await runThemeSubcommand(args)}],["feedback",async(args)=>{let{runFeedbackSubcommand}=await import("./chunk-qdp0w20h.js");await runFeedbackSubcommand(args)}],["daemon",async(args)=>{let{runDaemonSubcommand}=await import("./chunk-efdphna5.js");await runDaemonSubcommand(args)}],["doctor",async(args)=>{let{runDoctorSubcommand}=await import("./chunk-dgsrf048.js");await runDoctorSubcommand(args)}],["config",async(args)=>{let{runConfigSubcommand}=await import("./chunk-h5jhdjv7.js");await runConfigSubcommand(args)}],["reset",async(args)=>{let{runResetSubcommand}=await import("./chunk-2kvvykg1.js");await runResetSubcommand(args)}],["pty-host",async(args)=>{let{runPtyHostSubcommand}=await import("./chunk-xtr7ks02.js");await runPtyHostSubcommand(args)}],["skill",async(args)=>{let{runSkillSubcommand}=await import("./chunk-z4c6bmw0.js");await runSkillSubcommand(args)}],["plugin",async(args)=>{let{runPluginSubcommand}=await import("./chunk-3gvqnsty.js");await runPluginSubcommand(args)}],["hook",async(args)=>{let{runHookSubcommand}=await import("./chunk-7h7tqran.js");await runHookSubcommand(args)}]]);import{statSync}from"fs";import{resolve}from"path";async function openLocalOrchestrator(){let{TaskIndexStore}=await import("./chunk-j2j1kq3m.js"),{GitWorktreeManager}=await import("./chunk-6t2zhxmq.js"),{Orchestrator}=await import("./chunk-9j7507ap.js"),store=new TaskIndexStore;return await store.load(),new Orchestrator({store,worktrees:new GitWorktreeManager})}async function withDaemonOrLocal(bridge){let client=await connectIfRunning();if(client)try{return await bridge.daemon(client)}finally{client.close()}let orch=await openLocalOrchestrator();return bridge.local(orch)}function isPathLikeArg(arg){return arg==="."||arg===".."||arg.startsWith("./")||arg.startsWith("../")||arg.startsWith("/")||arg==="~"||arg.startsWith("~/")}async function projectRootFor(dir){let{isGitRepo,resolveRepoRoot}=await import("./chunk-d809qqsk.js"),{projectRejection}=await import("./chunk-c1xp9qx6.js"),top=resolveRepoRoot(dir);if(top!==dir)return null;return projectRejection(top,isGitRepo,"explicit")?null:top}async function runOpenDirectory(arg){let dir=resolve(process.cwd(),expandTilde(arg)),isDir=!1;try{isDir=statSync(dir).isDirectory()}catch{isDir=!1}if(!isDir)process.stderr.write(`${activeCliName()}: "${arg}" is not a directory (resolved to ${dir}).
4
- `),process.exit(1);let projectRoot=await projectRootFor(dir);await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-nzy3yafz.js");writeLastActiveTaskId(String(task.id))}});let{publishKobeTerminalTitle}=await import("./chunk-1tx1s5v6.js");publishKobeTerminalTitle();let{startTui}=await import("./chunk-xve4g8ct.js");await startTui()}function topLevelUsage(cliName=activeCliName()){return[`${cliName} ${CURRENT_VERSION}`,"",`Usage: ${cliName} [command] [options]`,"","Run with no command to launch PureTUI.",`Run \`${cliName} .\` (or \`${cliName} <path>\`) to open a directory as a standalone task.`,"","Commands:"," completions <shell> Generate shell completion script (bash/zsh/fish)"," add [path] Save a repo path for the new-task picker"," remove [path] Forget a saved project (inverse of add; non-destructive)"," adopt [glob] Import existing git worktrees as tasks"," export [--csv|--json] Print the task list (json/csv/table; daemon-free)"," repo <verb> Per-repo init script + first prompt (show|set|unset)",` api <verb> Scriptable RPC surface for agents (see \`${cliName} api --help\`)`," daemon <verb> Manage the daemon (start|stop|status|restart)"," doctor [--report|--fix] Diagnose daemon/PTY/engines/git; --fix walks the remedies",` config [--path] Open ${cliName}'s config file (state.json) in your editor`," reset [--hard] Stop runtimes; optionally wipe task/UI state"," theme <verb> Manage user themes (list|add|remove)",` skill <verb> Install the ${cliName} agent skill (install|status|command|print)`," plugin <verb> Install and run plugins (install|link|list|action|\u2026)"," feedback Send feedback to GitHub Discussions",` update [version|channel|list] Self-update ${cliName}, switch channel, or list versions`,"","Options:"," -v, --version Print version"," -h, --help Print this help"," --skill Print the agent skill file and exit"].join(`
3
+ import{matchPathGlob}from"./chunk-kg11c1py.js";import{CURRENT_VERSION}from"./chunk-dd93y7gx.js";import{expandTilde}from"./chunk-msr1xtay.js";import{argvHasFlag}from"./chunk-jvxh93nz.js";import{connectIfRunning}from"./chunk-2vgmx7rh.js";import"./chunk-0dqdymwa.js";import"./chunk-mqqnk8w7.js";import"./chunk-xxn3m0z5.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{rejectionReason}from"./chunk-3wj69b0a.js";import"./chunk-ch9b1d5y.js";import{coerceVendorId}from"./chunk-bq3fyc0p.js";import{activeCliName,prepareCliEnvironment}from"./chunk-p7s4xwgx.js";import"./chunk-4pmd0mxp.js";import"./chunk-g56kvet6.js";import"./chunk-k2ckx8zw.js";import"./chunk-pw6yfj10.js";import"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import{__require}from"./chunk-wqfp8d9w.js";import{resolve as resolve2}from"path";function debugEnabled(env){return env.KOBE_DEBUG==="1"||env.ROVE_DEBUG==="1"}function failureSubject(cliName,argv){let verb=argv[2];return verb&&!verb.startsWith("-")&&!verb.includes("/")?`${cliName} ${verb}`:cliName}function summarizeCliGitError(message,cwd){if(!/not a git repository/i.test(message))return null;return`${cwd} is not a git repository \u2014 run this inside one, or pass a repo path.`}function formatCliFailure(err,opts){let subject=failureSubject(opts.cliName,opts.argv);if(debugEnabled(opts.env))return`${subject}: ${String(err instanceof Error?err.stack??err:err)}`;let raw=errorMessage(err);return`${subject}: ${summarizeCliGitError(raw,opts.cwd)??raw}`}var DYNAMIC_COMMANDS=new Map([["completions",async(args)=>{let{runCompletionsSubcommand}=await import("./chunk-acz5t040.js");await runCompletionsSubcommand(args)}],["export",async(args)=>{let{runExportSubcommand}=await import("./chunk-6123622n.js");await runExportSubcommand(args)}],["repo",async(args)=>{let{runRepoSubcommand}=await import("./chunk-esk240e5.js");await runRepoSubcommand(args)}],["api",async(args)=>{let{runApiSubcommand}=await import("./chunk-s9ts2h6w.js");await runApiSubcommand(args)}],["update",async(args)=>{let{runUpdateSubcommand}=await import("./chunk-k9ev77fp.js");await runUpdateSubcommand(args)}],["theme",async(args)=>{let{runThemeSubcommand}=await import("./chunk-gkfd073t.js");await runThemeSubcommand(args)}],["feedback",async(args)=>{let{runFeedbackSubcommand}=await import("./chunk-53c27xa8.js");await runFeedbackSubcommand(args)}],["daemon",async(args)=>{let{runDaemonSubcommand}=await import("./chunk-92yjtx23.js");await runDaemonSubcommand(args)}],["doctor",async(args)=>{let{runDoctorSubcommand}=await import("./chunk-mh0nwzma.js");await runDoctorSubcommand(args)}],["config",async(args)=>{let{runConfigSubcommand}=await import("./chunk-yfy6031g.js");await runConfigSubcommand(args)}],["reset",async(args)=>{let{runResetSubcommand}=await import("./chunk-0pfrfrd1.js");await runResetSubcommand(args)}],["pty-host",async(args)=>{let{runPtyHostSubcommand}=await import("./chunk-c9zxw37m.js");await runPtyHostSubcommand(args)}],["skill",async(args)=>{let{runSkillSubcommand}=await import("./chunk-mkkp4c5t.js");await runSkillSubcommand(args)}],["plugin",async(args)=>{let{runPluginSubcommand}=await import("./chunk-6aa78w6b.js");await runPluginSubcommand(args)}],["hook",async(args)=>{let{runHookSubcommand}=await import("./chunk-116dnbbd.js");await runHookSubcommand(args)}]]);import{statSync}from"fs";import{resolve}from"path";async function openLocalOrchestrator(){let{TaskIndexStore}=await import("./chunk-8kaqpb7t.js"),{GitWorktreeManager}=await import("./chunk-4rfdprnn.js"),{Orchestrator}=await import("./chunk-624j6yb8.js"),store=new TaskIndexStore;return await store.load(),new Orchestrator({store,worktrees:new GitWorktreeManager})}async function withDaemonOrLocal(bridge){let client=await connectIfRunning();if(client)try{return await bridge.daemon(client)}finally{client.close()}let orch=await openLocalOrchestrator();return bridge.local(orch)}function isPathLikeArg(arg){return arg==="."||arg===".."||arg.startsWith("./")||arg.startsWith("../")||arg.startsWith("/")||arg==="~"||arg.startsWith("~/")}async function projectRootFor(dir){let{isGitRepo,resolveRepoRoot}=await import("./chunk-mp8v5gn8.js"),{projectRejection}=await import("./chunk-t3z4etp5.js"),top=resolveRepoRoot(dir);if(top!==dir)return null;return projectRejection(top,isGitRepo,"explicit")?null:top}async function runOpenDirectory(arg){let dir=resolve(process.cwd(),expandTilde(arg)),isDir=!1;try{isDir=statSync(dir).isDirectory()}catch{isDir=!1}if(!isDir)process.stderr.write(`${activeCliName()}: "${arg}" is not a directory (resolved to ${dir}).
4
+ `),process.exit(1);let projectRoot=await projectRootFor(dir);await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-rc668r26.js");writeLastActiveTaskId(String(task.id))}});let{publishKobeTerminalTitle}=await import("./chunk-1tx1s5v6.js");publishKobeTerminalTitle();let{startTui}=await import("./chunk-k3mjej0g.js");await startTui()}function topLevelUsage(cliName=activeCliName()){return[`${cliName} ${CURRENT_VERSION}`,"",`Usage: ${cliName} [command] [options]`,"","Run with no command to launch PureTUI.",`Run \`${cliName} .\` (or \`${cliName} <path>\`) to open a directory as a standalone task.`,"","Commands:"," completions <shell> Generate shell completion script (bash/zsh/fish)"," add [path] Save a repo path for the new-task picker"," remove [path] Forget a saved project (inverse of add; non-destructive)"," adopt [glob] Import existing git worktrees as tasks"," export [--csv|--json] Print the task list (json/csv/table; daemon-free)"," repo <verb> Per-repo init script + first prompt (show|set|unset)",` api <verb> Scriptable RPC surface for agents (see \`${cliName} api --help\`)`," daemon <verb> Manage the daemon (start|stop|status|restart)"," doctor [--report|--fix] Diagnose daemon/PTY/engines/git; --fix walks the remedies",` config [--path] Open ${cliName}'s config file (state.json) in your editor`," reset [--hard] Stop runtimes; optionally wipe task/UI state"," theme <verb> Manage user themes (list|add|remove)",` skill <verb> Install the ${cliName} agent skill (install|status|command|print)`," plugin <verb> Install and run plugins (install|link|list|action|\u2026)"," feedback Send feedback to GitHub Discussions",` update [version|channel|list] Self-update ${cliName}, switch channel, or list versions`,"","Options:"," -v, --version Print version"," -h, --help Print this help"," --skill Print the agent skill file and exit"].join(`
5
5
  `)}prepareCliEnvironment();var CLI_NAME=activeCliName(),ADD_USAGE=[`Usage: ${CLI_NAME} add [path]`,` ${CLI_NAME} add --remote --host <host> --user <user> --path <basePath> [--port N] [--key [path] | --password]`,"","Save a repo for the new-task picker. With --remote, register an SSH-backed","project whose worktrees live on <host>; engine launch over SSH is pending.",""].join(`
6
- `);async function runAddSubcommand(rest){let arg=rest[0];if(arg==="--help"||arg==="-h"||arg==="help"){process.stdout.write(ADD_USAGE);return}if(arg==="--remote"){let{runAddRemote}=await import("./chunk-73qrq7bg.js");await runAddRemote(rest.slice(1));return}if(arg?.startsWith("-"))process.stderr.write(`${CLI_NAME} add: unknown flag "${arg}"
6
+ `);async function runAddSubcommand(rest){let arg=rest[0];if(arg==="--help"||arg==="-h"||arg==="help"){process.stdout.write(ADD_USAGE);return}if(arg==="--remote"){let{runAddRemote}=await import("./chunk-32h9htyh.js");await runAddRemote(rest.slice(1));return}if(arg?.startsWith("-"))process.stderr.write(`${CLI_NAME} add: unknown flag "${arg}"
7
7
 
8
- ${ADD_USAGE}`),process.exit(2);let target=resolve2(process.cwd(),expandTilde(arg&&arg.length>0?arg:".")),{addSavedRepo}=await import("./chunk-d809qqsk.js"),result=addSavedRepo(target);if(result.rejected)process.stderr.write(`${CLI_NAME} add: "${arg&&arg.length>0?arg:"."}" cannot be a project \u2014 ${rejectionReason(result.rejected)} (resolved to ${result.path}).
8
+ ${ADD_USAGE}`),process.exit(2);let target=resolve2(process.cwd(),expandTilde(arg&&arg.length>0?arg:".")),{addSavedRepo}=await import("./chunk-mp8v5gn8.js"),result=addSavedRepo(target);if(result.rejected)process.stderr.write(`${CLI_NAME} add: "${arg&&arg.length>0?arg:"."}" cannot be a project \u2014 ${rejectionReason(result.rejected)} (resolved to ${result.path}).
9
9
  `),process.exit(1);if(result.added)console.log(`added ${result.path} (${result.total} saved repo${result.total===1?"":"s"} total)`);else console.log(`already saved: ${result.path}`);await ensureProjectMainTask(result.path),await adoptAllWorktrees(result.path)}async function ensureProjectMainTask(repo){try{await withDaemonOrLocal({daemon:(client)=>client.request("task.ensureMain",{repo}),local:(orch)=>orch.ensureMainTask(repo)})}catch(err){console.error(`(skipped project main-task setup: ${errorMessage(err)})`)}}var PURGE_FLAG="--purge-credentials",REMOVE_USAGE=[`Usage: ${CLI_NAME} remove [path] [--purge-credentials]`,"","Forget a saved project (drop it from the new-task picker). Non-destructive:","the repo's files, worktrees, branches and tasks all stay on disk. A remote","(ssh://) project also has its stored connection config dropped.",""," path defaults to the current directory. Pass an exact saved entry (e.g. a"," remote `ssh://user@host` key) to remove it verbatim. Run with no match to"," print the current saved projects.",""," --purge-credentials also delete the remote project's SSH password from"," the OS keychain. Off by default: forgetting a project"," should not silently destroy a stored secret.",""].join(`
10
10
  `);async function runRemoveSubcommand(rest){let purgeCredentials=argvHasFlag(rest,PURGE_FLAG),arg=rest.filter((a)=>a!==PURGE_FLAG&&!a.startsWith(`${PURGE_FLAG}=`))[0];if(arg==="--help"||arg==="-h"||arg==="help"){process.stdout.write(REMOVE_USAGE);return}if(arg?.startsWith("-"))process.stderr.write(`${CLI_NAME} remove: unknown flag "${arg}"
11
11
 
12
- ${REMOVE_USAGE}`),process.exit(2);let{getRemoteRepoConfig,getSavedRepos,resolveRepoRoot}=await import("./chunk-d809qqsk.js"),saved=getSavedRepos();if(saved.length===0){console.log("no saved projects to remove.");return}let raw=arg&&arg.length>0?arg:".",target=saved.includes(raw)?raw:(()=>{let abs=resolve2(process.cwd(),expandTilde(raw)),top=resolveRepoRoot(abs);if(saved.includes(top))return top;if(saved.includes(abs))return abs;return null})();if(target===null){process.stderr.write(`${CLI_NAME} remove: "${raw}" is not a saved project.
12
+ ${REMOVE_USAGE}`),process.exit(2);let{getRemoteRepoConfig,getSavedRepos,resolveRepoRoot}=await import("./chunk-mp8v5gn8.js"),saved=getSavedRepos();if(saved.length===0){console.log("no saved projects to remove.");return}let raw=arg&&arg.length>0?arg:".",target=saved.includes(raw)?raw:(()=>{let abs=resolve2(process.cwd(),expandTilde(raw)),top=resolveRepoRoot(abs);if(saved.includes(top))return top;if(saved.includes(abs))return abs;return null})();if(target===null){process.stderr.write(`${CLI_NAME} remove: "${raw}" is not a saved project.
13
13
 
14
14
  Saved projects:
15
15
  `);for(let p of saved)process.stderr.write(` ${p}
@@ -18,8 +18,8 @@ Saved projects:
18
18
 
19
19
  ${ADOPT_USAGE}
20
20
  `),process.exit(2)}async function runAdoptSubcommand(args){let glob,repoArg,vendorArg,yes=!1;for(let i=0;i<args.length;i++){let a=args[i];if(a==="--help"||a==="-h"||a==="help"){process.stdout.write(`${ADOPT_USAGE}
21
- `);return}if(a==="--repo"){if(repoArg=args[++i],repoArg===void 0)adoptUsageError("--repo requires a value")}else if(a==="--vendor"){if(vendorArg=args[++i],vendorArg===void 0)adoptUsageError("--vendor requires a value")}else if(a==="--yes"||a==="-y")yes=!0;else if(a&&!a.startsWith("-")&&glob===void 0)glob=a;else adoptUsageError(`unexpected argument "${a}"`)}let{resolveRepoRoot}=await import("./chunk-d809qqsk.js"),repo=resolveRepoRoot(resolve2(process.cwd(),expandTilde(repoArg&&repoArg.length>0?repoArg:"."))),vendor=coerceVendorId(vendorArg),orch=await openLocalOrchestrator(),worktrees=await orch.discoverAdoptableWorktrees(repo);if(worktrees.length===0){console.log(`no adoptable worktrees for ${repo} \u2014 every git worktree here is already a task`);return}let isMatch=(w)=>!glob||matchPathGlob(glob,w.path);console.log(`adoptable worktrees in ${repo}:`);for(let w of worktrees){let hit=glob?isMatch(w)?"*":" ":"-",tags=[w.dirty===!0?"dirty":w.dirty===null?"dirty?":"",w.kobeManaged?"":"external"].filter(Boolean).join(",");console.log(` ${hit} ${w.branch} ${w.path}${tags?` (${tags})`:""}`)}if(!glob){console.log(`
21
+ `);return}if(a==="--repo"){if(repoArg=args[++i],repoArg===void 0)adoptUsageError("--repo requires a value")}else if(a==="--vendor"){if(vendorArg=args[++i],vendorArg===void 0)adoptUsageError("--vendor requires a value")}else if(a==="--yes"||a==="-y")yes=!0;else if(a&&!a.startsWith("-")&&glob===void 0)glob=a;else adoptUsageError(`unexpected argument "${a}"`)}let{resolveRepoRoot}=await import("./chunk-mp8v5gn8.js"),repo=resolveRepoRoot(resolve2(process.cwd(),expandTilde(repoArg&&repoArg.length>0?repoArg:"."))),vendor=coerceVendorId(vendorArg),orch=await openLocalOrchestrator(),worktrees=await orch.discoverAdoptableWorktrees(repo);if(worktrees.length===0){console.log(`no adoptable worktrees for ${repo} \u2014 every git worktree here is already a task`);return}let isMatch=(w)=>!glob||matchPathGlob(glob,w.path);console.log(`adoptable worktrees in ${repo}:`);for(let w of worktrees){let hit=glob?isMatch(w)?"*":" ":"-",tags=[w.dirty===!0?"dirty":w.dirty===null?"dirty?":"",w.kobeManaged?"":"external"].filter(Boolean).join(",");console.log(` ${hit} ${w.branch} ${w.path}${tags?` (${tags})`:""}`)}if(!glob){console.log(`
22
22
  pass a path glob to adopt, e.g. ${CLI_NAME} adopt '${repo}/*' --yes`);return}let matched=worktrees.filter(isMatch);if(matched.length===0){console.log(`
23
23
  no worktrees match glob ${JSON.stringify(glob)}`);return}if(!yes){console.log(`
24
24
  ${matched.length} worktree(s) match \u2014 re-run with --yes to adopt them`);return}await adoptWorktreesInto(orch,repo,matched,vendor),console.log(`done \u2014 adopted ${matched.length} worktree(s)`)}function printTopLevelUsage(out){out.write(`${topLevelUsage()}
25
- `)}var COMMANDS=new Map([["add",runAddSubcommand],["remove",runRemoveSubcommand],["adopt",runAdoptSubcommand],...DYNAMIC_COMMANDS]);async function main(){let[,,...rawArgs]=process.argv,[subcommand,...rest]=rawArgs;if(subcommand==="--version"||subcommand==="-v"||subcommand==="version"){let{CURRENT_VERSION:CURRENT_VERSION2}=await import("./chunk-6s6pne9d.js");console.log(`${CLI_NAME} ${CURRENT_VERSION2}`);return}if(subcommand==="--help"||subcommand==="-h"||subcommand==="help"){printTopLevelUsage(process.stdout);return}if(subcommand==="--skill"){let{runSkillSubcommand}=await import("./chunk-z4c6bmw0.js");await runSkillSubcommand(["print"]);return}let handler=subcommand!==void 0?COMMANDS.get(subcommand):void 0;if(handler){await handler(rest);return}if(subcommand!==void 0&&isPathLikeArg(subcommand)){await runOpenDirectory(subcommand);return}if(subcommand!==void 0)console.error(`${CLI_NAME}: unknown command '${subcommand}'`),printTopLevelUsage(process.stderr),process.exit(2);let{publishKobeTerminalTitle}=await import("./chunk-1tx1s5v6.js");publishKobeTerminalTitle();let{maybeRunOnboarding}=await import("./chunk-55s4zykj.js");if(await maybeRunOnboarding())return;let{startTui}=await import("./chunk-xve4g8ct.js");await startTui()}main().catch((err)=>{console.error(formatCliFailure(err,{cliName:CLI_NAME,argv:process.argv,cwd:process.cwd(),env:process.env})),process.exit(1)});
25
+ `)}var COMMANDS=new Map([["add",runAddSubcommand],["remove",runRemoveSubcommand],["adopt",runAdoptSubcommand],...DYNAMIC_COMMANDS]);async function main(){let[,,...rawArgs]=process.argv,[subcommand,...rest]=rawArgs;if(subcommand==="--version"||subcommand==="-v"||subcommand==="version"){let{CURRENT_VERSION:CURRENT_VERSION2}=await import("./chunk-5x7bqhp7.js");console.log(`${CLI_NAME} ${CURRENT_VERSION2}`);return}if(subcommand==="--help"||subcommand==="-h"||subcommand==="help"){printTopLevelUsage(process.stdout);return}if(subcommand==="--skill"){let{runSkillSubcommand}=await import("./chunk-mkkp4c5t.js");await runSkillSubcommand(["print"]);return}let handler=subcommand!==void 0?COMMANDS.get(subcommand):void 0;if(handler){await handler(rest);return}if(subcommand!==void 0&&isPathLikeArg(subcommand)){await runOpenDirectory(subcommand);return}if(subcommand!==void 0)console.error(`${CLI_NAME}: unknown command '${subcommand}'`),printTopLevelUsage(process.stderr),process.exit(2);let{publishKobeTerminalTitle}=await import("./chunk-1tx1s5v6.js");publishKobeTerminalTitle();let{maybeRunOnboarding}=await import("./chunk-1re31mma.js");if(await maybeRunOnboarding())return;let{startTui}=await import("./chunk-k3mjej0g.js");await startTui()}main().catch((err)=>{console.error(formatCliFailure(err,{cliName:CLI_NAME,argv:process.argv,cwd:process.cwd(),env:process.env})),process.exit(1)});
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- import{markKobeInvocation,prepareCliEnvironment,prepareCliStateLayout}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import{__require}from"./chunk-wqfp8d9w.js";markKobeInvocation();prepareCliEnvironment();prepareCliStateLayout();await import("./index.js");
3
+ import{markKobeInvocation,prepareCliEnvironment,prepareCliStateLayout}from"./chunk-p7s4xwgx.js";import"./chunk-4pmd0mxp.js";import"./chunk-g56kvet6.js";import"./chunk-r3k9rbwm.js";import{__require}from"./chunk-wqfp8d9w.js";markKobeInvocation();prepareCliEnvironment();prepareCliStateLayout();await import("./index.js");
package/dist/cli/kobe.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{join as z1}from"node:path";import{createInterface as $1}from"node:readline/promises";import{pathToFileURL as J1}from"node:url";import{spawnSync as L}from"node:child_process";import{constants as m,accessSync as u}from"node:fs";import{homedir as l}from"node:os";import{basename as t,delimiter as o,dirname as r,join as Y}from"node:path";import{fileURLToPath as T}from"node:url";var h={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.153",description:"Rove — 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 U="rove",C="kobe";var V=C;var k=U;var E="ROVE_INVOKED_AS";function x(W=process.env){return W[E]===k?k:V}var F="ROVE_BUN",i="ROVE_NO_BUN_BOOTSTRAP",O="ROVE_SKIP_BUN_CHECK",G=h.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0",B=(W)=>{try{return u(W,m.X_OK),!0}catch{return!1}},a=(W)=>W==="win32"?"bun.exe":"bun",n=(W)=>{let b=L(W,["--version"],{encoding:"utf8",timeout:5000});if(b.error||b.status!==0)return null;return b.stdout?.split(`
3
- `)[0]?.trim()??""};function K(W){return W.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function j(W,b=G){let z=K(W),Q=K(b);if(!z||!Q)return!0;let J=z.split(".").map(Number),$=Q.split(".").map(Number);for(let X=0;X<3;X++){let q=J[X]??0,H=$[X]??0;if(q!==H)return q>H}return!0}function P(W=process.env){return W[O]==="1"}function p(W={}){let b=W.env??process.env,z=W.platform??process.platform,Q=W.home??b.HOME??b.USERPROFILE??l(),J=a(z),$=[],X=b[F]?.trim();if(X)$.push(X);for(let w of(b.PATH??b.Path??"").split(o))if(w)$.push(Y(w,J));let q=b.BUN_INSTALL?.trim();if(q)$.push(Y(q,"bin",J));if(Q)$.push(Y(Q,".bun","bin",J));let H=W.launcherDir;if(H)$.push(Y(H,"..","..","node_modules","bun","bin",J)),$.push(Y(H,"..","..","..","bun","bin",J));return $}function e(W={}){let b=W.isExecutable??B;return p(W).find((z)=>b(z))??null}function D(W={}){let b=W.isExecutable??B,z=W.bunVersionOf??n;if(P(W.env??process.env))return{bun:e(W),stale:null,unusable:null};let Q=null,J=null;for(let $ of p(W)){if(!b($))continue;let X=z($);if(X===null){J??=$;continue}if(j(X))return{bun:$,stale:Q,unusable:J};Q??={path:$,version:K(X)??X}}return{bun:null,stale:Q,unusable:J}}function A(W){return r(T(W))}function R(W){return t(T(W)).replace(/\.[cm]?[jt]s$/,"")}function W1(W=process.platform){return W==="win32"?["powershell","-NoProfile","-Command","irm bun.sh/install.ps1 | iex"]:["bash","-c","curl -fsSL https://bun.sh/install | bash"]}function y(W=x(),b=process.platform){let z=b==="win32"?'powershell -c "irm bun.sh/install.ps1 | iex"':"curl -fsSL https://bun.sh/install | bash";return[`${W}: Rove runs on the Bun runtime, and no Bun was found on this machine.`,"","Install Bun, then run this command again:",` ${z}`," npm install -g bun # any platform, if you already have npm","","Or install Bun and Rove together in one step:"," curl -fsSL https://rove.run/install.sh | sh","",`Already have Bun somewhere unusual? Point Rove at it: ${F}=/path/to/bun`,""].join(`
4
- `)}function g(W,b,z=x()){return[`${z}: this machine's Bun is too old for Rove — found ${b} at ${W}, need ${G} or newer.`,"","Rove's terminals are built on Bun's PTY API. An older Bun ignores it silently,","so every terminal and engine tab would open empty and stay empty.","","Upgrade Bun, then run this command again:"," bun upgrade # Bun installed itself (~/.bun)"," brew upgrade bun # Homebrew"," npm install -g bun@latest # npm-managed Bun","",`Have a newer Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,`Run on this one anyway (unsupported, terminals will be blank): ${O}=1`,""].join(`
5
- `)}function I(W,b=x()){return[`${b}: the Bun at ${W} could not be run — \`${W} --version\` failed or never returned.`,"","Rove skipped it rather than starting through it, which would hang or fail","with a message from that binary instead of this one.","","Reinstall Bun, then run this command again:"," curl -fsSL https://bun.sh/install | bash","",`Have a working Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,""].join(`
6
- `)}function f(W=process.env,b=process.stdin,z=process.stdout){if(W[i]==="1")return!1;if(W.CI==="true"||W.CI==="1")return!1;return Boolean(b.isTTY&&z.isTTY)}function c(W={},b=L){let z=W.platform??process.platform,[Q,...J]=W1(z);if(!Q)return null;let $=b(Q,J,{stdio:"inherit"});if($.error||$.status!==0)return null;return D(W).bun}function b1(W){if(typeof W.status==="number")return W.status;if(W.signal)return 128+(Object.hasOwn(M,W.signal)?M[W.signal]:0);return 1}var M={SIGINT:2,SIGQUIT:3,SIGKILL:9,SIGTERM:15};function _(W,b,z,Q=L){let J=Q(W,[b,...z],{stdio:"inherit"});if(J.error)return process.stderr.write(`rove: could not start Bun at ${W}: ${J.error.message}
7
- `),1;return b1(J)}var S=A(import.meta.url),Z=R(import.meta.url),N=z1(S,`${Z}-run.js`);async function Q1(W){let b=$1({input:process.stdin,output:process.stdout});try{let z=(await b.question(W)).trim().toLowerCase();return z===""||z==="y"||z==="yes"}finally{b.close()}}async function X1(){let W={launcherDir:S},b=D(W);if(b.bun||!f())return b;let z=b.stale?`${Z}: Bun ${b.stale.version} is too old for Rove (needs ${G}+). Install the latest Bun now? [Y/n] `:`${Z}: Rove runs on the Bun runtime, and none is installed. Install Bun now? [Y/n] `;if(!await Q1(z))return b;return{bun:c(W),stale:b.stale,unusable:b.unusable}}var v=globalThis.Bun;if(v){let W=v.version;if(W&&!P()&&!j(W))process.stderr.write(g(process.execPath,W,Z)),process.exit(1);await import(J1(N).href)}else{let{bun:W,stale:b,unusable:z}=await X1();if(!W){let Q=b?g(b.path,b.version,Z):z?I(z,Z):y(Z);process.stderr.write(Q),process.exit(1)}process.exit(_(W,N,process.argv.slice(2)))}
2
+ import{join as z1}from"node:path";import{createInterface as $1}from"node:readline/promises";import{pathToFileURL as J1}from"node:url";import{spawnSync as K}from"node:child_process";import{constants as m,accessSync as u}from"node:fs";import{homedir as l}from"node:os";import{basename as t,delimiter as r,dirname as o,join as Y}from"node:path";import{fileURLToPath as O}from"node:url";var U={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.155",description:"Rove — 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 C="rove",V="kobe";var T=V;var k=C;var s="ROVE_INVOKED_AS";function x(W=process.env){return W[s]===k?k:T}var F="ROVE_BUN",i="ROVE_NO_BUN_BOOTSTRAP",h="ROVE_SKIP_BUN_CHECK",G=U.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0",B=(W)=>{try{return u(W,m.X_OK),!0}catch{return!1}},a=(W)=>W==="win32"?"bun.exe":"bun",n=(W)=>{let b=K(W,["--version"],{encoding:"utf8",timeout:5000});if(b.error||b.status!==0)return null;return b.stdout?.split(`
3
+ `)[0]?.trim()??""};function L(W){return W.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function j(W,b=G){let z=L(W),Q=L(b);if(!z||!Q)return!0;let J=z.split(".").map(Number),$=Q.split(".").map(Number);for(let X=0;X<3;X++){let H=J[X]??0,q=$[X]??0;if(H!==q)return H>q}return!0}function P(W=process.env){return W[h]==="1"}function A(W={}){let b=W.env??process.env,z=W.platform??process.platform,Q=W.home??b.HOME??b.USERPROFILE??l(),J=a(z),$=[],X=b[F]?.trim();if(X)$.push(X);for(let w of(b.PATH??b.Path??"").split(r))if(w)$.push(Y(w,J));let H=b.BUN_INSTALL?.trim();if(H)$.push(Y(H,"bin",J));if(Q)$.push(Y(Q,".bun","bin",J));let q=W.launcherDir;if(q)$.push(Y(q,"..","..","node_modules","bun","bin",J)),$.push(Y(q,"..","..","..","bun","bin",J));return $}function e(W={}){let b=W.isExecutable??B;return A(W).find((z)=>b(z))??null}function D(W={}){let b=W.isExecutable??B,z=W.bunVersionOf??n;if(P(W.env??process.env))return{bun:e(W),stale:null,unusable:null};let Q=null,J=null;for(let $ of A(W)){if(!b($))continue;let X=z($);if(X===null){J??=$;continue}if(j(X))return{bun:$,stale:Q,unusable:J};Q??={path:$,version:L(X)??X}}return{bun:null,stale:Q,unusable:J}}function p(W){return o(O(W))}function y(W){return t(O(W)).replace(/\.[cm]?[jt]s$/,"")}function W1(W=process.platform){return W==="win32"?["powershell","-NoProfile","-Command","irm bun.sh/install.ps1 | iex"]:["bash","-c","curl -fsSL https://bun.sh/install | bash"]}function I(W=x(),b=process.platform){let z=b==="win32"?'powershell -c "irm bun.sh/install.ps1 | iex"':"curl -fsSL https://bun.sh/install | bash";return[`${W}: Rove runs on the Bun runtime, and no Bun was found on this machine.`,"","Install Bun, then run this command again:",` ${z}`," npm install -g bun # any platform, if you already have npm","","Or install Bun and Rove together in one step:"," curl -fsSL https://rove.run/install.sh | sh","",`Already have Bun somewhere unusual? Point Rove at it: ${F}=/path/to/bun`,""].join(`
4
+ `)}function g(W,b,z=x()){return[`${z}: this machine's Bun is too old for Rove — found ${b} at ${W}, need ${G} or newer.`,"","Rove's terminals are built on Bun's PTY API. An older Bun ignores it silently,","so every terminal and engine tab would open empty and stay empty.","","Upgrade Bun, then run this command again:"," bun upgrade # Bun installed itself (~/.bun)"," brew upgrade bun # Homebrew"," npm install -g bun@latest # npm-managed Bun","",`Have a newer Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,`Run on this one anyway (unsupported, terminals will be blank): ${h}=1`,""].join(`
5
+ `)}function R(W,b=x()){return[`${b}: the Bun at ${W} could not be run — \`${W} --version\` failed or never returned.`,"","Rove skipped it rather than starting through it, which would hang or fail","with a message from that binary instead of this one.","","Reinstall Bun, then run this command again:"," curl -fsSL https://bun.sh/install | bash","",`Have a working Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,""].join(`
6
+ `)}function f(W=process.env,b=process.stdin,z=process.stdout){if(W[i]==="1")return!1;if(W.CI==="true"||W.CI==="1")return!1;return Boolean(b.isTTY&&z.isTTY)}function _(W={},b=K){let z=W.platform??process.platform,[Q,...J]=W1(z);if(!Q)return null;let $=b(Q,J,{stdio:"inherit"});if($.error||$.status!==0)return null;return D(W).bun}function b1(W){if(typeof W.status==="number")return W.status;if(W.signal)return 128+(Object.hasOwn(M,W.signal)?M[W.signal]:0);return 1}var M={SIGINT:2,SIGQUIT:3,SIGKILL:9,SIGTERM:15};function N(W,b,z,Q=K){let J=Q(W,[b,...z],{stdio:"inherit"});if(J.error)return process.stderr.write(`rove: could not start Bun at ${W}: ${J.error.message}
7
+ `),1;return b1(J)}var v=p(import.meta.url),Z=y(import.meta.url),c=z1(v,`${Z}-run.js`);async function Q1(W){let b=$1({input:process.stdin,output:process.stdout});try{let z=(await b.question(W)).trim().toLowerCase();return z===""||z==="y"||z==="yes"}finally{b.close()}}async function X1(){let W={launcherDir:v},b=D(W);if(b.bun||!f())return b;let z=b.stale?`${Z}: Bun ${b.stale.version} is too old for Rove (needs ${G}+). Install the latest Bun now? [Y/n] `:`${Z}: Rove runs on the Bun runtime, and none is installed. Install Bun now? [Y/n] `;if(!await Q1(z))return b;return{bun:_(W),stale:b.stale,unusable:b.unusable}}var S=globalThis.Bun;if(S){let W=S.version;if(W&&!P()&&!j(W))process.stderr.write(g(process.execPath,W,Z)),process.exit(1);await import(J1(c).href)}else{let{bun:W,stale:b,unusable:z}=await X1();if(!W){let Q=b?g(b.path,b.version,Z):z?R(z,Z):I(Z);process.stderr.write(Q),process.exit(1)}process.exit(N(W,c,process.argv.slice(2)))}
@@ -30,16 +30,16 @@ var LEGACY_KOBE_ENV_PREFIX = "KOBE_";
30
30
  var ROVE_STATE_DIR_BASENAME = ".rove";
31
31
  var COMPAT_STATE_DIR_BASENAME = ".kobe";
32
32
  function readRoveEnv(suffix, env = process.env) {
33
- return env[`${ROVE_ENV_PREFIX}${suffix}`] ?? env[`${LEGACY_KOBE_ENV_PREFIX}${suffix}`];
34
- }
35
- function readRoveHomeDirEnv(env = process.env) {
36
- for (const key of [`${ROVE_ENV_PREFIX}HOME_DIR`, `${LEGACY_KOBE_ENV_PREFIX}HOME_DIR`]) {
33
+ for (const key of [`${ROVE_ENV_PREFIX}${suffix}`, `${LEGACY_KOBE_ENV_PREFIX}${suffix}`]) {
37
34
  const value = env[key]?.trim();
38
35
  if (value)
39
36
  return value;
40
37
  }
41
38
  return;
42
39
  }
40
+ function readRoveHomeDirEnv(env = process.env) {
41
+ return readRoveEnv("HOME_DIR", env);
42
+ }
43
43
 
44
44
  // ../kobe-daemon/src/daemon/paths.ts
45
45
  function stateDirs(homeDir) {
@@ -104,7 +104,7 @@ function windowsPipePath(homeDir, role) {
104
104
  }
105
105
  function defaultPtyHostSocketPath(homeDir, platform = process.platform) {
106
106
  const override = readRoveEnv("PTY_SOCKET_PATH");
107
- if (override && override.length > 0)
107
+ if (override)
108
108
  return override;
109
109
  const explicit = homeDir ?? readRoveHomeDirEnv();
110
110
  if (platform === "win32")
@@ -121,7 +121,7 @@ function defaultPtyHostSocketPath(homeDir, platform = process.platform) {
121
121
  }
122
122
  function defaultPtyHostPidPath(homeDir = readRoveHomeDirEnv() ?? homedir()) {
123
123
  const override = readRoveEnv("PTY_PID_PATH");
124
- if (override && override.length > 0)
124
+ if (override)
125
125
  return override;
126
126
  return runtimePath(homeDir, "pty.pid", "pty.pid");
127
127
  }
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- import{markRoveInvocation,prepareCliEnvironment,prepareCliStateLayout}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import{__require}from"./chunk-wqfp8d9w.js";markRoveInvocation();prepareCliEnvironment();prepareCliStateLayout();await import("./index.js");
3
+ import{markRoveInvocation,prepareCliEnvironment,prepareCliStateLayout}from"./chunk-p7s4xwgx.js";import"./chunk-4pmd0mxp.js";import"./chunk-g56kvet6.js";import"./chunk-r3k9rbwm.js";import{__require}from"./chunk-wqfp8d9w.js";markRoveInvocation();prepareCliEnvironment();prepareCliStateLayout();await import("./index.js");
package/dist/cli/rove.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{join as z1}from"node:path";import{createInterface as $1}from"node:readline/promises";import{pathToFileURL as J1}from"node:url";import{spawnSync as L}from"node:child_process";import{constants as m,accessSync as u}from"node:fs";import{homedir as l}from"node:os";import{basename as t,delimiter as o,dirname as r,join as Y}from"node:path";import{fileURLToPath as T}from"node:url";var h={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.153",description:"Rove — 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 U="rove",C="kobe";var V=C;var k=U;var E="ROVE_INVOKED_AS";function x(W=process.env){return W[E]===k?k:V}var F="ROVE_BUN",i="ROVE_NO_BUN_BOOTSTRAP",O="ROVE_SKIP_BUN_CHECK",G=h.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0",B=(W)=>{try{return u(W,m.X_OK),!0}catch{return!1}},a=(W)=>W==="win32"?"bun.exe":"bun",n=(W)=>{let b=L(W,["--version"],{encoding:"utf8",timeout:5000});if(b.error||b.status!==0)return null;return b.stdout?.split(`
3
- `)[0]?.trim()??""};function K(W){return W.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function j(W,b=G){let z=K(W),Q=K(b);if(!z||!Q)return!0;let J=z.split(".").map(Number),$=Q.split(".").map(Number);for(let X=0;X<3;X++){let q=J[X]??0,H=$[X]??0;if(q!==H)return q>H}return!0}function P(W=process.env){return W[O]==="1"}function p(W={}){let b=W.env??process.env,z=W.platform??process.platform,Q=W.home??b.HOME??b.USERPROFILE??l(),J=a(z),$=[],X=b[F]?.trim();if(X)$.push(X);for(let w of(b.PATH??b.Path??"").split(o))if(w)$.push(Y(w,J));let q=b.BUN_INSTALL?.trim();if(q)$.push(Y(q,"bin",J));if(Q)$.push(Y(Q,".bun","bin",J));let H=W.launcherDir;if(H)$.push(Y(H,"..","..","node_modules","bun","bin",J)),$.push(Y(H,"..","..","..","bun","bin",J));return $}function e(W={}){let b=W.isExecutable??B;return p(W).find((z)=>b(z))??null}function D(W={}){let b=W.isExecutable??B,z=W.bunVersionOf??n;if(P(W.env??process.env))return{bun:e(W),stale:null,unusable:null};let Q=null,J=null;for(let $ of p(W)){if(!b($))continue;let X=z($);if(X===null){J??=$;continue}if(j(X))return{bun:$,stale:Q,unusable:J};Q??={path:$,version:K(X)??X}}return{bun:null,stale:Q,unusable:J}}function A(W){return r(T(W))}function R(W){return t(T(W)).replace(/\.[cm]?[jt]s$/,"")}function W1(W=process.platform){return W==="win32"?["powershell","-NoProfile","-Command","irm bun.sh/install.ps1 | iex"]:["bash","-c","curl -fsSL https://bun.sh/install | bash"]}function y(W=x(),b=process.platform){let z=b==="win32"?'powershell -c "irm bun.sh/install.ps1 | iex"':"curl -fsSL https://bun.sh/install | bash";return[`${W}: Rove runs on the Bun runtime, and no Bun was found on this machine.`,"","Install Bun, then run this command again:",` ${z}`," npm install -g bun # any platform, if you already have npm","","Or install Bun and Rove together in one step:"," curl -fsSL https://rove.run/install.sh | sh","",`Already have Bun somewhere unusual? Point Rove at it: ${F}=/path/to/bun`,""].join(`
4
- `)}function g(W,b,z=x()){return[`${z}: this machine's Bun is too old for Rove — found ${b} at ${W}, need ${G} or newer.`,"","Rove's terminals are built on Bun's PTY API. An older Bun ignores it silently,","so every terminal and engine tab would open empty and stay empty.","","Upgrade Bun, then run this command again:"," bun upgrade # Bun installed itself (~/.bun)"," brew upgrade bun # Homebrew"," npm install -g bun@latest # npm-managed Bun","",`Have a newer Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,`Run on this one anyway (unsupported, terminals will be blank): ${O}=1`,""].join(`
5
- `)}function I(W,b=x()){return[`${b}: the Bun at ${W} could not be run — \`${W} --version\` failed or never returned.`,"","Rove skipped it rather than starting through it, which would hang or fail","with a message from that binary instead of this one.","","Reinstall Bun, then run this command again:"," curl -fsSL https://bun.sh/install | bash","",`Have a working Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,""].join(`
6
- `)}function f(W=process.env,b=process.stdin,z=process.stdout){if(W[i]==="1")return!1;if(W.CI==="true"||W.CI==="1")return!1;return Boolean(b.isTTY&&z.isTTY)}function c(W={},b=L){let z=W.platform??process.platform,[Q,...J]=W1(z);if(!Q)return null;let $=b(Q,J,{stdio:"inherit"});if($.error||$.status!==0)return null;return D(W).bun}function b1(W){if(typeof W.status==="number")return W.status;if(W.signal)return 128+(Object.hasOwn(M,W.signal)?M[W.signal]:0);return 1}var M={SIGINT:2,SIGQUIT:3,SIGKILL:9,SIGTERM:15};function _(W,b,z,Q=L){let J=Q(W,[b,...z],{stdio:"inherit"});if(J.error)return process.stderr.write(`rove: could not start Bun at ${W}: ${J.error.message}
7
- `),1;return b1(J)}var S=A(import.meta.url),Z=R(import.meta.url),N=z1(S,`${Z}-run.js`);async function Q1(W){let b=$1({input:process.stdin,output:process.stdout});try{let z=(await b.question(W)).trim().toLowerCase();return z===""||z==="y"||z==="yes"}finally{b.close()}}async function X1(){let W={launcherDir:S},b=D(W);if(b.bun||!f())return b;let z=b.stale?`${Z}: Bun ${b.stale.version} is too old for Rove (needs ${G}+). Install the latest Bun now? [Y/n] `:`${Z}: Rove runs on the Bun runtime, and none is installed. Install Bun now? [Y/n] `;if(!await Q1(z))return b;return{bun:c(W),stale:b.stale,unusable:b.unusable}}var v=globalThis.Bun;if(v){let W=v.version;if(W&&!P()&&!j(W))process.stderr.write(g(process.execPath,W,Z)),process.exit(1);await import(J1(N).href)}else{let{bun:W,stale:b,unusable:z}=await X1();if(!W){let Q=b?g(b.path,b.version,Z):z?I(z,Z):y(Z);process.stderr.write(Q),process.exit(1)}process.exit(_(W,N,process.argv.slice(2)))}
2
+ import{join as z1}from"node:path";import{createInterface as $1}from"node:readline/promises";import{pathToFileURL as J1}from"node:url";import{spawnSync as K}from"node:child_process";import{constants as m,accessSync as u}from"node:fs";import{homedir as l}from"node:os";import{basename as t,delimiter as r,dirname as o,join as Y}from"node:path";import{fileURLToPath as O}from"node:url";var U={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.155",description:"Rove — 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 C="rove",V="kobe";var T=V;var k=C;var s="ROVE_INVOKED_AS";function x(W=process.env){return W[s]===k?k:T}var F="ROVE_BUN",i="ROVE_NO_BUN_BOOTSTRAP",h="ROVE_SKIP_BUN_CHECK",G=U.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0",B=(W)=>{try{return u(W,m.X_OK),!0}catch{return!1}},a=(W)=>W==="win32"?"bun.exe":"bun",n=(W)=>{let b=K(W,["--version"],{encoding:"utf8",timeout:5000});if(b.error||b.status!==0)return null;return b.stdout?.split(`
3
+ `)[0]?.trim()??""};function L(W){return W.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function j(W,b=G){let z=L(W),Q=L(b);if(!z||!Q)return!0;let J=z.split(".").map(Number),$=Q.split(".").map(Number);for(let X=0;X<3;X++){let H=J[X]??0,q=$[X]??0;if(H!==q)return H>q}return!0}function P(W=process.env){return W[h]==="1"}function A(W={}){let b=W.env??process.env,z=W.platform??process.platform,Q=W.home??b.HOME??b.USERPROFILE??l(),J=a(z),$=[],X=b[F]?.trim();if(X)$.push(X);for(let w of(b.PATH??b.Path??"").split(r))if(w)$.push(Y(w,J));let H=b.BUN_INSTALL?.trim();if(H)$.push(Y(H,"bin",J));if(Q)$.push(Y(Q,".bun","bin",J));let q=W.launcherDir;if(q)$.push(Y(q,"..","..","node_modules","bun","bin",J)),$.push(Y(q,"..","..","..","bun","bin",J));return $}function e(W={}){let b=W.isExecutable??B;return A(W).find((z)=>b(z))??null}function D(W={}){let b=W.isExecutable??B,z=W.bunVersionOf??n;if(P(W.env??process.env))return{bun:e(W),stale:null,unusable:null};let Q=null,J=null;for(let $ of A(W)){if(!b($))continue;let X=z($);if(X===null){J??=$;continue}if(j(X))return{bun:$,stale:Q,unusable:J};Q??={path:$,version:L(X)??X}}return{bun:null,stale:Q,unusable:J}}function p(W){return o(O(W))}function y(W){return t(O(W)).replace(/\.[cm]?[jt]s$/,"")}function W1(W=process.platform){return W==="win32"?["powershell","-NoProfile","-Command","irm bun.sh/install.ps1 | iex"]:["bash","-c","curl -fsSL https://bun.sh/install | bash"]}function I(W=x(),b=process.platform){let z=b==="win32"?'powershell -c "irm bun.sh/install.ps1 | iex"':"curl -fsSL https://bun.sh/install | bash";return[`${W}: Rove runs on the Bun runtime, and no Bun was found on this machine.`,"","Install Bun, then run this command again:",` ${z}`," npm install -g bun # any platform, if you already have npm","","Or install Bun and Rove together in one step:"," curl -fsSL https://rove.run/install.sh | sh","",`Already have Bun somewhere unusual? Point Rove at it: ${F}=/path/to/bun`,""].join(`
4
+ `)}function g(W,b,z=x()){return[`${z}: this machine's Bun is too old for Rove — found ${b} at ${W}, need ${G} or newer.`,"","Rove's terminals are built on Bun's PTY API. An older Bun ignores it silently,","so every terminal and engine tab would open empty and stay empty.","","Upgrade Bun, then run this command again:"," bun upgrade # Bun installed itself (~/.bun)"," brew upgrade bun # Homebrew"," npm install -g bun@latest # npm-managed Bun","",`Have a newer Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,`Run on this one anyway (unsupported, terminals will be blank): ${h}=1`,""].join(`
5
+ `)}function R(W,b=x()){return[`${b}: the Bun at ${W} could not be run — \`${W} --version\` failed or never returned.`,"","Rove skipped it rather than starting through it, which would hang or fail","with a message from that binary instead of this one.","","Reinstall Bun, then run this command again:"," curl -fsSL https://bun.sh/install | bash","",`Have a working Bun elsewhere? Point Rove at it: ${F}=/path/to/bun`,""].join(`
6
+ `)}function f(W=process.env,b=process.stdin,z=process.stdout){if(W[i]==="1")return!1;if(W.CI==="true"||W.CI==="1")return!1;return Boolean(b.isTTY&&z.isTTY)}function _(W={},b=K){let z=W.platform??process.platform,[Q,...J]=W1(z);if(!Q)return null;let $=b(Q,J,{stdio:"inherit"});if($.error||$.status!==0)return null;return D(W).bun}function b1(W){if(typeof W.status==="number")return W.status;if(W.signal)return 128+(Object.hasOwn(M,W.signal)?M[W.signal]:0);return 1}var M={SIGINT:2,SIGQUIT:3,SIGKILL:9,SIGTERM:15};function N(W,b,z,Q=K){let J=Q(W,[b,...z],{stdio:"inherit"});if(J.error)return process.stderr.write(`rove: could not start Bun at ${W}: ${J.error.message}
7
+ `),1;return b1(J)}var v=p(import.meta.url),Z=y(import.meta.url),c=z1(v,`${Z}-run.js`);async function Q1(W){let b=$1({input:process.stdin,output:process.stdout});try{let z=(await b.question(W)).trim().toLowerCase();return z===""||z==="y"||z==="yes"}finally{b.close()}}async function X1(){let W={launcherDir:v},b=D(W);if(b.bun||!f())return b;let z=b.stale?`${Z}: Bun ${b.stale.version} is too old for Rove (needs ${G}+). Install the latest Bun now? [Y/n] `:`${Z}: Rove runs on the Bun runtime, and none is installed. Install Bun now? [Y/n] `;if(!await Q1(z))return b;return{bun:_(W),stale:b.stale,unusable:b.unusable}}var S=globalThis.Bun;if(S){let W=S.version;if(W&&!P()&&!j(W))process.stderr.write(g(process.execPath,W,Z)),process.exit(1);await import(J1(c).href)}else{let{bun:W,stale:b,unusable:z}=await X1();if(!W){let Q=b?g(b.path,b.version,Z):z?R(z,Z):I(Z);process.stderr.write(Q),process.exit(1)}process.exit(N(W,c,process.argv.slice(2)))}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@sma1lboy/rove",
4
- "version": "0.9.153",
4
+ "version": "0.9.155",
5
5
  "description": "Rove — the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",
6
6
  "keywords": [
7
7
  "terminal",
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{openDaemonSession,resolveActiveTaskId}from"./chunk-pxtx1gcf.js";import"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{resolveActiveTaskId,openDaemonSession};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{applyOnboardingChoices,detectShell,envReadyForTasks,installCompletions,maybeRunOnboarding}from"./chunk-tw2t78nk.js";import"./chunk-56m4hk0p.js";import"./chunk-yshnare4.js";import"./chunk-z83wxkg6.js";import"./chunk-kd870mfy.js";import"./chunk-dv7rxr77.js";import"./chunk-rkt1qjec.js";import"./chunk-2z90jxcn.js";import"./chunk-zaxdx0wd.js";import"./chunk-sexavazm.js";import"./chunk-sdyzxayr.js";import"./chunk-jvxh93nz.js";import"./chunk-g5nz190n.js";import"./chunk-7z9cqycv.js";import"./chunk-ea1r26pa.js";import"./chunk-w7zv47mp.js";import"./chunk-gwcneg6c.js";import"./chunk-9zb2wkfr.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-nywh3yb9.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-bq3fyc0p.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};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{releaseBodyLines,runShellUpdater}from"./chunk-2wdnqzbf.js";import{$jsx,$jsxs,bootPaneHost,pageCloseBindings,require_react_production,useBindings,useRenderer,useT,useTheme}from"./chunk-x7ssay77.js";import"./chunk-764bsyb0.js";import"./chunk-xqw5d5rv.js";import"./chunk-h4n8ffqy.js";import"./chunk-6xppe9bj.js";import{BREAKING_VERSIONS,CURRENT_VERSION,UPDATE_COMMAND,breakingVersionsCrossed,fetchReleaseNotes,fetchReleaseSummaries}from"./chunk-dv7rxr77.js";import"./chunk-nm802jgt.js";import"./chunk-zaxdx0wd.js";import"./chunk-sexavazm.js";import"./chunk-sdyzxayr.js";import"./chunk-b9h2ywc7.js";import"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-rsqx358z.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-07k2njwk.js";import"./chunk-cb2fpajx.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import{__toESM}from"./chunk-wqfp8d9w.js";import{TextAttributes}from"@opentui/core";var import_react2=__toESM(require_react_production(),1);var RELEASE_LIMIT=20;function VersionsPage(props){let{theme}=useTheme(),t=useT(),renderer=useRenderer(),[releases,setReleases]=import_react2.useState(null),[cursor,setCursor]=import_react2.useState(0),[notes,setNotes]=import_react2.useState({}),[status,setStatus]=import_react2.useState(null),selected=releases?.[cursor],crossings=selected?breakingVersionsCrossed(CURRENT_VERSION,selected.version):[];import_react2.useEffect(()=>{fetchReleaseSummaries(RELEASE_LIMIT).then((fetched)=>setReleases(fetched))},[]);let selectedVersion=selected?.version;import_react2.useEffect(()=>{if(selectedVersion===void 0||notes[selectedVersion]!==void 0)return;setNotes((cache)=>({...cache,[selectedVersion]:"loading"})),fetchReleaseNotes(selectedVersion).then((fetched)=>{setNotes((cache)=>({...cache,[selectedVersion]:fetched??"missing"}))})},[selectedVersion,notes]);function move(delta){let count=releases?.length??0;if(count===0)return;setCursor((index)=>(index+delta+count)%count)}async function installSelected(){if(!selected)return;setStatus(t("update.statusRunningUpdater")),await new Promise((resolve)=>setTimeout(resolve,30)),await runShellUpdater({renderer,t,targetLabel:selected.version,command:`${UPDATE_COMMAND} -s -- ${selected.version}`})}useBindings(()=>({bindings:[{key:"up",cmd:()=>move(-1)},{key:"down",cmd:()=>move(1)},{key:"k",cmd:()=>move(-1)},{key:"j",cmd:()=>move(1)},{key:"return",cmd:()=>void installSelected()},{key:"u",cmd:()=>void installSelected()},...pageCloseBindings(props.onClose)]}));let selectedNotes=selectedVersion===void 0?void 0:notes[selectedVersion];return $jsxs("box",{flexDirection:"column",flexGrow:1,paddingTop:1,paddingLeft:2,paddingRight:2,children:[$jsxs("box",{flexDirection:"row",justifyContent:"space-between",flexShrink:0,children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"none",children:t("update.versions.pageTitle")}),$jsx("text",{fg:theme.textMuted,wrapMode:"none",onMouseUp:props.onClose,children:"q / esc"})]}),$jsxs("box",{flexDirection:"row",flexGrow:1,paddingTop:1,gap:2,children:[$jsxs("box",{flexDirection:"column",width:26,flexShrink:0,children:[releases===null?$jsx("text",{fg:theme.textMuted,children:t("update.versions.loading")}):null,releases!==null&&releases.length===0?$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("update.versions.unavailable")}):null,(releases??[]).map((release,index)=>{let active=index===cursor,tags=[release.version===CURRENT_VERSION?t("update.versions.tagCurrent"):"",index===0?t("update.versions.tagLatest"):"",BREAKING_VERSIONS.includes(release.version)?t("update.versions.tagBreaking"):""].filter(Boolean).join(" ");return $jsxs("box",{flexDirection:"row",gap:1,paddingLeft:1,backgroundColor:active?theme.primary:void 0,onMouseUp:()=>setCursor(index),children:[$jsxs("text",{fg:active?theme.selectedListItemText:theme.text,attributes:release.version===CURRENT_VERSION?TextAttributes.BOLD:void 0,wrapMode:"none",children:["v",release.version]}),tags?$jsx("text",{fg:active?theme.selectedListItemText:theme.textMuted,wrapMode:"none",children:tags}):null]},release.version)})]}),$jsxs("box",{flexDirection:"column",flexGrow:1,flexShrink:1,children:[$jsx("scrollbox",{flexGrow:1,flexShrink:1,stickyScroll:!1,verticalScrollbarOptions:{trackOptions:{backgroundColor:theme.background,foregroundColor:theme.borderActive}},children:$jsxs("box",{flexDirection:"column",paddingRight:1,paddingBottom:1,gap:0,children:[selectedNotes==="loading"?$jsx("text",{fg:theme.textMuted,children:t("update.loadingNotes")}):null,selectedNotes==="missing"?$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("update.notesUnavailable")}):null,selectedNotes!==void 0&&selectedNotes!=="loading"&&selectedNotes!=="missing"?releaseBodyLines(selectedNotes.body).map((line,i)=>$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:line},`${i}:${line}`)):null]})}),crossings.length>0?$jsx("text",{fg:theme.warning,wrapMode:"word",children:t("update.versions.breakingWarning",{versions:crossings.join(", ")})}):null]})]}),status?$jsx("text",{fg:theme.info,wrapMode:"word",children:status}):null,$jsx("box",{flexShrink:0,paddingTop:1,children:$jsx("text",{fg:theme.textMuted,attributes:TextAttributes.DIM,wrapMode:"none",children:t("update.versions.footerHint")})})]})}var INLINE_ROWS=24;async function startVersionsHost(){await bootPaneHost({inlineRows:INLINE_ROWS,setup:()=>({root:()=>$jsx(VersionsPage,{onClose:()=>process.exit(0)})})})}export{startVersionsHost};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{GitWorktreeManager}from"./chunk-makzf3q1.js";import"./chunk-5snrwe65.js";import"./chunk-ke95ebrz.js";import"./chunk-6xppe9bj.js";import"./chunk-37gnmm2m.js";import"./chunk-bkba9c4n.js";import"./chunk-g2advs8t.js";import"./chunk-2fypr41w.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-a3a9gdc4.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{GitWorktreeManager};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{ensureGlobalKobeHooks,readTextWithTimeout,runHookSubcommand}from"./chunk-1a7ctg07.js";import"./chunk-3ry6prwn.js";import"./chunk-r2pztgm6.js";import"./chunk-d393z1mj.js";import"./chunk-jvxh93nz.js";import"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-7z9cqycv.js";import"./chunk-ea1r26pa.js";import"./chunk-w7zv47mp.js";import"./chunk-gwcneg6c.js";import"./chunk-9zb2wkfr.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-nywh3yb9.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-bq3fyc0p.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{runHookSubcommand,readTextWithTimeout,ensureGlobalKobeHooks};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{ENGINE_NOT_OBSERVED_REASON,ENGINE_START_POLL_MS,ENGINE_START_PROBE_MS,deferOrThrow,deliverHostedPrompt,deliverToKey,ensurePtyHost,findEngineKey,isTaskKey,killTaskSessions,listSessions,listSessionsOrNull,openPtyHost,outcomeFields,resolveComposerManifest,taskKeys}from"./chunk-xjskp76m.js";import"./chunk-z2aqaabp.js";import"./chunk-fd7swjnq.js";import"./chunk-37gnmm2m.js";import"./chunk-bkba9c4n.js";import"./chunk-g2advs8t.js";import"./chunk-e8493db0.js";import"./chunk-rkt1qjec.js";import"./chunk-7q67dz4c.js";import"./chunk-1cjd7h8p.js";import"./chunk-b99tf0jr.js";import"./chunk-z1e1bsv5.js";import"./chunk-hape5vwj.js";import"./chunk-2z90jxcn.js";import"./chunk-nm802jgt.js";import"./chunk-zaxdx0wd.js";import"./chunk-sexavazm.js";import"./chunk-sdyzxayr.js";import"./chunk-b9h2ywc7.js";import"./chunk-jvxh93nz.js";import"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-g5nz190n.js";import"./chunk-7z9cqycv.js";import"./chunk-ea1r26pa.js";import"./chunk-w7zv47mp.js";import"./chunk-gwcneg6c.js";import"./chunk-9zb2wkfr.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-nywh3yb9.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-bq3fyc0p.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{taskKeys,resolveComposerManifest,outcomeFields,openPtyHost,listSessionsOrNull,listSessions,killTaskSessions,isTaskKey,findEngineKey,ensurePtyHost,deliverToKey,deliverHostedPrompt,deferOrThrow,ENGINE_START_PROBE_MS,ENGINE_START_POLL_MS,ENGINE_NOT_OBSERVED_REASON};
@@ -1,4 +0,0 @@
1
- // @bun
2
- import{LEGACY_KOBE_CONFIG_DIR_BASENAME,LEGACY_KOBE_STATE_DIR_BASENAME,ROVE_CONFIG_DIR_BASENAME,ROVE_STATE_DIR_BASENAME}from"./chunk-cb2fpajx.js";import{readRoveEnv}from"./chunk-3bfm4hrs.js";import{randomUUID}from"crypto";import{constants,closeSync,copyFileSync,fsyncSync,linkSync,lstatSync,mkdirSync,openSync,readdirSync,readlinkSync,renameSync,symlinkSync,unlinkSync,writeFileSync}from"fs";import{homedir}from"os";import{dirname,join}from"path";var CLIENT_MIGRATION_MARKER=".layout-client-migration-v1",PLUGIN_MIGRATION_MARKER=".layout-plugins-migration-v1",DAEMON_MIGRATION_MARKER=".layout-daemon-migration-v1",CLIENT_STATE_ENTRIES=["attachments","settings","themes"],DAEMON_STATE_ENTRIES=["attention-inbox.json","automations.json","issue-assets","issues.json","notes","notes.json","tasks.json","worktree-init"];function errorText(err){return err instanceof Error?err.message:String(err)}function lstatIfExists(path){try{return lstatSync(path)}catch(err){if(err.code==="ENOENT")return;throw err}}function removeTemp(path){try{unlinkSync(path)}catch(err){if(err.code!=="ENOENT")throw err}}function syncFile(path){let handle=openSync(path,"r");try{fsyncSync(handle)}finally{closeSync(handle)}}function publishTemp(temp,destination){try{return linkSync(temp,destination),!0}catch(err){if(err.code==="EEXIST")return!1;throw err}}function copyRegularFile(source,destination){let temp=`${destination}.migration-${process.pid}-${randomUUID()}.tmp`;try{return copyFileSync(source,temp,constants.COPYFILE_EXCL),syncFile(temp),publishTemp(temp,destination)?1:0}finally{removeTemp(temp)}}function writeMarker(destination){let temp=`${destination}.migration-${process.pid}-${randomUUID()}.tmp`;try{writeFileSync(temp,`legacy kobe state copied without overwrite
3
- `,{flag:"wx"}),syncFile(temp),publishTemp(temp,destination)}finally{removeTemp(temp)}}function copyMissing(source,destination){let sourceStat=lstatIfExists(source);if(!sourceStat)return 0;let destinationStat=lstatIfExists(destination);if(destinationStat){if(!sourceStat.isDirectory()||!destinationStat.isDirectory())return 0;let copied=0;for(let name of readdirSync(source))copied+=copyMissing(join(source,name),join(destination,name));return copied}if(mkdirSync(dirname(destination),{recursive:!0}),sourceStat.isDirectory()){mkdirSync(destination,{recursive:!0,mode:sourceStat.mode});let copied=0;for(let name of readdirSync(source))copied+=copyMissing(join(source,name),join(destination,name));return copied}if(sourceStat.isSymbolicLink())try{return symlinkSync(readlinkSync(source),destination),1}catch(err){if(err.code==="EEXIST")return 0;throw err}return copyRegularFile(source,destination)}function migrateStateEntries(entries,markerName,includeConfig,env){let home=readRoveEnv("HOME_DIR",env)??homedir(),legacyState=join(home,LEGACY_KOBE_STATE_DIR_BASENAME),roveState=join(home,ROVE_STATE_DIR_BASENAME),legacyConfig=join(home,".config",LEGACY_KOBE_CONFIG_DIR_BASENAME,"state.json"),roveConfig=join(home,".config",ROVE_CONFIG_DIR_BASENAME,"state.json"),marker=join(roveState,markerName),hasSource;try{if(lstatIfExists(marker))return{attempted:!1,copied:0,warnings:[]};hasSource=Boolean(lstatIfExists(legacyState)||includeConfig&&lstatIfExists(legacyConfig))}catch(err){return{attempted:!0,copied:0,warnings:[`migration preflight: ${err instanceof Error?err.message:String(err)}`]}}if(!hasSource)return{attempted:!1,copied:0,warnings:[]};let copied=0,warnings=[];for(let name of entries)try{copied+=copyMissing(join(legacyState,name),join(roveState,name))}catch(err){warnings.push(`${name}: ${err instanceof Error?err.message:String(err)}`)}if(includeConfig)try{copied+=copyMissing(legacyConfig,roveConfig)}catch(err){warnings.push(`state.json: ${err instanceof Error?err.message:String(err)}`)}if(warnings.length===0){mkdirSync(roveState,{recursive:!0});try{writeMarker(marker)}catch(err){warnings.push(`migration marker: ${err instanceof Error?err.message:String(err)}`)}}return{attempted:!0,copied,warnings}}var PLUGIN_ENTRIES=["plugins.json","plugins","plugins-outdated.json"];function migrateLegacyPluginTree(env){let home=readRoveEnv("HOME_DIR",env)??homedir(),legacyState=join(home,LEGACY_KOBE_STATE_DIR_BASENAME),roveState=join(home,ROVE_STATE_DIR_BASENAME),marker=join(roveState,PLUGIN_MIGRATION_MARKER);try{if(lstatIfExists(marker)||lstatIfExists(join(roveState,"plugins.json")))return{attempted:!1,copied:0,warnings:[]};if(!lstatIfExists(join(legacyState,"plugins.json")))return{attempted:!1,copied:0,warnings:[]}}catch(err){return{attempted:!0,copied:0,warnings:[`plugin migration preflight: ${errorText(err)}`]}}mkdirSync(roveState,{recursive:!0});let moved=0,warnings=[];for(let name of PLUGIN_ENTRIES){let source=join(legacyState,name),destination=join(roveState,name);try{if(!lstatIfExists(source)||lstatIfExists(destination))continue;renameSync(source,destination),moved+=1;try{symlinkSync(destination,source)}catch{}}catch(err){warnings.push(`${name}: ${errorText(err)}`)}}if(warnings.length===0)try{writeMarker(marker)}catch(err){warnings.push(`plugin migration marker: ${errorText(err)}`)}return{attempted:!0,copied:moved,warnings}}function migrateRoveClientStateLayout(env=process.env){return migrateStateEntries(CLIENT_STATE_ENTRIES,CLIENT_MIGRATION_MARKER,!0,env)}function migrateRoveDaemonStateLayout(env=process.env){let state=migrateStateEntries(DAEMON_STATE_ENTRIES,DAEMON_MIGRATION_MARKER,!1,env),plugins=migrateLegacyPluginTree(env);return{attempted:state.attempted||plugins.attempted,copied:state.copied+plugins.copied,warnings:[...state.warnings,...plugins.warnings]}}
4
- export{DAEMON_MIGRATION_MARKER,migrateRoveClientStateLayout,migrateRoveDaemonStateLayout};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{Orchestrator}from"./chunk-fna6sxe4.js";import"./chunk-a4h476hv.js";import"./chunk-mmd7zehs.js";import"./chunk-makzf3q1.js";import"./chunk-5snrwe65.js";import"./chunk-ke95ebrz.js";import"./chunk-kpf3yaj9.js";import"./chunk-6xppe9bj.js";import{PLACEHOLDER_TASK_TITLE}from"./chunk-aq912vvw.js";import"./chunk-37gnmm2m.js";import"./chunk-bkba9c4n.js";import"./chunk-g2advs8t.js";import"./chunk-hape5vwj.js";import"./chunk-sdyzxayr.js";import"./chunk-gwcneg6c.js";import"./chunk-2fypr41w.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-bq3fyc0p.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{PLACEHOLDER_TASK_TITLE,Orchestrator};
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{errorMessage}from"./chunk-2brn8e1y.js";var PLACEHOLDER_TASK_TITLE="(new task)";function deriveTitleFromPrompt(prompt){if(typeof prompt!=="string")return"";let collapsed=prompt.replace(/\s+/g," ").trim();if(collapsed.length===0)return"";let points=[...collapsed];if(points.length<=40)return collapsed;return`${points.slice(0,40).join("")}\u2026`}function isPlaceholderDerivedBranch(branch,taskId){let id6=taskId.slice(-6).toLowerCase();if(branch===`rove/new-task-${id6}`||branch===`kobe/new-task-${id6}`)return!0;return/^(?:[^/]+\/)?new-task(?:-\d+)?$/.test(branch)}class IllegalTransitionError extends Error{from;to;taskId;constructor(from,to,taskId){super(`illegal transition for task ${taskId}: ${from} -> ${to}`);this.from=from;this.to=to;this.taskId=taskId;this.name="IllegalTransitionError"}}class TaskNotFoundError extends Error{constructor(taskId){super(`task not found: ${taskId}`);this.name="TaskNotFoundError"}}class CannotDeleteMainTaskError extends Error{constructor(){super("cannot delete a main task; remove the repo from saved repos instead");this.name="CannotDeleteMainTaskError"}}var DIRTY_WORKTREE_CODE="DIRTY_WORKTREE";class DirtyWorktreeError extends Error{taskId;ignored;constructor(taskId,ignored=[]){let what=ignored.length>0?`gitignored work git status cannot see: ${ignored.join(", ")}`:"uncommitted or untracked changes";super(`${DIRTY_WORKTREE_CODE}: task ${taskId} worktree has ${what}`);this.taskId=taskId;this.ignored=ignored;this.name="DirtyWorktreeError"}}class WorktreeRemoveFailedError extends Error{taskId;cause;constructor(taskId,cause){super(`failed to remove worktree for task ${taskId}: ${errorMessage(cause)}`);this.taskId=taskId;this.cause=cause;this.name="WorktreeRemoveFailedError"}}var TASK_DELETING_CODE="TASK_DELETING";class TaskDeletingError extends Error{taskId;constructor(taskId){super(`${TASK_DELETING_CODE}: task ${taskId} is being deleted`);this.taskId=taskId;this.name="TaskDeletingError"}}var MAIN_CHECKOUT_DIRTY_CODE="MAIN_CHECKOUT_DIRTY";class MainCheckoutDirtyError extends Error{repo;dir;constructor(repo,dir){super(`${MAIN_CHECKOUT_DIRTY_CODE}: base checkout at ${dir} has uncommitted changes; commit them before landing (never git stash \u2014 the stash stack is shared by every worktree of this repo)`);this.repo=repo;this.dir=dir;this.name="MainCheckoutDirtyError"}}var EMPTY_BRANCH_CODE="EMPTY_BRANCH";class EmptyBranchError extends Error{branch;landedOn;constructor(branch,landedOn){super(`${EMPTY_BRANCH_CODE}: '${branch}' has no commits ahead of '${landedOn}' \u2014 landing it would be a no-op (the worker may not have delivered anything)`);this.branch=branch;this.landedOn=landedOn;this.name="EmptyBranchError"}}var EMPTY_BRANCH_DIRTY_WORKTREE_CODE="EMPTY_BRANCH_DIRTY_WORKTREE";class EmptyBranchDirtyWorktreeError extends Error{branch;landedOn;worktreePath;files;constructor(branch,landedOn,worktreePath,files){let list=files.length>0?files.join(", "):"(none reported)";super(`${EMPTY_BRANCH_DIRTY_WORKTREE_CODE}: '${branch}' has no commits ahead of '${landedOn}' but its worktree ${worktreePath} has uncommitted changes (${list}) \u2014 commit them in the worktree first, then land again`);this.branch=branch;this.landedOn=landedOn;this.worktreePath=worktreePath;this.files=files;this.name="EmptyBranchDirtyWorktreeError"}}var MISSING_REF_CODE="MISSING_REF";class MissingRefError extends Error{branch;landedOn;dir;constructor(branch,landedOn,dir){super(`${MISSING_REF_CODE}: '${branch}' does not resolve in the base repo at ${dir} (comparing against '${landedOn}') \u2014 the branch was renamed or deleted outside Rove; re-point the task with \`rove api set-branch\` or recreate the branch`);this.branch=branch;this.landedOn=landedOn;this.dir=dir;this.name="MissingRefError"}}var LAND_CONFLICT_CODE="LAND_CONFLICT";class LandConflictError extends Error{taskId;branch;files;constructor(taskId,branch,files){let list=files.length>0?files.join(", "):"(none reported)";super(`${LAND_CONFLICT_CODE}: merging '${branch}' hit conflicts, merge aborted \u2014 conflicted files: ${list}`);this.taskId=taskId;this.branch=branch;this.files=files;this.name="LandConflictError"}}var GIT_COMMAND_FAILED_CODE="GIT_COMMAND_FAILED";class GitCommandFailedError extends Error{command;stderr;constructor(command,stderr,hint){let detail=stderr.trim()||"(git printed nothing on stderr)";super(`${GIT_COMMAND_FAILED_CODE}: \`git ${command}\` failed \u2014 ${detail}${hint?`; ${hint}`:""}`);this.command=command;this.stderr=stderr;this.name="GitCommandFailedError"}}
3
- export{PLACEHOLDER_TASK_TITLE,deriveTitleFromPrompt,isPlaceholderDerivedBranch,IllegalTransitionError,TaskNotFoundError,CannotDeleteMainTaskError,DIRTY_WORKTREE_CODE,DirtyWorktreeError,WorktreeRemoveFailedError,TASK_DELETING_CODE,TaskDeletingError,MainCheckoutDirtyError,EmptyBranchError,EMPTY_BRANCH_DIRTY_WORKTREE_CODE,EmptyBranchDirtyWorktreeError,MissingRefError,LandConflictError,GitCommandFailedError};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{KobeDaemonClient,RpcTimeoutError}from"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{RpcTimeoutError,KobeDaemonClient};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{getGlobalDefaultVendor,getRepoLastActiveVendor,resolvePreferredVendor,setGlobalDefaultVendor,setRepoLastActiveVendor}from"./chunk-kpf3yaj9.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-bq3fyc0p.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{setRepoLastActiveVendor,setGlobalDefaultVendor,resolvePreferredVendor,getRepoLastActiveVendor,getGlobalDefaultVendor};
@@ -1,5 +0,0 @@
1
- // @bun
2
- import{canonPath,normalizeMainRepo,randomDirTaskSuffix,repoWorkingDir,samePrStatus,titleFromRepo}from"./chunk-a4h476hv.js";import{readLastActiveTaskId,writeLastActiveTaskId}from"./chunk-mmd7zehs.js";import{GitWorktreeManager,defaultExecDeps}from"./chunk-makzf3q1.js";import{canonicalize,listWorktreeDirNames}from"./chunk-5snrwe65.js";import{resolvePreferredVendor}from"./chunk-kpf3yaj9.js";import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{CannotDeleteMainTaskError,DirtyWorktreeError,EmptyBranchDirtyWorktreeError,EmptyBranchError,GitCommandFailedError,IllegalTransitionError,LandConflictError,MainCheckoutDirtyError,MissingRefError,PLACEHOLDER_TASK_TITLE,TaskDeletingError,TaskNotFoundError,WorktreeRemoveFailedError,isPlaceholderDerivedBranch}from"./chunk-aq912vvw.js";import{detectLanguage}from"./chunk-hape5vwj.js";import{createStateCell}from"./chunk-sdyzxayr.js";import{addSavedRepo,getSavedRepos,isGitRepo,removeSavedRepo,resolveRepoRoot}from"./chunk-deejtpcr.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{projectRejection,rejectionReason}from"./chunk-s8eh3cf1.js";async function createTaskRow(deps,input){if(!input.repo)throw Error("createTask: repo is required");let repo=(await deps.mainTasks.ensureIfEligible(input.repo,input.projectIntent??"explicit"))?.repo??normalizeMainRepo(input.repo).repo,title=(input.title??PLACEHOLDER_TASK_TITLE).trim()||PLACEHOLDER_TASK_TITLE;return await deps.store.create({repo,title,branch:input.branch??"",worktreePath:"",status:"backlog",kind:"task",vendor:input.vendor??DEFAULT_TASK_VENDOR,...input.command?.trim()?{command:input.command.trim()}:{},...input.modelEffort?{modelEffort:input.modelEffort}:{},...input.groupId?{groupId:input.groupId}:{},...input.dispatcher?{dispatcher:input.dispatcher}:{},...input.routine?{routine:input.routine}:{},...input.baseRef?.trim()?{baseRef:input.baseRef.trim()}:{}})}async function openDirectoryTaskRow(deps,input){if(!input.dir)throw Error("openDirectoryTask: dir is required");let dir=canonPath(input.dir);return deps.store.create({repo:dir,title:input.scratch?"":`${titleFromRepo(dir)}-${randomDirTaskSuffix()}`,branch:"",worktreePath:dir,status:"backlog",kind:"dir",...input.scratch?{scratch:!0}:{},vendor:input.vendor??resolvePreferredVendor()})}async function adoptScratchRepoRow(deps,id,repo){let task=deps.store.get(id);if(!task||task.kind!=="dir"||task.scratch!==!0)return;let dir=canonPath(repo);await deps.store.update(id,{repo:dir,worktreePath:dir,scratch:!1,title:titleFromRepo(dir)})}function parseDirtyPaths(stdout){return stdout.split(`
3
- `).filter((line)=>line.length>3).map((line)=>line.slice(3).trim()).filter((line)=>line.length>0)}function baseRepoCtx(repo,deps){let basePath=deps.remoteBasePath(repo);return{exec:deps.execForRepo(repo),dir:basePath??repo}}async function landGit(exec,dir,args,opts){let r=await exec.run(["git",...args],{cwd:dir,env:opts?.readOnly?READ_ONLY_GIT_ENV:void 0});return{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode}}async function isDirty(exec,dir){return(await landGit(exec,dir,["status","--porcelain"],{readOnly:!0})).stdout.trim().length>0}async function landPreflight(task,deps=defaultExecDeps){let refuse=(pf,refusal)=>{let refused={...pf,refusal};return{...refused,message:landRefusalError(task,refused).message}},branch=task.branch.trim();if(!branch)throw Error(`landPreflight: task ${task.id} has no branch to land (never materialised)`);let{exec,dir}=baseRepoCtx(task.repo,deps),headOut=await landGit(exec,dir,["symbolic-ref","--short","HEAD"],{readOnly:!0}),landedOn=headOut.stdout.trim();if(headOut.exitCode!==0||!landedOn){let headCommit=await landGit(exec,dir,["rev-parse","--verify","--quiet","HEAD"],{readOnly:!0}),detached=headCommit.exitCode===0&&headCommit.stdout.trim().length>0;return refuse({branch,landedOn:"",baseDir:dir},detached?"DETACHED_HEAD":"UNREADABLE_BASE")}if(landedOn===branch)return refuse({branch,landedOn,baseDir:dir},"SAME_BRANCH");let baseDirty=await isDirty(exec,dir),aheadOut=await landGit(exec,dir,["rev-list","--count",`${landedOn}..${branch}`],{readOnly:!0});if(aheadOut.exitCode!==0){let baseHead=await landGit(exec,dir,["rev-parse","--verify","--quiet","HEAD"],{readOnly:!0});if(baseHead.exitCode!==0||!baseHead.stdout.trim())return refuse({branch,landedOn,baseDirty,baseDir:dir},"UNBORN_BASE");return refuse({branch,landedOn,baseDirty,baseDir:dir},baseDirty?"MAIN_CHECKOUT_DIRTY":"MISSING_REF")}let parsed=Number.parseInt(aheadOut.stdout.trim(),10),base={branch,landedOn,baseDirty,baseDir:dir,...Number.isFinite(parsed)?{ahead:parsed}:{}};if(baseDirty)return refuse(base,"MAIN_CHECKOUT_DIRTY");if(base.ahead!==0)return base;let worktreePath=task.worktreePath.trim();if(worktreePath){let manager=new GitWorktreeManager(deps),dirty=!1;try{dirty=await manager.isDirty(worktreePath)}catch{dirty=!1}if(dirty){let wtExec=deps.execForPath(worktreePath),files=parseDirtyPaths((await landGit(wtExec,worktreePath,["status","--porcelain"],{readOnly:!0})).stdout);return refuse({...base,dirtyFiles:files},"EMPTY_BRANCH_DIRTY_WORKTREE")}}return refuse(base,"EMPTY_BRANCH")}function landRefusalError(task,pf){switch(pf.refusal){case"DETACHED_HEAD":return Error(`landTask: base checkout at ${pf.baseDir} is in detached-HEAD state; check out a branch first`);case"UNREADABLE_BASE":return Error(`landTask: could not read HEAD of the base checkout at ${pf.baseDir} \u2014 is it still a git repo?`);case"UNBORN_BASE":return Error(`landTask: base checkout at ${pf.baseDir} is on '${pf.landedOn}' but has no commits yet, so there is nothing to merge '${pf.branch}' into; make the first commit there (or \`git merge --ff-only ${pf.branch}\`) and land again`);case"SAME_BRANCH":return Error(`landTask: base checkout is already on '${pf.branch}' \u2014 nothing to land onto`);case"MAIN_CHECKOUT_DIRTY":return new MainCheckoutDirtyError(task.repo,pf.baseDir);case"MISSING_REF":return new MissingRefError(pf.branch,pf.landedOn,pf.baseDir);case"EMPTY_BRANCH_DIRTY_WORKTREE":return new EmptyBranchDirtyWorktreeError(pf.branch,pf.landedOn,task.worktreePath.trim(),[...pf.dirtyFiles??[]]);case"EMPTY_BRANCH":return new EmptyBranchError(pf.branch,pf.landedOn)}}import path from"path";async function landTaskWithCleanup(task,opts,deps){if(task.kind==="main")throw Error("landTask: a main task has no branch to land");if(task.kind==="dir")throw Error("landTask: a directory task has no Rove-managed branch to land");let result=await landTask(task,{strategy:opts.strategy}),worktree=opts.removeWorktree===!1?void 0:await removeLandedWorktree(task,opts.callerCwd,deps),branchAnchor=null,branchKept,worktreeGone=!task.worktreePath.trim()||worktree?.removed===!0;if(opts.deleteBranch&&!worktreeGone)branchKept={reason:worktree?.reason??`worktree ${task.worktreePath} was kept, and still has the branch checked out`};else if(opts.deleteBranch)await deps.worktrees.deleteBranch(task.repo,result.branch,{force:!0,onAnchor:(record)=>{branchAnchor=record}});return{...result,...worktree?{worktree}:{},...branchAnchor?{branchAnchor}:{},...branchKept?{branchKept}:{}}}async function removeLandedWorktree(task,callerCwd,deps){let worktreePath=task.worktreePath.trim();if(!worktreePath)return{removed:!1,reason:"task has no worktree on disk (never materialised)"};let wt=canonicalize(worktreePath);if(wt===canonicalize(task.repo))return{removed:!1,reason:"refusing to remove the base checkout"};if(callerCwd){let rel=path.relative(wt,canonicalize(callerCwd));if(rel===""||!rel.startsWith("..")&&!path.isAbsolute(rel))return{removed:!1,reason:`refusing to remove the caller's own worktree (${worktreePath}) \u2014 re-run from outside it`}}if(deps.tearDownSession)try{await deps.tearDownSession(task.id)}catch{}let residue;try{await deps.worktrees.remove(worktreePath,{onResidue:(r)=>{residue=r}})}catch(err){return{removed:!1,reason:errText(err)}}try{await deps.clearWorktreePath(task.id)}catch(err){return{removed:!0,reason:`worktree removed, but clearing the task's worktree path failed: ${errText(err)}`,...residue?{residue}:{}}}return{removed:!0,...residue?{residue}:{}}}function errText(err){return err instanceof Error?err.message:String(err)}async function conflictedFiles(exec,dir){return(await landGit(exec,dir,["diff","--name-only","--diff-filter=U"],{readOnly:!0})).stdout.split(`
4
- `).map((l)=>l.trim()).filter((l)=>l.length>0)}async function landTask(task,input={},deps=defaultExecDeps){let strategy=input.strategy??"merge",preflight=await landPreflight(task,deps);if(preflight.refusal)throw landRefusalError(task,{...preflight,refusal:preflight.refusal});let{branch,landedOn}=preflight,{exec,dir}=baseRepoCtx(task.repo,deps);if(strategy==="squash"){if((await landGit(exec,dir,["merge","--squash",branch])).exitCode!==0){let files=await conflictedFiles(exec,dir);throw await landGit(exec,dir,["merge","--abort"]).catch(()=>{}),await landGit(exec,dir,["reset","--hard","HEAD"]).catch(()=>{}),new LandConflictError(task.id,branch,files)}let commit=await landGit(exec,dir,["commit","--no-edit","-m",`Land ${branch} (squash)`]);if(commit.exitCode!==0){if((await landGit(exec,dir,["diff","--cached","--quiet"],{readOnly:!0})).exitCode===0)throw await landGit(exec,dir,["reset","--hard","HEAD"]).catch(()=>{}),Error(`landTask: '${branch}' has nothing to land onto '${landedOn}' (already merged or empty)`);throw new GitCommandFailedError(`commit (squash-landing '${branch}' onto '${landedOn}')`,commit.stderr,"the squashed merge is left STAGED in the base checkout \u2014 fix the cause and `git commit` it, or `git reset --hard HEAD` to discard")}}else{let before=(await landGit(exec,dir,["rev-parse","HEAD"],{readOnly:!0})).stdout.trim(),merge=await landGit(exec,dir,["merge","--no-ff","-m",`Land ${branch}`,branch]);if(merge.exitCode!==0){let files=await conflictedFiles(exec,dir);if(await landGit(exec,dir,["merge","--abort"]).catch(()=>{}),files.length===0)throw new GitCommandFailedError(`merge --no-ff (landing '${branch}' onto '${landedOn}')`,merge.stderr,"the merge was aborted, so the base checkout is unchanged");throw new LandConflictError(task.id,branch,files)}let after=(await landGit(exec,dir,["rev-parse","HEAD"],{readOnly:!0})).stdout.trim();if(before===after)throw Error(`landTask: '${branch}' has nothing to land onto '${landedOn}' (already merged or empty)`)}let shaOut=await landGit(exec,dir,["rev-parse","--short","HEAD"],{readOnly:!0});return{branch,strategy,landedOn,commit:shaOut.stdout.trim()}}class MainTaskCoordinator{store;forgetWorktree;locks=new Map;constructor(store,forgetWorktree){this.store=store;this.forgetWorktree=forgetWorktree}async ensure(repo){let task=await this.ensureIfEligible(repo,"explicit");if(task)return task;let{repo:normalizedRepo}=normalizeMainRepo(repo),rejected=projectRejection(normalizedRepo,isGitRepo,"explicit")??"notGitRepo";throw Error(`cannot add ${normalizedRepo} as a project: ${rejectionReason(rejected)}`)}async ensureIfEligible(repo,intent="derived"){let{repo:normalizedRepo,key}=normalizeMainRepo(repo),onThisRoot=(task)=>normalizeMainRepo(task.repo).key===key,existing=this.store.list().find((task)=>task.kind==="main"&&onThisRoot(task));if(existing)return existing;if(projectRejection(normalizedRepo,isGitRepo,intent))return null;let inflight=this.locks.get(key);if(inflight)return inflight;let promise=(async()=>{addSavedRepo(normalizedRepo,{intent:"explicit"});let adoptable=this.store.list().find((task)=>task.kind==="dir"&&task.scratch!==!0&&onThisRoot(task));if(adoptable)return await this.store.update(adoptable.id,this.mainShape(normalizedRepo));return await this.store.create({...this.mainShape(normalizedRepo),status:"backlog",vendor:resolvePreferredVendor(normalizedRepo)})})();this.locks.set(key,promise);try{return await promise}finally{this.locks.delete(key)}}mainShape(normalizedRepo){return{kind:"main",title:titleFromRepo(normalizedRepo),repo:normalizedRepo,branch:"",worktreePath:repoWorkingDir(normalizedRepo)}}async forget(repo){if(!repo)throw Error("forgetProject: repo is required");let key=normalizeMainRepo(repo).key;for(let saved of getSavedRepos())if(normalizeMainRepo(saved).key===key)removeSavedRepo(saved);for(let task of this.store.list()){if(task.kind!=="main")continue;if(normalizeMainRepo(task.repo).key!==key)continue;await this.store.remove(task.id),this.forgetWorktree(task.id)}}}function promotableDirTasks(deps){let claimed=new Set(deps.tasks.filter((task)=>task.kind==="main").map((task)=>task.repo)),seen=new Set,out=[];for(let task of deps.tasks){if(task.kind!=="dir"||task.scratch===!0)continue;let path2=task.repo;if(!path2||claimed.has(path2)||seen.has(path2))continue;if(!deps.isRepoRoot(path2))continue;seen.add(path2),out.push(task)}return out}class TaskDeletionCoordinator{store;worktrees;forgetTask;onSalvage;onResidue;constructor(store,worktrees,forgetTask,onSalvage,onResidue){this.store=store;this.worktrees=worktrees;this.forgetTask=forgetTask;this.onSalvage=onSalvage;this.onResidue=onResidue}async prepare(id,opts){let task=this.store.get(id);if(!task)return!1;if(task.kind==="main")throw new CannotDeleteMainTaskError;if(task.deletion?.phase==="queued"||task.deletion?.phase==="running")return!0;let force=opts?.force===!0;if(task.worktreePath&&!force&&task.kind!=="dir"){let dirty=!1,ignored=[];try{if(dirty=await this.worktrees.isDirty(task.worktreePath),!dirty)ignored=await this.worktrees.ignoredWork(task.worktreePath)}catch{}if(dirty||ignored.length>0)throw new DirtyWorktreeError(task.id,ignored)}return await this.store.update(task.id,{deletion:{phase:"queued",force,deleteBranch:opts?.deleteBranch===!0,requestedAt:new Date().toISOString()}}),!0}async begin(id){let task=this.store.get(id);if(!task||!task.deletion||task.deletion.phase==="error")return!1;if(task.deletion.phase!=="running")await this.store.update(task.id,{deletion:{...task.deletion,phase:"running"}});return!0}async finish(id){let task=this.store.get(id);if(!task?.deletion||task.deletion.phase!=="running")return;try{if(task.worktreePath&&task.kind!=="dir")await this.worktrees.remove(task.worktreePath,{force:task.deletion.force,deleteBranch:task.deletion.deleteBranch===!0,repo:task.repo,branch:task.branch,onSalvage:(record)=>{if(record)this.onSalvage?.(task.id,record)},onResidue:(residue)=>this.onResidue?.(task.id,residue)})}catch(cause){let failure=new WorktreeRemoveFailedError(task.id,cause);throw await this.store.update(task.id,{deletion:{...task.deletion,phase:"error",error:errorMessage(failure)}}),failure}await this.store.remove(task.id),this.forgetTask(task.id)}async deleteNow(id,opts){if(!await this.prepare(id,opts))return;if(!await this.begin(id))return;await this.finish(id)}}var TYPE_PREFIXES=new Set(["feat","feature","fix","bugfix","hotfix","chore","docs","doc","refactor","test","tests","ci","build","perf","style","revert","release"]),BRAND_TOKENS=new Set(["rove","kobe"]);function inferBranchStyle(names){let typed=new Map,bare=0;for(let raw of new Set(names)){let name=raw.trim();if(!name||name==="HEAD")continue;let slash=name.indexOf("/");if(slash===-1){bare+=1;continue}let prefix=name.slice(0,slash);if(TYPE_PREFIXES.has(prefix))typed.set(prefix,(typed.get(prefix)??0)+1)}let typedTotal=0;for(let n of typed.values())typedTotal+=n;if(typedTotal===0||typedTotal<bare)return{kind:"bare"};let best="",bestN=0;for(let[prefix,n]of typed)if(n>bestN||n===bestN&&(best===""||prefix<best))best=prefix,bestN=n;return{kind:"typed",defaultPrefix:best}}function slugTokens(title){return title.toLowerCase().replace(/[^a-z0-9]+/g,"-").split("-").filter((t)=>t.length>0&&!BRAND_TOKENS.has(t))}function capSlug(tokens){return tokens.join("-").slice(0,32).replace(/-+$/,"")}function deriveConventionBranch(title,style){let tokens=slugTokens(title);if(style.kind==="typed"){let first=tokens[0];return`${first!==void 0&&TYPE_PREFIXES.has(first)?tokens.shift():style.defaultPrefix}/${capSlug(tokens)||"task"}`}return capSlug(tokens)||"task"}function uniqueBranchName(base,taken,taskId){if(!taken.has(base))return base;for(let n=2;n<=99;n+=1){let candidate=`${base}-${n}`;if(!taken.has(candidate))return candidate}return`${base}-${taskId.slice(-6).toLowerCase()}`}class TaskEditor{store;worktrees;constructor(store,worktrees){this.store=store,this.worktrees=worktrees}requireTask(id){let task=this.store.get(id);if(!task)throw new TaskNotFoundError(String(id));return task}async setTitle(id,title){let trimmed=title.trim();if(!trimmed)throw Error("setTitle: title is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.title===trimmed&&task.scratch!==!0)return;await this.store.update(task.id,{title:trimmed,...task.scratch===!0?{scratch:!1}:{}}),await this.followBranchToTitle(task,trimmed)}async followBranchToTitle(taskBefore,newTitle){if(taskBefore.kind==="main"||!taskBefore.worktreePath)return;if(!isPlaceholderDerivedBranch(taskBefore.branch,taskBefore.id))return;try{let names=await this.worktrees.listBranchNames(taskBefore.repo),base=deriveConventionBranch(newTitle,inferBranchStyle(names));if(base===taskBefore.branch)return;if(await this.worktrees.branchHasUpstream(taskBefore.worktreePath,taskBefore.branch))return;let taken=new Set(names.filter((n)=>n!==taskBefore.branch)),nextBranch=uniqueBranchName(base,taken,taskBefore.id);await this.setBranch(taskBefore.id,nextBranch)}catch(err){console.error(`[rove] follow-branch-to-title failed for ${taskBefore.id}:`,err)}}async setBranch(id,branch){let trimmed=branch.trim();if(!trimmed)throw Error("setBranch: branch is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.kind==="main")throw Error("setBranch: a main task tracks the repo's own branch; rename it with git directly");if(task.kind==="dir")throw Error("setBranch: a directory task tracks its own checkout; rename branches with git directly");if(task.branch===trimmed)return;if(task.worktreePath)await this.worktrees.renameBranch(task.worktreePath,task.branch,trimmed);await this.store.update(task.id,{branch:trimmed})}async observeLanguage(id,text){let observed=detectLanguage(text);if(!observed)return;let task=this.requireTask(id);if(task.observedLanguage===observed)return;await this.store.update(task.id,{observedLanguage:observed})}async setVendor(id,vendor,effort){let task=this.requireTask(id),nextEffort=effort?.trim()?effort.trim():void 0,effortChanges=effort!==void 0&&task.modelEffort!==nextEffort;if(task.vendor===vendor&&!effortChanges)return;await this.store.update(task.id,{vendor,...effort!==void 0?{modelEffort:nextEffort}:{}})}async setCommand(id,command,vendor){let trimmed=command.trim();if(!trimmed)throw Error("setCommand: command is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.command===trimmed&&(vendor===void 0||task.vendor===vendor))return;await this.store.update(task.id,{command:trimmed,...vendor?{vendor}:{}})}async setPinned(id,pinned){let task=this.requireTask(id);if(task.kind==="main")return;let next=pinned??!task.pinned;if((task.pinned??!1)===next)return;await this.store.update(task.id,{pinned:next})}async moveTask(id,delta){let task=this.requireTask(id),isMain=task.kind==="main",groupIds=this.store.list().filter((t)=>isMain?(t.kind??"task")==="main":(t.kind??"task")!=="main"&&t.repo===task.repo&&(t.pinned??!1)===(task.pinned??!1)).map((t)=>String(t.id));await this.store.move(task.id,delta,groupIds)}async setStatus(id,status){let task=this.requireTask(id);if(task.status===status)return;if(task.status==="done"&&status==="error"||task.status==="error"&&status==="done")throw new IllegalTransitionError(task.status,status,task.id);await this.store.update(task.id,{status})}async setPRStatus(id,prStatus){let task=this.requireTask(id);if((task.prStatus?.lastError??null)===(prStatus?.lastError??null)&&samePrStatus(task.prStatus,prStatus??void 0))return;await this.store.update(task.id,{prStatus:prStatus??void 0})}async setQuotaResume(id,state){let task=this.requireTask(id);if((task.quotaResume?.resumeAt??null)===(state?.resumeAt??null))return;await this.store.update(task.id,{quotaResume:state??void 0})}async setLinkedWorkItem(id,item){let task=this.requireTask(id);if((task.linkedWorkItem?.url??null)===(item?.url??null))return;await this.store.update(task.id,{linkedWorkItem:item??void 0})}async setPrompt(id,prompt){if(prompt.trim().length===0)throw Error("setPrompt: prompt is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.prompt===prompt)return;await this.store.update(task.id,{prompt})}}import{basename}from"path";var ANIMAL_NAMES=["aardvark","addax","adder","agouti","albatross","alpaca","anaconda","anchovy","anglerfish","anole","anteater","antelope","ape","argali","armadillo","avocet","axolotl","baboon","badger","banteng","barracuda","basilisk","bass","bat","beagle","bear","beaver","bee","beetle","beluga","betta","bison","blackbird","blenny","bluebird","bluegill","boar","bobcat","bonito","bovid","buffalo","bullfrog","bunting","bushbuck","butterfly","buzzard","caiman","camel","canary","capybara","caracal","cardinal","caribou","carp","cassowary","caterpillar","catfish","chameleon","chamois","char","cheetah","chickadee","chimp","chinchilla","chipmunk","chough","cicada","civet","clam","clownfish","cobra","cockatoo","condor","coot","copperhead","coral","cormorant","cougar","coyote","crab","crane","crawfish","crayfish","cricket","crocodile","crow","cuckoo","curlew","cuttlefish","deer","dikdik","dingo","dolphin","donkey","dormouse","dotterel","dove","dragonfly","dromedary","duck","dugong","dunlin","eagle","echidna","eel","egret","eider","eland","elephant","elk","emu","ermine","falcon","fawn","ferret","finch","firefly","flamingo","flounder","fox","frog","gadwall","gannet","gaur","gazelle","gecko","gemsbok","gerbil","gharial","gibbon","gnu","goat","goby","godwit","goldfish","goose","gopher","goral","gorilla","goshawk","grackle","grasshopper","grayling","grebe","grouse","guanaco","guillemot","guineafowl","guppy","halibut","hammerhead","hamster","hare","harrier","hartebeest","hawk","hedgehog","heron","herring","hippo","hornbill","hornet","horse","hummingbird","hyena","ibex","ibis","iguana","impala","indri","jacana","jackal","jaguar","jay","jellyfish","jerboa","junco","kakapo","kangaroo","kestrel","killdeer","kingfisher","kinglet","kite","kiwi","koala","kookaburra","krait","krill","kudu","ladybug","lamprey","langur","lapwing","lark","lemming","lemur","leopard","limpet","lion","lionfish","lizard","llama","lobster","locust","loon","lorikeet","loris","lynx","macaque","macaw","mackerel","magpie","mallard","mamba","mammoth","manatee","mandrill","manta","mantis","marlin","marmoset","marmot","marten","meerkat","merganser","mink","minnow","mole","mongoose","monitor","monkey","moose","moth","mouflon","mouse","mudpuppy","mule","muntjac","musk","muskox","muskrat","mussel","mustang","narwhal","newt","nightingale","numbat","nuthatch","nyala","ocelot","octopus","okapi","opossum","orangutan","orca","oriole","oryx","osprey","ostrich","otter","owl","oyster","oystercatcher","paca","panda","pangolin","panther","parakeet","parrot","parrotfish","partridge","peafowl","pelican","penguin","perch","petrel","pheasant","pigeon","pika","pike","pintail","pipefish","platypus","plover","pollock","pony","porcupine","porpoise","possum","ptarmigan","puffin","puma","pupfish","python","quail","quetzal","quokka","quoll","rabbit","raccoon","rail","rat","rattler","raven","ray","redpoll","reindeer","remora","rhino","roadrunner","robin","rook","sable","sailfish","salamander","salmon","sandpiper","sardine","scallop","scaup","scorpion","seahorse","seal","serval","shark","shearwater","shrew","shrike","shrimp","siskin","sitatunga","skate","skink","skua","skunk","sloth","smelt","snail","snipe","solenodon","sparrow","spider","springbok","squid","squirrel","starfish","starling","stilt","stingray","stoat","stork","sunbird","sunfish","swallow","swan","swift","swordfish","tahr","takin","tamarin","tanager","tapir","tarantula","tarpon","tarsier","teal","tenrec","terrapin","tern","tetra","thrasher","thrush","tiger","toad","tortoise","toucan","treecreeper","treefrog","trout","tuatara","tuna","turkey","turtle","urchin","urial","vicuna","viper","vole","vulture","wagtail","wallaby","walleye","walrus","warbler","warthog","waterbuck","weasel","wildebeest","wolf","wolverine","wombat","woodcock","woodpecker","wrasse","wren","yak","zebra","zebu","zorilla"];class SlugAllocator{activeSlugs;random;pool;pendingByRepo=new Map;chain=Promise.resolve();constructor(activeSlugs,options={}){this.activeSlugs=activeSlugs;if(this.random=options.random??Math.random,this.pool=options.pool??ANIMAL_NAMES,this.pool.length===0)throw Error("SlugAllocator: animal pool cannot be empty")}async allocate(repo){let previous=this.chain,release;this.chain=new Promise((resolve)=>{release=resolve}),await previous;try{return await this.pickLocked(repo)}finally{release()}}commit(repo,slug){this.deletePending(repo,slug)}cancel(repo,slug){this.deletePending(repo,slug)}async pickLocked(repo){let occupied=await this.occupiedSlugs(repo),candidates=this.pool.filter((n)=>!occupied.has(n));if(candidates.length>0){let pick=candidates[Math.floor(this.random()*candidates.length)];return this.addPending(repo,pick),pick}let base=this.pool[Math.floor(this.random()*this.pool.length)];for(let v=2;;v++){let candidate=`${base}-v${v}`;if(!occupied.has(candidate))return this.addPending(repo,candidate),candidate}}async occupiedSlugs(repo){let set=new Set(this.pendingByRepo.get(repo)??[]);for(let slug of this.activeSlugs(repo))if(slug)set.add(slug);for(let dir of await listWorktreeDirNames(repo))set.add(dir);return set}addPending(repo,slug){let pending=this.pendingByRepo.get(repo);if(!pending)pending=new Set,this.pendingByRepo.set(repo,pending);pending.add(slug)}deletePending(repo,slug){let pending=this.pendingByRepo.get(repo);if(!pending)return;if(pending.delete(slug),pending.size===0)this.pendingByRepo.delete(repo)}}class WorktreeCoordinator{store;worktrees;canonPath;ensureProject;slugs;worktreeLocks=new Map;adoptLocks=new Map;reservedBranches=new Set;constructor(store,worktrees,canonPath2,ensureProject){this.store=store,this.worktrees=worktrees,this.canonPath=canonPath2,this.ensureProject=ensureProject,this.slugs=new SlugAllocator((repo)=>this.store.list().filter((t)=>t.repo===repo&&t.kind!=="main").map((t)=>{return t.worktreePath.match(/([^/\\]+)[/\\]*$/)?.[1]??""}).filter((s)=>s.length>0))}forget(id){this.worktreeLocks.delete(id)}async ensure(task){let inflight=this.worktreeLocks.get(task.id);if(inflight)return inflight;let work=this.createWorktree(task);this.worktreeLocks.set(task.id,work);try{return await work}finally{this.worktreeLocks.delete(task.id)}}async createWorktree(task){let slug=await this.slugs.allocate(task.repo),branch=task.branch||await this.deriveAutoBranch(task),baseRef=task.baseRef,info;try{info=await this.worktrees.createForTask({repo:task.repo,slug,branch,baseRef})}catch(err){throw this.slugs.cancel(task.repo,slug),err}finally{this.reservedBranches.delete(branch)}try{await this.store.update(task.id,{worktreePath:info.path,branch})}catch(err){throw await this.rollbackWorktree(info.path),this.slugs.cancel(task.repo,slug),err}return this.slugs.commit(task.repo,slug),info.path}async deriveAutoBranch(task){let names=await this.worktrees.listBranchNames(task.repo),base=deriveConventionBranch(task.title,inferBranchStyle(names)),taken=new Set([...names,...this.reservedBranches]),branch=uniqueBranchName(base,taken,task.id);return this.reservedBranches.add(branch),branch}async rollbackWorktree(worktreePath){try{await this.worktrees.remove(worktreePath,{force:!0})}catch(err){console.error(`[rove] ensureWorktree rollback failed for ${worktreePath}:`,err)}}async discoverAdoptable(repo){let all=await this.worktrees.listAll(repo),linked=new Set(this.store.list().filter((t)=>t.worktreePath).map((t)=>this.canonPath(t.worktreePath)));return all.filter((wt)=>!linked.has(this.canonPath(wt.path)))}async adopt(input){let target=this.canonPath(input.worktreePath),inflight=this.adoptLocks.get(target);if(inflight)return inflight;let work=this.adoptLocked(input,target);this.adoptLocks.set(target,work);try{return await work}finally{this.adoptLocks.delete(target)}}async adoptLocked(input,target){let existing=this.store.list().find((t)=>t.worktreePath&&this.canonPath(t.worktreePath)===target);if(existing){if(input.ifExists==="return")return existing;throw Error(`adoptWorktree: ${input.worktreePath} is already adopted as a task`)}let match=(await this.worktrees.listAdoptablePaths(input.repo)).find((wt)=>this.canonPath(wt.path)===target);if(!match)throw Error(`adoptWorktree: ${input.worktreePath} is not an adoptable git worktree of ${input.repo} (unknown, detached, or the main checkout)`);let branch=input.branch?.trim()||match.branch,title=(input.title??basename(match.path)).trim()||PLACEHOLDER_TASK_TITLE;return await this.ensureProject(input.repo),this.store.create({repo:input.repo,title,branch,worktreePath:match.path,status:"backlog",kind:"task",vendor:input.vendor??DEFAULT_TASK_VENDOR})}}class Orchestrator{store;worktrees;worktreeCoordinator;editor;deletions;tasksAcc;activeTaskAcc;unsubscribeStore;mainTasks;tearDownSession;constructor(deps){this.store=deps.store,this.worktrees=deps.worktrees,this.tearDownSession=deps.tearDownSession,this.worktreeCoordinator=new WorktreeCoordinator(this.store,this.worktrees,canonPath,(repo)=>this.mainTasks.ensureIfEligible(repo)),this.mainTasks=new MainTaskCoordinator(this.store,(id)=>this.worktreeCoordinator.forget(id)),this.editor=new TaskEditor(this.store,this.worktrees),this.deletions=new TaskDeletionCoordinator(this.store,this.worktrees,(id)=>this.worktreeCoordinator.forget(id),deps.onSalvage,deps.onWorktreeResidue),this.tasksAcc=createStateCell(this.store.list());let persistedFocus=readLastActiveTaskId();this.activeTaskAcc=createStateCell(persistedFocus&&this.store.get(persistedFocus)?persistedFocus:null),this.unsubscribeStore=this.store.subscribe((snapshot)=>{this.tasksAcc.set(snapshot.slice())})}async init(){try{let promotable=promotableDirTasks({tasks:this.store.list(),isRepoRoot:(path2)=>isGitRepo(path2)&&resolveRepoRoot(path2)===path2});for(let task of promotable)await this.mainTasks.ensureIfEligible(task.repo,"explicit")}catch{}}activeTaskSignal(){return this.activeTaskAcc}async setActiveTask(id){let next=id===null?null:String(id);if(next&&this.store.get(next)?.deletion)throw new TaskDeletingError(next);if(this.activeTaskAcc.set(next),next&&this.store.get(next))writeLastActiveTaskId(next),this.store.touchRecency(next)}tasksSignal(){return this.tasksAcc}subscribeTasks(listener){return this.store.subscribe(listener)}dispose(){this.unsubscribeStore()}listTasks(){return this.store.list()}getTask(id){return this.store.get(id)}createTask=(input)=>createTaskRow({store:this.store,mainTasks:this.mainTasks},input);openDirectoryTask=(input)=>openDirectoryTaskRow({store:this.store},input);adoptScratchRepo=(id,repo)=>adoptScratchRepoRow({store:this.store},id,repo);async ensureMainTask(repo){return await this.mainTasks.ensure(repo)}async ensureWorktree(id){let task=this.requireTask(id);if(task.deletion)throw new TaskDeletingError(String(task.id));if(task.kind==="main")return repoWorkingDir(task.repo);if(task.kind==="dir")return task.worktreePath;if(task.worktreePath){if(await this.worktrees.pathExists(task.worktreePath))return task.worktreePath;return await this.worktrees.pruneWorktrees(task.repo),await this.store.update(task.id,{worktreePath:""}),this.worktreeCoordinator.ensure({...task,worktreePath:""})}return this.worktreeCoordinator.ensure(task)}async clearWorktreePath(id){let task=this.store.get(id);if(!task||!task.worktreePath)return;if(task.kind==="main"||task.kind==="dir")return;await this.store.update(task.id,{worktreePath:""}),this.worktreeCoordinator.forget(task.id)}setTitle=(id,title)=>this.editor.setTitle(id,title);setBranch=(id,branch)=>this.editor.setBranch(id,branch);observeLanguage=(id,text)=>this.editor.observeLanguage(id,text);setVendor=(id,vendor,effort)=>this.editor.setVendor(id,vendor,effort);setCommand=(id,command,vendor)=>this.editor.setCommand(id,command,vendor);setPinned=(id,pinned)=>this.editor.setPinned(id,pinned);moveTask=(id,delta)=>this.editor.moveTask(id,delta);setStatus=(id,status)=>this.editor.setStatus(id,status);setPRStatus=(id,prStatus)=>this.editor.setPRStatus(id,prStatus);setLinkedWorkItem=(id,item)=>this.editor.setLinkedWorkItem(id,item);setQuotaResume=(id,state)=>this.editor.setQuotaResume(id,state);setPrompt=(id,prompt)=>this.editor.setPrompt(id,prompt);async deleteTask(id,opts){await this.deletions.deleteNow(id,opts)}async prepareTaskDeletion(id,opts){return this.deletions.prepare(id,opts)}async beginTaskDeletion(id){return this.deletions.begin(id)}async finishTaskDeletion(id){return this.deletions.finish(id)}async landPreflight(id){let task=this.requireTask(id);if(task.kind==="main")throw Error("landTask: a main task has no branch to land");if(task.kind==="dir")throw Error("landTask: a directory task has no Rove-managed branch to land");if(task.deletion)throw new TaskDeletingError(String(task.id));return landPreflight(task)}async landTask(id,opts){let task=this.requireTask(id);if(task.deletion)throw new TaskDeletingError(String(task.id));return landTaskWithCleanup(task,opts??{},{worktrees:this.worktrees,clearWorktreePath:(tid)=>this.clearWorktreePath(tid),tearDownSession:this.tearDownSession})}async forgetProject(repo){await this.mainTasks.forget(repo)}async discoverAdoptableWorktrees(repo){if(!repo)throw Error("discoverAdoptableWorktrees: repo is required");return this.worktreeCoordinator.discoverAdoptable(repo)}async adoptWorktree(input){if(!input.repo)throw Error("adoptWorktree: repo is required");if(!input.worktreePath)throw Error("adoptWorktree: worktreePath is required");return this.worktreeCoordinator.adopt(input)}requireTask(id){let task=this.store.get(id);if(!task)throw new TaskNotFoundError(String(id));return task}}
5
- export{parseDirtyPaths,Orchestrator};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{API_VERBS,RETIRED_VERBS,VERBS,VERB_ALIASES,VERB_GROUPS,findVerb}from"./chunk-ed1y1wtm.js";import"./chunk-v9p6gxm0.js";import"./chunk-pxtx1gcf.js";import"./chunk-ap5bjaq8.js";import"./chunk-aq912vvw.js";import"./chunk-d393z1mj.js";import"./chunk-qkehg2c1.js";import"./chunk-dv7rxr77.js";import"./chunk-4tzgma89.js";import"./chunk-xjskp76m.js";import"./chunk-z2aqaabp.js";import"./chunk-fd7swjnq.js";import"./chunk-37gnmm2m.js";import"./chunk-bkba9c4n.js";import"./chunk-g2advs8t.js";import"./chunk-e8493db0.js";import"./chunk-rkt1qjec.js";import"./chunk-7q67dz4c.js";import"./chunk-1cjd7h8p.js";import"./chunk-b99tf0jr.js";import"./chunk-z1e1bsv5.js";import"./chunk-hape5vwj.js";import"./chunk-2z90jxcn.js";import"./chunk-nm802jgt.js";import"./chunk-zaxdx0wd.js";import"./chunk-sexavazm.js";import"./chunk-sdyzxayr.js";import"./chunk-b9h2ywc7.js";import"./chunk-jvxh93nz.js";import"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-g5nz190n.js";import"./chunk-7z9cqycv.js";import"./chunk-ea1r26pa.js";import"./chunk-w7zv47mp.js";import"./chunk-gwcneg6c.js";import"./chunk-9zb2wkfr.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-nywh3yb9.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-bq3fyc0p.js";import"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-rxvbm4vt.js";import"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{findVerb,VERB_GROUPS,VERB_ALIASES,VERBS,RETIRED_VERBS,API_VERBS};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{TaskIndexStore}from"./chunk-51y7sjhe.js";import"./chunk-qkehg2c1.js";import"./chunk-nywh3yb9.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-bq3fyc0p.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{TaskIndexStore};
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{getCustomEngineIds,getPersistedString,setPersistedString}from"./chunk-deejtpcr.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";import{isBuiltinVendor}from"./chunk-bq3fyc0p.js";var REPO_KEY_PREFIX="lastActiveVendor.";function validVendor(value,customIds){let v=value?.trim();if(!v)return;if(isBuiltinVendor(v)||customIds.includes(v))return v;return}function getRepoLastActiveVendor(repo){return validVendor(getPersistedString(REPO_KEY_PREFIX+repo),getCustomEngineIds())}function setRepoLastActiveVendor(repo,vendor){setPersistedString(REPO_KEY_PREFIX+repo,vendor)}function getGlobalDefaultVendor(){let customIds=getCustomEngineIds();return validVendor(getPersistedString("defaultVendor"),customIds)??validVendor(getPersistedString("lastSelectedVendor"),customIds)}function setGlobalDefaultVendor(vendor){setPersistedString("defaultVendor",vendor)}function resolvePreferredVendor(repo){return(repo?getRepoLastActiveVendor(repo):void 0)??getGlobalDefaultVendor()??DEFAULT_TASK_VENDOR}
3
- export{getRepoLastActiveVendor,setRepoLastActiveVendor,getGlobalDefaultVendor,setGlobalDefaultVendor,resolvePreferredVendor};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{engineProcessIn,foregroundEngine,foregroundEngineIn,hasAncestor,parsePsSnapshot,psSnapshot,vendorFromArgv}from"./chunk-g5nz190n.js";import"./chunk-7z9cqycv.js";import"./chunk-ea1r26pa.js";import"./chunk-w7zv47mp.js";import"./chunk-gwcneg6c.js";import"./chunk-9zb2wkfr.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-deejtpcr.js";import"./chunk-rsqx358z.js";import"./chunk-nywh3yb9.js";import"./chunk-xy8be792.js";import"./chunk-a3a9gdc4.js";import"./chunk-2brn8e1y.js";import"./chunk-s8eh3cf1.js";import"./chunk-07k2njwk.js";import"./chunk-bq3fyc0p.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{vendorFromArgv,psSnapshot,parsePsSnapshot,hasAncestor,foregroundEngineIn,foregroundEngine,engineProcessIn};
@@ -1,9 +0,0 @@
1
- // @bun
2
- import{canonicalize,isKobeManagedPath,isUnderManagedWorktreesRoot,managedWorktreeRootForPath,remoteManagedRootForPath,remoteWorktreePathFor,requireAbsolute,worktreePathFor}from"./chunk-5snrwe65.js";import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{execHostForRepo,execHostForWorktreePath}from"./chunk-37gnmm2m.js";import{getRemoteRepoConfig}from"./chunk-deejtpcr.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};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{readLastActiveTaskId,writeLastActiveTaskId}from"./chunk-mmd7zehs.js";import"./chunk-rsqx358z.js";import"./chunk-a3a9gdc4.js";import"./chunk-07k2njwk.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{writeLastActiveTaskId,readLastActiveTaskId};