@sma1lboy/rove 0.9.169 → 0.9.171

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/cli/{chunk-58rxg1df.js → chunk-1fpbk5mj.js} +1 -1
  2. package/dist/cli/{chunk-x532akk8.js → chunk-2ytd28ng.js} +1 -1
  3. package/dist/cli/{chunk-me9k96p4.js → chunk-3a1fjn0q.js} +1 -1
  4. package/dist/cli/{chunk-x2nxvy0s.js → chunk-3ppjycfg.js} +1 -1
  5. package/dist/cli/{chunk-9fff5sng.js → chunk-511nqhca.js} +1 -1
  6. package/dist/cli/{chunk-ssemfgv5.js → chunk-5jw5af60.js} +1 -1
  7. package/dist/cli/{chunk-wrwx9xtg.js → chunk-5wpdpghc.js} +1 -1
  8. package/dist/cli/{chunk-hk0arzxh.js → chunk-6q38ved5.js} +2 -2
  9. package/dist/cli/{chunk-cnqtvf4b.js → chunk-756rtc9n.js} +1 -1
  10. package/dist/cli/{chunk-ahrjn20k.js → chunk-7jbap5z2.js} +1 -1
  11. package/dist/cli/{chunk-pg9w7dpg.js → chunk-81ynhhq4.js} +1 -1
  12. package/dist/cli/{chunk-8wrzdj5x.js → chunk-855rzebn.js} +1 -1
  13. package/dist/cli/{chunk-h8m37225.js → chunk-8wrgvzy9.js} +2 -2
  14. package/dist/cli/{chunk-fhkhn8qw.js → chunk-9tq6exs5.js} +1 -1
  15. package/dist/cli/{chunk-62786g7s.js → chunk-a7wq1cba.js} +1 -1
  16. package/dist/cli/{chunk-571tfj6q.js → chunk-ap95e417.js} +2 -2
  17. package/dist/cli/{chunk-srn281km.js → chunk-aqvm6f5v.js} +1 -1
  18. package/dist/cli/{chunk-7e65s8j5.js → chunk-ba5a5faq.js} +1 -1
  19. package/dist/cli/{chunk-2fyapkh0.js → chunk-bhdtmwax.js} +2 -2
  20. package/dist/cli/{chunk-av4fw4ny.js → chunk-bpre78rc.js} +1 -1
  21. package/dist/cli/{chunk-7pxam13t.js → chunk-efkpbpkm.js} +1 -1
  22. package/dist/cli/{chunk-zfqm8rmp.js → chunk-enct2vtg.js} +1 -1
  23. package/dist/cli/{chunk-mb46dky0.js → chunk-f76j7drr.js} +1 -1
  24. package/dist/cli/{chunk-7vxswkn1.js → chunk-fkwaxx0y.js} +1 -1
  25. package/dist/cli/chunk-fndegq4p.js +3 -0
  26. package/dist/cli/{chunk-kx8ye934.js → chunk-g83jaj2y.js} +2 -2
  27. package/dist/cli/{chunk-cwnwj3r8.js → chunk-gv212jx6.js} +2 -2
  28. package/dist/cli/{chunk-nxspqeew.js → chunk-hqnephbs.js} +1 -1
  29. package/dist/cli/{chunk-2318tyyb.js → chunk-hxv7g8yq.js} +1 -1
  30. package/dist/cli/{chunk-jv1mzx1g.js → chunk-jdhhgxgv.js} +5 -3
  31. package/dist/cli/{chunk-6wfwskxn.js → chunk-k68brrpa.js} +1 -1
  32. package/dist/cli/{chunk-ann3wt0v.js → chunk-kbvyv1x2.js} +3 -3
  33. package/dist/cli/{chunk-25yb9edp.js → chunk-kj58sv01.js} +1 -1
  34. package/dist/cli/{chunk-kef4sq4z.js → chunk-kkx24j75.js} +1 -1
  35. package/dist/cli/{chunk-y0nq7amn.js → chunk-ky9e5s1q.js} +1 -1
  36. package/dist/cli/{chunk-9w8f8gw6.js → chunk-navjgqby.js} +1 -1
  37. package/dist/cli/{chunk-12gr0411.js → chunk-nxj2t0rq.js} +1 -1
  38. package/dist/cli/{chunk-v2cpe974.js → chunk-pthtyzcs.js} +1 -1
  39. package/dist/cli/{chunk-9tase72d.js → chunk-q86jajp5.js} +1 -1
  40. package/dist/cli/{chunk-xwekyjat.js → chunk-rxh74abe.js} +1 -1
  41. package/dist/cli/{chunk-h0wb7a5x.js → chunk-v0rgt7sh.js} +1 -1
  42. package/dist/cli/chunk-vetk9j99.js +3 -0
  43. package/dist/cli/chunk-wprfqncz.js +2 -0
  44. package/dist/cli/chunk-xb9b93ts.js +3 -0
  45. package/dist/cli/{chunk-p1n1efh6.js → chunk-yqardayk.js} +1 -1
  46. package/dist/cli/index.js +3 -3
  47. package/dist/cli/kobe.js +1 -1
  48. package/dist/cli/rove.js +1 -1
  49. package/package.json +1 -1
  50. package/dist/cli/chunk-275h7b12.js +0 -2
  51. package/dist/cli/chunk-9kefy6ev.js +0 -3
  52. package/dist/cli/chunk-m66t4fvt.js +0 -3
  53. package/dist/cli/chunk-me23en52.js +0 -3
@@ -4,4 +4,4 @@ import{SUBCOMMAND_VERBS}from"./chunk-s76r56rj.js";import{expandTilde}from"./chun
4
4
 
5
5
  ${REPO_USAGE}
6
6
  `),process.exit(2)}function readArgFile(path){try{return readFileSync(resolve(process.cwd(),expandTilde(path)),"utf8")}catch(err){usageError(`cannot read ${path}: ${errorMessage(err)}`)}}function parseRepoArgs(args){let out={};for(let i=0;i<args.length;i++){let a=args[i],need=()=>{let v=args[++i];if(v===void 0)usageError(`${a} requires a value`);return v};if(a==="--init-script")out.initScript=need();else if(a==="--init-script-file")out.initScript=readArgFile(need());else if(a==="--init-prompt")out.initPrompt=need();else if(a==="--init-prompt-file")out.initPrompt=readArgFile(need());else if(a.startsWith("-"))usageError(`unknown flag "${a}"`);else if(out.path===void 0)out.path=a;else usageError(`unexpected argument "${a}"`)}return out}function parseUnsetArgs(args){let path,clearScript=!1,clearPrompt=!1;for(let a of args)if(a==="--init-script")clearScript=!0;else if(a==="--init-prompt")clearPrompt=!0;else if(a.startsWith("-"))usageError(`unknown flag "${a}"`);else if(path===void 0)path=a;else usageError(`unexpected argument "${a}"`);if(!clearScript&&!clearPrompt)clearScript=!0,clearPrompt=!0;return{path,clearScript,clearPrompt}}async function runRepoSubcommand(args){let[verb,...rest]=args;if(verb===void 0||verb==="--help"||verb==="-h"||verb==="help"){process.stdout.write(`${REPO_USAGE}
7
- `);return}if(!SUBCOMMAND_VERBS.repo.includes(verb))usageError(`unknown verb "${verb}"`);let{getRepoInitOverride,setRepoInitOverride,resolveRepoRoot}=await import("./chunk-mmg7m9x2.js");if(verb==="show"){let[pathArg]=rest.filter((a)=>!a.startsWith("-")),repo=resolveRepoRoot(resolve(process.cwd(),expandTilde(pathArg??"."))),override=getRepoInitOverride(repo),{describeRepoInitSources}=await import("./chunk-12gr0411.js"),sources=describeRepoInitSources(repo);console.log(`repo: ${repo}`);for(let group of[sources.script,sources.prompt])group.forEach((source,index)=>{console.log(` ${`${source.rel}:`.padEnd(22)}${describeSource(group,index)}`)});console.log(` override initScript: ${override.initScript?quotePreview(override.initScript):"(unset)"}`),console.log(` override initPrompt: ${override.initPrompt?quotePreview(override.initPrompt):"(unset)"}`);return}if(verb==="set"){let flags=parseRepoArgs(rest);if(flags.initScript===void 0&&flags.initPrompt===void 0)usageError("set needs at least one of --init-script(-file) / --init-prompt(-file)");let repo=resolveRepoRoot(resolve(process.cwd(),expandTilde(flags.path??"."))),next=setRepoInitOverride(repo,{...flags.initScript!==void 0?{initScript:flags.initScript}:{},...flags.initPrompt!==void 0?{initPrompt:flags.initPrompt}:{}});console.log(`updated override for ${repo}`),console.log(` initScript: ${next.initScript?quotePreview(next.initScript):"(unset)"}`),console.log(` initPrompt: ${next.initPrompt?quotePreview(next.initPrompt):"(unset)"}`);return}if(verb==="unset"){let{path,clearScript,clearPrompt}=parseUnsetArgs(rest),repo=resolveRepoRoot(resolve(process.cwd(),expandTilde(path??"."))),next=setRepoInitOverride(repo,{...clearScript?{initScript:""}:{},...clearPrompt?{initPrompt:""}:{}});console.log(`cleared override for ${repo}`),console.log(` initScript: ${next.initScript?quotePreview(next.initScript):"(unset)"}`),console.log(` initPrompt: ${next.initPrompt?quotePreview(next.initPrompt):"(unset)"}`);return}usageError(`unknown verb "${verb}"`)}function describeSource(group,index){let source=group[index];if(!source)return"absent";if(source.effective)return"present (wins)";if(!source.present)return"absent";return group.slice(0,index).some((earlier)=>earlier.effective)?"present (shadowed)":"present but empty (ignored)"}function quotePreview(value){let oneLine=value.replace(/\s+/g," ").trim();return oneLine.length>60?`"${oneLine.slice(0,57)}\u2026"`:`"${oneLine}"`}export{runRepoSubcommand};
7
+ `);return}if(!SUBCOMMAND_VERBS.repo.includes(verb))usageError(`unknown verb "${verb}"`);let{getRepoInitOverride,setRepoInitOverride,resolveRepoRoot}=await import("./chunk-mmg7m9x2.js");if(verb==="show"){let[pathArg]=rest.filter((a)=>!a.startsWith("-")),repo=resolveRepoRoot(resolve(process.cwd(),expandTilde(pathArg??"."))),override=getRepoInitOverride(repo),{describeRepoInitSources}=await import("./chunk-nxj2t0rq.js"),sources=describeRepoInitSources(repo);console.log(`repo: ${repo}`);for(let group of[sources.script,sources.prompt])group.forEach((source,index)=>{console.log(` ${`${source.rel}:`.padEnd(22)}${describeSource(group,index)}`)});console.log(` override initScript: ${override.initScript?quotePreview(override.initScript):"(unset)"}`),console.log(` override initPrompt: ${override.initPrompt?quotePreview(override.initPrompt):"(unset)"}`);return}if(verb==="set"){let flags=parseRepoArgs(rest);if(flags.initScript===void 0&&flags.initPrompt===void 0)usageError("set needs at least one of --init-script(-file) / --init-prompt(-file)");let repo=resolveRepoRoot(resolve(process.cwd(),expandTilde(flags.path??"."))),next=setRepoInitOverride(repo,{...flags.initScript!==void 0?{initScript:flags.initScript}:{},...flags.initPrompt!==void 0?{initPrompt:flags.initPrompt}:{}});console.log(`updated override for ${repo}`),console.log(` initScript: ${next.initScript?quotePreview(next.initScript):"(unset)"}`),console.log(` initPrompt: ${next.initPrompt?quotePreview(next.initPrompt):"(unset)"}`);return}if(verb==="unset"){let{path,clearScript,clearPrompt}=parseUnsetArgs(rest),repo=resolveRepoRoot(resolve(process.cwd(),expandTilde(path??"."))),next=setRepoInitOverride(repo,{...clearScript?{initScript:""}:{},...clearPrompt?{initPrompt:""}:{}});console.log(`cleared override for ${repo}`),console.log(` initScript: ${next.initScript?quotePreview(next.initScript):"(unset)"}`),console.log(` initPrompt: ${next.initPrompt?quotePreview(next.initPrompt):"(unset)"}`);return}usageError(`unknown verb "${verb}"`)}function describeSource(group,index){let source=group[index];if(!source)return"absent";if(source.effective)return"present (wins)";if(!source.present)return"absent";return group.slice(0,index).some((earlier)=>earlier.effective)?"present (shadowed)":"present but empty (ignored)"}function quotePreview(value){let oneLine=value.replace(/\s+/g," ").trim();return oneLine.length>60?`"${oneLine.slice(0,57)}\u2026"`:`"${oneLine}"`}export{runRepoSubcommand};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{applyOnboardingChoices,detectShell,envReadyForTasks,installCompletions,maybeRunOnboarding}from"./chunk-571tfj6q.js";import"./chunk-8wrzdj5x.js";import"./chunk-3p2e2ry4.js";import"./chunk-m0g17ckn.js";import"./chunk-me9k96p4.js";import"./chunk-mb46dky0.js";import"./chunk-qqw3p4fc.js";import"./chunk-5agemmmn.js";import"./chunk-xwekyjat.js";import"./chunk-v2cpe974.js";import"./chunk-sdyzxayr.js";import"./chunk-jvxh93nz.js";import"./chunk-jn5dd6bv.js";import"./chunk-xhw8s2es.js";import"./chunk-khj0apc7.js";import"./chunk-nzscq4yf.js";import"./chunk-w7zv47mp.js";import"./chunk-dt51afhh.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-k1qe5qqa.js";import"./chunk-xy8be792.js";import"./chunk-6wpege0h.js";import"./chunk-j75axe29.js";import"./chunk-ayhhgfsz.js";import"./chunk-2brn8e1y.js";import"./chunk-bq3fyc0p.js";import"./chunk-3wj69b0a.js";import"./chunk-ch9b1d5y.js";import"./chunk-mv7ptt5w.js";import"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import"./chunk-pxk2c2vj.js";import"./chunk-k2ckx8zw.js";import"./chunk-pw6yfj10.js";import"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import"./chunk-wqfp8d9w.js";export{maybeRunOnboarding,installCompletions,envReadyForTasks,detectShell,applyOnboardingChoices};
2
+ import{applyOnboardingChoices,detectShell,envReadyForTasks,installCompletions,maybeRunOnboarding}from"./chunk-ap95e417.js";import"./chunk-855rzebn.js";import"./chunk-3p2e2ry4.js";import"./chunk-m0g17ckn.js";import"./chunk-3a1fjn0q.js";import"./chunk-f76j7drr.js";import"./chunk-qqw3p4fc.js";import"./chunk-5agemmmn.js";import"./chunk-rxh74abe.js";import"./chunk-pthtyzcs.js";import"./chunk-sdyzxayr.js";import"./chunk-jvxh93nz.js";import"./chunk-jn5dd6bv.js";import"./chunk-xhw8s2es.js";import"./chunk-khj0apc7.js";import"./chunk-nzscq4yf.js";import"./chunk-w7zv47mp.js";import"./chunk-dt51afhh.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-k1qe5qqa.js";import"./chunk-xy8be792.js";import"./chunk-6wpege0h.js";import"./chunk-j75axe29.js";import"./chunk-ayhhgfsz.js";import"./chunk-2brn8e1y.js";import"./chunk-bq3fyc0p.js";import"./chunk-3wj69b0a.js";import"./chunk-ch9b1d5y.js";import"./chunk-mv7ptt5w.js";import"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import"./chunk-pxk2c2vj.js";import"./chunk-k2ckx8zw.js";import"./chunk-pw6yfj10.js";import"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import"./chunk-wqfp8d9w.js";export{maybeRunOnboarding,installCompletions,envReadyForTasks,detectShell,applyOnboardingChoices};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{canonicalize}from"./chunk-me23en52.js";import{applyJitter,exponentialBackoff}from"./chunk-khj0apc7.js";import{getRemoteRepoConfig,isRemoteRepoKey,resolveRepoRoot}from"./chunk-6wpege0h.js";var canonPath=canonicalize;function randomDirTaskSuffix(){return Math.random().toString(36).slice(2,6).padEnd(4,"0")}function titleFromRepo(repo){let segs=repo.split(/[/\\]/).filter(Boolean);return segs.length>0?segs[segs.length-1]??repo:repo}function normalizeMainRepo(repo){let normalized=resolveRepoRoot(repo);return{repo:normalized,key:isRemoteRepoKey(normalized)?normalized:canonPath(normalized)}}function repoWorkingDir(repo){return getRemoteRepoConfig(repo)?.basePath??repo}var GH_PR_VIEW_FIELDS="number,url,title,state,baseRefName,reviewDecision,mergeable,statusCheckRollup";function lifecycleFromState(state,reviewDecision){switch((state??"").toUpperCase()){case"MERGED":return"merged";case"CLOSED":return"closed";case"OPEN":return(reviewDecision??"").toUpperCase()==="APPROVED"?"ready_to_merge":"open";default:return"unknown"}}function entryCheckState(entry){let status=(entry.status??"").toUpperCase(),conclusion=(entry.conclusion??"").toUpperCase(),contextState=(entry.state??"").toUpperCase();if(status&&status!=="COMPLETED")return"pending";if(conclusion){if(conclusion==="SUCCESS"||conclusion==="NEUTRAL"||conclusion==="SKIPPED")return"passing";return"failing"}if(contextState==="SUCCESS")return"passing";if(contextState==="PENDING"||contextState==="EXPECTED")return"pending";if(contextState==="FAILURE"||contextState==="ERROR")return"failing";return"unknown"}function checkStateFromRollup(rollup){if(!rollup||rollup.length===0)return"none";let sawPending=!1,sawPassing=!1;for(let entry of rollup){let s=entryCheckState(entry);if(s==="failing")return"failing";if(s==="pending")sawPending=!0;else if(s==="passing")sawPassing=!0}if(sawPending)return"pending";if(sawPassing)return"passing";return"unknown"}function mapGhPrView(view,at){if(!view||typeof view.number!=="number")return null;return{provider:"github",lifecycle:lifecycleFromState(view.state,view.reviewDecision),checkState:checkStateFromRollup(view.statusCheckRollup),number:view.number,url:view.url,title:view.title,baseRef:view.baseRefName,reviewDecision:view.reviewDecision||void 0,mergeable:view.mergeable||void 0,lastCheckedAt:at}}function samePrStatus(a,b){if(a===b)return!0;if(!a||!b)return!1;return a.provider===b.provider&&a.lifecycle===b.lifecycle&&a.checkState===b.checkState&&a.number===b.number&&a.url===b.url&&a.title===b.title&&a.baseRef===b.baseRef&&a.reviewDecision===b.reviewDecision&&a.mergeable===b.mergeable}var NO_REMOTE_PATTERNS=["none of the git remotes","no git remote","to use github cli in a github repository","not a github repository"],AUTH_PATTERNS=["gh auth login","authentication required","not logged in","http 401","bad credentials","requires authentication"],NETWORK_PATTERNS=["could not resolve host","no such host","dial tcp","connection refused","connection reset","network is unreachable","i/o timeout","timeout","tls handshake","http 5","rate limit","try again"];function matchesAny(haystack,needles){return needles.some((n)=>haystack.includes(n))}function classifyGhFailure(s){if(s.parseError)return{kind:"error",error:"parse"};if(s.timedOut)return{kind:"error",error:"timeout"};if(s.spawnError)return{kind:"error",error:"missing-binary"};let err=(s.stderr??"").toLowerCase();if(matchesAny(err,NO_REMOTE_PATTERNS))return{kind:"error",error:"no-remote"};if(matchesAny(err,AUTH_PATTERNS))return{kind:"error",error:"auth"};if(matchesAny(err,NETWORK_PATTERNS))return{kind:"error",error:"network"};return{kind:"error",error:"unknown"}}function nextPrPoll(outcome,prevFailures,now,cfg,rand=Math.random){let at=(delay)=>now+applyJitter(delay,cfg.jitterRatio,rand);if(outcome.kind==="pr")return{nextAllowedAt:at(outcome.settled?cfg.settledMs:cfg.tickMs),failures:0};if(outcome.kind==="empty")return{nextAllowedAt:at(cfg.noPrMs),failures:0};if(outcome.error==="no-remote")return{nextAllowedAt:at(cfg.noRemoteMs),failures:0};let failures=prevFailures+1;return{nextAllowedAt:at(exponentialBackoff(cfg.failureBaseMs,failures-1,cfg.failureCapMs)),failures}}function checkResolutionNotify(prev,next){if(prev!=="pending")return null;if(next==="passing"||next==="failing")return next;return null}
2
+ import{canonicalize}from"./chunk-fndegq4p.js";import{applyJitter,exponentialBackoff}from"./chunk-khj0apc7.js";import{getRemoteRepoConfig,isRemoteRepoKey,resolveRepoRoot}from"./chunk-6wpege0h.js";var canonPath=canonicalize;function randomDirTaskSuffix(){return Math.random().toString(36).slice(2,6).padEnd(4,"0")}function titleFromRepo(repo){let segs=repo.split(/[/\\]/).filter(Boolean);return segs.length>0?segs[segs.length-1]??repo:repo}function normalizeMainRepo(repo){let normalized=resolveRepoRoot(repo);return{repo:normalized,key:isRemoteRepoKey(normalized)?normalized:canonPath(normalized)}}function repoWorkingDir(repo){return getRemoteRepoConfig(repo)?.basePath??repo}var GH_PR_VIEW_FIELDS="number,url,title,state,baseRefName,reviewDecision,mergeable,statusCheckRollup";function lifecycleFromState(state,reviewDecision){switch((state??"").toUpperCase()){case"MERGED":return"merged";case"CLOSED":return"closed";case"OPEN":return(reviewDecision??"").toUpperCase()==="APPROVED"?"ready_to_merge":"open";default:return"unknown"}}function entryCheckState(entry){let status=(entry.status??"").toUpperCase(),conclusion=(entry.conclusion??"").toUpperCase(),contextState=(entry.state??"").toUpperCase();if(status&&status!=="COMPLETED")return"pending";if(conclusion){if(conclusion==="SUCCESS"||conclusion==="NEUTRAL"||conclusion==="SKIPPED")return"passing";return"failing"}if(contextState==="SUCCESS")return"passing";if(contextState==="PENDING"||contextState==="EXPECTED")return"pending";if(contextState==="FAILURE"||contextState==="ERROR")return"failing";return"unknown"}function checkStateFromRollup(rollup){if(!rollup||rollup.length===0)return"none";let sawPending=!1,sawPassing=!1;for(let entry of rollup){let s=entryCheckState(entry);if(s==="failing")return"failing";if(s==="pending")sawPending=!0;else if(s==="passing")sawPassing=!0}if(sawPending)return"pending";if(sawPassing)return"passing";return"unknown"}function mapGhPrView(view,at){if(!view||typeof view.number!=="number")return null;return{provider:"github",lifecycle:lifecycleFromState(view.state,view.reviewDecision),checkState:checkStateFromRollup(view.statusCheckRollup),number:view.number,url:view.url,title:view.title,baseRef:view.baseRefName,reviewDecision:view.reviewDecision||void 0,mergeable:view.mergeable||void 0,lastCheckedAt:at}}function samePrStatus(a,b){if(a===b)return!0;if(!a||!b)return!1;return a.provider===b.provider&&a.lifecycle===b.lifecycle&&a.checkState===b.checkState&&a.number===b.number&&a.url===b.url&&a.title===b.title&&a.baseRef===b.baseRef&&a.reviewDecision===b.reviewDecision&&a.mergeable===b.mergeable}var NO_REMOTE_PATTERNS=["none of the git remotes","no git remote","to use github cli in a github repository","not a github repository"],AUTH_PATTERNS=["gh auth login","authentication required","not logged in","http 401","bad credentials","requires authentication"],NETWORK_PATTERNS=["could not resolve host","no such host","dial tcp","connection refused","connection reset","network is unreachable","i/o timeout","timeout","tls handshake","http 5","rate limit","try again"];function matchesAny(haystack,needles){return needles.some((n)=>haystack.includes(n))}function classifyGhFailure(s){if(s.parseError)return{kind:"error",error:"parse"};if(s.timedOut)return{kind:"error",error:"timeout"};if(s.spawnError)return{kind:"error",error:"missing-binary"};let err=(s.stderr??"").toLowerCase();if(matchesAny(err,NO_REMOTE_PATTERNS))return{kind:"error",error:"no-remote"};if(matchesAny(err,AUTH_PATTERNS))return{kind:"error",error:"auth"};if(matchesAny(err,NETWORK_PATTERNS))return{kind:"error",error:"network"};return{kind:"error",error:"unknown"}}function nextPrPoll(outcome,prevFailures,now,cfg,rand=Math.random){let at=(delay)=>now+applyJitter(delay,cfg.jitterRatio,rand);if(outcome.kind==="pr")return{nextAllowedAt:at(outcome.settled?cfg.settledMs:cfg.tickMs),failures:0};if(outcome.kind==="empty")return{nextAllowedAt:at(cfg.noPrMs),failures:0};if(outcome.error==="no-remote")return{nextAllowedAt:at(cfg.noRemoteMs),failures:0};let failures=prevFailures+1;return{nextAllowedAt:at(exponentialBackoff(cfg.failureBaseMs,failures-1,cfg.failureCapMs)),failures}}function checkResolutionNotify(prev,next){if(prev!=="pending")return null;if(next==="passing"||next==="failing")return next;return null}
3
3
  export{GH_PR_VIEW_FIELDS,mapGhPrView,samePrStatus,classifyGhFailure,nextPrPoll,checkResolutionNotify,canonPath,randomDirTaskSuffix,titleFromRepo,normalizeMainRepo,repoWorkingDir};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{isDev}from"./chunk-ch9b1d5y.js";import{fileURLToPath}from"url";var package_default={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.169",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",keywords:["terminal","tui","cli","multiplexer","ai-agents","coding-agent","ai-coding-assistant","agentic-ai","parallel-agents","git-worktree","claude-code","codex","llm","developer-tools"],type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://rove.run",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build","plugin-sandbox":"bun run scripts/plugin-sandbox.ts"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8","smol-toml":"^1.7.1",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.19","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]};var CURRENT_VERSION=package_default.version,PACKAGE_NAME=package_default.name;function repoSlug(){let url=package_default.repository?.url;if(!url)return null;let m=url.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!m||!m[1]||!m[2])return null;return`${m[1]}/${m[2]}`}var UPDATE_SCRIPT_URL="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",UPDATE_COMMAND=`curl -fsSL ${UPDATE_SCRIPT_URL} | sh`;function owningNpmPrefix(modulePath=fileURLToPath(import.meta.url)){let at=modulePath.indexOf("/lib/node_modules/");if(at<=0)return null;return modulePath.slice(0,at)}function recommendedGlobalInstallCommand(prefix=owningNpmPrefix()){let target=`${PACKAGE_NAME}@latest`;return prefix===null?`npm install -g ${target}`:`npm install -g --prefix ${prefix} ${target}`}var BREAKING_VERSIONS=[];function breakingVersionsCrossed(from,to,breaking=BREAKING_VERSIONS){let[lo,hi]=compareSemver(from,to)<=0?[from,to]:[to,from];return breaking.filter((b)=>compareSemver(b,lo)>0&&compareSemver(b,hi)<=0)}var FETCH_TIMEOUT_MS=3000,RELEASE_CHANNELS=["latest","nightly"],DEFAULT_RELEASE_CHANNEL="latest";function channelOf(version=CURRENT_VERSION){return prereleaseOf(version)?.split(".")[0]==="nightly"?"nightly":DEFAULT_RELEASE_CHANNEL}async function fetchLatestFromRegistry(packageName,channel){let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let encoded=packageName.replace("/","%2F"),res=await fetch(`https://registry.npmjs.org/${encoded}/${channel}`,{signal:ctrl.signal,headers:{accept:"application/json"}});if(!res.ok)return null;let body=await res.json();if(typeof body.version!=="string")return null;return body.version}catch{return null}finally{clearTimeout(timer)}}function isNewerSemver(latest,current){let core=compareSemver(latest,current);if(core!==0)return core>0;return comparePrerelease(prereleaseOf(latest),prereleaseOf(current))>0}function prereleaseOf(version){let dash=version.indexOf("-");return dash===-1?void 0:version.slice(dash+1)||void 0}function comparePrerelease(a,b){if(a===b)return 0;if(a===void 0)return 1;if(b===void 0)return-1;let aParts=a.split("."),bParts=b.split(".");for(let i=0;i<Math.max(aParts.length,bParts.length);i++){let av=aParts[i],bv=bParts[i];if(av===void 0)return-1;if(bv===void 0)return 1;if(av===bv)continue;let an=/^\d+$/.test(av)?Number.parseInt(av,10):null,bn=/^\d+$/.test(bv)?Number.parseInt(bv,10):null;if(an!==null&&bn!==null)return an>bn?1:-1;if(an!==null)return-1;if(bn!==null)return 1;return av>bv?1:-1}return 0}function compareSemver(aVersion,bVersion){let norm=(v)=>v.split("-")[0]??v,a=norm(aVersion).split(".").map((s)=>Number.parseInt(s,10)),b=norm(bVersion).split(".").map((s)=>Number.parseInt(s,10));for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(Number.isNaN(av)||Number.isNaN(bv))return 0;if(av>bv)return 1;if(av<bv)return-1}return 0}async function checkLatestVersion(opts={}){let channel=opts.channel??channelOf(),fake=process.env.KOBE_FAKE_UPDATE;if(fake)return{current:CURRENT_VERSION,latest:fake,hasUpdate:isNewerSemver(fake,CURRENT_VERSION),channel};if(isDev()&&!opts.force)return null;let latest=await fetchLatestFromRegistry(PACKAGE_NAME,channel);if(!latest)return null;return{current:CURRENT_VERSION,latest,hasUpdate:isNewerSemver(latest,CURRENT_VERSION),channel}}function versionFromTagName(tagName){if(typeof tagName!=="string")return null;return tagName.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function fetchReleaseNotes(version){let slug=repoSlug();if(!slug)return null;let tag=`v${version}`,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases/tags/${tag}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return null;let body=await res.json();if(typeof body.body!=="string"||typeof body.html_url!=="string")return null;return{body:body.body,url:body.html_url,version}}catch{return null}finally{clearTimeout(timer)}}async function fetchReleaseNotesRange(args){let slug=repoSlug();if(!slug)return[];let limit=args.limit??100,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string"||typeof release.body!=="string")return null;if(compareSemver(version,args.current)<=0)return null;if(compareSemver(version,args.latest)>0)return null;return{version,url:release.html_url,body:release.body}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}async function fetchReleaseSummaries(limit=12){let slug=repoSlug();if(!slug)return[];let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string")return null;return{version,url:release.html_url}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}function releasePageUrl(version){let slug=repoSlug();if(!slug)return null;return`https://github.com/${slug}/releases/tag/v${version}`}
2
+ import{isDev}from"./chunk-ch9b1d5y.js";import{fileURLToPath}from"url";var package_default={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.171",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",keywords:["terminal","tui","cli","multiplexer","ai-agents","coding-agent","ai-coding-assistant","agentic-ai","parallel-agents","git-worktree","claude-code","codex","llm","developer-tools"],type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://rove.run",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build","plugin-sandbox":"bun run scripts/plugin-sandbox.ts"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8","smol-toml":"^1.7.1",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.19","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]};var CURRENT_VERSION=package_default.version,PACKAGE_NAME=package_default.name;function repoSlug(){let url=package_default.repository?.url;if(!url)return null;let m=url.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!m||!m[1]||!m[2])return null;return`${m[1]}/${m[2]}`}var UPDATE_SCRIPT_URL="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",UPDATE_COMMAND=`curl -fsSL ${UPDATE_SCRIPT_URL} | sh`;function owningNpmPrefix(modulePath=fileURLToPath(import.meta.url)){let at=modulePath.indexOf("/lib/node_modules/");if(at<=0)return null;return modulePath.slice(0,at)}function recommendedGlobalInstallCommand(prefix=owningNpmPrefix()){let target=`${PACKAGE_NAME}@latest`;return prefix===null?`npm install -g ${target}`:`npm install -g --prefix ${prefix} ${target}`}var BREAKING_VERSIONS=[];function breakingVersionsCrossed(from,to,breaking=BREAKING_VERSIONS){let[lo,hi]=compareSemver(from,to)<=0?[from,to]:[to,from];return breaking.filter((b)=>compareSemver(b,lo)>0&&compareSemver(b,hi)<=0)}var FETCH_TIMEOUT_MS=3000,RELEASE_CHANNELS=["latest","nightly"],DEFAULT_RELEASE_CHANNEL="latest";function channelOf(version=CURRENT_VERSION){return prereleaseOf(version)?.split(".")[0]==="nightly"?"nightly":DEFAULT_RELEASE_CHANNEL}async function fetchLatestFromRegistry(packageName,channel){let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let encoded=packageName.replace("/","%2F"),res=await fetch(`https://registry.npmjs.org/${encoded}/${channel}`,{signal:ctrl.signal,headers:{accept:"application/json"}});if(!res.ok)return null;let body=await res.json();if(typeof body.version!=="string")return null;return body.version}catch{return null}finally{clearTimeout(timer)}}function isNewerSemver(latest,current){let core=compareSemver(latest,current);if(core!==0)return core>0;return comparePrerelease(prereleaseOf(latest),prereleaseOf(current))>0}function prereleaseOf(version){let dash=version.indexOf("-");return dash===-1?void 0:version.slice(dash+1)||void 0}function comparePrerelease(a,b){if(a===b)return 0;if(a===void 0)return 1;if(b===void 0)return-1;let aParts=a.split("."),bParts=b.split(".");for(let i=0;i<Math.max(aParts.length,bParts.length);i++){let av=aParts[i],bv=bParts[i];if(av===void 0)return-1;if(bv===void 0)return 1;if(av===bv)continue;let an=/^\d+$/.test(av)?Number.parseInt(av,10):null,bn=/^\d+$/.test(bv)?Number.parseInt(bv,10):null;if(an!==null&&bn!==null)return an>bn?1:-1;if(an!==null)return-1;if(bn!==null)return 1;return av>bv?1:-1}return 0}function compareSemver(aVersion,bVersion){let norm=(v)=>v.split("-")[0]??v,a=norm(aVersion).split(".").map((s)=>Number.parseInt(s,10)),b=norm(bVersion).split(".").map((s)=>Number.parseInt(s,10));for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(Number.isNaN(av)||Number.isNaN(bv))return 0;if(av>bv)return 1;if(av<bv)return-1}return 0}async function checkLatestVersion(opts={}){let channel=opts.channel??channelOf(),fake=process.env.KOBE_FAKE_UPDATE;if(fake)return{current:CURRENT_VERSION,latest:fake,hasUpdate:isNewerSemver(fake,CURRENT_VERSION),channel};if(isDev()&&!opts.force)return null;let latest=await fetchLatestFromRegistry(PACKAGE_NAME,channel);if(!latest)return null;return{current:CURRENT_VERSION,latest,hasUpdate:isNewerSemver(latest,CURRENT_VERSION),channel}}function versionFromTagName(tagName){if(typeof tagName!=="string")return null;return tagName.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function fetchReleaseNotes(version){let slug=repoSlug();if(!slug)return null;let tag=`v${version}`,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases/tags/${tag}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return null;let body=await res.json();if(typeof body.body!=="string"||typeof body.html_url!=="string")return null;return{body:body.body,url:body.html_url,version}}catch{return null}finally{clearTimeout(timer)}}async function fetchReleaseNotesRange(args){let slug=repoSlug();if(!slug)return[];let limit=args.limit??100,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string"||typeof release.body!=="string")return null;if(compareSemver(version,args.current)<=0)return null;if(compareSemver(version,args.latest)>0)return null;return{version,url:release.html_url,body:release.body}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}async function fetchReleaseSummaries(limit=12){let slug=repoSlug();if(!slug)return[];let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string")return null;return{version,url:release.html_url}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}function releasePageUrl(version){let slug=repoSlug();if(!slug)return null;return`https://github.com/${slug}/releases/tag/v${version}`}
3
3
  export{package_default,CURRENT_VERSION,PACKAGE_NAME,repoSlug,UPDATE_SCRIPT_URL,UPDATE_COMMAND,owningNpmPrefix,recommendedGlobalInstallCommand,BREAKING_VERSIONS,breakingVersionsCrossed,RELEASE_CHANNELS,DEFAULT_RELEASE_CHANNEL,channelOf,isNewerSemver,compareSemver,checkLatestVersion,fetchReleaseNotes,fetchReleaseNotesRange,fetchReleaseSummaries,releasePageUrl};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{envReadyForTasks}from"./chunk-571tfj6q.js";import{wizardKeyLines}from"./chunk-p1n1efh6.js";import"./chunk-8wrzdj5x.js";import"./chunk-3p2e2ry4.js";import"./chunk-m0g17ckn.js";import"./chunk-me9k96p4.js";import{$Fragment,$jsx,$jsxs,bootPaneHost,currentPrefixConfiguration,pageCloseBindings,require_react_production,useBindings,useRenderer,useT,useTheme}from"./chunk-wrwx9xtg.js";import"./chunk-764bsyb0.js";import"./chunk-xqw5d5rv.js";import"./chunk-h4n8ffqy.js";import"./chunk-6xppe9bj.js";import"./chunk-msr1xtay.js";import"./chunk-mb46dky0.js";import"./chunk-qqw3p4fc.js";import"./chunk-5agemmmn.js";import"./chunk-y0nq7amn.js";import"./chunk-zqfbyq0a.js";import"./chunk-xwekyjat.js";import"./chunk-v2cpe974.js";import"./chunk-sdyzxayr.js";import"./chunk-jvxh93nz.js";import"./chunk-h9mqdxvs.js";import"./chunk-8wv8526c.js";import"./chunk-0gepyh6e.js";import"./chunk-bkvr06xn.js";import"./chunk-mnqxgvyb.js";import"./chunk-jn5dd6bv.js";import"./chunk-xhw8s2es.js";import"./chunk-khj0apc7.js";import"./chunk-nzscq4yf.js";import"./chunk-w7zv47mp.js";import"./chunk-dt51afhh.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-k1qe5qqa.js";import"./chunk-xy8be792.js";import"./chunk-6wpege0h.js";import"./chunk-j75axe29.js";import"./chunk-ayhhgfsz.js";import"./chunk-2brn8e1y.js";import"./chunk-bq3fyc0p.js";import"./chunk-3wj69b0a.js";import"./chunk-ch9b1d5y.js";import"./chunk-mv7ptt5w.js";import"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import"./chunk-pxk2c2vj.js";import"./chunk-k2ckx8zw.js";import"./chunk-pw6yfj10.js";import"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import{__toESM}from"./chunk-wqfp8d9w.js";import{TextAttributes}from"@opentui/core";var import_react2=__toESM(require_react_production(),1);function inlineRowsFor(env){return 15+env.engines.lines.length+envActionKeys(env).length}function envActionKeys(env){let keys=[];if(!env.engines.anyUsable)keys.push("doctor.fix.noEngineAction");if(!env.git.found)keys.push("doctor.fix.gitAction");return keys}function WizardPage(props){let{theme}=useTheme(),t=useT(),renderer=useRenderer(),steps=(props.mode??"full")==="primer"?[]:props.shell===null?["skill"]:["completions","skill"],[stepIndex,setStepIndex]=import_react2.useState(0),[yes,setYes]=import_react2.useState(!0),[answers,setAnswers]=import_react2.useState({}),[page,setPage]=import_react2.useState(steps.length===0?"env":"questions"),step=steps[stepIndex];function finish(finalAnswers){renderer?.destroy(),props.onDone({completions:finalAnswers.completions??!1,skill:finalAnswers.skill??!1})}function confirm(choice=yes){if(page==="env"){setPage("keys");return}if(page==="keys"){finish(answers);return}let next={...answers,[step]:choice};if(setAnswers(next),stepIndex+1>=steps.length){setPage("env");return}setStepIndex(stepIndex+1),setYes(!0)}useBindings(()=>({bindings:[{key:"up",cmd:()=>setYes(!0)},{key:"k",cmd:()=>setYes(!0)},{key:"down",cmd:()=>setYes(!1)},{key:"j",cmd:()=>setYes(!1)},{key:"return",cmd:()=>confirm()},...pageCloseBindings(()=>finish(answers))]}));function questionFor(s){return s==="completions"?t("onboarding.completionsQuestion",{shell:props.shell??""}):t("onboarding.skillQuestion")}let explain=step==="completions"?t("onboarding.completionsExplain"):t("onboarding.skillExplain"),ready=envReadyForTasks(props.env);return $jsxs("box",{flexDirection:"column",flexGrow:1,paddingTop:1,paddingLeft:2,paddingRight:2,children:[$jsx("text",{fg:theme.primary,attributes:TextAttributes.BOLD,wrapMode:"none",children:t("onboarding.title")}),$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("onboarding.subtitle")}),$jsxs("box",{flexDirection:"column",paddingTop:1,children:[steps.slice(0,page==="questions"?stepIndex:steps.length).map((answered)=>$jsxs("box",{flexDirection:"row",gap:1,children:[$jsx("text",{fg:theme.success,wrapMode:"none",children:"\u2713"}),$jsx("text",{fg:theme.textMuted,wrapMode:"none",children:questionFor(answered)}),$jsx("text",{fg:theme.text,wrapMode:"none",children:answers[answered]?t("onboarding.optionYes"):t("onboarding.optionNo")})]},answered)),page==="env"?$jsxs("box",{flexDirection:"column",onMouseUp:()=>confirm(),children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"word",children:t("onboarding.envTitle")}),$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("onboarding.envExplain")}),$jsxs("box",{flexDirection:"column",paddingTop:1,children:[$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:props.env.git.line}),props.env.engines.lines.map((line)=>$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:line},line))]}),$jsxs("box",{paddingTop:1,flexDirection:"column",children:[$jsx("text",{fg:ready?theme.success:theme.error,wrapMode:"word",children:ready?t("onboarding.envReady"):t("onboarding.envNotReady")}),envActionKeys(props.env).map((key)=>$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:`\u2192 ${t(key)}`},key))]})]}):null,page==="keys"?$jsxs("box",{flexDirection:"column",onMouseUp:()=>confirm(),children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"word",children:t("onboarding.keysTitle")}),wizardKeyLines(currentPrefixConfiguration().key).map((line)=>$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t(`onboarding.${line.msg}`,line.params)},line.msg))]}):null,page==="questions"?$jsxs($Fragment,{children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"word",children:questionFor(step)}),$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:explain}),[!0,!1].map((option)=>{let active=yes===option;return $jsxs("box",{flexDirection:"row",gap:1,paddingLeft:1,onMouseUp:()=>confirm(option),children:[$jsx("text",{fg:active?theme.primary:theme.textMuted,wrapMode:"none",children:active?"\u276F":" "}),$jsx("text",{fg:active?theme.primary:theme.textMuted,attributes:active?TextAttributes.BOLD:void 0,wrapMode:"none",children:option?t("onboarding.optionYes"):t("onboarding.optionNo")})]},String(option))})]}):null]}),$jsx("box",{paddingTop:1,children:$jsx("text",{fg:theme.textMuted,attributes:TextAttributes.DIM,wrapMode:"none",children:t(page==="keys"?"onboarding.keysLegend":page==="env"?"onboarding.envLegend":"onboarding.legend")})})]})}async function runOnboardingWizard(shell,env,mode){return await new Promise((resolve)=>{bootPaneHost({inlineRows:inlineRowsFor(env),setup:()=>({root:()=>$jsx(WizardPage,{shell,env,mode,onDone:resolve})})})})}export{runOnboardingWizard,WizardPage};
2
+ import{envReadyForTasks}from"./chunk-ap95e417.js";import{wizardKeyLines}from"./chunk-yqardayk.js";import"./chunk-855rzebn.js";import"./chunk-3p2e2ry4.js";import"./chunk-m0g17ckn.js";import"./chunk-3a1fjn0q.js";import{$Fragment,$jsx,$jsxs,bootPaneHost,currentPrefixConfiguration,pageCloseBindings,require_react_production,useBindings,useRenderer,useT,useTheme}from"./chunk-5wpdpghc.js";import"./chunk-764bsyb0.js";import"./chunk-xqw5d5rv.js";import"./chunk-h4n8ffqy.js";import"./chunk-6xppe9bj.js";import"./chunk-msr1xtay.js";import"./chunk-f76j7drr.js";import"./chunk-qqw3p4fc.js";import"./chunk-5agemmmn.js";import"./chunk-ky9e5s1q.js";import"./chunk-zqfbyq0a.js";import"./chunk-rxh74abe.js";import"./chunk-pthtyzcs.js";import"./chunk-sdyzxayr.js";import"./chunk-jvxh93nz.js";import"./chunk-h9mqdxvs.js";import"./chunk-8wv8526c.js";import"./chunk-0gepyh6e.js";import"./chunk-bkvr06xn.js";import"./chunk-mnqxgvyb.js";import"./chunk-jn5dd6bv.js";import"./chunk-xhw8s2es.js";import"./chunk-khj0apc7.js";import"./chunk-nzscq4yf.js";import"./chunk-w7zv47mp.js";import"./chunk-dt51afhh.js";import"./chunk-7jkf3tvr.js";import"./chunk-2fypr41w.js";import"./chunk-k1qe5qqa.js";import"./chunk-xy8be792.js";import"./chunk-6wpege0h.js";import"./chunk-j75axe29.js";import"./chunk-ayhhgfsz.js";import"./chunk-2brn8e1y.js";import"./chunk-bq3fyc0p.js";import"./chunk-3wj69b0a.js";import"./chunk-ch9b1d5y.js";import"./chunk-mv7ptt5w.js";import"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import"./chunk-pxk2c2vj.js";import"./chunk-k2ckx8zw.js";import"./chunk-pw6yfj10.js";import"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import{__toESM}from"./chunk-wqfp8d9w.js";import{TextAttributes}from"@opentui/core";var import_react2=__toESM(require_react_production(),1);function inlineRowsFor(env){return 15+env.engines.lines.length+envActionKeys(env).length}function envActionKeys(env){let keys=[];if(!env.engines.anyUsable)keys.push("doctor.fix.noEngineAction");if(!env.git.found)keys.push("doctor.fix.gitAction");return keys}function WizardPage(props){let{theme}=useTheme(),t=useT(),renderer=useRenderer(),steps=(props.mode??"full")==="primer"?[]:props.shell===null?["skill"]:["completions","skill"],[stepIndex,setStepIndex]=import_react2.useState(0),[yes,setYes]=import_react2.useState(!0),[answers,setAnswers]=import_react2.useState({}),[page,setPage]=import_react2.useState(steps.length===0?"env":"questions"),step=steps[stepIndex];function finish(finalAnswers){renderer?.destroy(),props.onDone({completions:finalAnswers.completions??!1,skill:finalAnswers.skill??!1})}function confirm(choice=yes){if(page==="env"){setPage("keys");return}if(page==="keys"){finish(answers);return}let next={...answers,[step]:choice};if(setAnswers(next),stepIndex+1>=steps.length){setPage("env");return}setStepIndex(stepIndex+1),setYes(!0)}useBindings(()=>({bindings:[{key:"up",cmd:()=>setYes(!0)},{key:"k",cmd:()=>setYes(!0)},{key:"down",cmd:()=>setYes(!1)},{key:"j",cmd:()=>setYes(!1)},{key:"return",cmd:()=>confirm()},...pageCloseBindings(()=>finish(answers))]}));function questionFor(s){return s==="completions"?t("onboarding.completionsQuestion",{shell:props.shell??""}):t("onboarding.skillQuestion")}let explain=step==="completions"?t("onboarding.completionsExplain"):t("onboarding.skillExplain"),ready=envReadyForTasks(props.env);return $jsxs("box",{flexDirection:"column",flexGrow:1,paddingTop:1,paddingLeft:2,paddingRight:2,children:[$jsx("text",{fg:theme.primary,attributes:TextAttributes.BOLD,wrapMode:"none",children:t("onboarding.title")}),$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("onboarding.subtitle")}),$jsxs("box",{flexDirection:"column",paddingTop:1,children:[steps.slice(0,page==="questions"?stepIndex:steps.length).map((answered)=>$jsxs("box",{flexDirection:"row",gap:1,children:[$jsx("text",{fg:theme.success,wrapMode:"none",children:"\u2713"}),$jsx("text",{fg:theme.textMuted,wrapMode:"none",children:questionFor(answered)}),$jsx("text",{fg:theme.text,wrapMode:"none",children:answers[answered]?t("onboarding.optionYes"):t("onboarding.optionNo")})]},answered)),page==="env"?$jsxs("box",{flexDirection:"column",onMouseUp:()=>confirm(),children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"word",children:t("onboarding.envTitle")}),$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("onboarding.envExplain")}),$jsxs("box",{flexDirection:"column",paddingTop:1,children:[$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:props.env.git.line}),props.env.engines.lines.map((line)=>$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:line},line))]}),$jsxs("box",{paddingTop:1,flexDirection:"column",children:[$jsx("text",{fg:ready?theme.success:theme.error,wrapMode:"word",children:ready?t("onboarding.envReady"):t("onboarding.envNotReady")}),envActionKeys(props.env).map((key)=>$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:`\u2192 ${t(key)}`},key))]})]}):null,page==="keys"?$jsxs("box",{flexDirection:"column",onMouseUp:()=>confirm(),children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"word",children:t("onboarding.keysTitle")}),wizardKeyLines(currentPrefixConfiguration().key).map((line)=>$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t(`onboarding.${line.msg}`,line.params)},line.msg))]}):null,page==="questions"?$jsxs($Fragment,{children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"word",children:questionFor(step)}),$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:explain}),[!0,!1].map((option)=>{let active=yes===option;return $jsxs("box",{flexDirection:"row",gap:1,paddingLeft:1,onMouseUp:()=>confirm(option),children:[$jsx("text",{fg:active?theme.primary:theme.textMuted,wrapMode:"none",children:active?"\u276F":" "}),$jsx("text",{fg:active?theme.primary:theme.textMuted,attributes:active?TextAttributes.BOLD:void 0,wrapMode:"none",children:option?t("onboarding.optionYes"):t("onboarding.optionNo")})]},String(option))})]}):null]}),$jsx("box",{paddingTop:1,children:$jsx("text",{fg:theme.textMuted,attributes:TextAttributes.DIM,wrapMode:"none",children:t(page==="keys"?"onboarding.keysLegend":page==="env"?"onboarding.envLegend":"onboarding.legend")})})]})}async function runOnboardingWizard(shell,env,mode){return await new Promise((resolve)=>{bootPaneHost({inlineRows:inlineRowsFor(env),setup:()=>({root:()=>$jsx(WizardPage,{shell,env,mode,onDone:resolve})})})})}export{runOnboardingWizard,WizardPage};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{PROJECT_DIR_TOKEN,WORKTREE_BASE_KEY,defaultLocalWorktreesRoot,legacyLocalWorktreesRoot,managedWorktreeRootsFor,normalizeWorktreeBase,worktreeRootFor}from"./chunk-5f80ggc3.js";import{execHostForRepo}from"./chunk-rhsvvdcn.js";import{getRemoteRepoConfig,isRemoteRepoKey}from"./chunk-6wpege0h.js";import{loadStateFile}from"./chunk-j75axe29.js";import{errorMessage}from"./chunk-2brn8e1y.js";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";function describeDirtyWorktreeWork(ignored){return ignored==="unknown"?"gitignored work this check could not read (git status --ignored failed) \u2014 nothing here can confirm it is empty":ignored.length>0?`gitignored work git status cannot see: ${ignored.join(", ")}`:"uncommitted or untracked changes"}class DirtyWorktreeError extends Error{taskId;ignored;constructor(taskId,ignored=[]){super(`${DIRTY_WORKTREE_CODE}: task ${taskId} worktree has ${describeDirtyWorktreeWork(ignored)}`);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"}}import fs from"fs";import path from"path";var WORKTREE_BASE_CUSTOM_KEY="worktree.basePath.custom",PROJECT_SIBLING_BASE=`${PROJECT_DIR_TOKEN}/..`;function worktreeBaseKindOf(raw){let trimmed=raw.trim();if(!trimmed)return"default";if(trimmed.replace(/\/+$/,"")===PROJECT_SIBLING_BASE)return"nextToProject";return"custom"}function getWorktreeBaseOverride(projectDir){let value=loadStateFile()[WORKTREE_BASE_KEY];return normalizeWorktreeBase(typeof value==="string"?value:null,projectDir)}function worktreeRootFor2(repo){return worktreeRootFor(repo,getWorktreeBaseOverride(repo))}function managedWorktreeRootsFor2(repo){return managedWorktreeRootsFor(repo,getWorktreeBaseOverride(repo))}function worktreePathFor(repo,slug){if(!slug||/[/\\\0]/.test(slug))throw Error(`worktreePathFor: invalid slug: ${JSON.stringify(slug)}`);return path.join(worktreeRootFor2(repo),slug)}async function listWorktreeDirNames(repo){if(isRemoteRepoKey(repo)){let basePath=getRemoteRepoConfig(repo)?.basePath;if(!basePath)return[];let names2=new Set,host=execHostForRepo(repo),entries=await Promise.all(remoteManagedWorktreeRootsFor(basePath).map((root)=>host.readdir(root)));for(let list of entries)for(let name of list)names2.add(name);return[...names2]}let names=new Set;for(let root of managedWorktreeRootsFor2(repo))try{for(let e of fs.readdirSync(root,{withFileTypes:!0}))if(e.isDirectory())names.add(e.name)}catch{}return[...names]}function managedWorktreeRootForPath(repo,candidate){if(!path.isAbsolute(repo)||!path.isAbsolute(candidate))return null;let target=canonicalize(candidate);for(let rootPath of managedWorktreeRootsFor2(repo)){let root=canonicalize(rootPath),rel=path.relative(root,target);if(rel!==""&&!rel.startsWith("..")&&!path.isAbsolute(rel))return rootPath}return null}function isKobeManagedPath(repo,candidate){return managedWorktreeRootForPath(repo,candidate)!==null}function isUnderManagedWorktreesRoot(candidate,projectDir){if(!path.isAbsolute(candidate))return!1;let target=canonicalize(candidate),roots=[getWorktreeBaseOverride(projectDir)??"",defaultLocalWorktreesRoot(),legacyLocalWorktreesRoot()];for(let rootPath of roots){if(!rootPath)continue;let root=canonicalize(rootPath),rel=path.relative(root,target);if(rel.startsWith("..")||path.isAbsolute(rel))continue;if(rel.split(path.sep).filter(Boolean).length===2)return!0}return!1}function remoteWorktreeRootFor(basePath){return`${stripTrailingSlash(basePath)}/.rove/worktrees`}function remoteManagedWorktreeRootsFor(basePath){let base=stripTrailingSlash(basePath);return[`${base}/.rove/worktrees`,`${base}/.kobe/worktrees`]}function remoteWorktreePathFor(basePath,slug){if(!slug||/[/\\\0]/.test(slug))throw Error(`remoteWorktreePathFor: invalid slug: ${JSON.stringify(slug)}`);return`${remoteWorktreeRootFor(basePath)}/${slug}`}function remoteManagedRootForPath(basePath,candidate){for(let root of remoteManagedWorktreeRootsFor(basePath))if(candidate===root||candidate.startsWith(`${root}/`))return root;return null}function stripTrailingSlash(p){return p.length>1&&p.endsWith("/")?p.replace(/\/+$/,""):p}function requireAbsolute(name,value){if(!value||!path.isAbsolute(value))throw Error(`${name} must be an absolute path, got: ${JSON.stringify(value)}`)}function canonicalize(p){try{return fs.realpathSync(p)}catch{return path.resolve(p)}}
3
+ export{IllegalTransitionError,TaskNotFoundError,CannotDeleteMainTaskError,DIRTY_WORKTREE_CODE,describeDirtyWorktreeWork,DirtyWorktreeError,WorktreeRemoveFailedError,TASK_DELETING_CODE,TaskDeletingError,MainCheckoutDirtyError,EmptyBranchError,EMPTY_BRANCH_DIRTY_WORKTREE_CODE,EmptyBranchDirtyWorktreeError,MissingRefError,LandConflictError,GitCommandFailedError,WORKTREE_BASE_CUSTOM_KEY,PROJECT_SIBLING_BASE,worktreeBaseKindOf,worktreePathFor,listWorktreeDirNames,managedWorktreeRootForPath,isKobeManagedPath,isUnderManagedWorktreesRoot,remoteWorktreePathFor,remoteManagedRootForPath,requireAbsolute,canonicalize};
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{buildPaneArgv}from"./chunk-9xt05etk.js";import{PluginCliError,installPlugin,linkPlugin}from"./chunk-cnqtvf4b.js";import{resolvePluginBinPath}from"./chunk-d4vadrmy.js";import{buildPluginEnv}from"./chunk-41ahvk51.js";import{currentPluginPlatform,loadPluginRegistry,pluginCheckoutDir,pluginConfigDir,pluginLogPath,qualifiedActionId,readPluginManifest,removePluginEntry,savePluginRegistry,supportsPlatform}from"./chunk-38272eqv.js";import{SUBCOMMAND_VERBS}from"./chunk-s76r56rj.js";import"./chunk-mb46dky0.js";import"./chunk-b99tf0jr.js";import{flagValue}from"./chunk-jvxh93nz.js";import"./chunk-mnqxgvyb.js";import"./chunk-w7zv47mp.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-ch9b1d5y.js";import{activeCliName}from"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import{defaultDaemonSocketPath}from"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import{__require}from"./chunk-wqfp8d9w.js";import{spawnSync}from"child_process";import{readFileSync,rmSync}from"fs";var CLI_NAME=activeCliName();function printUsage(out){out.write([`usage: ${CLI_NAME} plugin <command>`,""," install <owner/repo[/subdir]> [--yes] [--ref <rev>] clone from GitHub, preview, build, register"," link <dir> register a local plugin directory (dev)"," list installed + linked plugins"," search [query] browse the marketplace (GitHub topic rove-plugin)"," outdated check GitHub-installed plugins against upstream"," update <id\u2026> | --all [--yes] reinstall stale plugins from GitHub"," enable <id> | disable <id> toggle a plugin without unregistering it"," unlink <id> unregister a linked plugin (files untouched)"," uninstall <id-or-spec> unregister + remove the managed checkout"," config-dir <id> print the plugin's config directory"," log <id> [-n <count>] tail the plugin's command-run log"," action list [--plugin <id>] declared actions"," action invoke <plugin-id.action-id> run an action now"," pane open <plugin-id.pane-id> [--task <task-id>] open a plugin pane as a terminal tab (JSON:"," clients \u2014 0 = no attached UI performed the split)","","Marketplace: https://github.com/topics/rove-plugin (legacy kobe-plugin is included)",""].join(`
2
+ import{buildPaneArgv}from"./chunk-9xt05etk.js";import{PluginCliError,installPlugin,linkPlugin}from"./chunk-756rtc9n.js";import{resolvePluginBinPath}from"./chunk-d4vadrmy.js";import{buildPluginEnv}from"./chunk-41ahvk51.js";import{currentPluginPlatform,loadPluginRegistry,pluginCheckoutDir,pluginConfigDir,pluginLogPath,qualifiedActionId,readPluginManifest,removePluginEntry,savePluginRegistry,supportsPlatform}from"./chunk-38272eqv.js";import{SUBCOMMAND_VERBS}from"./chunk-s76r56rj.js";import"./chunk-f76j7drr.js";import"./chunk-b99tf0jr.js";import{flagValue}from"./chunk-jvxh93nz.js";import"./chunk-mnqxgvyb.js";import"./chunk-w7zv47mp.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-ch9b1d5y.js";import{activeCliName}from"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import{defaultDaemonSocketPath}from"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import{__require}from"./chunk-wqfp8d9w.js";import{spawnSync}from"child_process";import{readFileSync,rmSync}from"fs";var CLI_NAME=activeCliName();function printUsage(out){out.write([`usage: ${CLI_NAME} plugin <command>`,""," install <owner/repo[/subdir]> [--yes] [--ref <rev>] clone from GitHub, preview, build, register"," link <dir> register a local plugin directory (dev)"," list installed + linked plugins"," search [query] browse the marketplace (GitHub topic rove-plugin)"," outdated check GitHub-installed plugins against upstream"," update <id\u2026> | --all [--yes] reinstall stale plugins from GitHub"," enable <id> | disable <id> toggle a plugin without unregistering it"," unlink <id> unregister a linked plugin (files untouched)"," uninstall <id-or-spec> unregister + remove the managed checkout"," config-dir <id> print the plugin's config directory"," log <id> [-n <count>] tail the plugin's command-run log"," action list [--plugin <id>] declared actions"," action invoke <plugin-id.action-id> run an action now"," pane open <plugin-id.pane-id> [--task <task-id>] open a plugin pane as a terminal tab (JSON:"," clients \u2014 0 = no attached UI performed the split)","","Marketplace: https://github.com/topics/rove-plugin (legacy kobe-plugin is included)",""].join(`
3
3
  `))}function loadAll(){return loadPluginRegistry().plugins.map((entry)=>{try{return{entry,manifest:readPluginManifest(entry.root).manifest}}catch{return{entry,manifest:void 0}}})}function requireEntry(id){let entry=loadPluginRegistry().plugins.find((p)=>p.id===id);if(!entry)throw new PluginCliError(`no plugin registered as \`${id}\`; see \`${CLI_NAME} plugin list\``);return entry}function listPlugins(){let all=loadAll();if(all.length===0){console.log(`no plugins installed. Try: ${CLI_NAME} plugin install <owner/repo> \u2014 browse the \`rove-plugin\` GitHub topic.`);return}for(let{entry,manifest}of all){let state=entry.enabled?"enabled":"disabled",kind=entry.source.kind==="link"?`linked ${entry.root}`:entry.source.spec,broken=manifest?"":" [manifest unreadable]";console.log(`${entry.id} v${entry.version} ${state} (${kind})${broken}`)}}function setEnabled(id,enabled){let entry=requireEntry(id),registry=loadPluginRegistry();savePluginRegistry({plugins:registry.plugins.map((p)=>p.id===id?{...entry,enabled}:p)}),console.log(`${enabled?"enabled":"disabled"} ${id}`)}function unlink(id){let entry=requireEntry(id);if(entry.source.kind!=="link")throw new PluginCliError(`\`${id}\` is a GitHub install; use uninstall`);savePluginRegistry(removePluginEntry(loadPluginRegistry(),id)),console.log(`unlinked ${id} (files untouched at ${entry.root})`)}function uninstall(idOrSpec){let registry=loadPluginRegistry(),entry=registry.plugins.find((p)=>p.id===idOrSpec||p.source.kind==="github"&&p.source.spec===idOrSpec);if(!entry)throw new PluginCliError(`no plugin registered as \`${idOrSpec}\``);if(entry.source.kind==="link")throw new PluginCliError(`\`${entry.id}\` is linked; use unlink`);savePluginRegistry(removePluginEntry(registry,entry.id)),rmSync(pluginCheckoutDir(entry.id),{recursive:!0,force:!0}),console.log(`uninstalled ${entry.id} (config/state kept under ~/.rove/plugins/${entry.id}/)`)}function listActions(pluginFilter){for(let{entry,manifest}of loadAll()){if(!manifest||pluginFilter&&entry.id!==pluginFilter)continue;for(let action of manifest.actions)console.log(`${qualifiedActionId(entry.id,action.id)} ${action.title}`)}}function findByLongestPluginPrefix(qualified,options,findItem){for(let{entry,manifest}of loadAll().filter(({entry:entry2,manifest:manifest2})=>Boolean(manifest2&&(!options.enabledOnly||entry2.enabled)&&qualified.startsWith(`${entry2.id}.`))).sort((a,b)=>b.entry.id.length-a.entry.id.length)){let item=findItem(manifest,qualified.slice(entry.id.length+1));if(item!==void 0)return{entry,manifest,item}}return}function assertPlatformSupported(label,item,manifest){if(supportsPlatform(item,manifest,currentPluginPlatform()))return;let declared=(item.platforms??manifest.platforms??[]).join(", ");throw new PluginCliError(`\`${label}\` is not supported on this platform (declares ${declared})`)}function invokeAction(qualified,extraArgs){let hit=findByLongestPluginPrefix(qualified,{enabledOnly:!0},(manifest,actionId)=>manifest.actions.find((a)=>a.id===actionId));if(!hit)throw new PluginCliError(`no action \`${qualified}\`; see \`${CLI_NAME} plugin action list\``);assertPlatformSupported(qualified,hit.item,hit.manifest);let action=hit.item,[cmd,...args]=[...action.command,...extraArgs],res=spawnSync(cmd,args,{cwd:hit.entry.root,stdio:"inherit",env:buildPluginEnv({socketPath:defaultDaemonSocketPath(),binPath:resolvePluginBinPath(),pluginId:hit.entry.id,pluginRoot:hit.entry.root,extra:{ROVE_PLUGIN_ACTION_ID:action.id,ROVE_PLUGIN_INVOKE_CWD:process.cwd()}})});process.exit(res.status??1)}function resolvePaneQualified(qualified){let hit=findByLongestPluginPrefix(qualified,{enabledOnly:!1},(manifest,entrypoint)=>manifest.panes.find((p)=>p.id===entrypoint));if(!hit)throw new PluginCliError(`no pane \`${qualified}\`; see \`${CLI_NAME} plugin list\``);return{pluginId:hit.entry.id,entrypoint:hit.item.id}}async function openPane(pluginId,entrypoint,taskFlag){let loaded=loadAll().find(({entry})=>entry.id===pluginId);if(!loaded?.manifest)throw new PluginCliError(`no plugin \`${pluginId}\` (or its manifest is unreadable)`);if(!loaded.entry.enabled)throw new PluginCliError(`\`${pluginId}\` is disabled`);let pane=loaded.manifest.panes.find((p)=>p.id===entrypoint);if(!pane)throw new PluginCliError(`no pane \`${entrypoint}\` in \`${pluginId}\`; declare it under [[panes]]`);assertPlatformSupported(`${pluginId}.${pane.id}`,pane,loaded.manifest);let{openDaemonSession,resolveActiveTaskId}=await import("./chunk-syxg74zr.js"),session=await openDaemonSession({mode:"start"});try{let taskId=taskFlag??await resolveActiveTaskId(session.client);if(!taskId)throw new PluginCliError("no active task; pass --task <id>");let argv=buildPaneArgv(loaded.entry.id,loaded.entry.root,pane,{socketPath:defaultDaemonSocketPath(),binPath:resolvePluginBinPath(),taskId}),reply=await session.client.request("tab.open",{taskId,argv,title:pane.title,placement:pane.placement});console.log(JSON.stringify({...reply,ok:!0,pane:`${pluginId}.${pane.id}`,taskId,title:pane.title}))}finally{session.close()}}function tailLog(id,count){requireEntry(id);let text;try{text=readFileSync(pluginLogPath(id),"utf8")}catch{console.log("(no runs logged yet)");return}let lines=text.trimEnd().split(`
4
- `);for(let line of lines.slice(-count))console.log(line)}async function runPluginSubcommand(rest){let[command,...args]=rest;if(command!==void 0&&!SUBCOMMAND_VERBS.plugin.includes(command)){let isHelp=command==="help"||command==="--help"||command==="-h";if(printUsage(isHelp?process.stdout:process.stderr),!isHelp)process.exit(2);return}try{switch(command){case"install":{let spec=args.find((a)=>!a.startsWith("-"));if(!spec)throw new PluginCliError("install needs <owner/repo[/subdir]>");await installPlugin(spec,{yes:args.includes("--yes"),ref:flagValue(args,"--ref")});return}case"link":{if(!args[0])throw new PluginCliError("link needs a directory");linkPlugin(args[0]);return}case"list":listPlugins();return;case"search":{let{searchMarketplace}=await import("./chunk-2hbhmvjw.js");await searchMarketplace(args.find((a)=>!a.startsWith("-")));return}case"outdated":{let{printOutdated}=await import("./chunk-fhkhn8qw.js");printOutdated();return}case"update":{let{updatePlugins}=await import("./chunk-fhkhn8qw.js");await updatePlugins(args.filter((a)=>!a.startsWith("-")),{all:args.includes("--all"),yes:args.includes("--yes")});return}case"enable":case"disable":{if(!args[0])throw new PluginCliError(`${command} needs a plugin id`);setEnabled(args[0],command==="enable");return}case"unlink":{if(!args[0])throw new PluginCliError("unlink needs a plugin id");unlink(args[0]);return}case"uninstall":{if(!args[0])throw new PluginCliError("uninstall needs a plugin id or owner/repo spec");uninstall(args[0]);return}case"config-dir":{if(!args[0])throw new PluginCliError("config-dir needs a plugin id");requireEntry(args[0]),console.log(pluginConfigDir(args[0]));return}case"log":{if(!args[0])throw new PluginCliError("log needs a plugin id");tailLog(args[0],Number.parseInt(flagValue(args,"-n")??"20",10)||20);return}case"pane":{let[sub,...paneArgs]=args;if(sub==="open"){let positional=paneArgs.find((a)=>!a.startsWith("-")&&a!==flagValue(paneArgs,"--task")),pluginId=flagValue(paneArgs,"--plugin"),entrypoint=flagValue(paneArgs,"--entrypoint");if(!pluginId||!entrypoint){if(!positional)throw new PluginCliError("pane open needs <plugin-id.pane-id> (or --plugin <id> --entrypoint <pane-id>) [--task <task-id>]");({pluginId,entrypoint}=resolvePaneQualified(positional))}await openPane(pluginId,entrypoint,flagValue(paneArgs,"--task"));return}printUsage(process.stderr),process.exit(2);return}case"action":{let[sub,...actionArgs]=args;if(sub==="list"){listActions(flagValue(actionArgs,"--plugin"));return}if(sub==="invoke"){if(!actionArgs[0])throw new PluginCliError("action invoke needs <plugin-id.action-id>");invokeAction(actionArgs[0],actionArgs.slice(1));return}printUsage(process.stderr),process.exit(2);return}default:{let isHelp=command===void 0||command==="help"||command==="--help"||command==="-h";if(printUsage(isHelp?process.stdout:process.stderr),!isHelp)process.exit(2);return}}}catch(err){if(err instanceof PluginCliError)console.error(`${CLI_NAME} plugin: ${err.message}`),process.exit(1);console.error(`${CLI_NAME} plugin: ${errorMessage(err)}`),process.exit(1)}}export{runPluginSubcommand};
4
+ `);for(let line of lines.slice(-count))console.log(line)}async function runPluginSubcommand(rest){let[command,...args]=rest;if(command!==void 0&&!SUBCOMMAND_VERBS.plugin.includes(command)){let isHelp=command==="help"||command==="--help"||command==="-h";if(printUsage(isHelp?process.stdout:process.stderr),!isHelp)process.exit(2);return}try{switch(command){case"install":{let spec=args.find((a)=>!a.startsWith("-"));if(!spec)throw new PluginCliError("install needs <owner/repo[/subdir]>");await installPlugin(spec,{yes:args.includes("--yes"),ref:flagValue(args,"--ref")});return}case"link":{if(!args[0])throw new PluginCliError("link needs a directory");linkPlugin(args[0]);return}case"list":listPlugins();return;case"search":{let{searchMarketplace}=await import("./chunk-2hbhmvjw.js");await searchMarketplace(args.find((a)=>!a.startsWith("-")));return}case"outdated":{let{printOutdated}=await import("./chunk-9tq6exs5.js");printOutdated();return}case"update":{let{updatePlugins}=await import("./chunk-9tq6exs5.js");await updatePlugins(args.filter((a)=>!a.startsWith("-")),{all:args.includes("--all"),yes:args.includes("--yes")});return}case"enable":case"disable":{if(!args[0])throw new PluginCliError(`${command} needs a plugin id`);setEnabled(args[0],command==="enable");return}case"unlink":{if(!args[0])throw new PluginCliError("unlink needs a plugin id");unlink(args[0]);return}case"uninstall":{if(!args[0])throw new PluginCliError("uninstall needs a plugin id or owner/repo spec");uninstall(args[0]);return}case"config-dir":{if(!args[0])throw new PluginCliError("config-dir needs a plugin id");requireEntry(args[0]),console.log(pluginConfigDir(args[0]));return}case"log":{if(!args[0])throw new PluginCliError("log needs a plugin id");tailLog(args[0],Number.parseInt(flagValue(args,"-n")??"20",10)||20);return}case"pane":{let[sub,...paneArgs]=args;if(sub==="open"){let positional=paneArgs.find((a)=>!a.startsWith("-")&&a!==flagValue(paneArgs,"--task")),pluginId=flagValue(paneArgs,"--plugin"),entrypoint=flagValue(paneArgs,"--entrypoint");if(!pluginId||!entrypoint){if(!positional)throw new PluginCliError("pane open needs <plugin-id.pane-id> (or --plugin <id> --entrypoint <pane-id>) [--task <task-id>]");({pluginId,entrypoint}=resolvePaneQualified(positional))}await openPane(pluginId,entrypoint,flagValue(paneArgs,"--task"));return}printUsage(process.stderr),process.exit(2);return}case"action":{let[sub,...actionArgs]=args;if(sub==="list"){listActions(flagValue(actionArgs,"--plugin"));return}if(sub==="invoke"){if(!actionArgs[0])throw new PluginCliError("action invoke needs <plugin-id.action-id>");invokeAction(actionArgs[0],actionArgs.slice(1));return}printUsage(process.stderr),process.exit(2);return}default:{let isHelp=command===void 0||command==="help"||command==="--help"||command==="-h";if(printUsage(isHelp?process.stdout:process.stderr),!isHelp)process.exit(2);return}}}catch(err){if(err instanceof PluginCliError)console.error(`${CLI_NAME} plugin: ${err.message}`),process.exit(1);console.error(`${CLI_NAME} plugin: ${errorMessage(err)}`),process.exit(1)}}export{runPluginSubcommand};
@@ -1,10 +1,10 @@
1
1
  // @bun
2
- import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{canonicalize,isKobeManagedPath,isUnderManagedWorktreesRoot,managedWorktreeRootForPath,remoteManagedRootForPath,remoteWorktreePathFor,requireAbsolute,worktreePathFor}from"./chunk-me23en52.js";import{execHostForRepo,execHostForWorktreePath}from"./chunk-rhsvvdcn.js";import{getRemoteRepoConfig}from"./chunk-6wpege0h.js";import path3 from"path";function parseDirtyPaths(stdout){return stdout.split(`
2
+ import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{DIRTY_WORKTREE_CODE,canonicalize,describeDirtyWorktreeWork,isKobeManagedPath,isUnderManagedWorktreesRoot,managedWorktreeRootForPath,remoteManagedRootForPath,remoteWorktreePathFor,requireAbsolute,worktreePathFor}from"./chunk-fndegq4p.js";import{execHostForRepo,execHostForWorktreePath}from"./chunk-rhsvvdcn.js";import{getRemoteRepoConfig}from"./chunk-6wpege0h.js";import path3 from"path";function parseDirtyPaths(stdout){return stdout.split(`
3
3
  `).filter((line)=>line.length>3).map((line)=>line.slice(3).trim()).filter((line)=>line.length>0)}function isDirtyOutput(stdout){return parseDirtyPaths(stdout).length>0}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(`
4
4
  `)){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(`
5
5
  `)){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"unknown";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"unknown"}}async function gitlinkPaths(git,tree){let out=await git(["ls-tree","-r",tree]);if(out.exitCode!==0)return[];return out.stdout.split(`
6
6
  `).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 probe=await smallIgnoredPaths(exec,worktreePath),ignored=probe==="unknown"?[]:probe;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(`
7
7
  `).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{deleted:!1,reason:"no branch to delete"};let out=await deps.runGit(exec,["branch",force?"-D":"-d",branch],{cwd:repo,allowFail:!0});if(out.exitCode===0)return{deleted:!0};if(!await branchExists(deps,{exec,dir:repo,remote:exec.isRemote},branch))return{deleted:!0};return{deleted:!1,reason:out.stderr.trim()||out.stdout.trim()||`git branch exited ${out.exitCode}`}}async function deleteBranchAnchored(deps,exec,repo,branch,opts){if(opts.force)opts.onAnchor?.(await anchorBranchTip(deps,exec,repo,branch));return 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(`
8
8
  `)){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(`
9
- `)){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){let outcome=await deleteBranchAnchored(deps.branchDeps(),exec,goneRepo,opts.branch,{force});if(!outcome.deleted)opts.onBranchKept?.({branch:opts.branch,reason:outcome.reason})}}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);if(ignored==="unknown")throw Error(`remove(): refusing to remove worktree at ${worktreePath} \u2014 git status --ignored failed, so nothing can confirm it holds no gitignored work (pass { force: true } to override, which salvages first)`);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){let outcome=await deleteBranchAnchored(deps.branchDeps(),exec,repo,branch,{force});if(!outcome.deleted)opts?.onBranchKept?.({branch,reason:outcome.reason})}}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);return 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){let out=await this.runGit(this.execAt(worktreePath),["status","--porcelain"],{cwd:worktreePath,readOnly:!0});return isDirtyOutput(out.stdout)}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
+ `)){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))}function dirtyRefusal(worktreePath,ignored){return`${DIRTY_WORKTREE_CODE}: ${worktreePath} has ${describeDirtyWorktreeWork(ignored)} \u2014 forcing the removal salvages it to a ref first`}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){let outcome=await deleteBranchAnchored(deps.branchDeps(),exec,goneRepo,opts.branch,{force});if(!outcome.deleted)opts.onBranchKept?.({branch:opts.branch,reason:outcome.reason})}}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(dirtyRefusal(worktreePath,[]));let ignored=await deps.ignoredWork(worktreePath);if(ignored==="unknown"||ignored.length>0)throw Error(dirtyRefusal(worktreePath,ignored))}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){let outcome=await deleteBranchAnchored(deps.branchDeps(),exec,repo,branch,{force});if(!outcome.deleted)opts?.onBranchKept?.({branch,reason:outcome.reason})}}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);return 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){let out=await this.runGit(this.execAt(worktreePath),["status","--porcelain"],{cwd:worktreePath,readOnly:!0});return isDirtyOutput(out.stdout)}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}}}
10
10
  export{parseDirtyPaths,isDirtyOutput,defaultExecDeps,GitWorktreeManager};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{CURRENT_VERSION,repoSlug}from"./chunk-mb46dky0.js";import{spawnSync}from"child_process";var DEFAULT_FEEDBACK_CATEGORY_SLUG="feedback",DISCUSSION_CATEGORY_QUERY=`
2
+ import{CURRENT_VERSION,repoSlug}from"./chunk-f76j7drr.js";import{spawnSync}from"child_process";var DEFAULT_FEEDBACK_CATEGORY_SLUG="feedback",DISCUSSION_CATEGORY_QUERY=`
3
3
  query($owner: String!, $name: String!) {
4
4
  repository(owner: $owner, name: $name) {
5
5
  id
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{stampResetGate}from"./chunk-me9k96p4.js";import{clearFrozenSessions}from"./chunk-t2v3ad8y.js";import{stopLegacyTmux}from"./chunk-dqndd97s.js";import"./chunk-mb46dky0.js";import"./chunk-7q67dz4c.js";import{stopDaemonProcess}from"./chunk-8wv8526c.js";import"./chunk-0gepyh6e.js";import"./chunk-bkvr06xn.js";import"./chunk-mnqxgvyb.js";import"./chunk-j75axe29.js";import"./chunk-ayhhgfsz.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{kvStatePath,legacyKobeKvStatePath,legacyKobeStateDir,roveStateDir}from"./chunk-ch9b1d5y.js";import"./chunk-mv7ptt5w.js";import{activeCliName}from"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import"./chunk-k2ckx8zw.js";import"./chunk-pw6yfj10.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyFreezeDir,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import"./chunk-wqfp8d9w.js";import{readFileSync}from"fs";import{unlink}from"fs/promises";import{join}from"path";import{createInterface}from"readline";var CLI_NAME=activeCliName();function printUsage(out){out.write([`Usage: ${CLI_NAME} reset [--hard] [--yes]`,"","Recover a wedged install: stop the daemon, Hosted PTY host, and any pre-v0.8 tmux sessions.","This ends background terminal and engine sessions; the next launch starts fresh.","Never touches your git worktrees.","","Options:"," --hard Also DELETE the task index and the whole settings file"," (saved projects, custom engines, theme, language, onboarding)"," -y, --yes Skip the interactive confirmation. REQUIRED without a terminal;"," a non-interactive run without it exits 2 and changes nothing."," -h, --help Print this help",""].join(`
2
+ import{stampResetGate}from"./chunk-3a1fjn0q.js";import{clearFrozenSessions}from"./chunk-t2v3ad8y.js";import{stopLegacyTmux}from"./chunk-dqndd97s.js";import"./chunk-f76j7drr.js";import"./chunk-7q67dz4c.js";import{stopDaemonProcess}from"./chunk-8wv8526c.js";import"./chunk-0gepyh6e.js";import"./chunk-bkvr06xn.js";import"./chunk-mnqxgvyb.js";import"./chunk-j75axe29.js";import"./chunk-ayhhgfsz.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{kvStatePath,legacyKobeKvStatePath,legacyKobeStateDir,roveStateDir}from"./chunk-ch9b1d5y.js";import"./chunk-mv7ptt5w.js";import{activeCliName}from"./chunk-v0zxyqrq.js";import"./chunk-e29hx18x.js";import"./chunk-g56kvet6.js";import"./chunk-k2ckx8zw.js";import"./chunk-pw6yfj10.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyFreezeDir,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-mcdv19rs.js";import"./chunk-r3k9rbwm.js";import"./chunk-wqfp8d9w.js";import{readFileSync}from"fs";import{unlink}from"fs/promises";import{join}from"path";import{createInterface}from"readline";var CLI_NAME=activeCliName();function printUsage(out){out.write([`Usage: ${CLI_NAME} reset [--hard] [--yes]`,"","Recover a wedged install: stop the daemon, Hosted PTY host, and any pre-v0.8 tmux sessions.","This ends background terminal and engine sessions; the next launch starts fresh.","Never touches your git worktrees.","","Options:"," --hard Also DELETE the task index and the whole settings file"," (saved projects, custom engines, theme, language, onboarding)"," -y, --yes Skip the interactive confirmation. REQUIRED without a terminal;"," a non-interactive run without it exits 2 and changes nothing."," -h, --help Print this help",""].join(`
3
3
  `))}function taskCount(path){try{let parsed=JSON.parse(readFileSync(path,"utf8"));return Array.isArray(parsed.tasks)?parsed.tasks.length:null}catch{return null}}function stateSummary(path){let parsed;try{parsed=JSON.parse(readFileSync(path,"utf8"))}catch{return[]}let count=(key)=>Array.isArray(parsed[key])?parsed[key].length:0,lines=[` saved projects: ${count("savedRepos")}`,` custom engines: ${count("customEngineIds")} (their launch commands live here and nowhere else)`],present=[["activeTheme","theme"],["defaultVendor","default engine"],["locale","language"],["onboarded","onboarding (the wizard runs again)"]].filter(([key])=>parsed[key]!==void 0).map(([,label])=>label);if(present.length>0)lines.push(` also set: ${present.join(", ")}`);return lines.push(` ${Object.keys(parsed).length} setting(s) in total`),lines}async function confirmTty(prompt){let readline=createInterface({input:process.stdin,output:process.stdout});try{let answer=await new Promise((resolve)=>readline.question(prompt,resolve));return/^y(es)?$/i.test(answer.trim())}finally{readline.close()}}async function removeStateFile(path,label){try{await unlink(path),console.log(` removed ${label} (${path})`)}catch(err){if(err.code==="ENOENT")console.log(` ${label}: already absent`);else throw Error(`failed to remove ${label} (${path}): ${errorMessage(err)}`)}}async function runResetSubcommand(argv){if(argv.some((arg)=>arg==="--help"||arg==="-h"||arg==="help")){printUsage(process.stdout);return}let known=new Set(["--hard","--yes","-y"]),unknown=argv.find((arg)=>!known.has(arg));if(unknown!==void 0)process.stderr.write(`${CLI_NAME} reset: unknown argument "${unknown}"
4
4
 
5
5
  `),printUsage(process.stderr),process.exit(2);let hard=argv.includes("--hard"),yes=argv.includes("--yes")||argv.includes("-y"),daemonSocket=defaultDaemonSocketPath(),tasksPath=join(roveStateDir(),"tasks.json"),legacyTasksPath=join(legacyKobeStateDir(),"tasks.json"),statePath=kvStatePath(),legacyStatePath=legacyKobeKvStatePath();if(console.log(`${CLI_NAME} reset will:`),console.log(" \u2022 stop the Rove daemon (graceful \u2192 SIGTERM \u2192 SIGKILL)"),console.log(` \u2022 remove its socket + pidfile (${daemonSocket})`),console.log(" \u2022 stop the standalone Hosted PTY host and all background terminal/engine sessions"),console.log(" \u2022 stop any pre-v0.8 tmux sessions after SIGTERM-ing their pane process groups"),hard){let count=taskCount(tasksPath)??taskCount(legacyTasksPath);console.log(` \u2022 DELETE the task index${count===null?"":` (${count} task(s))`} \u2014 ${tasksPath}`),console.log(` \u2022 DELETE the whole settings file \u2014 ${statePath}`);for(let line of stateSummary(statePath))console.log(line);console.log(" \u2022 DELETE the pre-Rove task/UI indexes too, so migration cannot restore reset state")}if(console.log(" \u2022 NOT touch your git worktrees under ~/.rove/worktrees/, ~/.kobe/worktrees/, or repo-local roots"),!hard)console.log(" (your task list, settings & worktrees are kept \u2014 add --hard to also delete the task index and settings file)");if(!yes){if(!process.stdin.isTTY){console.log(`