@sma1lboy/rove 0.9.258 → 0.9.262

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/cli/{chunk-rx2604ry.js → chunk-06wk3r66.js} +1 -1
  2. package/dist/cli/chunk-0wy0w6jd.js +3 -0
  3. package/dist/cli/{chunk-wyt2vgjv.js → chunk-1bfcy0n9.js} +1 -1
  4. package/dist/cli/chunk-1dzr3fba.js +2 -0
  5. package/dist/cli/{chunk-mmc662x2.js → chunk-1pfsfpcg.js} +1 -1
  6. package/dist/cli/{chunk-jtpjdmb6.js → chunk-1x6yahf1.js} +1 -1
  7. package/dist/cli/{chunk-tq6pq1ws.js → chunk-2676cb62.js} +1 -1
  8. package/dist/cli/{chunk-ehb0hbrg.js → chunk-2cwzyxcs.js} +2 -2
  9. package/dist/cli/{chunk-r6f8h111.js → chunk-31h3d4re.js} +2 -2
  10. package/dist/cli/{chunk-68113ts1.js → chunk-36y93k92.js} +1 -1
  11. package/dist/cli/chunk-37v3752z.js +2 -0
  12. package/dist/cli/{chunk-0604fza5.js → chunk-3ds88mym.js} +1 -1
  13. package/dist/cli/{chunk-cewyvr3c.js → chunk-4ntrjm11.js} +1 -1
  14. package/dist/cli/{chunk-kgddz8pw.js → chunk-4t1dvw2h.js} +1 -1
  15. package/dist/cli/chunk-4tgz542w.js +3 -0
  16. package/dist/cli/chunk-53p99fe7.js +66 -0
  17. package/dist/cli/{chunk-sabpcket.js → chunk-5a3c9fnd.js} +1 -1
  18. package/dist/cli/{chunk-ke3t032y.js → chunk-5js4agdd.js} +1 -1
  19. package/dist/cli/{chunk-zqq3djrw.js → chunk-65kx9ksj.js} +3 -3
  20. package/dist/cli/{chunk-cb7hc2xm.js → chunk-68xcxsbg.js} +1 -1
  21. package/dist/cli/{chunk-pb5g6161.js → chunk-6an1v8vq.js} +1 -1
  22. package/dist/cli/{chunk-s0jbtyd9.js → chunk-6ks6s8b2.js} +3 -2
  23. package/dist/cli/{chunk-45thgqdr.js → chunk-6nw0s0ab.js} +1 -1
  24. package/dist/cli/{chunk-t25xke74.js → chunk-73fw8277.js} +1 -1
  25. package/dist/cli/{chunk-1xrbb7gf.js → chunk-74e3k701.js} +1 -1
  26. package/dist/cli/{chunk-stcvcsfm.js → chunk-7697syt8.js} +1 -1
  27. package/dist/cli/{chunk-3q1rv3rm.js → chunk-7nqzg7h6.js} +2 -2
  28. package/dist/cli/chunk-7t9q7k4d.js +4 -0
  29. package/dist/cli/{chunk-0d57z680.js → chunk-8e8y2m0b.js} +1 -1
  30. package/dist/cli/chunk-8k04kxqq.js +20 -0
  31. package/dist/cli/chunk-951xzbsm.js +3 -0
  32. package/dist/cli/{chunk-dqprpnd6.js → chunk-95gk3twe.js} +1 -1
  33. package/dist/cli/chunk-b7w3q5f1.js +2 -0
  34. package/dist/cli/chunk-c0gvp57p.js +3 -0
  35. package/dist/cli/{chunk-pwbtezsa.js → chunk-c3g1bfn6.js} +1 -1
  36. package/dist/cli/{chunk-yktnbb14.js → chunk-c7j05xps.js} +37 -37
  37. package/dist/cli/chunk-db61d8dz.js +3 -0
  38. package/dist/cli/{chunk-95jzkqp2.js → chunk-dc3n6nf7.js} +1 -1
  39. package/dist/cli/{chunk-x8rkpfqd.js → chunk-dq3m7rhj.js} +1 -1
  40. package/dist/cli/{chunk-hfvz23r6.js → chunk-edrw4tby.js} +1 -1
  41. package/dist/cli/chunk-ephcyh6v.js +3 -0
  42. package/dist/cli/{chunk-jd02zgwf.js → chunk-esk09jfb.js} +1 -1
  43. package/dist/cli/{chunk-cq5qv93a.js → chunk-fg55dc4s.js} +1 -1
  44. package/dist/cli/{chunk-278sc87n.js → chunk-fq3s9q62.js} +1 -1
  45. package/dist/cli/{chunk-1egwgg6p.js → chunk-gc3f7zbs.js} +1 -1
  46. package/dist/cli/{chunk-y0gybgba.js → chunk-gc78tfn9.js} +1 -1
  47. package/dist/cli/chunk-h0pg8e0g.js +70 -0
  48. package/dist/cli/{chunk-b47k0cnw.js → chunk-h5znx9v9.js} +1 -1
  49. package/dist/cli/chunk-hrgd7vws.js +2 -0
  50. package/dist/cli/chunk-jc2jwy0j.js +2 -0
  51. package/dist/cli/{chunk-8gjpnb83.js → chunk-k21hb0rj.js} +1 -1
  52. package/dist/cli/{chunk-rc2nwsdd.js → chunk-k71h719j.js} +1 -1
  53. package/dist/cli/chunk-karefnj8.js +11 -0
  54. package/dist/cli/chunk-kkzmdwfr.js +7 -0
  55. package/dist/cli/chunk-kqdq5g1x.js +3 -0
  56. package/dist/cli/{chunk-6x0trw81.js → chunk-m2qajv9v.js} +1 -1
  57. package/dist/cli/{chunk-1vwngrmf.js → chunk-m3773n9n.js} +1 -1
  58. package/dist/cli/chunk-m3nfbnxy.js +2 -0
  59. package/dist/cli/{chunk-edpbz0gz.js → chunk-m5kxc6m3.js} +3 -3
  60. package/dist/cli/chunk-mgx6w27b.js +2 -0
  61. package/dist/cli/{chunk-ebea569y.js → chunk-n8p8b9qd.js} +1 -1
  62. package/dist/cli/{chunk-9v18qy3s.js → chunk-nnda6138.js} +1 -1
  63. package/dist/cli/{chunk-edsm15ht.js → chunk-nwevnc6k.js} +1 -1
  64. package/dist/cli/{chunk-7cd1epfw.js → chunk-nxdm60xy.js} +1 -1
  65. package/dist/cli/{chunk-pw87thvf.js → chunk-p0ycfqw2.js} +1 -1
  66. package/dist/cli/{chunk-sma961wh.js → chunk-q07r6hf7.js} +1 -1
  67. package/dist/cli/{chunk-jf46jsdp.js → chunk-q55z079p.js} +1 -1
  68. package/dist/cli/{chunk-xnaehfby.js → chunk-qc376zm1.js} +1 -1
  69. package/dist/cli/chunk-qk9tgve2.js +2 -0
  70. package/dist/cli/{chunk-jv11f2c2.js → chunk-qwhajjyw.js} +3 -3
  71. package/dist/cli/chunk-r03m4san.js +2 -0
  72. package/dist/cli/{chunk-kqf371ff.js → chunk-r1epx453.js} +1 -1
  73. package/dist/cli/chunk-r3zkpbf5.js +9 -0
  74. package/dist/cli/{chunk-6p9yxt3q.js → chunk-r7p1dhrv.js} +1 -1
  75. package/dist/cli/{chunk-y8xb4ys7.js → chunk-rcqckj34.js} +1 -1
  76. package/dist/cli/{chunk-zam29b9x.js → chunk-rh5vxymy.js} +1 -1
  77. package/dist/cli/chunk-rrqjk4rn.js +16 -0
  78. package/dist/cli/chunk-s83qnstd.js +2 -0
  79. package/dist/cli/{chunk-rnxk3587.js → chunk-sp9cmc7p.js} +1 -1
  80. package/dist/cli/{chunk-yjyjg7sk.js → chunk-stng29vp.js} +2 -2
  81. package/dist/cli/{chunk-80zzjcvp.js → chunk-syqbc3a3.js} +1 -1
  82. package/dist/cli/chunk-t228jyth.js +4 -0
  83. package/dist/cli/{chunk-ya0h6hcd.js → chunk-tj1w7jb7.js} +5 -5
  84. package/dist/cli/{chunk-t60qcvcj.js → chunk-traxwyfz.js} +1 -1
  85. package/dist/cli/chunk-tx4b93j7.js +2 -0
  86. package/dist/cli/{chunk-c8anewjn.js → chunk-tykb6n4m.js} +1 -1
  87. package/dist/cli/{chunk-cqychwvw.js → chunk-vznz1yf0.js} +1 -1
  88. package/dist/cli/{chunk-v7prawj1.js → chunk-wqcs5mz0.js} +1 -1
  89. package/dist/cli/chunk-wv6d96t6.js +2 -0
  90. package/dist/cli/{chunk-tpt3fn1q.js → chunk-xwynw0t0.js} +1 -1
  91. package/dist/cli/{chunk-k2cnmb5q.js → chunk-xywr9nj6.js} +1 -1
  92. package/dist/cli/chunk-y5wt6c1s.js +3 -0
  93. package/dist/cli/{chunk-yaqkajw4.js → chunk-y7nkgnzn.js} +17 -17
  94. package/dist/cli/{chunk-qpc8bv02.js → chunk-yxsec1f1.js} +4 -4
  95. package/dist/cli/chunk-z3qhpthz.js +3 -0
  96. package/dist/cli/{chunk-8q1g1xq0.js → chunk-z5evzj1q.js} +1 -1
  97. package/dist/cli/{chunk-eyzjma6q.js → chunk-zqfvxz1g.js} +1 -1
  98. package/dist/cli/{chunk-1zqzqbek.js → chunk-zsth2jk6.js} +1 -1
  99. package/dist/cli/{chunk-hdnqq66w.js → chunk-zt0dmqn5.js} +1 -1
  100. package/dist/cli/index.js +4 -4
  101. package/dist/cli/pty-host-node.mjs +4 -0
  102. package/dist/cli/rove.js +1 -1
  103. package/dist/completions/rove.bash +2 -2
  104. package/dist/completions/rove.fish +2 -2
  105. package/dist/completions/rove.zsh +2 -2
  106. package/dist/skills/rove/SKILL.md +1 -1
  107. package/dist/skills/rove/references/api-flags.md +28 -11
  108. package/dist/web/assets/index-BLCf4p1g.js +109 -0
  109. package/dist/web/assets/index-CdjFB6v7.css +1 -0
  110. package/dist/web/index.html +2 -2
  111. package/package.json +3 -3
  112. package/dist/cli/chunk-1378mh2w.js +0 -3
  113. package/dist/cli/chunk-1qge84t7.js +0 -3
  114. package/dist/cli/chunk-1vxykwb9.js +0 -3
  115. package/dist/cli/chunk-2yjpqb47.js +0 -3
  116. package/dist/cli/chunk-4ab8y1yp.js +0 -15
  117. package/dist/cli/chunk-4d4d59vp.js +0 -20
  118. package/dist/cli/chunk-658859k9.js +0 -31
  119. package/dist/cli/chunk-6t5d02s4.js +0 -2
  120. package/dist/cli/chunk-79r3wbhh.js +0 -2
  121. package/dist/cli/chunk-7nr405tr.js +0 -9
  122. package/dist/cli/chunk-82zpp3yx.js +0 -4
  123. package/dist/cli/chunk-8dggnfaf.js +0 -2
  124. package/dist/cli/chunk-csdne12x.js +0 -3
  125. package/dist/cli/chunk-dd0mtzje.js +0 -3
  126. package/dist/cli/chunk-fehxbwcb.js +0 -6
  127. package/dist/cli/chunk-g846fbp7.js +0 -52
  128. package/dist/cli/chunk-hkv6t5v9.js +0 -2
  129. package/dist/cli/chunk-jetsx9zr.js +0 -3
  130. package/dist/cli/chunk-q301ewyq.js +0 -2
  131. package/dist/cli/chunk-qn04z4zb.js +0 -2
  132. package/dist/cli/chunk-rmk69hvh.js +0 -2
  133. package/dist/cli/chunk-s1rg1zae.js +0 -3
  134. package/dist/cli/chunk-skpkscne.js +0 -11
  135. package/dist/cli/chunk-x7cv6deh.js +0 -2
  136. package/dist/cli/chunk-y85e24s9.js +0 -2
  137. package/dist/cli/chunk-yc9bytrj.js +0 -2
  138. package/dist/web/assets/index-BiUiNIOp.css +0 -1
  139. package/dist/web/assets/index-jy27XaL0.js +0 -109
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{BREAKING_VERSIONS,CURRENT_VERSION,compareSemver}from"./chunk-1xrbb7gf.js";import{loadStateFile,patchStateFile}from"./chunk-g4281a0g.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";var LAST_RUN_VERSION_KEY="app.lastRunVersion";function resetGateBlockers(lastRun,current=CURRENT_VERSION,breaking=BREAKING_VERSIONS){if(typeof lastRun!=="string"||lastRun.length===0)return[];let[lo,hi]=compareSemver(lastRun,current)<=0?[lastRun,current]:[current,lastRun];return breaking.filter((b)=>compareSemver(b,lo)>0&&compareSemver(b,hi)<=0)}function enforceResetGate(){let cliName=ROVE_PRODUCT_NAME,lastRun=loadStateFile()[LAST_RUN_VERSION_KEY],blockers=resetGateBlockers(lastRun);if(blockers.length>0){let from=typeof lastRun==="string"?lastRun:"unknown";console.error([`${cliName} ${CURRENT_VERSION}: cannot start \u2014 version ${blockers.join(", ")} introduced breaking changes`,`(last run: ${from}). Your daemon/session state may be incompatible.`,"","Run:",` ${cliName} reset # stop daemon + PTY host + sessions (tasks kept)`,` ${cliName} reset --hard # additionally wipe the task index + UI state`,"","Then relaunch Rove. Worktrees are never touched."].join(`
2
+ import{BREAKING_VERSIONS,CURRENT_VERSION,compareSemver}from"./chunk-74e3k701.js";import{loadStateFile,patchStateFile}from"./chunk-g4281a0g.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";var LAST_RUN_VERSION_KEY="app.lastRunVersion";function resetGateBlockers(lastRun,current=CURRENT_VERSION,breaking=BREAKING_VERSIONS){if(typeof lastRun!=="string"||lastRun.length===0)return[];let[lo,hi]=compareSemver(lastRun,current)<=0?[lastRun,current]:[current,lastRun];return breaking.filter((b)=>compareSemver(b,lo)>0&&compareSemver(b,hi)<=0)}function enforceResetGate(){let cliName=ROVE_PRODUCT_NAME,lastRun=loadStateFile()[LAST_RUN_VERSION_KEY],blockers=resetGateBlockers(lastRun);if(blockers.length>0){let from=typeof lastRun==="string"?lastRun:"unknown";console.error([`${cliName} ${CURRENT_VERSION}: cannot start \u2014 version ${blockers.join(", ")} introduced breaking changes`,`(last run: ${from}). Your daemon/session state may be incompatible.`,"","Run:",` ${cliName} reset # stop daemon + PTY host + sessions (tasks kept)`,` ${cliName} reset --hard # additionally wipe the task index + UI state`,"","Then relaunch Rove. Worktrees are never touched."].join(`
3
3
  `)),process.exit(1)}if(lastRun!==CURRENT_VERSION)stampResetGate()}function stampResetGate(){try{patchStateFile({[LAST_RUN_VERSION_KEY]:CURRENT_VERSION})}catch{}}
4
4
  export{LAST_RUN_VERSION_KEY,enforceResetGate,stampResetGate};
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath}from"./chunk-t25xke74.js";import{hasRoveActivityHooks}from"./chunk-7zyyvc3d.js";import"./chunk-r6k3ve2g.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import{isObject}from"./chunk-7ghwdjdc.js";import"./chunk-tdhk4dz8.js";import{installedSkillDirs}from"./chunk-ehb0hbrg.js";import"./chunk-22d0yc7m.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-g4281a0g.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{readFileSync}from"fs";import{homedir}from"os";var PLUGIN_NAME="rove";function readSettings(path){try{let parsed=JSON.parse(readFileSync(path,"utf8"));return isObject(parsed)?parsed:null}catch{return null}}function isRovePluginEnabled(settingsFilePath=claudeSettingsPath()){let settings=readSettings(settingsFilePath);if(!settings||!isObject(settings.enabledPlugins))return!1;return Object.entries(settings.enabledPlugins).some(([key,on])=>on===!0&&key.split("@")[0]===PLUGIN_NAME)}function detectLegacyInstalls(opts={}){let settingsFilePath=opts.settingsFilePath??claudeSettingsPath(),home=opts.home??homedir(),settings=readSettings(settingsFilePath),legacyHooks=settings!==null&&(hasRoveActivityHooks(settings,CLAUDE_HOOK_EVENT_MAP)||settingsHasWorktreeWatch(settings)),legacySkillDirs=installedSkillDirs(home);return{legacyHooks,legacySkillDirs}}function settingsHasWorktreeWatch(settings){let hooks=isObject(settings.hooks)?settings.hooks:{};return Object.values(hooks).some((groups)=>Array.isArray(groups)&&groups.some((g)=>isObject(g)&&Array.isArray(g.hooks)&&g.hooks.some((h)=>isObject(h)&&typeof h.command==="string"&&h.command.includes("worktree-created")&&!h.command.includes("CLAUDE_PLUGIN_ROOT"))))}function migrationHint(findings,cliName){if(!findings.legacyHooks&&findings.legacySkillDirs.length===0)return null;let lines=[`${cliName}: the Rove Claude Code plugin is enabled, but legacy installs remain:`];if(findings.legacyHooks)lines.push(" \u2022 ~/.claude/settings.json still has the settings-managed Rove hooks (every event fires TWICE).",` Run \`${cliName} hook cleanup\` to remove them (only Rove's own entries are touched).`);for(let dir of findings.legacySkillDirs)lines.push(` \u2022 legacy skill copy at ${dir} (the plugin bundles the skill \u2014 two copies double-register).`," Remove that directory to keep the plugin's copy only.");return lines.push(" Reading this inside a session? Just ask your agent to run the cleanup for you."),`${lines.join(`
2
+ import{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath}from"./chunk-73fw8277.js";import{hasRoveActivityHooks}from"./chunk-7zyyvc3d.js";import"./chunk-r6k3ve2g.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import{isObject}from"./chunk-7ghwdjdc.js";import"./chunk-tdhk4dz8.js";import{installedSkillDirs}from"./chunk-2cwzyxcs.js";import"./chunk-22d0yc7m.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-g4281a0g.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{readFileSync}from"fs";import{homedir}from"os";var PLUGIN_NAME="rove";function readSettings(path){try{let parsed=JSON.parse(readFileSync(path,"utf8"));return isObject(parsed)?parsed:null}catch{return null}}function isRovePluginEnabled(settingsFilePath=claudeSettingsPath()){let settings=readSettings(settingsFilePath);if(!settings||!isObject(settings.enabledPlugins))return!1;return Object.entries(settings.enabledPlugins).some(([key,on])=>on===!0&&key.split("@")[0]===PLUGIN_NAME)}function detectLegacyInstalls(opts={}){let settingsFilePath=opts.settingsFilePath??claudeSettingsPath(),home=opts.home??homedir(),settings=readSettings(settingsFilePath),legacyHooks=settings!==null&&(hasRoveActivityHooks(settings,CLAUDE_HOOK_EVENT_MAP)||settingsHasWorktreeWatch(settings)),legacySkillDirs=installedSkillDirs(home);return{legacyHooks,legacySkillDirs}}function settingsHasWorktreeWatch(settings){let hooks=isObject(settings.hooks)?settings.hooks:{};return Object.values(hooks).some((groups)=>Array.isArray(groups)&&groups.some((g)=>isObject(g)&&Array.isArray(g.hooks)&&g.hooks.some((h)=>isObject(h)&&typeof h.command==="string"&&h.command.includes("worktree-created")&&!h.command.includes("CLAUDE_PLUGIN_ROOT"))))}function migrationHint(findings,cliName){if(!findings.legacyHooks&&findings.legacySkillDirs.length===0)return null;let lines=[`${cliName}: the Rove Claude Code plugin is enabled, but legacy installs remain:`];if(findings.legacyHooks)lines.push(" \u2022 ~/.claude/settings.json still has the settings-managed Rove hooks (every event fires TWICE).",` Run \`${cliName} hook cleanup\` to remove them (only Rove's own entries are touched).`);for(let dir of findings.legacySkillDirs)lines.push(` \u2022 legacy skill copy at ${dir} (the plugin bundles the skill \u2014 two copies double-register).`," Remove that directory to keep the plugin's copy only.");return lines.push(" Reading this inside a session? Just ask your agent to run the cleanup for you."),`${lines.join(`
3
3
  `)}
4
4
  `}export{migrationHint,isRovePluginEnabled,detectLegacyInstalls};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{bundleWithBun,childProbeCommand,ensurePtyHostReachable,liveChildCount,ptyHostHasLiveSessions,resolveNodeBinary,resolveNodePtyHostSpawn,runChildProbe,sweepPtyHostSessions}from"./chunk-t228jyth.js";import"./chunk-rxqdw6s5.js";import"./chunk-r1epx453.js";import"./chunk-m3773n9n.js";import"./chunk-c7j05xps.js";import"./chunk-wqckm0k6.js";import"./chunk-yt15y085.js";import"./chunk-6ks6s8b2.js";import"./chunk-fq3s9q62.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{sweepPtyHostSessions,runChildProbe,resolveNodePtyHostSpawn,resolveNodeBinary,ptyHostHasLiveSessions,liveChildCount,ensurePtyHostReachable,childProbeCommand,bundleWithBun};
@@ -1,8 +1,8 @@
1
1
  // @bun
2
- import{generateCompletions,isShellKind,mergeSubVerbs,shippedCompletionsPath}from"./chunk-ke3t032y.js";import"./chunk-1qge84t7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync,readFileSync}from"fs";var HELP_WORDS=["--help","-h","help"];function completionUsage(cliName){return[`Usage: ${cliName} completions <bash|zsh|fish> [--path|--install]`,"",`Print a shell completion script for ${cliName}, or locate the copy shipped`,"with this install.","",` ${cliName} completions zsh --path print the shipped script's path`,` ${cliName} completions zsh --install hook it into your shell config`,"","Install:",` zsh source <(${cliName} completions zsh) # one-off, or in ~/.zshrc after compinit`," # with no process start per shell \u2014 what the first-run wizard writes:",` # ${cliName} completions zsh --install`,` bash ${cliName} completions bash --install # appends to ~/.bashrc`,` fish ${cliName} completions fish --install # writes ~/.config/fish/completions/${cliName}.fish`," # the manual way, any shell:",` # ${cliName} completions zsh > ~/.zsh/completions/_${cliName}`," # fpath=(~/.zsh/completions $fpath) # in ~/.zshrc, BEFORE compinit"," # rm -f ~/.zcompdump && exec zsh # rebuild the completion cache",""].join(`
2
+ import{generateCompletions,isShellKind,mergeSubVerbs,shippedCompletionsPath}from"./chunk-5js4agdd.js";import"./chunk-z3qhpthz.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync,readFileSync}from"fs";var HELP_WORDS=["--help","-h","help"];function completionUsage(cliName){return[`Usage: ${cliName} completions <bash|zsh|fish> [--path|--install]`,"",`Print a shell completion script for ${cliName}, or locate the copy shipped`,"with this install.","",` ${cliName} completions zsh --path print the shipped script's path`,` ${cliName} completions zsh --install hook it into your shell config`,"","Install:",` zsh source <(${cliName} completions zsh) # one-off, or in ~/.zshrc after compinit`," # with no process start per shell \u2014 what the first-run wizard writes:",` # ${cliName} completions zsh --install`,` bash ${cliName} completions bash --install # appends to ~/.bashrc`,` fish ${cliName} completions fish --install # writes ~/.config/fish/completions/${cliName}.fish`," # the manual way, any shell:",` # ${cliName} completions zsh > ~/.zsh/completions/_${cliName}`," # fpath=(~/.zsh/completions $fpath) # in ~/.zshrc, BEFORE compinit"," # rm -f ~/.zcompdump && exec zsh # rebuild the completion cache",""].join(`
3
3
  `)}async function runCompletionsSubcommand(rest,cliName=ROVE_PRODUCT_NAME,deps={}){let usage=completionUsage(cliName),fail=(message)=>{process.stderr.write(`${cliName} completions: ${message}
4
4
 
5
5
  ${usage}`),process.exit(2)};if(rest.some((arg)=>HELP_WORDS.includes(arg))){process.stdout.write(usage);return}let flags=rest.filter((arg)=>arg.startsWith("-")),shells=rest.filter((arg)=>!arg.startsWith("-")),unknownFlag=flags.find((flag)=>flag!=="--path"&&flag!=="--install");if(unknownFlag)fail(`unknown option "${unknownFlag}"`);if(new Set(flags).size>1)fail("--path and --install are different things; pass one");let shell=shells.length===1?shells[0]:void 0;if(!isShellKind(shell))fail(`unknown shell "${shells.join(" ")}"`);let scriptPath=shippedCompletionsPath(shell,cliName,deps.shippedDir),shipped=existsSync(scriptPath)?scriptPath:null;if(flags[0]==="--path"){if(!shipped)fail(`no pre-generated ${shell} script at ${scriptPath}
6
6
  ${cliName} completions ${shell} # print the script to stdout instead`);process.stdout.write(`${shipped}
7
- `);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-pw87thvf.js"),import("./chunk-jtpjdmb6.js")]),completion=installCompletions(shell,deps.home,cliName,shipped);settleWelcomeInstall("completions",shell);let line=completion.installed?"onboarding.appliedCompletions":"onboarding.keptCompletions";process.stdout.write(`${t(line,{path:completion.path})}
8
- `);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-rmk69hvh.js");process.stdout.write(generateCompletions(shell,cliName,mergeSubVerbs(API_VERBS)))}export{runCompletionsSubcommand};
7
+ `);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-p0ycfqw2.js"),import("./chunk-1x6yahf1.js")]),completion=installCompletions(shell,deps.home,cliName,shipped);settleWelcomeInstall("completions",shell);let line=completion.installed?"onboarding.appliedCompletions":"onboarding.keptCompletions";process.stdout.write(`${t(line,{path:completion.path})}
8
+ `);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-m3nfbnxy.js");process.stdout.write(generateCompletions(shell,cliName,mergeSubVerbs(API_VERBS)))}export{runCompletionsSubcommand};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{openDaemonSession,resolveActiveTaskId}from"./chunk-r7p1dhrv.js";import"./chunk-r1epx453.js";import"./chunk-m3773n9n.js";import"./chunk-c7j05xps.js";import"./chunk-wqckm0k6.js";import"./chunk-yt15y085.js";import"./chunk-6ks6s8b2.js";import"./chunk-fq3s9q62.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{resolveActiveTaskId,openDaemonSession};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{stopDaemonProcess}from"./chunk-1vwngrmf.js";import{spawnDetachedDaemon}from"./chunk-yktnbb14.js";import{isProcessAlive,readPidFile}from"./chunk-wqckm0k6.js";import{DAEMON_PROTOCOL_VERSION,RoveDaemonClient}from"./chunk-s0jbtyd9.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath}from"./chunk-n0rtj4z7.js";import{ROVE_PRODUCT_NAME}from"./chunk-nc46gddg.js";import{closeSync,existsSync,mkdirSync,openSync,statSync,unlinkSync}from"fs";import{dirname,resolve}from"path";import{fileURLToPath}from"url";var DAEMON_START_ARGS=["daemon","start"],DAEMON_HELLO_TIMEOUT_MS=3000,BUSY_DAEMON_GRACE_MS=15000;function insideEngineSession(env=process.env){return typeof env.ROVE_TASK_ID==="string"&&env.ROVE_TASK_ID!==""}function autospawnDaemonEnv(env=process.env,reason="autospawn"){let{ROVE_TASK_ID:_task,ROVE_TAB_ID:_tab,ROVE_TUI:_tui,ROVE_TERMINAL_PTY:_pty,ROVE_TASK_ID:_roveTask,ROVE_TAB_ID:_roveTab,ROVE_TUI:_roveTui,ROVE_TERMINAL_PTY:_rovePty,...rest}=env;return{...rest,ROVE_DAEMON_AUTOSPAWNED:"1",ROVE_DAEMON_SPAWN_REASON:reason}}function daemonSpawnReason(env=process.env){let raw=env.ROVE_DAEMON_SPAWN_REASON;if(raw==="explicit-restart"||raw==="autospawn")return raw;return env.ROVE_DAEMON_AUTOSPAWNED==="1"?"autospawn":"manual"}var SPAWN_LOCK_STALE_MS=40000,SPAWN_LOCK_WAIT_MS=30000;function tryAcquireSpawnLock(lockPath,staleMs=SPAWN_LOCK_STALE_MS){let create=()=>{return mkdirSync(dirname(lockPath),{recursive:!0}),closeSync(openSync(lockPath,"wx")),!0};try{return create()}catch{try{if(Date.now()-statSync(lockPath).mtimeMs<=staleMs)return!1;return unlinkSync(lockPath),create()}catch{return!1}}}async function ensureDaemonReachable(resolveSpawn=resolveRoveSpawn,spawnReason="autospawn"){let socketPath=defaultDaemonSocketPath(),state=await probeDaemonSocket(socketPath);if(state==="alive")return socketPath;if(state==="wedged"&&insideEngineSession())throw Error(`rove: daemon at ${socketPath} is not answering hello (busy or wedged); not restarting it from inside an engine session \u2014 retry, or run \`rove daemon restart\` from a regular shell`);let lockPath=`${defaultDaemonPidPath()}.spawn-lock`;if(!tryAcquireSpawnLock(lockPath)){let deadline=Date.now()+SPAWN_LOCK_WAIT_MS;while(Date.now()<deadline){if(await testDaemonResponds(socketPath))return socketPath;await new Promise((resolveTimer)=>setTimeout(resolveTimer,150))}throw Error(`rove: another process is starting the daemon but it never became reachable at ${socketPath}; check ${defaultDaemonLogPath()} or run \`rove doctor\``)}try{if(await probeDaemonSocket(socketPath)==="alive")return socketPath;let livePid=await readPidFile(defaultDaemonPidPath());if(livePid!==null&&livePid!==process.pid&&isProcessAlive(livePid)){let deadline2=Date.now()+BUSY_DAEMON_GRACE_MS;while(Date.now()<deadline2){if(await new Promise((resolveTimer)=>setTimeout(resolveTimer,250)),await testDaemonResponds(socketPath))return socketPath;if(!isProcessAlive(livePid))break}}let[command,...args]=resolveSpawn(DAEMON_START_ARGS);await stopDaemonProcess(socketPath,defaultDaemonPidPath()).catch(()=>{}),spawnDetachedDaemon(command,args,autospawnDaemonEnv(process.env,spawnReason),defaultDaemonLogPath());let deadline=Date.now()+5000;while(Date.now()<deadline){if(await testDaemonResponds(socketPath))return socketPath;await new Promise((resolveTimer)=>setTimeout(resolveTimer,100))}throw Error(`rove: daemon did not start (or stayed wedged) at ${socketPath}; check ${defaultDaemonLogPath()} or run \`rove doctor\``)}finally{try{unlinkSync(lockPath)}catch{}}}async function connectOrStartDaemon(spawnReason="autospawn"){let socketPath=await ensureDaemonReachable(resolveRoveSpawn,spawnReason),client=new RoveDaemonClient(socketPath);return await client.connect(),client}async function connectIfRunning(){let socketPath=defaultDaemonSocketPath();if(!await testDaemonResponds(socketPath))return null;let client=new RoveDaemonClient(socketPath);return await client.connect(),client}async function probeDaemonSocket(socketPath,timeoutMs=DAEMON_HELLO_TIMEOUT_MS){let probe=new RoveDaemonClient(socketPath);try{await probe.connect()}catch{return probe.close(),"absent"}let droppedByPeer=!1,offClose=probe.onLifecycle("close",()=>{droppedByPeer=!0}),replied=probe.request("hello",{protocolVersion:DAEMON_PROTOCOL_VERSION}).then(()=>!0).catch(()=>!0),timer,timedOut=new Promise((resolve2)=>{timer=setTimeout(()=>resolve2(!1),timeoutMs)}),settled=await Promise.race([replied,timedOut]);if(timer)clearTimeout(timer);if(offClose(),probe.close(),droppedByPeer)return"absent";return settled?"alive":"wedged"}async function testDaemonResponds(socketPath,timeoutMs=DAEMON_HELLO_TIMEOUT_MS){return await probeDaemonSocket(socketPath,timeoutMs)==="alive"}class StaleInstallError extends Error{candidates;constructor(cliName,dir,candidates){super(`${cliName}: this process is running from an install that no longer exists on disk \u2014 no ${cliName} entry near ${dir} (checked ${candidates.join(", ")}). Reinstall (\`npm install -g @sma1lboy/rove\`) and relaunch Rove.`);this.name="StaleInstallError",this.candidates=candidates}}function isStaleInstallError(err){return err instanceof Error&&err.name==="StaleInstallError"}function resolveRoveSpawn(subcommand,env=process.env,moduleFile=fileURLToPath(import.meta.url)){let here=moduleFile;if(here.startsWith("/$bunfs")||here.startsWith("B:\\~BUN"))return[process.execPath,...subcommand];let dir=dirname(here),cliName=ROVE_PRODUCT_NAME,candidates=[resolve(dir,`../cli/${cliName}.ts`),resolve(dir,`../../../rove/src/cli/${cliName}.ts`),resolve(dir,`../cli/${cliName}.js`),resolve(dir,"../cli/index.ts"),resolve(dir,"../../../rove/src/cli/index.ts"),resolve(dir,"../cli/index.js")],entry=candidates.find((candidate)=>existsSync(candidate));if(entry)return[process.execPath,entry,...subcommand];throw new StaleInstallError(cliName,dir,candidates)}
2
+ import{stopDaemonProcess}from"./chunk-m3773n9n.js";import{spawnDetachedDaemon}from"./chunk-c7j05xps.js";import{isProcessAlive,readPidFile}from"./chunk-wqckm0k6.js";import{DAEMON_PROTOCOL_VERSION,RoveDaemonClient}from"./chunk-6ks6s8b2.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath}from"./chunk-n0rtj4z7.js";import{ROVE_PRODUCT_NAME}from"./chunk-nc46gddg.js";import{closeSync,existsSync,mkdirSync,openSync,statSync,unlinkSync}from"fs";import{dirname,resolve}from"path";import{fileURLToPath}from"url";var DAEMON_START_ARGS=["daemon","start"],DAEMON_HELLO_TIMEOUT_MS=3000,BUSY_DAEMON_GRACE_MS=15000;function insideEngineSession(env=process.env){return typeof env.ROVE_TASK_ID==="string"&&env.ROVE_TASK_ID!==""}function autospawnDaemonEnv(env=process.env,reason="autospawn"){let{ROVE_TASK_ID:_task,ROVE_TAB_ID:_tab,ROVE_TUI:_tui,ROVE_TERMINAL_PTY:_pty,ROVE_TASK_ID:_roveTask,ROVE_TAB_ID:_roveTab,ROVE_TUI:_roveTui,ROVE_TERMINAL_PTY:_rovePty,...rest}=env;return{...rest,ROVE_DAEMON_AUTOSPAWNED:"1",ROVE_DAEMON_SPAWN_REASON:reason}}function daemonSpawnReason(env=process.env){let raw=env.ROVE_DAEMON_SPAWN_REASON;if(raw==="explicit-restart"||raw==="autospawn")return raw;return env.ROVE_DAEMON_AUTOSPAWNED==="1"?"autospawn":"manual"}var SPAWN_LOCK_STALE_MS=40000,SPAWN_LOCK_WAIT_MS=30000;function tryAcquireSpawnLock(lockPath,staleMs=SPAWN_LOCK_STALE_MS){let create=()=>{return mkdirSync(dirname(lockPath),{recursive:!0}),closeSync(openSync(lockPath,"wx")),!0};try{return create()}catch{try{if(Date.now()-statSync(lockPath).mtimeMs<=staleMs)return!1;return unlinkSync(lockPath),create()}catch{return!1}}}async function ensureDaemonReachable(resolveSpawn=resolveRoveSpawn,spawnReason="autospawn"){let socketPath=defaultDaemonSocketPath(),state=await probeDaemonSocket(socketPath);if(state==="alive")return socketPath;if(state==="wedged"&&insideEngineSession())throw Error(`rove: daemon at ${socketPath} is not answering hello (busy or wedged); not restarting it from inside an engine session \u2014 retry, or run \`rove daemon restart\` from a regular shell`);let lockPath=`${defaultDaemonPidPath()}.spawn-lock`;if(!tryAcquireSpawnLock(lockPath)){let deadline=Date.now()+SPAWN_LOCK_WAIT_MS;while(Date.now()<deadline){if(await testDaemonResponds(socketPath))return socketPath;await new Promise((resolveTimer)=>setTimeout(resolveTimer,150))}throw Error(`rove: another process is starting the daemon but it never became reachable at ${socketPath}; check ${defaultDaemonLogPath()} or run \`rove doctor\``)}try{if(await probeDaemonSocket(socketPath)==="alive")return socketPath;let livePid=await readPidFile(defaultDaemonPidPath());if(livePid!==null&&livePid!==process.pid&&isProcessAlive(livePid)){let deadline2=Date.now()+BUSY_DAEMON_GRACE_MS;while(Date.now()<deadline2){if(await new Promise((resolveTimer)=>setTimeout(resolveTimer,250)),await testDaemonResponds(socketPath))return socketPath;if(!isProcessAlive(livePid))break}}let[command,...args]=resolveSpawn(DAEMON_START_ARGS);await stopDaemonProcess(socketPath,defaultDaemonPidPath()).catch(()=>{}),spawnDetachedDaemon(command,args,autospawnDaemonEnv(process.env,spawnReason),defaultDaemonLogPath());let deadline=Date.now()+5000;while(Date.now()<deadline){if(await testDaemonResponds(socketPath))return socketPath;await new Promise((resolveTimer)=>setTimeout(resolveTimer,100))}throw Error(`rove: daemon did not start (or stayed wedged) at ${socketPath}; check ${defaultDaemonLogPath()} or run \`rove doctor\``)}finally{try{unlinkSync(lockPath)}catch{}}}async function connectOrStartDaemon(spawnReason="autospawn"){let socketPath=await ensureDaemonReachable(resolveRoveSpawn,spawnReason),client=new RoveDaemonClient(socketPath);return await client.connect(),client}async function connectIfRunning(){let socketPath=defaultDaemonSocketPath();if(!await testDaemonResponds(socketPath))return null;let client=new RoveDaemonClient(socketPath);return await client.connect(),client}async function probeDaemonSocket(socketPath,timeoutMs=DAEMON_HELLO_TIMEOUT_MS){let probe=new RoveDaemonClient(socketPath);try{await probe.connect()}catch{return probe.close(),"absent"}let droppedByPeer=!1,offClose=probe.onLifecycle("close",()=>{droppedByPeer=!0}),replied=probe.request("hello",{protocolVersion:DAEMON_PROTOCOL_VERSION}).then(()=>!0).catch(()=>!0),timer,timedOut=new Promise((resolve2)=>{timer=setTimeout(()=>resolve2(!1),timeoutMs)}),settled=await Promise.race([replied,timedOut]);if(timer)clearTimeout(timer);if(offClose(),probe.close(),droppedByPeer)return"absent";return settled?"alive":"wedged"}async function testDaemonResponds(socketPath,timeoutMs=DAEMON_HELLO_TIMEOUT_MS){return await probeDaemonSocket(socketPath,timeoutMs)==="alive"}class StaleInstallError extends Error{candidates;constructor(cliName,dir,candidates){super(`${cliName}: this process is running from an install that no longer exists on disk \u2014 no ${cliName} entry near ${dir} (checked ${candidates.join(", ")}). Reinstall (\`npm install -g @sma1lboy/rove\`) and relaunch Rove.`);this.name="StaleInstallError",this.candidates=candidates}}function isStaleInstallError(err){return err instanceof Error&&err.name==="StaleInstallError"}function resolveRoveSpawn(subcommand,env=process.env,moduleFile=fileURLToPath(import.meta.url)){let here=moduleFile;if(here.startsWith("/$bunfs")||here.startsWith("B:\\~BUN"))return[process.execPath,...subcommand];let dir=dirname(here),cliName=ROVE_PRODUCT_NAME,candidates=[resolve(dir,`../cli/${cliName}.ts`),resolve(dir,`../../../rove/src/cli/${cliName}.ts`),resolve(dir,`../cli/${cliName}.js`),resolve(dir,"../cli/index.ts"),resolve(dir,"../../../rove/src/cli/index.ts"),resolve(dir,"../cli/index.js")],entry=candidates.find((candidate)=>existsSync(candidate));if(entry)return[process.execPath,entry,...subcommand];throw new StaleInstallError(cliName,dir,candidates)}
3
3
  export{autospawnDaemonEnv,daemonSpawnReason,tryAcquireSpawnLock,ensureDaemonReachable,connectOrStartDaemon,connectIfRunning,probeDaemonSocket,testDaemonResponds,StaleInstallError,isStaleInstallError,resolveRoveSpawn};
@@ -0,0 +1,9 @@
1
+ // @bun
2
+ import{shQuote}from"./chunk-b7xjhgts.js";import{loadStateFile,updateStateFile}from"./chunk-g4281a0g.js";import{homeDir}from"./chunk-prqeddy7.js";import{shortHomeTag}from"./chunk-n0rtj4z7.js";var LOCAL_MACHINE_ID="local",ALIAS_RE=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function isValidMachineAlias(alias){return alias!==LOCAL_MACHINE_ID&&alias.length<=64&&ALIAS_RE.test(alias)}function parseSshTarget(target){let trimmed=target.trim();if(!trimmed)return null;let at=trimmed.lastIndexOf("@"),user=at>=0?trimmed.slice(0,at):void 0,rest=at>=0?trimmed.slice(at+1):trimmed;if(at>=0&&!user)return null;let bracketed=/^\[([^\]]+)\](?::(\d{1,5}))?$/.exec(rest),portMatch=bracketed?null:/^([^:]*):(\d{1,5})$/.exec(rest),host=bracketed?bracketed[1]??"":portMatch?portMatch[1]??"":rest,rawPort=bracketed?bracketed[2]:portMatch?.[2],port=rawPort?Number(rawPort):void 0;if(!host||/\s/.test(host))return null;if(port!==void 0&&(port<1||port>65535))return null;return{host,...user?{user}:{},...port?{port}:{}}}function defaultMachineAlias(args){let source=!args.typedUser&&args.port===void 0&&!isIpLiteral(args.typedHost)?args.typedHost:args.remoteHostname||args.typedHost;return sanitizeAlias(source)}function isIpLiteral(host){return host.includes(":")||/^\d{1,3}(\.\d{1,3}){3}$/.test(host)}function sanitizeAlias(raw){return(raw.split(".")[0]??raw).replace(/[^A-Za-z0-9._-]/g,"-").slice(0,64)}function sshTargetOf(config){return config.user?`${config.user}@${config.host}`:config.host}function readMachines(state){let raw=state.machines;if(!raw||typeof raw!=="object"||Array.isArray(raw))return{};return raw}function listMachines(){let machines=readMachines(loadStateFile());return Object.entries(machines).map(([alias,config])=>({alias,...config}))}function getMachine(alias){return readMachines(loadStateFile())[alias]??null}function addMachine(alias,config){let added=!1;return updateStateFile((state)=>{let machines={...readMachines(state)};added=machines[alias]===void 0,machines[alias]={...config,addedAt:config.addedAt??machines[alias]?.addedAt??new Date().toISOString()},state.machines=machines;return}),{added}}function updateMachine(alias,patch){updateStateFile((state)=>{let machines={...readMachines(state)},existing=machines[alias];if(!existing)return!1;machines[alias]={...existing,...patch},state.machines=machines;return})}function setMachineIdentity(alias,identity){updateMachine(alias,{identity})}function removeMachine(alias){let removed=!1;return updateStateFile((state)=>{let machines={...readMachines(state)};if(removed=machines[alias]!==void 0,!removed)return!1;delete machines[alias],state.machines=machines;return}),removed}function dedupeMachines(entries){let kept=[],seen=[];for(let entry of entries){let identity=entry.identity;if(identity){if(seen.some((other)=>sameMachine(other,identity)))continue;seen.push(identity)}kept.push(entry)}return kept}function sameMachine(a,b){return a.hostname===b.hostname&&a.homeDir===b.homeDir&&a.daemonPid===b.daemonPid}function duplicateAliasOf(machines,self,identity){for(let[alias,config]of Object.entries(machines)){if(alias===self)continue;let other=config.identity;if(!other)continue;if(other.hostname===identity.hostname&&other.homeDir===identity.homeDir&&other.daemonPid===identity.daemonPid)return alias}return null}import{tmpdir}from"os";import{join}from"path";var CONTROL_PERSIST_SECONDS=300;function machineSocketDir(alias,home=homeDir()){let natural=join(home,".rove","machines",alias);if(Buffer.byteLength(join(natural,"daemon.sock"),"utf8")<=SOCKET_PATH_LIMIT)return natural;return join(tmpdir(),`rove-m-${shortHomeTag(home)}-${shortHomeTag(alias)}`)}var SOCKET_PATH_LIMIT=100;function localDaemonSocketPath(alias,home=homeDir()){return join(machineSocketDir(alias,home),"daemon.sock")}function localPtySocketPath(alias,home=homeDir()){return join(machineSocketDir(alias,home),"pty.sock")}function controlPath(alias,home=homeDir()){return join(machineSocketDir(alias,home),"cm")}function machineSshArgs(alias,config,opts={}){let argv=["ssh"];if(opts.batch!==!1)argv.push("-o","BatchMode=yes");if(opts.mux!==!1&&process.platform!=="win32")argv.push("-o","ControlMaster=auto","-o",`ControlPath=${controlPath(alias,opts.home)}`,"-o",`ControlPersist=${CONTROL_PERSIST_SECONDS}`);if(argv.push("-o","StrictHostKeyChecking=accept-new"),config.port)argv.push("-p",String(config.port));if(config.auth.kind==="key"&&config.auth.keyPath)argv.push("-i",config.auth.keyPath);return argv.push(sshTargetOf(config)),argv}import{spawn}from"child_process";import{mkdirSync}from"fs";import{posix}from"path";var PATTERNS=[["host-key-changed",/REMOTE HOST IDENTIFICATION HAS CHANGED|Host key for .* has changed/i],["host-key-unverified",/Host key verification failed|No .*host key is known for/i],["auth-denied",/Permission denied \(|Too many authentication failures|no matching host key type/i],["unresolved",/Could not resolve hostname|Name or service not known|nodename nor servname/i],["refused",/Connection refused/i],["timeout",/timed out|Operation timed out|No route to host|Network is unreachable/i]];function classifySshFailure(stderr){for(let[kind,pattern]of PATTERNS)if(pattern.test(stderr))return kind;return"unknown"}function sshFailureRemedy(kind,target){switch(kind){case"unresolved":return`${target} does not resolve to an address. Check the name, or the Host block in ~/.ssh/config; on a tailnet, check \`tailscale status\`.`;case"refused":return`${target} refused the connection: nothing listens for ssh there. Enable Remote Login / start sshd on it, or pass the right --port.`;case"timeout":return`${target} did not answer. Is it awake and on this network (or VPN / tailnet)?`;case"host-key-changed":return`${target}'s host key CHANGED since you last connected. That is either a reinstall or someone in the middle. If you reinstalled it, remove the old key with \`ssh-keygen -R <host>\` and retry; otherwise stop here.`;case"host-key-unverified":return`${target}'s host key is not trusted yet. Run \`rove machine add\` in a terminal to confirm its fingerprint, or connect once with \`ssh ${target}\`.`;case"auth-denied":return`${target} rejected every key ssh offered. Load your key into ssh-agent, pass --identity <key>, or install a key there with \`ssh-copy-id ${target}\`.`;case"unknown":return`ssh to ${target} failed. Run \`ssh ${target} true\` to see why.`}}async function runOnMachine(alias,config,command,opts={}){try{mkdirSync(machineSocketDir(alias,opts.home),{recursive:!0,mode:448})}catch{}let argv=[...machineSshArgs(alias,config,{home:opts.home}),command];return await new Promise((resolve)=>{let stdout="",stderr="",settled=!1,done=(exitCode)=>{if(settled)return;settled=!0,clearTimeout(timer),resolve({stdout,stderr,exitCode})},child=spawn(argv[0]??"ssh",argv.slice(1),{stdio:["ignore","pipe","pipe"]}),timer=setTimeout(()=>{child.kill("SIGKILL"),stderr+=`
3
+ timed out`,done(-1)},opts.timeoutMs??30000);child.stdout?.on("data",(c)=>{stdout+=c.toString()}),child.stderr?.on("data",(c)=>{stderr+=c.toString()}),child.on("error",()=>done(-1)),child.on("close",(code)=>done(code??-1))})}async function discoverMachine(alias,config,opts={}){let found=await probe(alias,config,roveCommand(config.roveBin),opts);if(found.ok||found.code!=="NO_ROVE")return found;let located=parseLocatedRove((await runOnMachine(alias,config,LOCATE_ROVE_SCRIPT,opts)).stdout);if(!located||located===config.roveBin)return found;let retry=await probe(alias,config,roveCommand(located),opts);return retry.ok?{...retry,roveBin:located}:retry}function roveCommand(roveBin){if(!roveBin)return"rove";return`PATH=${shQuote(posix.dirname(roveBin))}:"$PATH" ${shQuote(roveBin)}`}var LOCATE_ROVE_SCRIPT=[`p=$("\${SHELL:-sh}" -lc 'command -v rove' 2>/dev/null)`,'if [ -n "$p" ] && [ -x "$p" ]; then echo "ROVE_BIN=$p"; exit 0; fi','for p in "$HOME/.bun/bin/rove" "$HOME/.npm-global/bin/rove" "$HOME/.local/bin/rove" /opt/homebrew/bin/rove /usr/local/bin/rove "$HOME"/.nvm/versions/node/*/bin/rove; do',' if [ -x "$p" ]; then echo "ROVE_BIN=$p"; exit 0; fi',"done","exit 1"].join(`
4
+ `);function parseLocatedRove(stdout){return/^ROVE_BIN=(\/\S.*)$/m.exec(stdout)?.[1]?.trim()??null}var ROVE_MISSING=/(?:^|\W)rove:? (?:command not found|not found)|command not found:? rove|\/rove:? No such file or directory|no such file or directory: \S*\/rove\b/i;async function probe(alias,config,rove,opts){let first=await runOnMachine(alias,config,`${rove} daemon status --json`,opts),parsed=parseStatusJson(first.stdout);if(parsed)return{ok:!0,status:parsed};let combined=`${first.stdout}
5
+ ${first.stderr}`.trim();if(ROVE_MISSING.test(combined))return{ok:!1,code:"NO_ROVE",message:`Rove is not installed on ${alias}: not on its PATH, its login shell's PATH, or the usual bun/npm/nvm install dirs. Install it there with \`npm i -g @sma1lboy/rove\`, then re-run.`};if(first.exitCode===255||first.exitCode===-1){let ssh=classifySshFailure(first.stderr),remedy=sshFailureRemedy(ssh,sshTargetOf(config));return{ok:!1,code:"SSH_FAILED",ssh,message:ssh==="unknown"&&combined?`${remedy}
6
+ ${combined}`:remedy}}let started=await runOnMachine(alias,config,`${rove} daemon restart`,{...opts,timeoutMs:60000}),second=await runOnMachine(alias,config,`${rove} daemon status --json`,opts),retry=parseStatusJson(second.stdout);if(retry)return{ok:!0,status:retry};if(looksLikeOldStatus(second.stdout))return{ok:!1,code:"BAD_STATUS",message:`${alias} runs a Rove too old for machines (its \`daemon status\` reports no pty socket). Upgrade it: \`ssh ${alias} npm i -g @sma1lboy/rove\`.`};return{ok:!1,code:started.exitCode===0?"BAD_STATUS":"NO_DAEMON",message:`could not read a daemon status from ${alias}: ${`${second.stdout}
7
+ ${second.stderr}
8
+ ${started.stderr}`.trim()||"no output"}`}}function firstJsonObject(text){let start=text.indexOf("{");if(start<0)return null;let depth=0,inString=!1,escaped=!1;for(let i=start;i<text.length;i++){let ch=text[i];if(inString){if(escaped)escaped=!1;else if(ch==="\\")escaped=!0;else if(ch==='"')inString=!1;continue}if(ch==='"')inString=!0;else if(ch==="{")depth++;else if(ch==="}"&&--depth===0)return text.slice(start,i+1)}return null}function looksLikeOldStatus(stdout){let json=firstJsonObject(stdout);if(json===null)return!1;try{let raw=JSON.parse(json);return typeof raw.socketPath==="string"&&typeof raw.ptySocketPath!=="string"}catch{return!1}}function parseStatusJson(stdout){let json=firstJsonObject(stdout);if(json===null)return null;let raw;try{raw=JSON.parse(json)}catch{return null}if(!raw||typeof raw!=="object")return null;let o=raw,socketPath=typeof o.socketPath==="string"?o.socketPath:"",ptySocketPath=typeof o.ptySocketPath==="string"?o.ptySocketPath:"";if(!socketPath||!ptySocketPath)return null;return{socketPath,ptySocketPath,homeDir:typeof o.homeDir==="string"?o.homeDir:"",hostname:typeof o.hostname==="string"?o.hostname:"",roveVersion:typeof o.roveVersion==="string"?o.roveVersion:"",daemonPid:typeof o.daemonPid==="number"?o.daemonPid:0}}
9
+ export{isValidMachineAlias,parseSshTarget,defaultMachineAlias,sanitizeAlias,sshTargetOf,readMachines,listMachines,getMachine,addMachine,updateMachine,setMachineIdentity,removeMachine,dedupeMachines,duplicateAliasOf,machineSocketDir,localDaemonSocketPath,localPtySocketPath,machineSshArgs,discoverMachine,roveCommand};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{connectIfRunning,connectOrStartDaemon}from"./chunk-kqf371ff.js";async function openDaemonSession(opts={}){let client=opts.mode==="require-running"?await connectIfRunning():await connectOrStartDaemon();if(!client)return null;return{client,close:()=>client.close()}}async function resolveActiveTaskId(client){let activeId=null,off=client.onChannel("active-task",(payload)=>{activeId=payload.taskId});try{await client.subscribe()}finally{off()}return activeId}
2
+ import{connectIfRunning,connectOrStartDaemon}from"./chunk-r1epx453.js";async function openDaemonSession(opts={}){let client=opts.mode==="require-running"?await connectIfRunning():await connectOrStartDaemon();if(!client)return null;return{client,close:()=>client.close()}}async function resolveActiveTaskId(client){let activeId=null,off=client.onChannel("active-task",(payload)=>{activeId=payload.taskId});try{await client.subscribe()}finally{off()}return activeId}
3
3
  export{openDaemonSession,resolveActiveTaskId};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{clearFrozenSessions}from"./chunk-spee6wv8.js";import{stopLegacyTmux}from"./chunk-gkdfct7t.js";import"./chunk-4250pw6r.js";import{stopDaemonProcess}from"./chunk-1vwngrmf.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{stampResetGate}from"./chunk-jf46jsdp.js";import"./chunk-1xrbb7gf.js";import"./chunk-g4281a0g.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import{kvStatePath,legacyRoveKvStatePath,legacyRoveStateDir,roveStateDir}from"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyFreezeDir,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{readFileSync}from"fs";import{unlink}from"fs/promises";import{join}from"path";import{createInterface}from"readline";var CLI_NAME=ROVE_PRODUCT_NAME;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{stopLegacyTmux}from"./chunk-gkdfct7t.js";import{clearFrozenSessions}from"./chunk-spee6wv8.js";import"./chunk-4250pw6r.js";import{stopDaemonProcess}from"./chunk-m3773n9n.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{stampResetGate}from"./chunk-q55z079p.js";import"./chunk-74e3k701.js";import"./chunk-g4281a0g.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import{kvStatePath,legacyRoveKvStatePath,legacyRoveStateDir,roveStateDir}from"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-6ks6s8b2.js";import"./chunk-fq3s9q62.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyFreezeDir,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{readFileSync}from"fs";import{unlink}from"fs/promises";import{join}from"path";import{createInterface}from"readline";var CLI_NAME=ROVE_PRODUCT_NAME;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(legacyRoveStateDir(),"tasks.json"),statePath=kvStatePath(),legacyStatePath=legacyRoveKvStatePath();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/ or existing 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(`
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{StaleInstallError,autospawnDaemonEnv,connectIfRunning,connectOrStartDaemon,daemonSpawnReason,ensureDaemonReachable,isStaleInstallError,probeDaemonSocket,resolveRoveSpawn,testDaemonResponds,tryAcquireSpawnLock}from"./chunk-kqf371ff.js";import"./chunk-1vwngrmf.js";import"./chunk-yktnbb14.js";import"./chunk-wqckm0k6.js";import"./chunk-yt15y085.js";import"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{tryAcquireSpawnLock,testDaemonResponds,resolveRoveSpawn,probeDaemonSocket,isStaleInstallError,ensureDaemonReachable,daemonSpawnReason,connectOrStartDaemon,connectIfRunning,autospawnDaemonEnv,StaleInstallError};
2
+ import{StaleInstallError,autospawnDaemonEnv,connectIfRunning,connectOrStartDaemon,daemonSpawnReason,ensureDaemonReachable,isStaleInstallError,probeDaemonSocket,resolveRoveSpawn,testDaemonResponds,tryAcquireSpawnLock}from"./chunk-r1epx453.js";import"./chunk-m3773n9n.js";import"./chunk-c7j05xps.js";import"./chunk-wqckm0k6.js";import"./chunk-yt15y085.js";import"./chunk-6ks6s8b2.js";import"./chunk-fq3s9q62.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{tryAcquireSpawnLock,testDaemonResponds,resolveRoveSpawn,probeDaemonSocket,isStaleInstallError,ensureDaemonReachable,daemonSpawnReason,connectOrStartDaemon,connectIfRunning,autospawnDaemonEnv,StaleInstallError};