@sma1lboy/rove 0.9.274 → 0.9.276

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 (195) hide show
  1. package/dist/cli/chunk-0d7517kk.js +6 -0
  2. package/dist/cli/{chunk-55ajzrj6.js → chunk-0r1jf8m9.js} +1 -1
  3. package/dist/cli/{chunk-qe7xb4rm.js → chunk-1ca2j9w6.js} +2 -2
  4. package/dist/cli/chunk-1eef3z5v.js +3 -0
  5. package/dist/cli/{chunk-8h437k1q.js → chunk-1jjqk7sq.js} +1 -1
  6. package/dist/cli/chunk-1n03wzx4.js +3 -0
  7. package/dist/cli/{chunk-9trbc3kj.js → chunk-22rgewg0.js} +2 -2
  8. package/dist/cli/{chunk-jwedmkm8.js → chunk-283vd9h7.js} +1 -1
  9. package/dist/cli/chunk-2kqxz9a4.js +5 -0
  10. package/dist/cli/chunk-2xsxcdp6.js +3 -0
  11. package/dist/cli/{chunk-bj6sa371.js → chunk-372g44dg.js} +1 -1
  12. package/dist/cli/{chunk-4dxc29mm.js → chunk-387w0db1.js} +1 -1
  13. package/dist/cli/{chunk-ypd337d0.js → chunk-3xkhcfet.js} +2 -2
  14. package/dist/cli/{chunk-qvnr8c18.js → chunk-3y9xzbqh.js} +1 -1
  15. package/dist/cli/chunk-4117kgmx.js +2 -0
  16. package/dist/cli/chunk-4a05fgdh.js +2 -0
  17. package/dist/cli/chunk-4dt1gfb3.js +3 -0
  18. package/dist/cli/{chunk-ycd28edp.js → chunk-4xvmrg86.js} +3 -4
  19. package/dist/cli/{chunk-sa48rtjz.js → chunk-511103e8.js} +1 -1
  20. package/dist/cli/chunk-59p3h5e9.js +2 -0
  21. package/dist/cli/{chunk-egpcaxwb.js → chunk-5e9y8aw5.js} +1 -1
  22. package/dist/cli/chunk-5nvg3ek8.js +3 -0
  23. package/dist/cli/chunk-5yfffvqe.js +2 -0
  24. package/dist/cli/{chunk-16ttm9x6.js → chunk-63cwjceg.js} +1 -1
  25. package/dist/cli/{chunk-y5axx6ev.js → chunk-6mtfafaw.js} +1 -1
  26. package/dist/cli/{chunk-0g3sjn8z.js → chunk-6xga1a2d.js} +1 -1
  27. package/dist/cli/{chunk-xbwq4bc0.js → chunk-745pg3xm.js} +1 -1
  28. package/dist/cli/{chunk-29s67j3k.js → chunk-81thm1eb.js} +4 -4
  29. package/dist/cli/chunk-82apkcrk.js +5 -0
  30. package/dist/cli/chunk-84pvn784.js +2 -0
  31. package/dist/cli/{chunk-1exwrmjd.js → chunk-883fyezq.js} +1 -1
  32. package/dist/cli/{chunk-gryq2vgw.js → chunk-8dd60adw.js} +1 -1
  33. package/dist/cli/{chunk-qfe1wf5c.js → chunk-91tcwxph.js} +1 -1
  34. package/dist/cli/{chunk-mxgtz5vz.js → chunk-9c3brkb3.js} +1 -1
  35. package/dist/cli/chunk-9gh8kgjs.js +2 -0
  36. package/dist/cli/{chunk-h8t4xg1p.js → chunk-9rj2fx6v.js} +1 -1
  37. package/dist/cli/{chunk-w9cdc97q.js → chunk-a4r45qdn.js} +1 -1
  38. package/dist/cli/{chunk-p6jw0zcd.js → chunk-agvtzads.js} +1 -1
  39. package/dist/cli/{chunk-gcg5h667.js → chunk-awh7np6x.js} +1 -1
  40. package/dist/cli/chunk-b035pej7.js +20 -0
  41. package/dist/cli/{chunk-ez438kn3.js → chunk-b95q6zhk.js} +1 -1
  42. package/dist/cli/chunk-brgfsm5v.js +2 -0
  43. package/dist/cli/chunk-bw98jn7g.js +18 -0
  44. package/dist/cli/{chunk-bexnp6g4.js → chunk-c63vgbkw.js} +1 -1
  45. package/dist/cli/{chunk-8sggyn8y.js → chunk-c6fy8xew.js} +1 -1
  46. package/dist/cli/chunk-c7mz2aq0.js +2 -0
  47. package/dist/cli/{chunk-ec7f3wcm.js → chunk-cbrt4s7m.js} +2 -2
  48. package/dist/cli/chunk-ccwe9n56.js +19 -0
  49. package/dist/cli/chunk-cfzg8q3e.js +4 -0
  50. package/dist/cli/{chunk-387ecqb8.js → chunk-d0hpes59.js} +1 -1
  51. package/dist/cli/{chunk-edrxs4cy.js → chunk-d7f022eb.js} +5 -5
  52. package/dist/cli/{chunk-by6fjf7m.js → chunk-d7xbm9jp.js} +1 -1
  53. package/dist/cli/{chunk-3v9s3bcz.js → chunk-d9643dwf.js} +1 -1
  54. package/dist/cli/{chunk-x20bs6bs.js → chunk-dgx02565.js} +1 -1
  55. package/dist/cli/{chunk-ecrw211n.js → chunk-dt676ks9.js} +1 -1
  56. package/dist/cli/{chunk-g9yba5vh.js → chunk-e3cd4qd2.js} +2 -2
  57. package/dist/cli/chunk-e3t1zbv1.js +5 -0
  58. package/dist/cli/{chunk-0rrmz6k6.js → chunk-eege1x0a.js} +1 -1
  59. package/dist/cli/{chunk-t34kjg5y.js → chunk-ehm9abge.js} +4 -3
  60. package/dist/cli/{chunk-mmq6922s.js → chunk-eq7vey2j.js} +2 -2
  61. package/dist/cli/chunk-eyvw70yb.js +2 -0
  62. package/dist/cli/{chunk-m6yy3qc1.js → chunk-f76gzvq3.js} +1 -1
  63. package/dist/cli/{chunk-xkmdxcjg.js → chunk-fn7ffyam.js} +1 -1
  64. package/dist/cli/chunk-g4dtqbrj.js +2 -0
  65. package/dist/cli/chunk-g9ba25q5.js +3 -0
  66. package/dist/cli/{chunk-22d4fjjb.js → chunk-gafkp74h.js} +1 -1
  67. package/dist/cli/chunk-gctqthxq.js +97 -0
  68. package/dist/cli/{chunk-dpq60qph.js → chunk-gq57he03.js} +1 -1
  69. package/dist/cli/chunk-h2gznz46.js +2 -0
  70. package/dist/cli/{chunk-03rbg95q.js → chunk-h64rsbrx.js} +5 -5
  71. package/dist/cli/{chunk-5dd7trgf.js → chunk-h7vwn62z.js} +1 -1
  72. package/dist/cli/chunk-hcvp84b3.js +4 -0
  73. package/dist/cli/chunk-hhcmzs67.js +78 -0
  74. package/dist/cli/chunk-hmjg1qh3.js +2 -0
  75. package/dist/cli/{chunk-jd7p0y5x.js → chunk-j9b285x6.js} +1 -1
  76. package/dist/cli/{chunk-tw9w8pzg.js → chunk-jckx79gk.js} +3 -3
  77. package/dist/cli/{chunk-r77pfw4m.js → chunk-je80r59s.js} +1 -1
  78. package/dist/cli/{chunk-sbds7zx4.js → chunk-jfcn77n9.js} +1 -1
  79. package/dist/cli/chunk-jn10xeft.js +2 -0
  80. package/dist/cli/{chunk-g263457v.js → chunk-k1pwp155.js} +1 -1
  81. package/dist/cli/chunk-k235z3ct.js +2 -0
  82. package/dist/cli/{chunk-qs1r0tqr.js → chunk-m2a19yt4.js} +1 -1
  83. package/dist/cli/{chunk-5gzpq34w.js → chunk-m73x5nry.js} +3 -3
  84. package/dist/cli/chunk-ma21srvx.js +3 -0
  85. package/dist/cli/chunk-mdc7b01e.js +3 -0
  86. package/dist/cli/{chunk-kgs56yns.js → chunk-mkfc9a09.js} +1 -1
  87. package/dist/cli/{chunk-9er68n24.js → chunk-mq88bvj6.js} +1 -1
  88. package/dist/cli/chunk-mqfvzdpr.js +3 -0
  89. package/dist/cli/{chunk-m4dvx7bd.js → chunk-mz1ffkqb.js} +3 -3
  90. package/dist/cli/{chunk-1rjq808h.js → chunk-n0rdn2fn.js} +1 -1
  91. package/dist/cli/{chunk-sza3tyhs.js → chunk-n6marmjn.js} +1 -1
  92. package/dist/cli/chunk-n8t4y0bj.js +10 -0
  93. package/dist/cli/chunk-nbpq1tkx.js +98 -0
  94. package/dist/cli/{chunk-b492aee1.js → chunk-ne6x6g2c.js} +1 -1
  95. package/dist/cli/{chunk-fexzfgd1.js → chunk-nr7e3e82.js} +1 -1
  96. package/dist/cli/chunk-ns35rdyk.js +3 -0
  97. package/dist/cli/chunk-pap7k3b4.js +3 -0
  98. package/dist/cli/chunk-pdq3ya2e.js +3 -0
  99. package/dist/cli/chunk-q8ffd1pc.js +3 -0
  100. package/dist/cli/{chunk-39sfhppm.js → chunk-qna1s1r4.js} +1 -1
  101. package/dist/cli/{chunk-tjj9bt7n.js → chunk-qqr4tfhk.js} +1 -1
  102. package/dist/cli/chunk-r7kmn4js.js +2 -0
  103. package/dist/cli/chunk-r7ntkd6y.js +15 -0
  104. package/dist/cli/{chunk-rtpa8hg3.js → chunk-rjfdzjhj.js} +1 -1
  105. package/dist/cli/chunk-syfs63r2.js +2 -0
  106. package/dist/cli/{chunk-4hnz77xf.js → chunk-syn0tfwy.js} +1 -1
  107. package/dist/cli/chunk-t4qr9sv4.js +4 -0
  108. package/dist/cli/{chunk-6jk2khme.js → chunk-t52gzaeb.js} +1 -1
  109. package/dist/cli/chunk-teh40faw.js +1 -1
  110. package/dist/cli/{chunk-gqh6atvp.js → chunk-tjhw09bz.js} +1 -1
  111. package/dist/cli/chunk-tq0h3vy6.js +3 -0
  112. package/dist/cli/{chunk-snqa07h6.js → chunk-tvdrvgen.js} +1 -1
  113. package/dist/cli/chunk-tz373e5w.js +3 -0
  114. package/dist/cli/chunk-v1r83m3n.js +3 -0
  115. package/dist/cli/chunk-vp171as9.js +65 -0
  116. package/dist/cli/chunk-vtcr71fs.js +8 -0
  117. package/dist/cli/{chunk-zaw71cf4.js → chunk-vz0f8e8q.js} +1 -1
  118. package/dist/cli/chunk-w77s2df8.js +3 -0
  119. package/dist/cli/chunk-w7v4jzwy.js +3 -0
  120. package/dist/cli/chunk-wvqn1t55.js +2 -0
  121. package/dist/cli/{chunk-r40aj7z6.js → chunk-x1ghdmp1.js} +1 -1
  122. package/dist/cli/{chunk-nzbq51h9.js → chunk-x3n4y5sp.js} +1 -1
  123. package/dist/cli/{chunk-q6septaj.js → chunk-xb3p11g0.js} +1 -1
  124. package/dist/cli/{chunk-yzkhwn31.js → chunk-xd93fm1k.js} +1 -1
  125. package/dist/cli/chunk-xn2f56tg.js +3 -0
  126. package/dist/cli/chunk-xv3217yv.js +2 -0
  127. package/dist/cli/chunk-yhytkwpv.js +2 -0
  128. package/dist/cli/{chunk-hfdk7j28.js → chunk-yk9b8zgn.js} +1 -1
  129. package/dist/cli/chunk-zat16a83.js +2 -0
  130. package/dist/cli/chunk-zcrs4sm2.js +3 -0
  131. package/dist/cli/{chunk-kx53jjee.js → chunk-zkp6nty3.js} +8 -6
  132. package/dist/cli/index.js +5 -5
  133. package/dist/cli/pty-host-node.mjs +258 -29
  134. package/dist/cli/rove-run.js +1 -1
  135. package/dist/cli/rove.js +1 -1
  136. package/dist/completions/rove.bash +2 -2
  137. package/dist/completions/rove.fish +2 -2
  138. package/dist/completions/rove.zsh +2 -2
  139. package/dist/skills/rove/SKILL.md +23 -9
  140. package/dist/skills/rove/references/api-flags.md +20 -11
  141. package/dist/web/assets/index-C5t3gibI.css +1 -0
  142. package/dist/web/assets/index-Djp7M6r8.js +122 -0
  143. package/dist/web/index.html +2 -2
  144. package/dist/web/sw.js +52 -0
  145. package/package.json +3 -3
  146. package/dist/cli/chunk-033k4ap7.js +0 -2
  147. package/dist/cli/chunk-0ppkvphp.js +0 -2
  148. package/dist/cli/chunk-11wyec8z.js +0 -2
  149. package/dist/cli/chunk-15fp4p9v.js +0 -15
  150. package/dist/cli/chunk-1ffqacz9.js +0 -3
  151. package/dist/cli/chunk-2v68zaaa.js +0 -2
  152. package/dist/cli/chunk-2y29zrm1.js +0 -2
  153. package/dist/cli/chunk-4d1v6066.js +0 -3
  154. package/dist/cli/chunk-5zsdjrgz.js +0 -4
  155. package/dist/cli/chunk-68wpp5y8.js +0 -20
  156. package/dist/cli/chunk-6h4qdckd.js +0 -3
  157. package/dist/cli/chunk-6jj82bej.js +0 -2
  158. package/dist/cli/chunk-783d1ba0.js +0 -3
  159. package/dist/cli/chunk-78v1q5mz.js +0 -2
  160. package/dist/cli/chunk-7z463zkx.js +0 -3
  161. package/dist/cli/chunk-97m9nyw7.js +0 -2
  162. package/dist/cli/chunk-9bae7f3m.js +0 -4
  163. package/dist/cli/chunk-b5c7p22a.js +0 -2
  164. package/dist/cli/chunk-b5pytfgm.js +0 -2
  165. package/dist/cli/chunk-b68dd36h.js +0 -3
  166. package/dist/cli/chunk-bbksmb5a.js +0 -3
  167. package/dist/cli/chunk-cpf78z3x.js +0 -4
  168. package/dist/cli/chunk-cyzp2btw.js +0 -63
  169. package/dist/cli/chunk-e01321zn.js +0 -5
  170. package/dist/cli/chunk-erx7x9xg.js +0 -97
  171. package/dist/cli/chunk-ewqqwtrj.js +0 -2
  172. package/dist/cli/chunk-fmbv4m3y.js +0 -25
  173. package/dist/cli/chunk-fs51wx31.js +0 -3
  174. package/dist/cli/chunk-fvvb0072.js +0 -3
  175. package/dist/cli/chunk-g3tv8kht.js +0 -2
  176. package/dist/cli/chunk-g53yqr82.js +0 -78
  177. package/dist/cli/chunk-k67vbszb.js +0 -3
  178. package/dist/cli/chunk-kyt9ytz2.js +0 -20
  179. package/dist/cli/chunk-n2ejvjrd.js +0 -3
  180. package/dist/cli/chunk-p4s826r2.js +0 -96
  181. package/dist/cli/chunk-p6334e7v.js +0 -2
  182. package/dist/cli/chunk-q9zgj6kw.js +0 -3
  183. package/dist/cli/chunk-rzef6szc.js +0 -3
  184. package/dist/cli/chunk-sqxdfzdq.js +0 -5
  185. package/dist/cli/chunk-sz2xs0a2.js +0 -4
  186. package/dist/cli/chunk-t5y8k772.js +0 -2
  187. package/dist/cli/chunk-vht2e44j.js +0 -10
  188. package/dist/cli/chunk-vjp7drne.js +0 -2
  189. package/dist/cli/chunk-vm551pxs.js +0 -2
  190. package/dist/cli/chunk-w09356fj.js +0 -20
  191. package/dist/cli/chunk-xmqv1zx6.js +0 -2
  192. package/dist/cli/chunk-xn7bk4f9.js +0 -3
  193. package/dist/cli/chunk-zybjm7d5.js +0 -2
  194. package/dist/web/assets/index-C9vaSoIJ.js +0 -113
  195. package/dist/web/assets/index-sA2EEQJw.css +0 -1
@@ -1,4 +0,0 @@
1
- // @bun
2
- import{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath}from"./chunk-6h4qdckd.js";import{hasRoveActivityHooks}from"./chunk-e01321zn.js";import"./chunk-7kysxgbq.js";import"./chunk-b68dd36h.js";import"./chunk-ec7f3wcm.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import{isObject}from"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import{installedSkillDirs}from"./chunk-68wpp5y8.js";import"./chunk-rfp0ayra.js";import"./chunk-40dgv828.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import"./chunk-bejhca6z.js";import"./chunk-z1nj22va.js";import"./chunk-br8r72bf.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.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
- `)}
4
- `}export{migrationHint,isRovePluginEnabled,detectLegacyInstalls};
@@ -1,20 +0,0 @@
1
- // @bun
2
- import{getPersistedString,setPersistedString}from"./chunk-rfp0ayra.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{__require}from"./chunk-91sykzqq.js";import{accessSync,existsSync,constants as fsConstants,readFileSync,statSync}from"fs";import{homedir}from"os";import{delimiter,dirname,join,resolve}from"path";import{fileURLToPath}from"url";var ROVE_SKILL_VERSION=89,ROVE_SKILL_REL_PATHS=[".agents/skills/rove/SKILL.md",".claude/skills/rove/SKILL.md"],SKILL_REL_PATHS=ROVE_SKILL_REL_PATHS;function skillInstallCommand(env=process.env){return`${ROVE_PRODUCT_NAME} skill install`}var SKILL_SOURCE_SLUG="Sma1lboy/rove";function bundledSkillDir(){let here=fileURLToPath(import.meta.url);return[resolve(here,"../../../../../.agents/skills/rove"),resolve(here,"../../skills/rove")].find((dir)=>existsSync(join(dir,"SKILL.md")))??null}function npxSkillsArgv(opts={}){let source=opts.source!==void 0?opts.source:bundledSkillDir(),agents=opts.agent===void 0?[]:typeof opts.agent==="string"?[opts.agent]:opts.agent;return["skills","add",source??SKILL_SOURCE_SLUG,"--skill",ROVE_PRODUCT_NAME,...opts.global===!1?[]:["--global"],...agents.flatMap((a)=>["--agent",a])]}function npxSkillsCommand(opts={}){return`npx ${npxSkillsArgv(opts).join(" ")}`}var NPX_MISSING_EXIT=127;function isNpxMissing(){let parts=(process.env.PATH??"").split(delimiter).filter(Boolean);if(parts.length===0)return!1;return!parts.some((dir)=>{try{return accessSync(join(dir,"npx"),fsConstants.X_OK),!0}catch{return!1}})}function npxMissingMessage(){return`${ROVE_PRODUCT_NAME} skill install needs \`npx\` (part of Node.js), which isn't on your PATH.
3
- Install Node.js (https://nodejs.org) and run it again \u2014 the Rove installer only installs Bun and Rove.`}async function runNpxSkillsInstall(agent,global){if(isNpxMissing())return process.stderr.write(`
4
- ${npxMissingMessage()}
5
-
6
- `),NPX_MISSING_EXIT;return await Bun.spawn(["npx",...npxSkillsArgv({...agent===void 0?{}:{agent},global})],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited}var HINT_SEEN_KEY="skillHintSeen";function markSkillHintSeen(){setPersistedString(HINT_SEEN_KEY,"1")}function roveSkillPaths(opts={}){let home=opts.home??homedir(),cwd=opts.cwd??process.cwd();return[home,cwd].flatMap((root)=>SKILL_REL_PATHS.map((rel)=>join(root,rel)))}function parseSkillVersion(content){let m=content.match(/rove-skill-version:\s*(\d+)/);return m?Number.parseInt(m[1],10):null}function skillVersionAt(path){try{return parseSkillVersion(readFileSync(path,"utf8"))}catch{return null}}function inodeKey(path){try{let stat=statSync(path);return`${stat.dev}:${stat.ino}`}catch{return path}}function distinctSkillFiles(roots,rels){let seen=new Set,out=[];for(let root of roots)for(let rel of rels){let path=join(root,rel);if(!existsSync(path))continue;let key=inodeKey(path);if(seen.has(key))continue;seen.add(key),out.push(path)}return out}function installedSkillDirs(home=homedir()){return distinctSkillFiles([home],SKILL_REL_PATHS).map((path)=>dirname(path))}function roveSkillState(opts={}){let roots=[opts.home??homedir(),opts.cwd??process.cwd()],best=[...distinctSkillFiles(roots,ROVE_SKILL_REL_PATHS).map((path)=>({path,version:skillVersionAt(path)}))].sort((a,b)=>(b.version??-1)-(a.version??-1))[0];if(!best)return{installed:!1,installedVersion:null,currentVersion:ROVE_SKILL_VERSION,stale:!1,path:null};let stale=best.version===null||best.version<ROVE_SKILL_VERSION;return{installed:!0,installedVersion:best.version,currentVersion:ROVE_SKILL_VERSION,stale,path:best.path}}function installedSkillDiffersFromBundled(installedPath){let bundled=bundledSkillDir();if(!bundled)return!1;try{return readFileSync(join(bundled,"SKILL.md"),"utf8")!==readFileSync(installedPath,"utf8")}catch{return!1}}function promptLine(){return new Promise((resolve2)=>{process.stdin.resume(),process.stdin.once("data",(d)=>{process.stdin.pause(),resolve2(String(d))})})}async function maybeHintSkillInstall(io={}){let{isRovePluginEnabled}=await import("./chunk-5zsdjrgz.js");if(isRovePluginEnabled())return;let cliName=ROVE_PRODUCT_NAME,installCommand=skillInstallCommand(),state=roveSkillState();if(!state.installed){if(getPersistedString(HINT_SEEN_KEY)==="1")return;setPersistedString(HINT_SEEN_KEY,"1"),process.stderr.write(`
7
- ${cliName}: the Rove agent skill isn't installed \u2014 install it so your coding agent can drive Rove via \`${cliName} api\`:
8
- ${installCommand}
9
- (wraps \`${npxSkillsCommand()}\`; check anytime with \`${cliName} doctor\`)
10
-
11
- `);return}let key=`${HINT_SEEN_KEY}:v${state.currentVersion}`;if(!state.stale)return;if(getPersistedString(key)==="1")return;let was=state.installedVersion===null?"an older version":`v${state.installedVersion}`;if(!(io.ask!==void 0||Boolean(process.stdin.isTTY&&process.stderr.isTTY))){setPersistedString(key,"1"),process.stderr.write(`
12
- ${cliName}: your Rove agent skill is out of date (${was}; this Rove wants v${state.currentVersion}) \u2014 refresh it so \`${cliName} api\` guidance matches:
13
- ${installCommand}
14
-
15
- `);return}process.stderr.write(`
16
- ${cliName}: a new version of the Rove agent skill is available (${was} \u2192 v${state.currentVersion}).
17
- Update now? [y]es / [n]o / [d]on't notify for this version: `);let answer=(await(io.ask??promptLine)()).trim().toLowerCase();if(answer==="y"||answer==="yes"){let code=await(io.install??runNpxSkillsInstall)();if(code===0)process.stderr.write(`${cliName}: skill updated.
18
- `);else process.stderr.write(`${cliName}: skill update failed (exit ${code}) \u2014 run \`${installCommand}\` manually.
19
- `)}else if(answer.startsWith("d"))setPersistedString(key,"1")}
20
- export{skillInstallCommand,bundledSkillDir,npxSkillsArgv,npxSkillsCommand,NPX_MISSING_EXIT,isNpxMissing,runNpxSkillsInstall,markSkillHintSeen,roveSkillPaths,installedSkillDirs,roveSkillState,installedSkillDiffersFromBundled,maybeHintSkillInstall};
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{JsonHookAdapter,editJsonSettings,removeRoveHooks,vendorConfigHome}from"./chunk-e01321zn.js";import{isObject}from"./chunk-7ghwdjdc.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{__require}from"./chunk-91sykzqq.js";import{join}from"path";var CLAUDE_HOOK_EVENT_MAP=[{event:"SessionStart",verb:"session-start"},{event:"UserPromptSubmit",verb:"turn-start"},{event:"Stop",verb:"turn-complete"},{event:"StopFailure",verb:"turn-failed"},{event:"Notification",matcher:"permission_prompt",verb:"awaiting-input"},{event:"Notification",matcher:"elicitation_dialog",verb:"awaiting-input"},{event:"SessionEnd",verb:"session-end"},{event:"PreCompact",verb:"pre-compact"},{event:"PostCompact",verb:"post-compact"},{event:"SubagentStart",verb:"subagent-start"},{event:"SubagentStop",verb:"subagent-stop"},{event:"PreToolUse",verb:"tool-pre"},{event:"PostToolUse",verb:"tool-post"},{event:"PostToolUseFailure",verb:"tool-failed"}],ROVE_HOOK_EVENTS=[...new Set(CLAUDE_HOOK_EVENT_MAP.map((e)=>e.event))];function failureFromErrorType(errorType){if(typeof errorType!=="string")return"other";if(errorType==="rate_limit"||errorType==="overloaded")return"rate_limit";if(errorType==="billing_error")return"billing";return"other"}function claudeSettingsPath(){return join(vendorConfigHome("claude"),"settings.json")}var WORKTREE_SYNC_VERB="worktree-created";function mergeWorktreeSyncHook(current,command){let{hooks:rawHooks,...restSettings}=current,{WorktreeCreate,...otherHooks}=isObject(rawHooks)?rawHooks:{},prior=Array.isArray(WorktreeCreate)?WorktreeCreate:[],kept=removeRoveHooks(prior,[WORKTREE_SYNC_VERB]);if(command!==null)kept.push({hooks:[{type:"command",command}]});let nextHooks={...otherHooks};if(kept.length>0)nextHooks.WorktreeCreate=kept;return Object.keys(nextHooks).length>0?{...restSettings,hooks:nextHooks}:{...restSettings}}class ClaudeHookAdapter extends JsonHookAdapter{vendor="claude";eventMap=CLAUDE_HOOK_EVENT_MAP;globalSettingsPath(){return claudeSettingsPath()}activityDetailFromPayload(kind,payload){if(kind==="turn-failed")return{failure:failureFromErrorType(payload.error_type)};if(kind==="awaiting-input")return{waiting:payload.notification_type==="elicitation_dialog"?"input":"permission"};if(kind==="tool-pre"||kind==="tool-post"||kind==="tool-failed")return{tool:{...typeof payload.tool_name==="string"?{name:payload.tool_name}:{},...typeof payload.tool_use_id==="string"?{id:payload.tool_use_id}:{}}};if(kind==="pre-compact"||kind==="post-compact")return{compact:{trigger:payload.trigger==="manual"?"manual":"auto"}};if(kind==="subagent-start"||kind==="subagent-stop")return{subagent:{...typeof payload.agent_type==="string"?{type:payload.agent_type}:{},...typeof payload.agent_id==="string"?{id:payload.agent_id}:{}}};return}sessionFromPayload(payload){if(typeof payload.session_id!=="string"||!payload.session_id)return;return{sessionId:payload.session_id,...typeof payload.transcript_path==="string"&&payload.transcript_path?{transcriptPath:payload.transcript_path}:{}}}isUnattendedSession(env){return env.CLAUDE_CODE_SESSION_ATTENDED==="0"}async externallyManagedHooks(){let{isRovePluginEnabled,detectLegacyInstalls,migrationHint}=await import("./chunk-5zsdjrgz.js");if(!isRovePluginEnabled())return;let notice=migrationHint(detectLegacyInstalls(),ROVE_PRODUCT_NAME);return notice?{notice}:{}}supportsWorktreeSync(){return!0}async removeWorktreeSyncHook(settingsFilePath){await editJsonSettings(settingsFilePath,(cur)=>mergeWorktreeSyncHook(cur,null))}}
3
- export{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath,ClaudeHookAdapter};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{Orchestrator}from"./chunk-sqxdfzdq.js";import"./chunk-x20bs6bs.js";import"./chunk-c1dz3qg3.js";import"./chunk-kx53jjee.js";import"./chunk-xmwp6je4.js";import{PLACEHOLDER_TASK_TITLE}from"./chunk-q9zgj6kw.js";import"./chunk-mmq6922s.js";import"./chunk-gq36nzg8.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import"./chunk-y1xnjx8x.js";import"./chunk-2tfnscxk.js";import"./chunk-h8t4xg1p.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-6xppe9bj.js";import"./chunk-2brn8e1y.js";import"./chunk-7kysxgbq.js";import"./chunk-ec7f3wcm.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-rfp0ayra.js";import"./chunk-40dgv828.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import"./chunk-bejhca6z.js";import"./chunk-z1nj22va.js";import"./chunk-br8r72bf.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-cmp64q4j.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{PLACEHOLDER_TASK_TITLE,Orchestrator};
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{BUNDLED_THEME_JSONS,parseRgbLiteral}from"./chunk-yzkhwn31.js";import{loadStateFile,patchStateFile}from"./chunk-32j6y5d1.js";import{kvStatePath}from"./chunk-z1nj22va.js";import{DEFAULT_LOCALE,isLocaleId}from"./chunk-1ffqacz9.js";import{RGBA as RGBA3}from"@opentui/core";import{RGBA}from"@opentui/core";var BREATH_TICKS=30,SPEED_MIN=0.2,SPEED_SWING=0.9333333333333333,INK_FLOOR=0.3;function breathLevel(tick){return 0.5-0.5*Math.cos(2*Math.PI*tick/BREATH_TICKS)}function breathPhase(tick){let wave=tick/2-BREATH_TICKS/(4*Math.PI)*Math.sin(2*Math.PI*tick/BREATH_TICKS);return SPEED_MIN*tick+SPEED_SWING*wave}function breathGlyph(frames,tick){let index=Math.floor(breathPhase(tick)+0.000000001)%frames.length;return frames[index]??frames[0]??""}function mixInk(accent,muted,share){if(accent.intent!=="rgb"||muted.intent!=="rgb")return accent;let[ar,ag,ab,aa]=accent.toInts(),[mr,mg,mb]=muted.toInts(),mix=(a,m)=>Math.round(m+(a-m)*share);return RGBA.fromInts(mix(ar,mr),mix(ag,mg),mix(ab,mb),aa)}function breathColor(accent,muted,tick){return mixInk(accent,muted,INK_FLOOR+(1-INK_FLOOR)*breathLevel(tick))}var toLinear=(v)=>v<=0.04045?v/12.92:((v+0.055)/1.055)**2.4,toGamma=(v)=>v<=0.0031308?12.92*v:1.055*v**0.4166666666666667-0.055;function toOklch(color){let[r,g,b]=color.toInts().map((v)=>toLinear(v/255)),l=Math.cbrt(0.4122214708*r+0.5363325363*g+0.0514459929*b),m=Math.cbrt(0.2119034982*r+0.6806995451*g+0.1073969566*b),s=Math.cbrt(0.0883024619*r+0.2817188376*g+0.6299787005*b),L=0.2104542553*l+0.793617785*m-0.0040720468*s,A=1.9779984951*l-2.428592205*m+0.4505937099*s,B=0.0259040371*l+0.7827717662*m-0.808675766*s;return{l:L,c:Math.hypot(A,B),h:Math.atan2(B,A)}}function linearRgb({l:L,c,h}){let A=c*Math.cos(h),B=c*Math.sin(h),l=(L+0.3963377774*A+0.2158037573*B)**3,m=(L-0.1055613458*A-0.0638541728*B)**3,s=(L-0.0894841775*A-1.291485548*B)**3;return[4.0767416621*l-3.3077115913*m+0.2309699292*s,-1.2684380046*l+2.6097574011*m-0.3413193965*s,-0.0041960863*l-0.7034186147*m+1.707614701*s]}function fromOklch(color,alpha){let ch=(v)=>Math.round(Math.min(1,Math.max(0,toGamma(v)))*255),[r,g,b]=linearRgb(color);return RGBA.fromInts(ch(r),ch(g),ch(b),alpha)}function turnHue(accent,deg,lightness=1,chroma=1){if(accent.intent!=="rgb")return accent;let base=toOklch(accent),turned={l:base.l*lightness,c:base.c*chroma,h:base.h+deg*Math.PI/180};return fromOklch(turned,accent.toInts()[3])}var inGamut=(color)=>linearRgb(color).every((v)=>v>=-0.0001&&v<=1.0001);function inkAtHue(deg,lightness,chroma,alpha=255){let h=deg*Math.PI/180,c=chroma;while(c>0&&!inGamut({l:lightness,c,h}))c-=0.005;return fromOklch({l:lightness,c:Math.max(0,c),h},alpha)}function oklchCusp(deg){let key=Math.round(deg)%360,hit=cuspCache.get(key);if(hit)return hit;let h=key*Math.PI/180,best={l:1,c:0};for(let l=0.2;l<=1;l+=0.01){let lo=0,hi=0.4;for(let i=0;i<16;i++){let mid=(lo+hi)/2;if(inGamut({l,c:mid,h}))lo=mid;else hi=mid}if(lo>best.c)best={l,c:lo}}return cuspCache.set(key,best),best}var cuspCache=new Map;import{RGBA as RGBA2}from"@opentui/core";var HOST_TEXT_MIN_CONTRAST=4.5;function srgbChannelToLinear(c){let v=c/255;return v<=0.04045?v/12.92:((v+0.055)/1.055)**2.4}function relativeLuminance([r,g,b]){return 0.2126*srgbChannelToLinear(r)+0.7152*srgbChannelToLinear(g)+0.0722*srgbChannelToLinear(b)}function contrastRatioTriplet(fg,bg){let l1=relativeLuminance(fg),l2=relativeLuminance(bg),lighter=Math.max(l1,l2),darker=Math.min(l1,l2);return(lighter+0.05)/(darker+0.05)}function rgbToHsl([r,g,b]){let rn=r/255,gn=g/255,bn=b/255,max=Math.max(rn,gn,bn),min=Math.min(rn,gn,bn),l=(max+min)/2;if(max===min)return[0,0,l];let d=max-min,s=l>0.5?d/(2-max-min):d/(max+min),h;if(max===rn)h=((gn-bn)/d+(gn<bn?6:0))*60;else if(max===gn)h=((bn-rn)/d+2)*60;else h=((rn-gn)/d+4)*60;return[h,s,l]}function hslToRgb(h,s,l){if(s===0){let v=Math.round(l*255);return[v,v,v]}let q=l<0.5?l*(1+s):l+s-l*s,p=2*l-q,channel=(t)=>{let tn=t;if(tn<0)tn+=1;if(tn>1)tn-=1;let c=tn<0.16666666666666666?p+(q-p)*6*tn:tn<0.5?q:tn<0.6666666666666666?p+(q-p)*(0.6666666666666666-tn)*6:p;return Math.round(c*255)};return[channel(h/360+0.3333333333333333),channel(h/360),channel(h/360-0.3333333333333333)]}var MID_HOST_LUMINANCE=0.5;function ensureContrast(fg,bg,minRatio=HOST_TEXT_MIN_CONTRAST){let fgInts=fg.toInts(),bgInts=bg.toInts(),fgTriplet=[fgInts[0],fgInts[1],fgInts[2]],bgTriplet=[bgInts[0],bgInts[1],bgInts[2]];if(contrastRatioTriplet(fgTriplet,bgTriplet)>=minRatio)return fg;let[h,s,l]=rgbToHsl(fgTriplet),lighten=relativeLuminance(bgTriplet)<=MID_HOST_LUMINANCE,at=(lightness)=>contrastRatioTriplet(hslToRgb(h,s,lightness),bgTriplet),lo=lighten?l:0,hi=lighten?1:l;for(let i=0;i<32;i++){let mid=(lo+hi)/2;if(at(mid)>=minRatio)if(lighten)hi=mid;else lo=mid;else if(lighten)lo=mid;else hi=mid}let[r,g,b]=hslToRgb(h,s,lighten?hi:lo);return RGBA2.fromInts(r,g,b,fgInts[3])}var BUNDLED_THEMES=BUNDLED_THEME_JSONS,DEFAULT_THEME="claude";function hasBundledTheme(name){return Boolean(BUNDLED_THEMES[name])}var THEME_MODE_PREFERENCES=["dark","light","auto"],DEFAULT_THEME_MODE="dark";function resolveThemeMode(preference,detected){return preference==="auto"?detected??"dark":preference}var FOCUS_ACCENT_SLOTS=["primary","success","info"];function resolveTheme(theme,mode="dark"){let defs=theme.defs??{};function resolve(c,chain=[]){if(typeof c==="string"){if(c==="transparent"||c==="none")return RGBA3.fromInts(0,0,0,0);if(c.startsWith("#"))return RGBA3.fromHex(c);let rgb=parseRgbLiteral(c);if(rgb)return RGBA3.fromInts(rgb.r,rgb.g,rgb.b,rgb.a);if(chain.includes(c))return RGBA3.fromInts(0,0,0);let next=defs[c]??theme.theme[c];if(next===void 0)return RGBA3.fromInts(0,0,0);return resolve(next,[...chain,c])}return resolve(c[mode],chain)}let out={};for(let[k,v]of Object.entries(theme.theme))out[k]=resolve(v);let text=out.text??RGBA3.fromHex("#ffffff"),background=out.background??RGBA3.fromHex("#000000");return{...{primary:out.primary??text,secondary:out.secondary??text,accent:out.accent??out.primary??text,error:out.error??text,warning:out.warning??text,warningOnHost:out.warning??text,success:out.success??text,info:out.info??text,text,textMuted:out.textMuted??text,background,backgroundPanel:out.backgroundPanel??background,backgroundElement:out.backgroundElement??background,backgroundMenu:out.backgroundMenu??out.backgroundElement??background,backgroundDialog:out.backgroundDialog??out.backgroundPanel??background,border:out.border??text,borderActive:out.borderActive??out.border??text,borderSubtle:out.borderSubtle??out.border??text,diffAdded:out.diffAdded??out.success??text,diffRemoved:out.diffRemoved??out.error??text,diffContext:out.diffContext??out.textMuted??text,diffHunkHeader:out.diffHunkHeader??out.textMuted??text,diffAddedBg:out.diffAddedBg??background,diffRemovedBg:out.diffRemovedBg??background,selectedListItemText:out.selectedListItemText??background},...out}}function applyDisplayOverlay(base,focusAccent,transparentBackground,hostBackground){let v={...base,focusAccent:base[focusAccent]??base.primary,warningOnHost:base.warning};if(!transparentBackground)return v;let[backgroundR,backgroundG,backgroundB]=base.background.toInts(),[panelR,panelG,panelB]=base.backgroundPanel.toInts(),transparent={...v,background:RGBA3.fromInts(backgroundR,backgroundG,backgroundB,0),backgroundPanel:RGBA3.fromInts(panelR,panelG,panelB,0)};if(!hostBackground)return transparent;return{...transparent,text:ensureContrast(transparent.text,hostBackground),textMuted:ensureContrast(transparent.textMuted,hostBackground),warningOnHost:ensureContrast(transparent.warning,hostBackground)}}function diffInks(theme,colorblind){let added=(ink)=>colorblind?turnHue(ink,60,1,0.71):ink;return{added:added(theme.diffAdded),removed:theme.diffRemoved,addedBg:added(theme.diffAddedBg),removedBg:theme.diffRemovedBg}}import{readFileSync}from"fs";var LOCALE_KEY="locale";function defaultTransparentBackground(platform=process.platform){return platform!=="win32"}function readPersistedUiPrefs(fallbackTheme,isKnownTheme=hasBundledTheme){try{let parsed=JSON.parse(readFileSync(kvStatePath(),"utf8")),theme=typeof parsed.activeTheme==="string"&&isKnownTheme(parsed.activeTheme)?parsed.activeTheme:fallbackTheme,themeMode=THEME_MODE_PREFERENCES.includes(parsed.themeMode)?parsed.themeMode:DEFAULT_THEME_MODE,transparent=typeof parsed.transparentBackground==="boolean"?parsed.transparentBackground:defaultTransparentBackground(),focusAccent=typeof parsed.focusAccent==="string"&&FOCUS_ACCENT_SLOTS.includes(parsed.focusAccent)?parsed.focusAccent:null,locale=isLocaleId(parsed[LOCALE_KEY])?parsed[LOCALE_KEY]:DEFAULT_LOCALE;return{theme,themeMode,transparent,focusAccent,locale}}catch{return{theme:fallbackTheme,themeMode:DEFAULT_THEME_MODE,transparent:defaultTransparentBackground(),focusAccent:null,locale:DEFAULT_LOCALE}}}var TERMINAL_TABS_PREFIX="terminalTabs.";function terminalTabsKey(taskId){return`${TERMINAL_TABS_PREFIX}${taskId}`}var stateFileTabsPersistence={load(){let out={};for(let[key,value]of Object.entries(loadStateFile())){if(!key.startsWith(TERMINAL_TABS_PREFIX))continue;let state=value;if(state&&Array.isArray(state.tabs))out[key.slice(TERMINAL_TABS_PREFIX.length)]=state}return out},save(changes){let patch={};for(let[taskId,state]of Object.entries(changes))patch[terminalTabsKey(taskId)]=state??void 0;patchStateFile(patch)}};
3
- export{breathGlyph,mixInk,breathColor,toOklch,turnHue,inkAtHue,oklchCusp,relativeLuminance,ensureContrast,BUNDLED_THEMES,DEFAULT_THEME,THEME_MODE_PREFERENCES,DEFAULT_THEME_MODE,resolveThemeMode,FOCUS_ACCENT_SLOTS,resolveTheme,applyDisplayOverlay,diffInks,LOCALE_KEY,defaultTransparentBackground,readPersistedUiPrefs,TERMINAL_TABS_PREFIX,terminalTabsKey,stateFileTabsPersistence};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{bundleWithBun,childProbeCommand,ensurePtyHostReachable,hasFrozenPtySessions,listPtyHostSessions,liveChildCount,ptyHostHasLiveSessions,resolveNodeBinary,resolveNodePtyHostSpawn,runChildProbe,sweepPtyHostSessions}from"./chunk-sz2xs0a2.js";import"./chunk-fvvb0072.js";import"./chunk-rxqdw6s5.js";import"./chunk-387ecqb8.js";import"./chunk-kgs56yns.js";import"./chunk-4hnz77xf.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-sza3tyhs.js";import"./chunk-96kvwzj8.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{sweepPtyHostSessions,runChildProbe,resolveNodePtyHostSpawn,resolveNodeBinary,ptyHostHasLiveSessions,liveChildCount,listPtyHostSessions,hasFrozenPtySessions,ensurePtyHostReachable,childProbeCommand,bundleWithBun};
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{managedWorktreeRootsFor,readWorktreeBaseOverride}from"./chunk-gq36nzg8.js";import{pathIdentity,pathSyntax,pathWithin,samePath}from"./chunk-pn5ygqn6.js";import{existsSync}from"fs";import path from"path";function ownerFirst(a,b){let rank=(t)=>t.sharesWorkspaceOf?1:0;return rank(a)-rank(b)||(a.id<b.id?-1:a.id>b.id?1:0)}function resolvePtyOwner(tasks,taskId,tabId){if(!tabId)return taskId;return tasks.find((t)=>t.ptyAlias?.taskId===taskId&&t.ptyAlias.tabId===tabId)?.id??taskId}function crossesRepoBoundary(wt,cwd){let syntax=pathSyntax(cwd);for(let dir=cwd;!samePath(dir,wt);dir=syntax.dirname(dir)){if(existsSync(syntax.join(dir,".git")))return!0;if(samePath(dir,syntax.dirname(dir)))break}return!1}function worktreesOf(t){return[t.worktreePath,...(t.extraRepos??[]).map((x)=>x.worktreePath)].filter((p)=>!!p)}function matchTaskByCwd(tasks,cwd){let target=pathIdentity(cwd),best,bestWt="";for(let t of tasks)for(let worktree of worktreesOf(t)){let wt=pathIdentity(worktree);if(pathWithin(wt,target)===null)continue;if(!best||wt.length>bestWt.length||wt.length===bestWt.length&&ownerFirst(t,best)<0)best=t,bestWt=wt}if(best&&crossesRepoBoundary(bestWt,target))return;return best?.id}function tasksAtWorktreePath(tasks,worktreePath){let target=pathIdentity(worktreePath);return tasks.filter((t)=>worktreesOf(t).some((wt)=>pathIdentity(wt)===target)).sort(ownerFirst).map((t)=>t.id)}function findAdoptableWorktree(tasks,cwd){let target=pathIdentity(cwd),repos=new Set,known=new Set;for(let t of tasks){if(t.repo&&path.isAbsolute(t.repo))repos.add(pathIdentity(t.repo));for(let wt of worktreesOf(t))known.add(pathIdentity(wt))}for(let repo of repos)for(let root of managedWorktreeRootsFor(repo,readWorktreeBaseOverride(repo)).map(pathIdentity)){let prefix=root.endsWith("/")?root:`${root}/`,rest=pathWithin(root,target);if(!rest)continue;let name=rest.split("/")[0];if(!name)continue;let worktreePath=`${prefix}${name}`;if(known.has(worktreePath))return;return{repo,worktreePath}}return}var DISPATCH_PROMPT_HEAD_CHARS=160;var SETTLED=new Set(["done","failed"]);function next(status,state){if(state==="error"||state==="dead")return"failed";if(state==="running"&&(status==="delivered"||status==="asking"))return"working";if(state==="permission_needed"&&(status==="delivered"||status==="working"))return"asking";if((state==="turn_complete"||state==="idle")&&(status==="working"||status==="asking"))return"done";return}class DispatchLedger{bus;rows=[];seq=1;rev=0;expiry=null;off;now;constructor(bus,now){this.bus=bus;this.now=now??Date.now,this.off=bus.onPublish((event)=>{if(event.channel==="engine-state")this.take(event.payload)})}list(){return{rows:this.rows,rev:this.rev}}record(input){let at=this.now(),row={id:`x-${this.seq++}`,kind:input.kind,from:input.from,...input.routine?{routine:input.routine}:{},to:input.to,promptHead:input.promptHead.replace(/\s+/g," ").trim().slice(0,160),at,status:input.delivered?"delivered":"failed",statusAt:at,...input.reason?{reason:input.reason}:{},...input.deliveryId?{deliveryId:input.deliveryId}:{}};return this.rows=[...this.rows,row],this.publish(),row}close(){this.off(),this.clearExpiry()}take(payload){let p=payload;if(typeof p.taskId!=="string"||typeof p.state!=="string")return;let tabId=typeof p.tabId==="string"&&p.tabId?p.tabId:null,at=typeof p.at==="number"?p.at:this.now(),changed=!1;if(this.rows=this.rows.map((row)=>{if(SETTLED.has(row.status)||row.to.taskId!==p.taskId||at<row.at)return row;if(row.to.tabId!==null&&tabId!==null&&row.to.tabId!==tabId)return row;let status=next(row.status,p.state);if(!status)return row;return changed=!0,{...row,to:row.to.tabId===null&&tabId!==null?{...row.to,tabId}:row.to,status,statusAt:at,...status==="failed"?{reason:p.state}:{}}}),changed)this.publish()}publish(){this.rows=prune(this.rows,this.now()),this.rev+=1,this.bus.publish("dispatch.snapshot",this.list()),this.scheduleExpiry()}scheduleExpiry(){this.clearExpiry();let open=this.rows.filter((r)=>!SETTLED.has(r.status));if(open.length===0)return;let due=Math.min(...open.map((r)=>r.statusAt))+21600000;this.expiry=setTimeout(()=>{if(this.expiry=null,prune(this.rows,this.now()).length!==this.rows.length)this.publish();else this.scheduleExpiry()},Math.max(0,due-this.now())),this.expiry.unref?.()}clearExpiry(){if(this.expiry)clearTimeout(this.expiry);this.expiry=null}}function prune(rows,now){let open=rows.filter((r)=>!SETTLED.has(r.status)&&now-r.statusAt<21600000).slice(-100),settled=rows.filter((r)=>SETTLED.has(r.status)).slice(-40),keep=new Set([...open,...settled]);return rows.filter((r)=>keep.has(r))}function ownEngineTabs(tabs){return tabs.filter((tab)=>tab.kind==="engine"&&tab.ptyTask===void 0)}function canonicalEngineTab(tabs){let own=ownEngineTabs(tabs);return own.find((tab)=>tab.id==="tab-1")??own[0]}
3
- export{DISPATCH_PROMPT_HEAD_CHARS,DispatchLedger,resolvePtyOwner,matchTaskByCwd,tasksAtWorktreePath,findAdoptableWorktree,ownEngineTabs,canonicalEngineTab};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{ensureForwards,startTunnel}from"./chunk-zaw71cf4.js";import"./chunk-sq6zj3fb.js";import"./chunk-y1xnjx8x.js";import"./chunk-7kysxgbq.js";import"./chunk-32j6y5d1.js";import"./chunk-bejhca6z.js";import"./chunk-z1nj22va.js";import"./chunk-br8r72bf.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-sza3tyhs.js";import"./chunk-96kvwzj8.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{startTunnel,ensureForwards};
@@ -1,4 +0,0 @@
1
- // @bun
2
- import{dedupeMachines,discoverMachine,ensureForwards,learnedFrom,listMachines,localDaemonSocketPath,localPtySocketPath,updateMachine}from"./chunk-zaw71cf4.js";import{ApiError}from"./chunk-r5j8fycq.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{getSavedRepos,isRemoteRepoKey}from"./chunk-rfp0ayra.js";import{loadStateFile,updateStateFile}from"./chunk-32j6y5d1.js";import{RoveDaemonClient,normalizeRemoteUrl}from"./chunk-sza3tyhs.js";import{ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import{hostname}from"os";import{spawnSync}from"child_process";import{existsSync}from"fs";import{join}from"path";function git(cwd,args){let res=spawnSync("git",["-C",cwd,...args],{encoding:"utf8",timeout:5000});return res.status===0?res.stdout.trim():null}function repoIdentity(path){if(!existsSync(path)||git(path,["rev-parse","--git-dir"])===null)return null;let origin=git(path,["remote","get-url","origin"]),root=git(path,["rev-list","--max-parents=0","HEAD"])?.split(`
3
- `).filter(Boolean).sort()[0];return{...origin?{origin:normalizeRemoteUrl(origin)}:{},...root?{root}:{}}}function isLocalCheckout(path){return existsSync(join(path,".git"))||existsSync(path)&&git(path,["rev-parse","--git-dir"])!==null}function unpushedCommits(path,ref){if(git(path,["rev-parse","--verify","--quiet",`${ref}^{commit}`])===null)return null;let ahead=git(path,["rev-list","--count",`${ref}@{upstream}..${ref}`]);if(ahead!==null)return Number.parseInt(ahead,10)||0;let lone=git(path,["rev-list","--count",ref,"--not","--remotes"]);return lone===null?null:Number.parseInt(lone,10)||0}import{spawnSync as spawnSync2}from"child_process";import{existsSync as existsSync2,mkdirSync}from"fs";import{homedir}from"os";import{dirname,isAbsolute,join as join2,resolve}from"path";var URL_LIKE=/^[a-z][a-z0-9+.-]*:\/\//i,SCP_LIKE=/^[^@/\s]+@[^:/\s]+:[^\s]+$/,SEGMENT=/^[A-Za-z0-9_.-]+$/;function parseRepoRef(raw,cwd=process.cwd(),exists=existsSync2){let value=raw.trim(),asPath={kind:"path",path:value};if(value===""||isRemoteRepoKey(value))return asPath;if(URL_LIKE.test(value)||SCP_LIKE.test(value))return{kind:"id",id:normalizeRemoteUrl(value),cloneUrl:value};if(isAbsolute(value)||/^[A-Za-z]:[\\/]/.test(value)||/^[~.\\]/.test(value))return asPath;if(exists(resolve(cwd,value)))return asPath;let parts=value.replace(/\.git$/i,"").split("/");if(!parts.every((p)=>SEGMENT.test(p)))return asPath;if(parts.length===2){let id=`github.com/${parts.join("/")}`.toLowerCase();return{kind:"id",id,cloneUrl:`https://${id}.git`}}if(parts.length>=3&&parts[0]?.includes(".")){let id=parts.join("/").toLowerCase();return{kind:"id",id,cloneUrl:`https://${id}.git`}}return asPath}function repoIdOf(identity){if(!identity)return null;if(identity.origin)return identity.origin;return identity.root?`root:${identity.root}`:null}function findCheckouts(want,candidates){let out=[];for(let c of candidates){let sameRoot=Boolean(want.root&&c.identity.root===want.root),sameOrigin=Boolean(want.origin&&c.identity.origin===want.origin);if(!sameRoot&&!sameOrigin)continue;let fork=sameRoot&&!sameOrigin&&Boolean(want.origin&&c.identity.origin);out.push({path:c.path,via:sameRoot?"root":"origin",fork})}return out}function pickCheckout(matches,opts){let usable=matches.filter((m)=>opts.allowFork||!m.fork);if(usable.length===0){let fork=matches.find((m)=>m.fork)?.path;return fork?{path:null,fork}:{path:null}}let primary=usable.find((m)=>m.path===opts.primary);if(primary)return{path:primary.path};if(usable.length>1&&opts.isClean){let clean=usable.find((m)=>opts.isClean?.(m.path));if(clean)return{path:clean.path}}return{path:usable[0]?.path??null}}function isCleanCheckout(path){let res=spawnSync2("git",["-C",path,"status","--porcelain","--untracked-files=no"],{encoding:"utf8",timeout:5000});return res.status===0&&res.stdout.trim()===""}var REPO_PRIMARY_KEY="repoPrimary";function primaryCheckouts(state=loadStateFile()){let raw=state[REPO_PRIMARY_KEY],out={};if(raw&&typeof raw==="object"){for(let[id,path]of Object.entries(raw))if(typeof path==="string")out[id]=path}return out}function setPrimaryCheckout(id,path){updateStateFile((state)=>{let next=primaryCheckouts(state);if(path===null)Reflect.deleteProperty(next,id);else next[id]=path;return state[REPO_PRIMARY_KEY]=next,!0})}function cloneDirFor(id,home=homedir()){return join2(home,".rove","repos",...id.split("/"))}function cloneRepo(ref,home){let dir=cloneDirFor(ref.id,home);if(repoIdentity(dir))return dir;mkdirSync(dirname(dir),{recursive:!0});let res=spawnSync2("git",["clone",ref.cloneUrl,dir],{encoding:"utf8",timeout:600000,env:{...process.env,GIT_TERMINAL_PROMPT:"0"}});if(res.status!==0)throw Error((res.stderr||res.stdout||"git clone failed").trim());return dir}var LOCAL_MACHINE="local";async function machineDaemonSocket(entry){let socketPath=localDaemonSocketPath(entry.alias);if(await answers(socketPath))return socketPath;if(!entry.sockets||!await forward(entry,entry.sockets))return null;if(await answers(socketPath))return socketPath;let found=await discoverMachine(entry.alias,entry);if(!found.ok)return null;let learned=learnedFrom(found);return updateMachine(entry.alias,learned),await forward({...entry,...learned},learned.sockets)&&await answers(socketPath)?socketPath:null}function forward(entry,sockets){return ensureForwards({alias:entry.alias,config:{...entry,sockets},remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty})}async function answers(socketPath){let client=new RoveDaemonClient(socketPath);try{return await client.request("hello",{}),!0}catch{return!1}finally{client.close()}}async function machineTasks(entry){let socketPath=await machineDaemonSocket(entry);if(!socketPath)return null;let client=new RoveDaemonClient(socketPath);try{return(await client.request("task.list")).tasks??[]}catch{return null}finally{client.close()}}function requireMachine(alias){let entry=listMachines().find((m)=>m.alias===alias);if(entry)return entry;throw new ApiError(`no machine named "${alias}"`,"UNKNOWN_MACHINE",{hint:"list the registered machines and retry with one of their aliases, or register it first",nextCommandArgs:["machine","list"]})}var AUTO_MACHINE="auto",busy=(tasks)=>tasks.filter((task)=>task.status==="in_progress").length;async function pickMachine(localTasks,readTasks=machineTasks,machines=dedupeMachines(listMachines()),hosts){let[local,...remote]=await Promise.all([localTasks().catch(()=>[]),...machines.map((entry)=>readTasks(entry))]),loads={[LOCAL_MACHINE]:busy(local)};machines.forEach((entry,i)=>{let tasks=remote[i];if(tasks)loads[entry.alias]=busy(tasks)});let pool=[null,...machines.filter((entry)=>loads[entry.alias]!==void 0)],skipped;if(hosts){let ok=await Promise.all(pool.map((entry)=>hosts(entry).catch(()=>!1)));if(ok.some(Boolean))skipped=pool.filter((_,i)=>!ok[i]).map((entry)=>entry?.alias??LOCAL_MACHINE),pool=pool.filter((_,i)=>ok[i])}let best=null,bestLoad=Number.POSITIVE_INFINITY;for(let entry of pool){let load=loads[entry?.alias??LOCAL_MACHINE]??0;if(load<bestLoad)best=entry,bestLoad=load}return{entry:best,loads,...skipped?{skipped}:{}}}function repoWanted(repo){if(typeof repo!=="string")return null;let ref=parseRepoRef(repo);if(ref.kind==="id")return{origin:ref.id};return isLocalCheckout(ref.path)?repoIdentity(ref.path):null}function repoHosts(params){if(flagOn(params.clone))return;let want=repoWanted(params.repo);if(!want||!want.origin&&!want.root)return;return async(entry)=>{if(entry===null){if(typeof params.repo==="string"&&parseRepoRef(params.repo).kind==="path")return!0;return getSavedRepos().some((path)=>findCheckouts(want,[{path,identity:repoIdentity(path)??{}}]).length)}let socket=await machineDaemonSocket(entry);if(!socket)return!1;let client=new RoveDaemonClient(socket);try{let res=await client.request("api.invoke",{verb:"repo-match",params:{...want.origin?{origin:want.origin}:{},...want.root?{root:want.root}:{}},forwarded:!0,from:hostname()});return res.ok&&Boolean(res.result.repo)}finally{client.close()}}}async function routeTarget(args){if(args.machine===AUTO_MACHINE){let hosts=args.params?repoHosts(args.params):void 0;return(await pickMachine(args.localTasks??(async()=>[]),machineTasks,void 0,hosts)).entry}if(args.machine!==void 0&&args.machine!==LOCAL_MACHINE)return requireMachine(args.machine);if(args.machine===LOCAL_MACHINE||!args.taskId)return null;let machines=dedupeMachines(listMachines());if(machines.length===0||await args.isLocalTask(args.taskId))return null;for(let entry of machines)if((await machineTasks(entry))?.some((task)=>task.id===args.taskId))return entry;return null}async function forwardVerb(entry,verb,params,socketPath){let target=socketPath??await machineDaemonSocket(entry);if(!target)return offline(entry.alias);let client=new RoveDaemonClient(target);try{let repo=await translateRepo(client,entry.alias,params);if(repo.failure)return repo.failure;if(verb==="land"&&params["dry-run"]===void 0){let published=await client.request("api.invoke",{verb:"publish",params:{"task-id":params["task-id"]},forwarded:!0,from:hostname()});if(published.ok||published.error.code!=="UNKNOWN_VERB")return published}return await client.request("api.invoke",{verb,params:repo.params,forwarded:!0,from:hostname()})}catch(err){let message=errorMessage(err);if(/unknown daemon request:/i.test(message))return tooOld(entry.alias);return failure("MACHINE_UNREACHABLE",`machine "${entry.alias}": ${message}`,{hint:"check the machine is up and reachable over ssh, then retry",nextCommandArgs:["machine","list"]})}finally{client.close()}}async function translateRepo(client,alias,params){let repo=params.repo;if(typeof repo!=="string")return{params};let ref=parseRepoRef(repo),local=ref.kind==="path"&&isLocalCheckout(ref.path);if(ref.kind==="path"&&!local)return{params};let identity=ref.kind==="id"?{origin:ref.id}:repoIdentity(repo);if(!identity?.origin&&!identity?.root)return{params};let allowFork=flagOn(params["allow-fork"]),ask=await client.request("api.invoke",{verb:"repo-match",params:{...identity.origin?{origin:identity.origin}:{},...identity.root?{root:identity.root}:{},...allowFork?{"allow-fork":!0}:{}},forwarded:!0,from:hostname()});if(!ask.ok)return ask.error.code==="UNKNOWN_VERB"?{params}:{failure:ask};let answer=ask.result,found=answer.repo;if(found){let base=params["base-branch"],unpushed=local&&typeof base==="string"?unpushedCommits(repo,base):null;if(typeof base==="string"&&unpushed)return{failure:failure("UNPUSHED_BASE",`${base} has ${unpushed} commit${unpushed===1?"":"s"} no remote has; ${alias} cannot base a task on it`,{hint:`push it first (\`git -C ${repo} push -u origin ${base}\`), then dispatch again`})};return{params:{...params,repo:found}}}if(answer.fork)return{failure:failure("FORK_MATCH",`machine "${alias}" only has ${answer.fork}, a fork of ${identity.origin??repo} (same history, other origin)`,{hint:"pass --allow-fork to use it, or --clone with the repo id to fetch the repo itself there"})};if(flagOn(params.clone)&&identity.origin)return{params:{...params,repo:ref.kind==="id"?repo:identity.origin}};return{failure:failure("NO_REMOTE_CHECKOUT",`machine "${alias}" has no checkout of ${identity.origin??repo}`,{hint:identity.origin?`pass --clone to clone it on ${alias}, or --repo with ${alias}'s own path`:`clone it on ${alias} (and open it there once so Rove knows it), or pass --repo with ${alias}'s own path`})}}var flagOn=(value)=>value===!0||value==="true";function offline(alias){return failure("MACHINE_UNREACHABLE",`machine "${alias}" did not answer`,{hint:`check \`ssh ${alias} true\` works without a prompt, then retry`,nextCommandArgs:["machine","list"]})}function tooOld(alias){return failure("MACHINE_VERSION_SKEW",`machine "${alias}" runs a Rove too old to accept forwarded verbs`,{hint:`upgrade Rove on ${alias} (\`rove update\` there), then retry`})}function failure(code,message,data){return{apiVersion:ROVE_API_VERSION,ok:!1,error:{message,code,...data}}}async function invokeRouted(args){if(args.forwarded)return args.runHere();let taskId=args.params["task-id"],target;try{target=await routeTarget({machine:args.machine,taskId:typeof taskId==="string"?taskId:void 0,isLocalTask:args.isLocalTask,...args.localTasks?{localTasks:args.localTasks}:{},params:args.params})}catch(err){if(!(err instanceof ApiError))throw err;return failure(err.code,err.message,err.data??{})}return target?forwardVerb(target,args.verb,args.params):args.runHere()}async function machinePtySocket(alias){let entry=requireMachine(alias);if(!await machineDaemonSocket(entry))throw new ApiError(`machine "${alias}" did not answer`,"MACHINE_UNREACHABLE");return localPtySocketPath(alias)}
4
- export{repoIdentity,parseRepoRef,repoIdOf,findCheckouts,pickCheckout,isCleanCheckout,primaryCheckouts,setPrimaryCheckout,cloneDirFor,cloneRepo,LOCAL_MACHINE,machineDaemonSocket,machineTasks,requireMachine,AUTO_MACHINE,pickMachine,repoWanted,repoHosts,routeTarget,forwardVerb,invokeRouted,machinePtySocket};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{AUTO_MACHINE,LOCAL_MACHINE,forwardVerb,invokeRouted,machineDaemonSocket,machinePtySocket,machineTasks,pickMachine,repoHosts,repoWanted,requireMachine,routeTarget}from"./chunk-9bae7f3m.js";import"./chunk-zaw71cf4.js";import"./chunk-sq6zj3fb.js";import"./chunk-r5j8fycq.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-y1xnjx8x.js";import"./chunk-2brn8e1y.js";import"./chunk-7kysxgbq.js";import"./chunk-rfp0ayra.js";import"./chunk-40dgv828.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import"./chunk-bejhca6z.js";import"./chunk-z1nj22va.js";import"./chunk-br8r72bf.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-sza3tyhs.js";import"./chunk-96kvwzj8.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{routeTarget,requireMachine,repoWanted,repoHosts,pickMachine,machineTasks,machinePtySocket,machineDaemonSocket,invokeRouted,forwardVerb,LOCAL_MACHINE,AUTO_MACHINE};
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{openDaemonSession,resolveActiveTaskId}from"./chunk-snqa07h6.js";import"./chunk-387ecqb8.js";import"./chunk-kgs56yns.js";import"./chunk-4hnz77xf.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-sza3tyhs.js";import"./chunk-96kvwzj8.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{resolveActiveTaskId,openDaemonSession};
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{MULTI_REPO_CAP,REPO_NAME_RE,SESSION_PR_CAP,canonicalPrUrl}from"./chunk-ec7f3wcm.js";import{toTaskId}from"./chunk-xy8be792.js";import{coerceVendorId}from"./chunk-h2m7em1e.js";import{DAEMON_MIGRATION_MARKER}from"./chunk-8t7qbr1e.js";import{LockfileError,acquire}from"./chunk-bejhca6z.js";import{logClient}from"./chunk-0g4wc808.js";import{pathSyntax,samePath}from"./chunk-pn5ygqn6.js";import{defaultClientLogPath}from"./chunk-eqdbfgq5.js";import{existsSync}from"fs";import{copyFile,readFile}from"fs/promises";import{dirname,join}from"path";function coerceTask(value){if(!value||typeof value!=="object")return null;let v=value;if(typeof v.id!=="string"||typeof v.title!=="string"||typeof v.repo!=="string"||typeof v.branch!=="string"||typeof v.worktreePath!=="string"||typeof v.status!=="string"||typeof v.createdAt!=="string"||typeof v.updatedAt!=="string")return null;if(!isTaskStatus(v.status))return null;let kind=v.kind==="main"?"main":v.kind==="dir"?"dir":"task",scratch=kind==="dir"&&v.scratch===!0,noProject=kind==="dir"&&v.noProject===!0,healedStatus=kind==="main"&&(v.status==="in_progress"||v.status==="done")?"backlog":v.status,deletion=coerceDeletion(v.deletion),quotaResume=coerceQuotaResume(v.quotaResume),linkedWorkItem=coerceLinkedWorkItem(v.linkedWorkItem),dispatcher=coerceDispatcher(v.dispatcher),lineage=coerceLineage(v,kind),routine=coerceRoutine(v.routine),extraRepos=coerceExtraRepos(v.extraRepos,v.repo),sessionPrs=coerceSessionPrs(v.sessionPrs),report=coerceWorkerReport(v.report);return{id:toTaskId(v.id),title:v.title,repo:v.repo,branch:v.branch,worktreePath:v.worktreePath,status:healedStatus,pinned:typeof v.pinned==="boolean"?v.pinned:!1,kind,...scratch?{scratch:!0}:{},...noProject?{noProject:!0}:{},...routine?{routine}:{},vendor:coerceVendorId(typeof v.vendor==="string"?v.vendor:void 0),...typeof v.command==="string"&&v.command.trim().length>0?{command:v.command}:{},prStatus:coercePRStatus(v.prStatus),...typeof v.modelEffort==="string"&&v.modelEffort.length>0?{modelEffort:v.modelEffort}:{},...typeof v.model==="string"&&v.model.length>0?{model:v.model}:{},...typeof v.tier==="string"&&v.tier.length>0?{tier:v.tier}:{},...typeof v.groupId==="string"&&v.groupId.length>0?{groupId:v.groupId}:{},...v.observedLanguage==="zh"||v.observedLanguage==="en"?{observedLanguage:v.observedLanguage}:{},...deletion?{deletion}:{},...quotaResume?{quotaResume}:{},...linkedWorkItem?{linkedWorkItem}:{},...dispatcher?{dispatcher}:{},...lineage,...v.deleteBranchPending===!0?{deleteBranchPending:!0}:{},...typeof v.prompt==="string"&&v.prompt.length>0?{prompt:v.prompt}:{},...typeof v.baseRef==="string"&&v.baseRef.trim().length>0?{baseRef:v.baseRef}:{},...typeof v.worktreeName==="string"&&v.worktreeName.trim().length>0?{worktreeName:v.worktreeName}:{},...extraRepos?{extraRepos}:{},...sessionPrs?{sessionPrs}:{},...report?{report}:{},...v.requireReport===!0?{requireReport:!0}:{},...v.archived===!0?{archived:!0}:{},createdAt:v.createdAt,updatedAt:v.updatedAt}}function coerceExtraRepos(value,primary){if(!Array.isArray(value))return;let out=[];for(let entry of value){if(out.length>=MULTI_REPO_CAP-1)break;if(!entry||typeof entry!=="object")continue;let e=entry;if(typeof e.name!=="string"||!REPO_NAME_RE.test(e.name))continue;if(typeof e.repo!=="string"||!pathSyntax(e.repo).isAbsolute(e.repo))continue;let repo=e.repo;if(samePath(repo,primary)||out.some((o)=>o.name===e.name||samePath(o.repo,repo)))continue;out.push({name:e.name,repo,branch:typeof e.branch==="string"?e.branch:"",worktreePath:typeof e.worktreePath==="string"?e.worktreePath:"",...typeof e.baseRef==="string"&&e.baseRef.trim().length>0?{baseRef:e.baseRef}:{},...coercePRStatus(e.prStatus)?{prStatus:coercePRStatus(e.prStatus)}:{}})}return out.length>0?out:void 0}function coerceSessionPrs(value){if(!Array.isArray(value))return;let out=[];for(let entry of value){if(!entry||typeof entry!=="object")continue;let e=entry,url=typeof e.url==="string"?canonicalPrUrl(e.url):void 0;if(!url||typeof e.addedAt!=="string"||out.some((o)=>o.url===url))continue;let status=coercePRStatus(e.status);out.push({url,addedAt:e.addedAt,...status?{status}:{}})}return out.length>0?out.slice(-SESSION_PR_CAP):void 0}function coerceWorkerReport(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(typeof v.at!=="string"||v.at.length===0)return;return{at:v.at,...typeof v.branch==="string"&&v.branch.length>0?{branch:v.branch}:{},...typeof v.pr==="number"&&Number.isFinite(v.pr)?{pr:v.pr}:{},...typeof v.summary==="string"&&v.summary.length>0?{summary:v.summary}:{}}}function coerceDispatcher(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(typeof v.taskId!=="string"||v.taskId.length===0)return;if(typeof v.tabId!=="string"||v.tabId.length===0)return;return{taskId:v.taskId,tabId:v.tabId}}function coerceTaskRef(value,selfId){return typeof value==="string"&&value.length>0&&value!==selfId?value:void 0}function coerceCwdSubpath(value){if(typeof value!=="string"||value.length===0)return;if(/^[/\\]|^[a-z]:/i.test(value))return;return value.split(/[/\\]/).includes("..")?void 0:value}function coerceLineage(v,kind){let selfId=v.id,parentTaskId=coerceTaskRef(v.parentTaskId,selfId),sharesWorkspaceOf=kind==="main"?void 0:coerceTaskRef(v.sharesWorkspaceOf,selfId),cwdSubpath=coerceCwdSubpath(v.cwdSubpath),ptyAlias=coerceDispatcher(v.ptyAlias);return{...parentTaskId?{parentTaskId:toTaskId(parentTaskId)}:{},...sharesWorkspaceOf?{sharesWorkspaceOf:toTaskId(sharesWorkspaceOf)}:{},...cwdSubpath?{cwdSubpath}:{},...ptyAlias?{ptyAlias}:{}}}function coerceRoutine(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(typeof v.automationId!=="string"||v.automationId.length===0)return;return{automationId:v.automationId}}function coerceQuotaResume(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(typeof v.resumeAt!=="string"||v.resumeAt.length===0)return;if(typeof v.requestedAt!=="string"||v.requestedAt.length===0)return;return{resumeAt:v.resumeAt,requestedAt:v.requestedAt}}function coerceLinkedWorkItem(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(v.provider!=="github")return;if(v.type!=="issue"&&v.type!=="pr")return;if(typeof v.number!=="number"||!Number.isFinite(v.number))return;if(typeof v.title!=="string"||typeof v.url!=="string"||v.url.length===0)return;return{provider:v.provider,type:v.type,number:v.number,title:v.title,url:v.url}}function coerceDeletion(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(v.phase!=="queued"&&v.phase!=="running"&&v.phase!=="error"||typeof v.force!=="boolean"||typeof v.requestedAt!=="string"||v.requestedAt.length===0||v.error!==void 0&&typeof v.error!=="string")return;return{phase:v.phase,force:v.force,...typeof v.deleteBranch==="boolean"?{deleteBranch:v.deleteBranch}:{},requestedAt:v.requestedAt,...typeof v.error==="string"?{error:v.error}:{}}}function coercePRStatus(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let v=value;if(!isPRProviderId(v.provider)||!isPRLifecycleState(v.lifecycle)||!isPRCheckState(v.checkState))return;return{provider:v.provider,lifecycle:v.lifecycle,checkState:v.checkState,...typeof v.number==="number"&&Number.isFinite(v.number)?{number:v.number}:{},...typeof v.url==="string"?{url:v.url}:{},...typeof v.title==="string"?{title:v.title}:{},...typeof v.additions==="number"&&Number.isFinite(v.additions)?{additions:v.additions}:{},...typeof v.deletions==="number"&&Number.isFinite(v.deletions)?{deletions:v.deletions}:{},...typeof v.baseRef==="string"?{baseRef:v.baseRef}:{},...typeof v.reviewDecision==="string"?{reviewDecision:v.reviewDecision}:{},...typeof v.mergeable==="string"?{mergeable:v.mergeable}:{},...typeof v.lastCheckedAt==="string"?{lastCheckedAt:v.lastCheckedAt}:{},...typeof v.lastError==="string"?{lastError:v.lastError}:{}}}function isPRProviderId(v){return v==="github"||v==="gitlab"||v==="bitbucket"||v==="unknown"}function isPRLifecycleState(v){return v==="creating"||v==="open"||v==="ready_to_merge"||v==="merged"||v==="closed"||v==="unknown"}function isPRCheckState(v){return v==="none"||v==="pending"||v==="passing"||v==="failing"||v==="unknown"}function isTaskStatus(s){return s==="backlog"||s==="in_progress"||s==="in_review"||s==="done"||s==="canceled"||s==="error"}var sleep=(ms)=>new Promise((resolve)=>setTimeout(resolve,ms)),LOCK_RETRY_DELAY_MS=25,LOCK_MAX_WAIT_MS=5000;async function acquireWithRetry(lockPath){let deadline=Date.now()+LOCK_MAX_WAIT_MS;for(;;)try{return await acquire(lockPath)}catch(err){if(!(err instanceof LockfileError)||Date.now()>=deadline)throw err;await sleep(LOCK_RETRY_DELAY_MS)}}var CURRENT_VERSION=3;async function backupCorruptManifest(path,now=()=>new Date){let backupPath=`${path}.corrupt-${now().toISOString().replaceAll(":","-")}`;try{return await copyFile(path,backupPath),backupPath}catch{return null}}var SUPPORTED_VERSIONS=new Set([1,2,3]);function warnManifestRecovery(message,manifestPath){console.warn(message),logClient("tasks-index",message,manifestPath?defaultClientLogPath(dirname(dirname(manifestPath))):void 0)}async function recoverUnsupportedVersion(parsed,sourcePath){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return!1;let version=parsed.version;if(version===void 0||SUPPORTED_VERSIONS.has(version))return!1;let backup=await backupCorruptManifest(sourcePath);return warnManifestRecovery(`[rove] tasks.json at ${sourcePath} has unsupported version=${String(version)}; recovering with empty index.${backup?` Original bytes backed up to ${backup}.`:" Backup copy failed; the stale file is left in place."}`,sourcePath),!0}function normalizeIndex(parsed,source){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return warnManifestRecovery(`[rove] tasks.json at ${source} is not an object; recovering with empty index.`,source),{version:CURRENT_VERSION,tasks:[]};let obj=parsed,version=obj.version;if(version!==void 0&&!SUPPORTED_VERSIONS.has(version))return warnManifestRecovery(`[rove] tasks.json at ${source} has unsupported version=${String(version)}; recovering with empty index.`,source),{version:CURRENT_VERSION,tasks:[]};let rawTasks=Array.isArray(obj.tasks)?obj.tasks:[],tasks=[];for(let entry of rawTasks){let task=coerceTask(entry);if(task)tasks.push(task);else console.warn(`[rove] dropping malformed task entry from ${source}: ${JSON.stringify(entry)}`)}return{version:CURRENT_VERSION,tasks}}var TOMBSTONE_TTL_MS=2592000000;function readableLegacyIndexPath(canonicalPath,legacyPath){return existsSync(join(dirname(canonicalPath),DAEMON_MIGRATION_MARKER))?void 0:legacyPath}async function readDiskIndex(path,legacyPath){let raw,sourcePath=path;try{raw=await readFile(sourcePath,"utf8")}catch(err){if(err.code!=="ENOENT")throw err;let legacy=readableLegacyIndexPath(path,legacyPath);if(!legacy)return{tasks:[],removed:[]};sourcePath=legacy;try{raw=await readFile(sourcePath,"utf8")}catch(legacyErr){if(legacyErr.code==="ENOENT")return{tasks:[],removed:[]};throw legacyErr}}let parsed;try{parsed=JSON.parse(raw)}catch{return await backupCorruptManifest(sourcePath),{tasks:[],removed:[]}}if(await recoverUnsupportedVersion(parsed,sourcePath))return{tasks:[],removed:[]};return{tasks:normalizeIndex(parsed,sourcePath).tasks,removed:coerceTombstones(parsed)}}function coerceTombstones(parsed){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return[];let raw=parsed.removed;if(!Array.isArray(raw))return[];let out=[];for(let entry of raw){if(!entry||typeof entry!=="object")continue;let v=entry;if(typeof v.id==="string"&&v.id.length>0&&typeof v.at==="string")out.push({id:v.id,at:v.at})}return out}function mergeTasksWithDisk(cacheTasks,diskTasks,dirty,removed,diskRemoved=[],now=Date.now()){let tombstones=new Map;for(let t of diskRemoved){let at=Date.parse(t.at);if(!Number.isFinite(at)||now-at>TOMBSTONE_TTL_MS)continue;tombstones.set(t.id,t.at)}for(let[id,at]of removed)tombstones.set(id,at);let diskById=new Map(diskTasks.map((t)=>[t.id,t])),result=[],included=new Set;for(let task of cacheTasks){if(tombstones.has(task.id))continue;if(dirty.has(task.id))result.push(task);else{let onDisk=diskById.get(task.id);if(onDisk===void 0)continue;result.push(onDisk)}included.add(task.id)}for(let task of diskTasks){if(included.has(task.id)||tombstones.has(task.id))continue;result.push(task),included.add(task.id)}return{tasks:result,removed:[...tombstones].map(([id,at])=>({id,at}))}}async function recoverIndexFromDisk(path,legacyPath){let raw,sourcePath=path;try{raw=await readFile(path,"utf8")}catch(err){if(err.code!=="ENOENT")throw err;let legacy=readableLegacyIndexPath(path,legacyPath),legacyRaw;if(legacy)try{legacyRaw=await readFile(legacy,"utf8"),sourcePath=legacy}catch(legacyErr){if(legacyErr.code!=="ENOENT")throw legacyErr}if(legacyRaw===void 0)return{version:CURRENT_VERSION,tasks:[]};raw=legacyRaw}let parsed;try{parsed=JSON.parse(raw)}catch(err){let backup=await backupCorruptManifest(sourcePath);return warnManifestRecovery(`[rove] tasks.json at ${sourcePath} is corrupted (${err.message}); recovering with empty index.${backup?` Original bytes backed up to ${backup}.`:" Backup copy failed; the stale file is left in place."}`,sourcePath),{version:CURRENT_VERSION,tasks:[]}}if(await recoverUnsupportedVersion(parsed,sourcePath))return{version:CURRENT_VERSION,tasks:[]};return normalizeIndex(parsed,sourcePath)}
3
- export{acquireWithRetry,readableLegacyIndexPath,readDiskIndex,mergeTasksWithDisk,recoverIndexFromDisk};
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{deriveTitleFromPrompt}from"./chunk-q9zgj6kw.js";import{TaskDeletingError}from"./chunk-mmq6922s.js";import{awaitEngineProcess,buildEngineSessionLaunch,deliverToHostedKey,enginePresence,ensureHostedEngine,ensureHostedSessionHost,findHostedEngineKey,hostedSessionFailureLine,hostedTaskKeys,killHostedSessions,launchReposOf,listHostedSessions,openHostedSessionHost,pastePromptWhenEngineUp,trustEngineWorktree,trustExtraRepos}from"./chunk-15fp4p9v.js";import{engineLaunchArgv,protocolEntry}from"./chunk-rzef6szc.js";import{hostedKeyFor}from"./chunk-sz2xs0a2.js";import{resolveSessionShell}from"./chunk-tn9gtf18.js";import{taskCwd}from"./chunk-ec7f3wcm.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";var MAX_SESSIONS_SCANNED=8;function titleFromMessages(messages){let firstUser=messages.find((m)=>m.role==="user");if(!firstUser)return"";let text=firstUser.blocks.filter((b)=>b.type==="text").map((b)=>b.text).join(" "),title=deriveTitleFromPrompt(text);return title.length>0?Buffer.from(title,"utf8").toString("utf8"):title}async function deriveTitleFromSession(worktree,vendor=DEFAULT_TASK_VENDOR){if(!worktree)return"";let{history}=protocolEntry(vendor),ids=await history.listSessionIdsForWorktree(worktree);for(let sessionId of ids.slice(0,MAX_SESSIONS_SCANNED)){let title=titleFromMessages(await history.readHistory(sessionId));if(title)return title}return""}async function deriveTitleFromSessionId(vendor,sessionId){if(!sessionId)return"";try{return titleFromMessages(await protocolEntry(vendor).history.readHistory(sessionId))}catch{return""}}async function getTask(link,taskId){let{task}=await link.request("task.get",{taskId});return task}async function ensureTaskWorktree(link,taskId){let task=await getTask(link,taskId);if(task.deletion)throw new TaskDeletingError(taskId);let hasExtras=Boolean(task.extraRepos?.length);if(task.worktreePath&&!hasExtras){let repos=task.sharesWorkspaceOf?await launchReposOf(link,taskId):void 0;return{task,worktreePath:taskCwd(task),repos}}let{worktreePath}=await link.request("task.ensureWorktree",{taskId});if(!worktreePath)throw Error(`task ${taskId} has no worktree`);return{task,worktreePath:taskCwd({worktreePath,cwdSubpath:task.cwdSubpath}),repos:hasExtras||task.sharesWorkspaceOf?await launchReposOf(link,taskId):void 0}}async function ensureTaskSessionAdapter(link,taskId){let{task,worktreePath,repos}=await ensureTaskWorktree(link,taskId),launch=taskEngineLaunch(task,worktreePath,{kind:"repo-init"},repos),host=await ensureHostedSessionHost();try{if(!(await ensureHostedEngine(host.rpc,worktreePath,launch)).alive)throw Error(`failed to start hosted engine session for ${taskId}`);if(launch.firstMessage){let engineBin=engineLaunchArgv({command:task.command,vendor:task.vendor,effort:task.modelEffort,model:task.model})[0];await pastePromptWhenEngineUp(host.rpc,launch.key,engineBin,launch.firstMessage,{initMarkerPath:launch.initMarkerPath,initTimeoutMs:launch.initTimeoutMs}).catch(()=>!1)}}finally{host.close()}return{session:launch.key,worktreePath}}async function startTaskSessionWithPromptAdapter(link,taskId,prompt){let{task,worktreePath,repos}=await ensureTaskWorktree(link,taskId);await link.request("task.observeLanguage",{taskId,text:prompt}).catch(()=>{});let launch=taskEngineLaunch(task,worktreePath,{kind:"new-task",prompt},repos),host=await ensureHostedSessionHost();try{if(!(await ensureHostedEngine(host.rpc,worktreePath,launch)).alive)return{started:!1,error:"hosted session did not open"};let engineBin=engineLaunchArgv({command:task.command,vendor:task.vendor,effort:task.modelEffort,model:task.model})[0],wait={initMarkerPath:launch.initMarkerPath,initTimeoutMs:launch.initTimeoutMs};if(launch.firstMessage){if(await pastePromptWhenEngineUp(host.rpc,launch.key,engineBin,launch.firstMessage,wait)!==null)return{started:!0};return{started:!1,error:await startFailureReason(host.rpc,launch.key)}}if(await awaitEngineProcess(host.rpc,launch.key,engineBin,wait)!==null)return{started:!0};return{started:!1,error:await startFailureReason(host.rpc,launch.key)}}finally{host.close()}}async function startFailureReason(rpc,key){let tail=await hostedSessionFailureLine(rpc,key),base="engine process never started";return tail?`engine process never started; last session output: ${tail}`:"engine process never started"}function taskEngineLaunch(task,worktreePath,promptIntent,repos){return trustEngineWorktree(task.vendor,worktreePath),trustExtraRepos(task.vendor,repos),buildEngineSessionLaunch({task:{id:task.id,kind:task.kind,vendor:task.vendor,repo:task.repo,repos},worktreePath,shell:resolveSessionShell(),argv:engineLaunchArgv({command:task.command,vendor:task.vendor,effort:task.modelEffort,model:task.model}),promptIntent})}async function deliverPromptToLiveEngineAdapter(task,prompt){let host=await openHostedSessionHost();if(!host)return!1;try{let sessions=await listHostedSessions(host.rpc),engineArgv=engineLaunchArgv({command:task.command,vendor:task.vendor}),key=findHostedEngineKey(sessions,task.id,engineArgv[0],task.scope);if(!key)return!1;let presence=await enginePresence(sessions.find((s)=>s.key===key)?.pid,engineArgv);if(presence.kind!=="engine")return!1;return await deliverToHostedKey(host.rpc,key,prompt,{vendor:presence.vendor})!==null}catch{return!1}finally{host.close()}}function tabIdFromHostedKey(key){return key.split("::")[1]??"tab-1"}async function deliverPromptToLiveEngineDetailedAdapter(task,prompt){let host=await openHostedSessionHost();if(!host)return{outcome:"no-session"};try{let sessions=await listHostedSessions(host.rpc),engineArgv=engineLaunchArgv({command:task.command,vendor:task.vendor}),key=findHostedEngineKey(sessions,task.id,engineArgv[0],task.scope);if(!key)return{outcome:"no-session"};let presence=await enginePresence(sessions.find((s)=>s.key===key)?.pid,engineArgv);if(presence.kind!=="engine")return{outcome:"no-engine",tabId:tabIdFromHostedKey(key)};return await deliverToHostedKey(host.rpc,key,prompt,{vendor:presence.vendor})===null?{outcome:"no-session"}:{outcome:"delivered",tabId:tabIdFromHostedKey(key)}}catch{return{outcome:"no-session"}}finally{host.close()}}async function deliverPromptToLiveEngineTabDetailedAdapter(target,prompt){let host=await openHostedSessionHost();if(!host)return{outcome:"no-session"};try{let key=hostedKeyFor(target.id,target.tabId,target.scope);if(!key)return{outcome:"no-session"};let sessions;try{sessions=await listHostedSessions(host.rpc)}catch{return{outcome:"no-session"}}let session=sessions.find((candidate)=>candidate.alive&&candidate.key===key);if(!session)return{outcome:"no-session"};let engineArgv=engineLaunchArgv({command:target.command,vendor:target.vendor}),presence=await enginePresence(session.pid,engineArgv);if(presence.kind!=="engine")return{outcome:"no-engine",tabId:target.tabId};return await deliverToHostedKey(host.rpc,key,prompt,{vendor:presence.vendor})===null?{outcome:"no-session"}:{outcome:"delivered",tabId:target.tabId}}finally{host.close()}}async function tearDownTaskSessionAdapter(taskId,scope){let host=await openHostedSessionHost();if(!host)return;try{let keys=hostedTaskKeys(await listHostedSessions(host.rpc),taskId,scope);await killHostedSessions(host.rpc,keys,{wait:!0})}catch{}finally{host.close()}}
3
- export{deriveTitleFromSession,deriveTitleFromSessionId,ensureTaskSessionAdapter,startTaskSessionWithPromptAdapter,deliverPromptToLiveEngineAdapter,deliverPromptToLiveEngineDetailedAdapter,deliverPromptToLiveEngineTabDetailedAdapter,tearDownTaskSessionAdapter};
@@ -1,4 +0,0 @@
1
- // @bun
2
- import{embeddedTerminalEnv}from"./chunk-7bgbansg.js";import{ClientWriter,LineReceiver,clearTransientStatuses,createOscSignals,objectPayload,optionalBoolean,requireString,scanOscSignals}from"./chunk-k67vbszb.js";import{writeTextAtomic}from"./chunk-5mhvjytn.js";import{DEFAULT_TERMINAL_COLORS,FREEZE_RESTORE_MAX_BYTES,FREEZE_TTL_MS,fileFreezeSink,foldDefaultColorQueries,formatDefaultColorReply,freezeSession,freshModeTrack,loadFrozenSessions,parseTerminalDefaultColors,scanTerminalModes,terminalModePreamble,thawSession}from"./chunk-fvvb0072.js";import{installDaemonCrashHandlers,logDaemonError}from"./chunk-rxqdw6s5.js";import{resolveSessionShell}from"./chunk-tn9gtf18.js";import{recordPtyExit}from"./chunk-2w228s7t.js";import"./chunk-etfh8f4z.js";import{spawnDetachedDaemon,withoutPtyJob}from"./chunk-4hnz77xf.js";import{CURRENT_VERSION}from"./chunk-w9cdc97q.js";import"./chunk-z1nj22va.js";import{listenOnUnixSocket}from"./chunk-br8r72bf.js";import"./chunk-zt7wfnva.js";import{ensureOwnerOnlyStateDir}from"./chunk-yt15y085.js";import{DAEMON_PROTOCOL_VERSION,PTY_STOP_REFUSED,frameToLine}from"./chunk-sza3tyhs.js";import"./chunk-96kvwzj8.js";import{rotateLogIfNeeded}from"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import{defaultPtyFreezeDir,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath,endpointPathFor,isWindowsPipePath,resolveDaemonHomeDir}from"./chunk-eqdbfgq5.js";import{preRenameStateDir}from"./chunk-f8gg8cqh.js";import{ROVE_STATE_DIR_BASENAME,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";function formatPtyHostLine(event,message,now=new Date){return`[${now.toISOString()}] pty-host [${event}]: ${message}`}import{readFileSync}from"fs";import{mkdir,unlink}from"fs/promises";import{createServer}from"net";import{dirname}from"path";import{existsSync,lstatSync,mkdirSync,renameSync}from"fs";import{homedir}from"os";import{join}from"path";var PTY_HOST_DATA_ENTRIES=["pty-exits.json","pty-sessions"];function lstatIfExists(path){try{return lstatSync(path)}catch{return}}function migrateLegacyPtyHostData(homeDir=readRoveHomeDirEnv()??homedir()){let canonicalDir=join(homeDir,ROVE_STATE_DIR_BASENAME),legacyDir=preRenameStateDir(homeDir);if(canonicalDir===legacyDir)return[];let moved=[];for(let name of PTY_HOST_DATA_ENTRIES){let canonical=join(canonicalDir,name),legacy=join(legacyDir,name);try{if(existsSync(canonical))continue;let stat=lstatIfExists(legacy);if(!stat||stat.isSymbolicLink())continue;mkdirSync(canonicalDir,{recursive:!0}),renameSync(legacy,canonical),moved.push(name)}catch{}}return moved}import{randomUUID as randomUUID2}from"crypto";var TERMINAL_NAME="xterm-256color";function bunTerminalDriver(spawn){let spawnTerminal=spawn??((argv,options)=>Bun.spawn(argv,options));return(request)=>{let proc=spawnTerminal([...request.argv],{cwd:request.cwd,env:request.env,terminal:{cols:request.cols,rows:request.rows,name:TERMINAL_NAME,data:(_terminal,data)=>request.onData(data)}});return{pid:proc.pid,exited:proc.exited.then(()=>({code:proc.exitCode??null,signal:proc.signalCode??null}),()=>({code:null,signal:null})),write:(data)=>proc.terminal?.write(data),resize:(cols,rows)=>proc.terminal?.resize(cols,rows),close:()=>proc.terminal?.close(),kill:(signal)=>proc.kill(signal)}}}import{randomUUID}from"crypto";import{StringDecoder}from"string_decoder";function freshSessionState(key,spec,argv){return{key,generation:randomUUID(),cwd:spec.cwd,proc:null,alive:!0,chunks:[],bytes:0,totalBytes:0,cols:spec.cols??80,rows:spec.rows??24,command:argv,title:"",titleCarry:"",titleDecoder:new StringDecoder("utf8"),colorQueryCarry:"",defaultColors:parseTerminalDefaultColors(spec.defaultColors)??DEFAULT_TERMINAL_COLORS,modes:freshModeTrack(),ringModes:freshModeTrack(),sinks:new Map,emulatorSinks:new Set,parked:!1,parkedScreenBytes:0,exit:null,restored:!1,lastFreezeAtMs:0,frozenTotalBytes:0}}function sessionInfo(s){return{key:s.key,generation:s.generation,alive:s.alive,pid:s.proc?.pid??null,command:s.command,title:s.title,programStatusEvent:s.programStatusEvent,programStatus:s.oscSignals?.records.get(""),contexts:s.oscSignals?.contexts,totalBytes:s.totalBytes,parked:s.parked,parkedScreenBytes:s.parkedScreenBytes,exit:s.exit,restored:s.restored||void 0}}function describeExit(exit){if(exit?.signal)return` (signal ${exit.signal})`;if(exit&&exit.code!==null)return` (code ${exit.code})`;return" (cause unknown)"}function ringTail(chunks,bytes,maxBytes){let skip=Math.max(0,bytes-maxBytes),seen=0,parts=[];for(let chunk of chunks){if(seen+chunk.byteLength>skip)parts.push(seen>=skip?chunk:chunk.subarray(skip-seen));seen+=chunk.byteLength}return Buffer.concat(parts).toString("utf8")}function hostStats(sessions,perSessionCap,parkRestoreDeltas,parkRestoreFallbacks){let ringBytes=0,count=0,parkedSessions=0,parkedScreenBytes=0;for(let session of sessions)if(count++,ringBytes+=session.bytes,session.parked)parkedSessions++,parkedScreenBytes+=session.parkedScreenBytes;return{ringBytes,ringCapacityBytes:count*perSessionCap,parkedSessions,parkedScreenBytes,parkRestoreDeltas,parkRestoreFallbacks}}var OSC_TITLE_RE=/\x1b\][02];([^\x07\x1b]*)(?:\x07|\x1b\\)/g,TITLE_CARRY_CAP=1024;function titleCarryFrom(rest){let osc=rest.lastIndexOf("\x1B]");if(osc!==-1)return rest.slice(osc,osc+TITLE_CARRY_CAP);return rest.endsWith("\x1B")?"\x1B":""}function foldOscTitle(prevCarry,chunkText){let text=prevCarry+chunkText,title=null,end=0;OSC_TITLE_RE.lastIndex=0;for(let match=OSC_TITLE_RE.exec(text);match;match=OSC_TITLE_RE.exec(text))title=match[1]??"",end=match.index+match[0].length;return{title,carry:titleCarryFrom(text.slice(end))}}function scanOscTitle(session,buf){let{title,carry}=foldOscTitle(session.titleCarry,session.titleDecoder.write(buf));if(title!==null)session.title=title;session.titleCarry=carry}function peekRing(session,sinceOffset){if(!session)return{exists:!1,alive:!1,pid:null,offset:0,data:"",sinceValid:!1,exit:null};let windowStart=session.totalBytes-session.bytes,buf=Buffer.concat(session.chunks),sinceValid=!1;if(sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes)buf=buf.subarray(sinceOffset-windowStart),sinceValid=!0;return{exists:!0,alive:session.alive,pid:session.proc?.pid??null,offset:session.totalBytes,data:buf.toString("base64"),sinceValid,exit:session.exit??null}}async function settledWithin(exited,ms){let timer,settled=await Promise.race([exited.then(()=>!0,()=>!0),new Promise((resolve)=>{timer=setTimeout(()=>resolve(!1),ms)})]);if(timer)clearTimeout(timer);return settled}function signalProcessGroup(pid,signal,fallback,platform=process.platform,onSignal){if(platform!=="win32"&&pid>1)try{process.kill(-pid,signal),onSignal?.(`sent ${signal} to process group -${pid}`);return}catch{}try{fallback(),onSignal?.(`sent ${signal} to pid ${pid} (per-process fallback)`)}catch{}}var TERMINATION_GRACE_MS=500;async function terminatePtyChild(proc,onSettled,onSignal){if(proc.endTree){onSignal?.(await proc.endTree()),signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS),onSettled();return}if(signalProcessGroup(proc.pid,"SIGTERM",()=>proc.kill("SIGTERM"),process.platform,onSignal),!await settledWithin(proc.exited,TERMINATION_GRACE_MS))signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS);onSettled()}class PtyChildController{deps;constructor(deps){this.deps=deps}spawn(key,spec,spare=!1){let argv=spec.command&&spec.command.length>0?[...spec.command]:[spec.shell??resolveSessionShell()],session=freshSessionState(key,spec,argv);if(this.startChild(session),session.alive)this.deps.log?.("pty",`spawned ${argv[0]} for ${key} (pid ${session.proc?.pid})`),this.deps.onSessionStart?.(spare);return session}startChild(session){session.generation=randomUUID2(),session.oscSignals=void 0,session.programStatusEvent=void 0,this.reportStatus(session,null);try{session.proc=(this.deps.driver??bunTerminalDriver())({argv:[...session.command],cwd:session.cwd,env:embeddedTerminalEnv(process.env,{TERM:"xterm-256color",COLUMNS:String(session.cols),LINES:String(session.rows),BASH_SILENCE_DEPRECATION_WARNING:"1",ROVE_TERMINAL_PTY:"1",...process.env.SHELL?.trim()?{}:{SHELL:resolveSessionShell()}}),cols:session.cols,rows:session.rows,onData:(data)=>this.onData(session,data)}),session.alive=!0,session.proc.exited.then((exit)=>this.markExited(session,exit),()=>this.markExited(session))}catch(err){session.alive=!1,this.deps.log?.("pty",`spawn failed for ${session.key}: ${err instanceof Error?err.message:String(err)}`)}}async endChild(session){if(!session.alive)return;let proc=session.proc;if(!proc){this.markExited(session);return}await terminatePtyChild(proc,()=>this.markExited(session),(line)=>this.deps.log?.("pty-signal",`${session.key}: ${line}`))}markExited(session,exit){if(!session.alive)return;if(session.alive=!1,session.oscSignals){let before=session.oscSignals.records.get("");if(clearTransientStatuses(session.oscSignals),before!==session.oscSignals.records.get(""))this.reportStatus(session,null)}let sessionExit={code:exit?.code??null,signal:exit?.signal??null,at:new Date().toISOString()};session.exit=sessionExit;try{session.proc?.close()}catch{}this.deps.onExit?.(session,sessionExit)}reportStatus(session,status){let event={key:session.key,generation:session.generation,revision:(session.programStatusEvent?.revision??0)+1,at:Date.now(),status};session.programStatusEvent=event,this.deps.onProgramStatus?.(event)}onData(session,data){let buf=typeof data==="string"?Buffer.from(data,"utf8"):Buffer.from(data),text=buf.toString("latin1");session.oscSignals??=createOscSignals();let queries=scanOscSignals(session.oscSignals,buf,Date.now(),(status)=>this.reportStatus(session,status)),colorQueries=foldDefaultColorQueries(session.colorQueryCarry,text);session.colorQueryCarry=colorQueries.carry;let replies=colorQueries.slots.map((slot)=>formatDefaultColorReply(slot,session.defaultColors));for(let i=0;i<Math.min(queries,16);i++)replies.push("\x1B]7501;?\x1B\\");let modeReplies=scanTerminalModes(session.modes,text);if(session.emulatorSinks.size===0)replies.push(...modeReplies);if(replies.length>0)try{session.proc?.write(replies.join(""))}catch{}scanOscTitle(session,buf),session.chunks.push(buf),session.bytes+=buf.byteLength,session.totalBytes+=buf.byteLength;while(session.bytes>this.deps.scrollbackCap&&session.chunks.length>1){let dropped=session.chunks.shift();if(!dropped)break;session.bytes-=dropped.byteLength,scanTerminalModes(session.ringModes,dropped.toString("latin1"))}this.deps.onOutput?.(session,buf)}}function shouldFreeze(session,now){let appended=session.totalBytes-(session.frozenTotalBytes??0);if(appended<=0)return!1;let since=now-session.lastFreezeAtMs;if(since<5000)return!1;return appended>=65536||since>=60000}class WarmSpare{deps;spare=null;constructor(deps){this.deps=deps}warm(cwd,shell,cols=80,rows=24){let argv0=shell??resolveSessionShell();if(this.spare?.alive&&this.spare.cwd===cwd&&this.spare.command[0]===argv0)return;let old=this.spare;if(this.spare=null,old)this.deps.endChild(old);let session=this.deps.spawn("::spare",{cwd,command:[argv0],cols,rows},!0);this.spare=session.alive?session:null}adopt(key,spec){let spare=this.spare;if(!spare?.alive||spare.cwd!==spec.cwd)return null;let want=spec.command&&spec.command.length>0?spec.command:[spec.shell??resolveSessionShell()];if(want.length!==1||want[0]!==spare.command[0])return null;this.spare=null,spare.key=key,spare.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??spare.defaultColors;let cols=spec.cols??spare.cols,rows=spec.rows??spare.rows;if(spare.cols!==cols||spare.rows!==rows){spare.cols=cols,spare.rows=rows;try{spare.proc?.resize(cols,rows)}catch{return this.deps.markExited(spare),null}}return this.deps.log?.("pty",`adopted warm shell for ${key} (pid ${spare.proc?.pid})`),this.deps.onSessionStart?.(),this.warm(spec.cwd,spare.command[0],cols,rows),spare}async end(){let spare=this.spare;if(this.spare=null,spare)await this.deps.endChild(spare)}}var LOGGED_WRITE_BYTES=1024,DEFAULT_SCROLLBACK_CAP=524288,EXIT_TAIL_BYTES=16384;class PtyHost{sessions=new Map;opts;scrollbackCap;parkRestoreDeltas=0;parkRestoreFallbacks=0;childController;warmSpare;constructor(opts={}){this.opts=opts,this.scrollbackCap=opts.scrollbackCap??DEFAULT_SCROLLBACK_CAP,this.childController=new PtyChildController({driver:opts.driver,onProgramStatus:(event)=>this.opts.onProgramStatus?.(event),scrollbackCap:this.scrollbackCap,onSessionStart:(spare)=>{if(!spare)this.opts.onSessionStart?.()},onOutput:(session,data)=>{if(session.sinks.size===0){this.maybeFreeze(session);return}let frame={type:"event",name:"pty.data",payload:{key:session.key,data:data.toString("base64"),offset:session.totalBytes}};for(let sink of session.sinks.values())sink(frame);this.maybeFreeze(session)},onExit:(session,exit)=>{let frame={type:"event",name:"pty.exit",payload:{key:session.key,pid:session.proc?.pid??null,...exit}};for(let sink of session.sinks.values())sink(frame);if(this.opts.log?.("pty",`session ${session.key} exited${describeExit(exit)}`),this.maybeFreeze(session,!0),!session.closedByRequest)try{this.opts.onSessionExit?.({key:session.key,pid:session.proc?.pid??null,exit,tail:ringTail(session.chunks,session.bytes,EXIT_TAIL_BYTES)})}catch{}this.opts.onSessionEnd?.()},log:(event,message)=>this.opts.log?.(event,message)}),this.warmSpare=new WarmSpare({spawn:(key,spec,spare)=>this.childController.spawn(key,spec,spare),endChild:(session)=>this.childController.endChild(session),markExited:(session)=>this.childController.markExited(session),log:(event,message)=>this.opts.log?.(event,message),onSessionStart:()=>this.opts.onSessionStart?.()})}open(key,spec,token,sink,sinceOffset,sincePid,answersQueries=!1){let session=this.sessions.get(key),created=!1,respawned=!1;if(!session)created=!0,session=this.warmSpare.adopt(key,spec)??this.childController.spawn(key,spec),this.sessions.set(key,session);else if(!session.alive&&session.restored)this.respawn(session,spec),respawned=session.alive;else if(session.alive&&spec.cols!==void 0&&spec.rows!==void 0&&(session.cols!==spec.cols||session.rows!==spec.rows))this.resize(key,spec.cols,spec.rows);let defaultColors=parseTerminalDefaultColors(spec.defaultColors);if(defaultColors)session.defaultColors=defaultColors;if(session.sinks.set(token,sink),answersQueries)session.emulatorSinks.add(token);else session.emulatorSinks.delete(token);session.parked=!1,session.parkedScreenBytes=0;let windowStart=session.totalBytes-session.bytes,replay=Buffer.concat(session.chunks),sinceValid=!1;if(!created&&sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes&&sincePid!==void 0&&sincePid===session.proc?.pid)replay=replay.subarray(sinceOffset-windowStart),sinceValid=!0;if(sinceOffset!==void 0&&sincePid!==void 0)if(sinceValid)this.parkRestoreDeltas++;else this.parkRestoreFallbacks++;if(!sinceValid)replay=Buffer.concat([Buffer.from(terminalModePreamble(session.ringModes.modes),"latin1"),replay]);return{replay:replay.toString("base64"),alive:session.alive,pid:session.proc?.pid??null,created,respawned,offset:session.totalBytes,sinceValid}}warm(cwd,shell,cols=80,rows=24){this.warmSpare.warm(cwd,shell,cols,rows)}write(key,data){let session=this.sessions.get(key);if(!session?.alive||data.length===0)return;if(data.length>=LOGGED_WRITE_BYTES)this.opts.log?.("pty",`wrote ${data.length} bytes to ${key}`);try{session.proc?.write(data)}catch(error){this.opts.log?.("pty",`write failed on ${key} (${data.length} bytes): ${String(error)}`)}}resize(key,cols,rows){let session=this.sessions.get(key);if(!session?.alive)return;session.cols=cols,session.rows=rows;try{session.proc?.resize(cols,rows)}catch{}}killIfGeneration(key,expectedGeneration){let session=this.sessions.get(key);if(!session)return{accepted:!1,reason:"missing-session"};if(session.generation!==expectedGeneration)return{accepted:!1,reason:"generation-mismatch"};return this.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}kill(key){let session=this.sessions.get(key);if(!session)return Promise.resolve();return this.sessions.delete(key),session.closedByRequest=!0,this.opts.freeze?.drop(key),this.childController.endChild(session)}rename(from,to){let session=this.sessions.get(from);if(!session||from===to||this.sessions.has(to))return!1;if(this.sessions.delete(from),session.key=to,session.programStatusEvent){let previous=session.programStatusEvent;this.opts.onProgramStatus?.({...previous,revision:previous.revision+1,at:Date.now(),status:null}),session.programStatusEvent={...previous,key:to,revision:previous.revision+1,at:Date.now()},this.opts.onProgramStatus?.(session.programStatusEvent)}return this.sessions.set(to,session),this.opts.freeze?.drop(from),this.maybeFreeze(session,!0),this.opts.log?.("pty",`renamed session ${from} \u2192 ${to}`),!0}detach(key,token,parked=!1,parkedScreenBytes=0){let session=this.sessions.get(key);if(!session)return;session.sinks.delete(token),session.emulatorSinks.delete(token),this.applyParkedOnDetach(session,parked,parkedScreenBytes)}detachClient(token){for(let session of this.sessions.values()){if(session.emulatorSinks.delete(token),!session.sinks.delete(token))continue;this.applyParkedOnDetach(session)}}applyParkedOnDetach(session,parked=!1,parkedScreenBytes=0){if(session.sinks.size!==0)return;session.parked=parked,session.parkedScreenBytes=parked?Math.max(0,parkedScreenBytes):0}list(){return Array.from(this.sessions.values(),(s)=>sessionInfo(s))}peek(key,sinceOffset,preamble=!1){let session=this.sessions.get(key),peek=peekRing(session,sinceOffset);if(!preamble||!session||sinceOffset!==void 0)return peek;let modes=Buffer.from(terminalModePreamble(session.ringModes.modes),"latin1");return{...peek,data:Buffer.concat([modes,Buffer.from(peek.data,"base64")]).toString("base64")}}stats(){return hostStats(this.sessions.values(),this.scrollbackCap,this.parkRestoreDeltas,this.parkRestoreFallbacks)}async killAll(){let sessions=Array.from(this.sessions.keys(),(key)=>this.kill(key));sessions.push(this.warmSpare.end()),await Promise.all(sessions)}async shutdown(){this.flushFrozen();let endings=Array.from(this.sessions.values(),(session)=>this.childController.endChild(session));endings.push(this.warmSpare.end()),await Promise.all(endings)}flushFrozen(){for(let session of this.sessions.values())this.maybeFreeze(session,!0)}restoreFrozen(records){let restoredCount=0;for(let record of records){if(this.sessions.has(record.key))continue;let session=thawSession(record,this.scrollbackCap);if(!session)continue;this.sessions.set(record.key,session),restoredCount++}if(restoredCount>0)this.opts.log?.("pty",`restored ${restoredCount} frozen session(s) from disk`);return restoredCount}respawn(session,spec){if(session.restored=!1,session.exit=null,spec.command&&spec.command.length>0)session.command=[...spec.command];if(session.cols=spec.cols??session.cols,session.rows=spec.rows??session.rows,session.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??session.defaultColors,this.childController.startChild(session),!session.alive)return;this.opts.log?.("pty",`respawned restored session ${session.key} (pid ${session.proc?.pid})`),this.opts.onSessionStart?.()}maybeFreeze(session,force=!1){let freeze=this.opts.freeze;if(!freeze||session.key.startsWith("::"))return;if(session.closedByRequest)return;let now=Date.now();if(!force&&!shouldFreeze(session,now))return;session.lastFreezeAtMs=now,session.frozenTotalBytes=session.totalBytes,freeze.save(freezeSession(session))}liveCount(){let n=0;for(let session of this.sessions.values())if(session.alive)n++;return n}}function dispatchPtyRequest(req,client,deps){let{ptys}=deps;switch(req.name){case"hello":return{protocolVersion:DAEMON_PROTOCOL_VERSION,ptyHost:!0,pid:process.pid};case"pty.openChecked":case"pty.open":{let payload=objectPayload(req.payload);if(req.name==="pty.openChecked"&&requireString(payload,"admissionToken")!==admissionToken(ptys))return{kind:"changed"};let open=ptys.open(requireString(payload,"key"),{cwd:requireString(payload,"cwd"),command:Array.isArray(payload.command)?payload.command.filter((c)=>typeof c==="string"):void 0,shell:typeof payload.shell==="string"?payload.shell:void 0,cols:typeof payload.cols==="number"?payload.cols:void 0,rows:typeof payload.rows==="number"?payload.rows:void 0,defaultColors:parseTerminalDefaultColors(payload.defaultColors)??void 0},client,(frame)=>deps.writeFrame(client,frame),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0,typeof payload.sincePid==="number"?payload.sincePid:void 0,payload.answersQueries===!0);return req.name==="pty.openChecked"?{kind:"opened",open}:open}case"pty.write":{let payload=objectPayload(req.payload);return ptys.write(requireString(payload,"key"),typeof payload.data==="string"?payload.data:""),{}}case"pty.resize":{let payload=objectPayload(req.payload);return ptys.resize(requireString(payload,"key"),typeof payload.cols==="number"?payload.cols:80,typeof payload.rows==="number"?payload.rows:24),{}}case"pty.kill":{let payload=objectPayload(req.payload),key=requireString(payload,"key");if("expectedGeneration"in payload)return ptys.killIfGeneration(key,requireString(payload,"expectedGeneration"));if(optionalBoolean(payload,"wait")===!0)return ptys.kill(key).then(()=>({accepted:!0,ended:!0}),(err)=>{return logDaemonError("pty-kill",err),{accepted:!0,ended:!1}});return ptys.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}case"pty.rename":{let payload=objectPayload(req.payload);return{renamed:ptys.rename(requireString(payload,"from"),requireString(payload,"to"))}}case"pty.detach":{let payload=objectPayload(req.payload);ptys.detach(requireString(payload,"key"),client,payload.parked===!0,typeof payload.parkedScreenBytes==="number"?payload.parkedScreenBytes:0)}return{};case"pty.watchStatus":client.watchProgramStatus=!0;for(let session of ptys.list())if(session.programStatusEvent)deps.writeFrame(client,{type:"event",name:"pty.programStatus",payload:session.programStatusEvent});return{supported:!0};case"pty.list":return{pid:process.pid,rssBytes:process.memoryUsage().rss,sessions:ptys.list(),admissionToken:admissionToken(ptys),stats:ptys.stats(),...deps.version?{version:deps.version}:{}};case"pty.peek":{let payload=objectPayload(req.payload);return ptys.peek(requireString(payload,"key"),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0,payload.preamble===!0)}case"pty.warm":{let payload=objectPayload(req.payload);return ptys.warm(requireString(payload,"cwd"),typeof payload.shell==="string"?payload.shell:void 0,typeof payload.cols==="number"?payload.cols:void 0,typeof payload.rows==="number"?payload.rows:void 0),{}}case"spawn.detached":{if(process.platform!=="win32")throw Error("spawn.detached is Windows-only");let payload=objectPayload(req.payload),env=objectPayload(payload.env);return spawnDetachedDaemon(requireString(payload,"command"),Array.isArray(payload.args)?payload.args.filter((a)=>typeof a==="string"):[],withoutPtyJob(Object.fromEntries(Object.entries(env).filter((e)=>typeof e[1]==="string"))),requireString(payload,"logPath")),{}}case"daemon.stop":{let live=ptys.liveCount();if(live>0&&optionalBoolean(objectPayload(req.payload),"force")!==!0)throw Object.assign(Error(`pty host holds ${live} live session(s); daemon.stop needs force to end them`),{name:PTY_STOP_REFUSED});return deps.requestStop(),{}}default:throw Error(`unknown pty-host request: ${req.name}`)}}function admissionToken(ptys){return JSON.stringify(ptys.list().map((s)=>[s.key,s.generation,s.pid,s.alive]))}var DEFAULT_IDLE_EXIT_MS=60000,DEFAULT_ORPHAN_CHECK_MS=30000;function resolveMaxLifetimeMs(){let raw=process.env.ROVE_PTY_MAX_LIFETIME_MS;if(raw===void 0)return null;let n=Number(raw);return Number.isFinite(n)&&n>0?n:null}function resolveIdleExitMs(){let raw=process.env.ROVE_PTY_IDLE_EXIT_MS;if(raw===void 0)return DEFAULT_IDLE_EXIT_MS;let n=Number(raw);return Number.isFinite(n)&&n>=0?n:DEFAULT_IDLE_EXIT_MS}async function startPtyHostServer(options={}){migrateLegacyPtyHostData();let socketPath=options.socketPath??defaultPtyHostSocketPath(),pidPath=options.pidPath??defaultPtyHostPidPath(),freezeDir=options.freezeDir??defaultPtyFreezeDir(),idleExitMs=options.idleExitMs||resolveIdleExitMs(),orphanCheckMs=options.orphanCheckMs||DEFAULT_ORPHAN_CHECK_MS,maxLifetimeMs=options.maxLifetimeMs??resolveMaxLifetimeMs(),bootedAtMs=Date.now(),log=options.log??(()=>{}),clients=new Set,stopping=!1,idleTimer=null,cancelIdle=()=>{if(idleTimer)clearTimeout(idleTimer);idleTimer=null},armIdle=()=>{if(stopping)return;cancelIdle(),idleTimer=setTimeout(()=>{if(stopping||ptys.liveCount()>0)return;log("idle",`no live sessions for ${idleExitMs}ms \u2014 exiting`),stop()},idleExitMs)},orphaned=()=>{if(maxLifetimeMs!==null&&Date.now()-bootedAtMs>=maxLifetimeMs)return`exceeded its ${maxLifetimeMs}ms lifetime ceiling`;let owner;try{owner=readFileSync(pidPath,"utf8").trim()}catch{return`pidfile ${pidPath} is gone`}let pid=Number.parseInt(owner,10);if(pid===process.pid)return null;return Number.isInteger(pid)?`pidfile ${pidPath} now names pid ${pid}`:`pidfile ${pidPath} is unreadable`},orphanTimer=setInterval(()=>{if(stopping)return;let reason=orphaned();if(!reason)return;log("orphan",`${reason} \u2014 exiting rather than outliving my owner`),stop()},orphanCheckMs);orphanTimer.unref?.();let ptys=new PtyHost({onProgramStatus:(event)=>{for(let client of clients)if(client.watchProgramStatus)writeFrame(client,{type:"event",name:"pty.programStatus",payload:event})},onSessionStart:cancelIdle,onSessionEnd:()=>{if(ptys.liveCount()===0)armIdle()},onSessionExit:(info)=>{try{recordPtyExit(info)}catch(err){log("pty",`exit record write failed for ${info.key}: ${err instanceof Error?err.message:String(err)}`)}},freeze:fileFreezeSink(freezeDir),driver:options.driver,log});ptys.restoreFrozen(loadFrozenSessions(freezeDir,Date.now(),(s)=>{let mib=(bytes)=>`${Math.round(bytes/1048576)}MB`,notes=[`restored ${s.restored} (${mib(s.bytesRead)})`];if(s.deferred>0)notes.push(`${s.deferred} left unread past the ${mib(FREEZE_RESTORE_MAX_BYTES)} budget`);if(s.expired>0)notes.push(`${s.expired} deleted past the ${FREEZE_TTL_MS/86400000}-day TTL`);if(s.unreadable>0)notes.push(`${s.unreadable} unreadable`);log("freeze",notes.join(", "))}));let pipeSocket=isWindowsPipePath(socketPath);if(await ensureOwnerOnlyStateDir(resolveDaemonHomeDir()),!pipeSocket)await mkdir(dirname(socketPath),{recursive:!0});await mkdir(dirname(pidPath),{recursive:!0});let server=createServer((socket)=>{let client={socket,writer:new ClientWriter(socket,{onOverflow:()=>{log("backpressure","disconnecting PTY client whose critical queue exceeded 8MiB"),socket.destroy()}})};clients.add(client);let receiver=new LineReceiver;socket.on("data",(chunk)=>{if(!receiver.push(chunk,(line)=>handleLine(client,line)))log("framing","disconnecting PTY client whose request exceeded 8MiB"),socket.destroy()}),socket.on("error",()=>{}),socket.on("close",()=>{clients.delete(client),ptys.detachClient(client)})}),api={socketPath,pidPath,async close(){if(stopping)return;stopping=!0,cancelIdle(),clearInterval(orphanTimer),await ptys.shutdown();for(let client of Array.from(clients))client.socket.destroy();if(await new Promise((resolve)=>server.close(()=>resolve())),!pipeSocket)await unlink(socketPath).catch(()=>{});await unlink(pidPath).catch(()=>{})}};async function stop(){await api.close().catch((err)=>logDaemonError("pty-host-shutdown",err)),options.onStop?.()}let verbDeps={ptys,writeFrame,requestStop:()=>{setTimeout(()=>void stop(),0).unref()},...options.version?{version:options.version}:{}};function handleLine(client,line){if(line.trim().length>0){let frame=null;try{frame=JSON.parse(line)}catch{writeFrame(client,{type:"response",id:"parse-error",error:{message:"malformed frame"}})}if(frame)if(frame.type!=="request")writeFrame(client,{type:"response",id:"parse-error",error:{message:"requests only"}});else{let req=frame,reply=(payload)=>writeFrame(client,{type:"response",id:req.id,name:req.name,payload}),fail=(err)=>writeFrame(client,{type:"response",id:req.id,name:req.name,error:{message:err instanceof Error?err.message:String(err),...err instanceof Error&&err.name!=="Error"?{name:err.name}:{}}});try{let payload=dispatchPtyRequest(req,client,verbDeps);if(payload instanceof Promise)payload.then(reply,fail);else reply(payload)}catch(err){fail(err)}}}}if(await listenOnUnixSocket(server,socketPath),await writeTextAtomic(pidPath,`${process.pid}
3
- `),!pipeSocket)await writeTextAtomic(endpointPathFor(pidPath),`${socketPath}
4
- `);return armIdle(),log("boot",`pty host listening on ${socketPath}`),api}function writeFrame(client,frame){client.writer.write(frameToLine(frame))}async function runPtyHostSubcommand(_argv){rotateLogIfNeeded(defaultPtyHostLogPath()),installDaemonCrashHandlers();let server=await startPtyHostServer({log:(event,message)=>console.log(formatPtyHostLine(event,message)),version:CURRENT_VERSION,onStop:()=>process.exit(0)});console.log(formatPtyHostLine("listen",`v${CURRENT_VERSION} listening on ${server.socketPath}`));let shutdown=async(signal)=>{console.log(formatPtyHostLine("signal",`${signal} received \u2014 closing host, frozen sessions kept`)),await server.close(),process.exit(0)};process.once("SIGINT",()=>void shutdown("SIGINT")),process.once("SIGTERM",()=>void shutdown("SIGTERM"))}export{runPtyHostSubcommand};