@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
@@ -0,0 +1,6 @@
1
+ // @bun
2
+ import{dedupeMachines,discoverMachine,ensureForwards,learnedFrom,listMachines,localDaemonSocketPath,localPtySocketPath,updateMachine}from"./chunk-vz0f8e8q.js";import{DISPATCH_PROMPT_HEAD_CHARS,resolvePtyOwner}from"./chunk-ns35rdyk.js";import{taskEngineArgv}from"./chunk-pdq3ya2e.js";import{roveApiInvocation}from"./chunk-1n03wzx4.js";import{ApiError}from"./chunk-r5j8fycq.js";import{ptyScopeFor}from"./chunk-g9ba25q5.js";import{getSavedRepos,isRemoteRepoKey}from"./chunk-rfp0ayra.js";import{connectIfRunning}from"./chunk-d0hpes59.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{loadStateFile,updateStateFile}from"./chunk-32j6y5d1.js";import{RoveDaemonClient,normalizeRemoteUrl}from"./chunk-n6marmjn.js";import{ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{__require}from"./chunk-91sykzqq.js";import{hostname}from"os";async function ptyScopeOf(daemon,task){let listed=await daemon.request("task.list",{}).catch(()=>({tasks:[]})),scope=ptyScopeFor(listed.tasks,task.id);return task.ptyAlias?{...scope,alias:task.ptyAlias}:scope}async function recordSend(daemon,sent){let self=await ownSession(daemon).catch(()=>null);await daemon.request("dispatch.record",{taskId:sent.taskId,...sent.tabId?{tabId:sent.tabId}:{},promptHead:sent.prompt.slice(0,DISPATCH_PROMPT_HEAD_CHARS),delivered:sent.delivered,...sent.deliveryId?{deliveryId:sent.deliveryId}:{},...self?{fromTaskId:self.taskId,fromTabId:self.tabId}:{}}).catch(()=>{})}var selfSessionOnce,identityWarning=null;async function realProbe(){let[{openPtyHost,listSessions},{psSnapshot}]=await Promise.all([import("./chunk-hmjg1qh3.js"),import("./chunk-k1pwp155.js")]);return{sessions:async()=>{let host=await openPtyHost();if(!host)return[];try{return await listSessions(host.rpc)}finally{host.close()}},ps:psSnapshot,pid:process.pid}}async function verifiedSelfSession(env=process.env,probe){if(!probe&&selfSessionOnce)return selfSessionOnce;let run=resolveSelfSession(env,probe);return selfSessionOnce=run,run}async function resolveSelfSession(env,probe){let taskId=env.ROVE_TASK_ID;if(!taskId)return null;let tabId=env.ROVE_TAB_ID||"tab-1";try{let p=probe??await realProbe(),key=`${taskId}::${tabId}`,session=(await p.sessions()).find((s)=>s.key===key&&s.alive);if(session?.pid){let{hasAncestor,parsePsSnapshot}=await import("./chunk-k1pwp155.js");if(hasAncestor(parsePsSnapshot(await p.ps([session.pid,p.pid])),p.pid,session.pid))return identityWarning=null,{taskId,tabId}}}catch{}return identityWarning=`$ROVE_TASK_ID/$ROVE_TASK_ID names task ${taskId} ${tabId}, but this process is not running inside that tab (an inherited env, not an identity) \u2014 dispatcher/peer provenance omitted`,null}function takeIdentityWarning(){let warning=identityWarning;return identityWarning=null,warning}async function ownSession(daemon,env=process.env,probe){let self=await verifiedSelfSession(env,probe);if(!self)return null;let listed=await daemon.request("task.list",{}).catch(()=>({tasks:[]}));return{...self,taskId:resolvePtyOwner(listed.tasks,self.taskId,self.tabId)}}async function dispatcherEnvPayload(daemon,env=process.env,probe){let self=await ownSession(daemon,env,probe);if(!self)return{};return{dispatcherTaskId:self.taskId,dispatcherTabId:self.tabId}}async function readOwnDispatcher(daemon){let self=await ownSession(daemon);if(!self)return null;try{return(await daemon.request("task.get",{taskId:self.taskId})).task.dispatcher??null}catch{return null}}async function resolveDispatcherTab(runtime,daemon,dispatcher){let task=await daemon.request("task.get",{taskId:dispatcher.taskId}).then((res)=>res.task).catch(()=>null),{tabs,running}=await runtime.taskTabs(dispatcher.taskId,void 0,task?await ptyScopeOf(daemon,task):void 0);if(tabs.some((t)=>t.id===dispatcher.tabId&&t.alive))return dispatcher.tabId;if(running)return;throw new ApiError(`dispatcher tab ${dispatcher.tabId} on task ${dispatcher.taskId} is dead and the task has no live engine tab \u2014 the reply has nowhere to land`,"DISPATCHER_UNREACHABLE",{dispatcher,hint:`address an alive target explicitly with --task-id/--tab (see \`${ROVE_PRODUCT_NAME} api pty-list\`), or notify the user with \`${ROVE_PRODUCT_NAME} api notify\``,nextCommandArgs:["api","pty-list"]})}async function replyTabOf(runtime,daemon,taskId){let self=await ownSession(daemon);if(self?.taskId===taskId)return self.tabId;let task=await daemon.request("task.get",{taskId}).then((res)=>res.task).catch(()=>null);if(!task)return;let{tabs}=await runtime.taskTabs(taskId,taskEngineArgv(task),await ptyScopeOf(daemon,task));return tabs.find((t)=>t.kind==="engine"&&t.alive===!0&&t.engineAlive!==!1)?.id}async function withPeerProvenance(daemon,targetTaskId,prompt){let self=await ownSession(daemon),senderId=self?.taskId;if(!self||!senderId||senderId===targetTaskId)return prompt;let label=senderId;try{let res=await daemon.request("task.get",{taskId:senderId});label=res.task.title||res.task.branch||senderId}catch{}let api=roveApiInvocation(),replyTarget=`--task-id ${senderId} --tab ${self.tabId}`;return`[ROVE PEER] from "${label}" (task ${senderId} \u2014 Rove agent skill /rove, read it once per session; reply only if it changes what I do next: \`${api} send ${replyTarget} --prompt "<text>"\`; verb reference: \`${api} schema\`)
3
+
4
+ ${prompt}`}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(`
5
+ `).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}let envelope=await client.request("api.invoke",{verb,params:repo.params,forwarded:!0,from:hostname()});return await recordHere(verb,params,envelope),envelope}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 recordHere(verb,params,envelope){if(verb!=="send"&&verb!=="dispatch"||!envelope.ok||typeof params.prompt!=="string")return;let sent=envelope.result,taskId=typeof sent.childTaskId==="string"?sent.childTaskId:sent.taskId;if(typeof taskId!=="string")return;let tabId=typeof sent.tabId==="string"?sent.tabId:typeof sent.session==="string"?sent.session.split("::")[1]:void 0,local=await connectIfRunning().catch(()=>null);if(!local)return;try{await recordSend(local,{taskId,...tabId?{tabId}:{},prompt:params.prompt,delivered:sent.delivered===!0})}finally{local.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)}
6
+ export{ptyScopeOf,recordSend,verifiedSelfSession,takeIdentityWarning,ownSession,dispatcherEnvPayload,readOwnDispatcher,resolveDispatcherTab,replyTabOf,withPeerProvenance,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,3 +1,3 @@
1
1
  // @bun
2
- import{parsePorcelainRows}from"./chunk-dmzg9zdc.js";import{readOnlyGitProcessEnv}from"./chunk-6xppe9bj.js";import{recordSpawn}from"./chunk-40dgv828.js";import{spawnSync}from"child_process";var ZERO={added:0,deleted:0};function sameWorktreeChanges(a,b){if(a===null||b===null)return a===b;return a.added===b.added&&a.deleted===b.deleted&&a.behind===b.behind&&a.ahead===b.ahead}function pickPushedChanges(pushed,worktreePath){if(!pushed)return null;if(pushed.has(worktreePath))return pushed.get(worktreePath)??"unknown";return ZERO}function readWorktreeChanges(worktreePath){if(!worktreePath)return null;try{recordSpawn("sidebar.worktreeChangesSync",["git","status","--porcelain=v1"],worktreePath);let out=spawnSync("git",["status","--porcelain=v1"],{cwd:worktreePath,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:readOnlyGitProcessEnv()});if(out.status!==0||out.stdout===void 0||out.stdout===null)return null;return parsePorcelain(out.stdout)}catch{return null}}function parsePorcelain(text){let added=0,deleted=0;for(let{x,y}of parsePorcelainRows(text))if(x==="D"||y==="D")deleted+=1;else added+=1;return{added,deleted}}
2
+ import{parsePorcelainRows}from"./chunk-dmzg9zdc.js";import{recordSpawn}from"./chunk-40dgv828.js";import{readOnlyGitProcessEnv}from"./chunk-6xppe9bj.js";import{spawnSync}from"child_process";var ZERO={added:0,deleted:0};function sameWorktreeChanges(a,b){if(a===null||b===null)return a===b;return a.added===b.added&&a.deleted===b.deleted&&a.behind===b.behind&&a.ahead===b.ahead}function pickPushedChanges(pushed,worktreePath){if(!pushed)return null;if(pushed.has(worktreePath))return pushed.get(worktreePath)??"unknown";return ZERO}function readWorktreeChanges(worktreePath){if(!worktreePath)return null;try{recordSpawn("sidebar.worktreeChangesSync",["git","status","--porcelain=v1"],worktreePath);let out=spawnSync("git",["status","--porcelain=v1"],{cwd:worktreePath,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:readOnlyGitProcessEnv()});if(out.status!==0||out.stdout===void 0||out.stdout===null)return null;return parsePorcelain(out.stdout)}catch{return null}}function parsePorcelain(text){let added=0,deleted=0;for(let{x,y}of parsePorcelainRows(text))if(x==="D"||y==="D")deleted+=1;else added+=1;return{added,deleted}}
3
3
  export{sameWorktreeChanges,pickPushedChanges,readWorktreeChanges,parsePorcelain};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{formatBytes}from"./chunk-my20q579.js";import{hookConfigIssues}from"./chunk-jd7p0y5x.js";import{applyFixes,daemonRestartFix,defaultFixRuntime,engineTabsManualFix,humanOnlyFix,killOrphansManualFix,noEngineFix,reinstallManualFix,resetManualFix,skillInstallFix,spawnHelperFix}from"./chunk-8sggyn8y.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-gkdfct7t.js";import"./chunk-cyzp2btw.js";import"./chunk-a4hsqj1b.js";import"./chunk-d9e4ssy7.js";import"./chunk-1exwrmjd.js";import"./chunk-k67vbszb.js";import"./chunk-cpgnm1xr.js";import"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{describeAccount,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-xkmdxcjg.js";import"./chunk-7z463zkx.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import"./chunk-1rjq808h.js";import"./chunk-gq36nzg8.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-rzef6szc.js";import{resolveNodeBinary}from"./chunk-sz2xs0a2.js";import"./chunk-fvvb0072.js";import{formatDaemonInfo}from"./chunk-rxqdw6s5.js";import"./chunk-tn9gtf18.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-qvnr8c18.js";import"./chunk-edrxs4cy.js";import"./chunk-03rbg95q.js";import"./chunk-w7zv47mp.js";import"./chunk-2tfnscxk.js";import"./chunk-2w228s7t.js";import"./chunk-etfh8f4z.js";import"./chunk-dmzg9zdc.js";import"./chunk-kg9kmwt9.js";import"./chunk-zsfyj36g.js";import{isStaleInstallError,resolveRoveSpawn}from"./chunk-387ecqb8.js";import"./chunk-kgs56yns.js";import"./chunk-4hnz77xf.js";import"./chunk-2brn8e1y.js";import"./chunk-6h4qdckd.js";import"./chunk-e01321zn.js";import"./chunk-7kysxgbq.js";import{readableLegacyIndexPath}from"./chunk-b68dd36h.js";import"./chunk-ec7f3wcm.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import{CURRENT_VERSION,package_default}from"./chunk-w9cdc97q.js";import{roveSkillState,skillInstallCommand}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{homeDir,kvStatePath,roveStateDir}from"./chunk-z1nj22va.js";import{readPidFile}from"./chunk-br8r72bf.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import{t}from"./chunk-bj6sa371.js";import"./chunk-1ffqacz9.js";import"./chunk-cmp64q4j.js";import{RoveDaemonClient,isForeignDaemonHome}from"./chunk-sza3tyhs.js";import"./chunk-96kvwzj8.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-eqdbfgq5.js";import{preRenameStateDir}from"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync,readFileSync as readFileSync2,statSync as statSync2}from"fs";import{join as join2}from"path";var MIN_BUN_VERSION=package_default.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0";function parseBunVersion(raw){return raw.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function isBunAtLeast(raw,minimum=MIN_BUN_VERSION){let found=parseBunVersion(raw),floor=parseBunVersion(minimum);if(!found||!floor)return!0;let a=found.split(".").map(Number),b=floor.split(".").map(Number);for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(av!==bv)return av>bv}return!0}function classifyHookChannel(input){let total=0,hooked=0;for(let tabs of Object.values(input.tabs))for(let entry of Object.values(tabs))if(total++,entry.source==="hook")hooked++;if(total===0)return{kind:"no-tabs"};if(hooked===0)return{kind:"down",totalTabs:total};return{kind:"live",hookTabs:hooked,totalTabs:total}}function hookChannelDoctorLines(verdict,input,cliName){let configLines=(input.configIssues??[]).flatMap((issue)=>[` \u26A0 hook install skipped: ${issue.file}`,` ${issue.reason} \u2014 fix the file, then relaunch Rove`]);if(verdict.kind==="no-tabs")return["hooks: \u2014 no engine tabs yet (nothing to check)",...configLines];if(verdict.kind==="live")return[`hooks: \u2713 engine hook channel live (${verdict.hookTabs}/${verdict.totalTabs} tab(s) hook-sourced)`,...configLines];let out=[`hooks: \u2717 NO hook events reaching the daemon (0/${verdict.totalTabs} tab(s) hook-sourced)`," badges fall back to a ~10s poll, so activity looks seconds late",` daemon socket: ${input.socketPath}`,...configLines];return out.push(' \u2192 compare with an engine tab\'s own path: `ps eww -p <engine-pid> | tr " " "\\n" | grep DAEMON_SOCKET_PATH`',` \u2192 restart the engine tabs (they may hold a stale socket path), or run \`${cliName} daemon restart\``,` \u2192 debug one hook directly: \`ROVE_HOOK_DEBUG=1 echo '{}' | ${cliName} hook turn-start --engine claude\``),out}import{readdirSync,statSync}from"fs";import{createRequire}from"module";import{dirname,join}from"path";function installedSpawnHelpers(){let pkg;try{pkg=dirname(createRequire(import.meta.url).resolve("node-pty/package.json"))}catch{return[]}let prebuilds=join(pkg,"prebuilds"),arches;try{arches=readdirSync(prebuilds).filter((name)=>name.startsWith("darwin-"))}catch{return[]}let helpers=[];for(let arch of arches){let path=join(prebuilds,arch,"spawn-helper");try{helpers.push({path,executable:(statSync(path).mode&64)!==0})}catch{}}return helpers}function spawnHelperDoctorLines(helpers){let broken=helpers.filter((helper)=>!helper.executable).map((helper)=>helper.path);if(helpers.length===0)return{lines:["node-pty: ? no darwin spawn-helper found next to node-pty"],broken};if(broken.length===0)return{lines:[`node-pty: \u2713 spawn-helper executable (${helpers.length} arch)`],broken};return{lines:["node-pty: \u2717 spawn-helper is not executable \u2014 every node-pty PTY spawn fails",...broken.map((path)=>` ${path}`),` \u2192 chmod 755 ${broken.join(" ")}`],broken}}import{appendFileSync,readFileSync}from"fs";var PTY_MARKER="ROVE_TERMINAL_PTY=1",run=async(argv)=>{try{let proc=Bun.spawn([...argv],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),[stdout,code]=await Promise.all([new Response(proc.stdout).text().catch(()=>""),proc.exited]);return{code,stdout}}catch{return{code:127,stdout:""}}};function parsePsRows(output){let rows=[];for(let line of output.split(`
2
+ import{formatBytes}from"./chunk-my20q579.js";import{hookConfigIssues}from"./chunk-j9b285x6.js";import{applyFixes,daemonRestartFix,defaultFixRuntime,engineTabsManualFix,humanOnlyFix,killOrphansManualFix,noEngineFix,reinstallManualFix,resetManualFix,skillInstallFix,spawnHelperFix}from"./chunk-c6fy8xew.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-gkdfct7t.js";import"./chunk-vp171as9.js";import"./chunk-a4hsqj1b.js";import"./chunk-d9e4ssy7.js";import"./chunk-883fyezq.js";import{skillOverview}from"./chunk-pap7k3b4.js";import"./chunk-tq0h3vy6.js";import"./chunk-cpgnm1xr.js";import"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{describeAccount,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-fn7ffyam.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-ns35rdyk.js";import"./chunk-gq36nzg8.js";import{resolveNodeBinary}from"./chunk-cfzg8q3e.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import{formatDaemonInfo}from"./chunk-rxqdw6s5.js";import"./chunk-1n03wzx4.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-tn9gtf18.js";import"./chunk-3y9xzbqh.js";import"./chunk-d7f022eb.js";import"./chunk-h64rsbrx.js";import"./chunk-w7zv47mp.js";import"./chunk-2tfnscxk.js";import"./chunk-2w228s7t.js";import"./chunk-etfh8f4z.js";import"./chunk-rfp0ayra.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-kg9kmwt9.js";import{CURRENT_VERSION,package_default}from"./chunk-a4r45qdn.js";import"./chunk-zsfyj36g.js";import{isStaleInstallError,resolveRoveSpawn}from"./chunk-d0hpes59.js";import"./chunk-mkfc9a09.js";import"./chunk-syn0tfwy.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import{t}from"./chunk-372g44dg.js";import"./chunk-1eef3z5v.js";import"./chunk-cmp64q4j.js";import{RoveDaemonClient,isForeignDaemonHome}from"./chunk-n6marmjn.js";import"./chunk-96kvwzj8.js";import"./chunk-2kqxz9a4.js";import"./chunk-e3t1zbv1.js";import"./chunk-7kysxgbq.js";import{readableLegacyIndexPath}from"./chunk-w7v4jzwy.js";import"./chunk-cbrt4s7m.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import{homeDir,kvStatePath,roveStateDir}from"./chunk-z1nj22va.js";import{readPidFile}from"./chunk-br8r72bf.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-eqdbfgq5.js";import{preRenameStateDir}from"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync,readFileSync as readFileSync2,statSync as statSync2}from"fs";import{join as join2}from"path";var MIN_BUN_VERSION=package_default.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0";function parseBunVersion(raw){return raw.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function isBunAtLeast(raw,minimum=MIN_BUN_VERSION){let found=parseBunVersion(raw),floor=parseBunVersion(minimum);if(!found||!floor)return!0;let a=found.split(".").map(Number),b=floor.split(".").map(Number);for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(av!==bv)return av>bv}return!0}function classifyHookChannel(input){let total=0,hooked=0;for(let tabs of Object.values(input.tabs))for(let entry of Object.values(tabs))if(total++,entry.source==="hook")hooked++;if(total===0)return{kind:"no-tabs"};if(hooked===0)return{kind:"down",totalTabs:total};return{kind:"live",hookTabs:hooked,totalTabs:total}}function hookChannelDoctorLines(verdict,input,cliName){let configLines=(input.configIssues??[]).flatMap((issue)=>[` \u26A0 hook install skipped: ${issue.file}`,` ${issue.reason} \u2014 fix the file, then relaunch Rove`]);if(verdict.kind==="no-tabs")return["hooks: \u2014 no engine tabs yet (nothing to check)",...configLines];if(verdict.kind==="live")return[`hooks: \u2713 engine hook channel live (${verdict.hookTabs}/${verdict.totalTabs} tab(s) hook-sourced)`,...configLines];let out=[`hooks: \u2717 NO hook events reaching the daemon (0/${verdict.totalTabs} tab(s) hook-sourced)`," badges fall back to a ~10s poll, so activity looks seconds late",` daemon socket: ${input.socketPath}`,...configLines];return out.push(' \u2192 compare with an engine tab\'s own path: `ps eww -p <engine-pid> | tr " " "\\n" | grep DAEMON_SOCKET_PATH`',` \u2192 restart the engine tabs (they may hold a stale socket path), or run \`${cliName} daemon restart\``,` \u2192 debug one hook directly: \`ROVE_HOOK_DEBUG=1 echo '{}' | ${cliName} hook turn-start --engine claude\``),out}import{readdirSync,statSync}from"fs";import{createRequire}from"module";import{dirname,join}from"path";function installedSpawnHelpers(){let pkg;try{pkg=dirname(createRequire(import.meta.url).resolve("node-pty/package.json"))}catch{return[]}let prebuilds=join(pkg,"prebuilds"),arches;try{arches=readdirSync(prebuilds).filter((name)=>name.startsWith("darwin-"))}catch{return[]}let helpers=[];for(let arch of arches){let path=join(prebuilds,arch,"spawn-helper");try{helpers.push({path,executable:(statSync(path).mode&64)!==0})}catch{}}return helpers}function spawnHelperDoctorLines(helpers){let broken=helpers.filter((helper)=>!helper.executable).map((helper)=>helper.path);if(helpers.length===0)return{lines:["node-pty: ? no darwin spawn-helper found next to node-pty"],broken};if(broken.length===0)return{lines:[`node-pty: \u2713 spawn-helper executable (${helpers.length} arch)`],broken};return{lines:["node-pty: \u2717 spawn-helper is not executable \u2014 every node-pty PTY spawn fails",...broken.map((path)=>` ${path}`),` \u2192 chmod 755 ${broken.join(" ")}`],broken}}import{appendFileSync,readFileSync}from"fs";var PTY_MARKER="ROVE_TERMINAL_PTY=1",run=async(argv)=>{try{let proc=Bun.spawn([...argv],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),[stdout,code]=await Promise.all([new Response(proc.stdout).text().catch(()=>""),proc.exited]);return{code,stdout}}catch{return{code:127,stdout:""}}};function parsePsRows(output){let rows=[];for(let line of output.split(`
3
3
  `)){let parts=line.trim().split(/\s+/);if(parts.length<6)continue;let[pid,ppid,pgid]=[parts[0],parts[1],parts[2]].map((value)=>Number.parseInt(value??"",10)),rssKb=Number.parseInt(parts[4]??"",10);if(!Number.isFinite(pid)||!Number.isFinite(ppid)||!Number.isFinite(pgid)||!Number.isFinite(rssKb))continue;rows.push({pid,ppid,pgid,etime:parts[3]??"",rssKb,command:parts.slice(5).join(" ")})}return rows}function pidAlive(pid,rows){return rows.some((row)=>row.pid===pid)}function orphanCandidates(rows,selfPgid,liveSessionPids){return rows.filter((row)=>row.ppid===1&&row.pgid!==selfPgid&&!liveSessionPids.has(row.pgid)&&!pidAlive(row.pgid,rows))}async function markedPids(pids,deps={}){let runProbe=deps.run??run,readEnviron=deps.readEnviron??((pid)=>readFileSync(`/proc/${pid}/environ`,"utf8")),marked=new Set;if(pids.length===0)return{marked,failed:null};if((deps.platform??process.platform)==="linux"){let refused=null;for(let pid of pids)try{if(readEnviron(pid).split("\x00").includes(PTY_MARKER))marked.add(pid)}catch(err){let code=err.code;if(code!=="ENOENT"&&code!=="ESRCH")refused??=`/proc/${pid}/environ: ${code??"unreadable"}`}return{marked,failed:refused}}let result=await runProbe(["ps","eww","-o","pid=,command=","-p",pids.join(",")]);if(result.code!==0)return{marked,failed:`ps eww exited ${result.code}`};let marker=new RegExp(`(^|\\s)${PTY_MARKER}(\\s|$)`);for(let line of result.stdout.split(`
4
4
  `)){let pid=Number.parseInt(line.trim().split(/\s+/)[0]??"",10);if(Number.isFinite(pid)&&marker.test(line))marked.add(pid)}return{marked,failed:null}}async function ownPgid(runProbe){let result=await runProbe(["ps","-o","pgid=","-p",String(process.pid)]),pgid=Number.parseInt(result.stdout.trim(),10);return Number.isFinite(pgid)?pgid:-1}async function collectOrphans(liveSessionPids,deps={}){let runProbe=deps.run??run;if((deps.platform??process.platform)==="win32")return{orphans:[],error:null};let ps=await runProbe(["ps","-A","-o","pid=,ppid=,pgid=,etime=,rss=,command="]);if(ps.code!==0)return{orphans:[],error:`could not read the process table \u2014 ps exited ${ps.code}`};let rows=parsePsRows(ps.stdout),candidates=orphanCandidates(rows,await ownPgid(runProbe),liveSessionPids),{marked,failed}=await markedPids(candidates.map((row)=>row.pid),deps);if(failed)return{orphans:[],error:`could not read process environments \u2014 ${failed}`};return{orphans:candidates.filter((row)=>marked.has(row.pid)),error:null}}function formatMb(rssKb){return`${(rssKb/1024).toFixed(0)} MB`}function orphanDoctorLines(orphans,error,cliName,killing=!1){if(error)return[`orphans: \u2717 ${error}`];if(orphans.length===0)return["orphans: \u2713 none \u2014 no processes left behind by a dead PTY session"];let totalMb=orphans.reduce((sum,row)=>sum+row.rssKb,0)/1024,lines=[`orphans: \u26A0 ${orphans.length} process(es) outlived the PTY session that spawned them (${totalMb.toFixed(0)} MB RSS)`," each is reparented to init, carries Rove's PTY marker, and its process"," group leader is gone \u2014 no live task owns them"];for(let row of[...orphans].sort((a,b)=>b.rssKb-a.rssKb))lines.push(` pid ${row.pid} (group ${row.pgid}) up ${row.etime}, ${formatMb(row.rssKb)}: ${row.command.slice(0,90)}`);if(!killing)lines.push(` \u2192 \`${cliName} doctor --kill-orphans\` ends those process groups (SIGTERM, then SIGKILL)`," read the list first: something you backgrounded from a Rove terminal and then"," closed the tab on looks exactly like a leak, and doctor cannot tell them apart");return lines}var GROUP_EXIT_GRACE_MS=2000,GROUP_POLL_MS=100;function logOrphanKill(pgid,signal,logPath=defaultDaemonLogPath()){try{appendFileSync(logPath,formatDaemonInfo("doctor-kill-orphans",`${signal} process group ${pgid}`))}catch{}}function groupAlive(pgid){try{return process.kill(-pgid,0),!0}catch(err){return err.code!=="ESRCH"}}async function killOrphanGroups(orphans){let groups=[...new Set(orphans.map((row)=>row.pgid))];for(let pgid of groups)try{process.kill(-pgid,"SIGTERM"),logOrphanKill(pgid,"SIGTERM")}catch{}let deadline=Date.now()+GROUP_EXIT_GRACE_MS,survivors=groups.filter(groupAlive);while(survivors.length>0&&Date.now()<deadline)await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),survivors=survivors.filter(groupAlive);for(let pgid of survivors)try{process.kill(-pgid,"SIGKILL"),logOrphanKill(pgid,"SIGKILL")}catch{}return await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),{groups,survivors:survivors.filter(groupAlive)}}function multiplexerLabel(env){if(env.TMUX)return"tmux";if(env.ZELLIJ)return"zellij";if(env.STY)return"screen";return"no"}function terminalEnvLines(env){let show=(v)=>v&&v.length>0?v:"(unset)",program=env.TERM_PROGRAM?`${env.TERM_PROGRAM}${env.TERM_PROGRAM_VERSION?` v${env.TERM_PROGRAM_VERSION}`:""}`:"(unset)";return[`terminal: TERM=${show(env.TERM)} TERM_PROGRAM=${program} COLORTERM=${show(env.COLORTERM)}`,` running inside a multiplexer: ${multiplexerLabel(env)}`]}function parseKittyProbeReply(data){let kitty=data.match(/\x1b\[\?(\d+)u/);if(kitty?.[1]!==void 0)return{kind:"supported",flags:Number.parseInt(kitty[1],10)};if(/\x1b\[\?[\d;]*c/.test(data))return{kind:"unsupported"};return null}function kittyProbeLine(result){switch(result.kind){case"supported":return` kitty keyboard protocol: \u2713 answered (flags=${result.flags})`;case"unsupported":return[" kitty keyboard protocol: \u2717 not supported \u2014 legacy key path"," (ctrl+h/ctrl+j arrive as C0 backspace/linefeed bytes; the"," split chords ctrl+\\ and ctrl+= cannot be encoded at all)"].join(`
5
5
  `);case"no-response":return" kitty keyboard protocol: ? no reply (terminal ignored both the kitty query and DA1)";case"skipped":return` kitty keyboard protocol: skipped (${result.reason})`}}async function probeKittyKeyboard(timeoutMs=300){let stdin=process.stdin;if(!stdin.isTTY||!process.stdout.isTTY)return{kind:"skipped",reason:"not an interactive terminal"};let wasRaw=stdin.isRaw===!0,buffer="";return await new Promise((resolve)=>{let done=!1,finish=(result)=>{if(done)return;if(done=!0,clearTimeout(timer),stdin.off("data",onData),stdin.pause(),!wasRaw)stdin.setRawMode(!1);resolve(result)},onData=(chunk)=>{buffer+=chunk.toString("latin1");let decided=parseKittyProbeReply(buffer);if(decided)finish(decided)},timer=setTimeout(()=>finish({kind:"no-response"}),timeoutMs);stdin.setRawMode(!0),stdin.resume(),stdin.on("data",onData),process.stdout.write("\x1B[?u\x1B[c")})}async function terminalDoctorLines(){return[...terminalEnvLines(process.env),kittyProbeLine(await probeKittyKeyboard())]}async function probeGit(){try{let proc=Bun.spawn(["git","--version"],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),text=(await new Response(proc.stdout).text()).trim();if(await proc.exited===0&&text)return{line:`git: \u2713 ${text}`,found:!0}}catch{}return{line:"git: \u2717 not found on PATH",found:!1}}function binaryLabel(binary){return binary.found?`\u2713 ${binary.path}`:`\u2717 ${binary.error}`}async function probeEngines(){let statuses=await detectEngineStatuses(await probeableEngineIds()),lines=["engines:"];for(let status of statuses){let account=describeAccount(status.account),name=`${status.vendor.padEnd(7)} `;if(lines.push(` ${name}${binaryLabel(status.binary)}${status.binary.found?` \u2014 ${account}`:""}`),status.accountError)lines.push(` \u26A0 ${status.accountError}`)}let{usable,signedOut}=summarizeEngines(statuses);return{lines,anyUsable:usable.length>0,signedOut}}var CLI_NAME=ROVE_PRODUCT_NAME;function isProcessAlive(pid){try{return process.kill(pid,0),!0}catch(err){return err.code==="EPERM"}}async function requestIfReachable(socketPath,name){let client=new RoveDaemonClient(socketPath);try{return await client.request(name,{})}catch{return null}finally{client.close()}}function fmtDuration(ms){let seconds=Math.floor(ms/1000);if(seconds<60)return`${seconds}s`;let minutes=Math.floor(seconds/60);if(minutes<60)return`${minutes}m ${seconds%60}s`;return`${Math.floor(minutes/60)}h ${minutes%60}m`}function describeFile(path){try{let stat=statSync2(path);return`present (${formatBytes(stat.size)}, modified ${stat.mtime.toISOString()})`}catch{return"absent"}}function taskCount(path){try{let parsed=JSON.parse(readFileSync2(path,"utf8"));return Array.isArray(parsed.tasks)?parsed.tasks.length:null}catch{return null}}function tailFile(path,count){try{return readFileSync2(path,"utf8").split(`
@@ -7,7 +7,7 @@ import{formatBytes}from"./chunk-my20q579.js";import{hookConfigIssues}from"./chun
7
7
  `)}catch{return""}}function describeInstall(){try{let[,entry]=resolveRoveSpawn([]);return{line:`install: \u2713 ${entry??process.execPath}`,ok:!0}}catch(err){if(!isStaleInstallError(err))return{line:`install: ? could not check (${String(err)})`,ok:!0};return{line:["install: \u2717 GONE \u2014 this process is running from an install that no longer exists on disk"," it cannot start a daemon; every reconnect fails the same way until you reinstall"," \u2192 npm install -g @sma1lboy/rove (then relaunch Rove)"].join(`
8
8
  `),ok:!1}}}async function appendUnavailableProcess(out,label,pidPath,socketPath){let pid=await readPidFile(pidPath),wedged=pid!==null&&pid!==void 0&&isProcessAlive(pid);if(wedged)out.push(`${label}: \u2717 WEDGED \u2014 process alive (pid ${pid}) but socket is unreachable`);else if(pid)out.push(`${label}: \u2717 not running (stale pidfile \u2192 pid ${pid} is gone)`);else out.push(`${label}: \u2717 not running (no pidfile)`);if(existsSync(socketPath))out.push(` orphan socket file present: ${socketPath}`);return wedged?"wedged":"down"}async function collectDoctor(){let daemonSocket=defaultDaemonSocketPath(),daemonLog=defaultDaemonLogPath(),ptySocket=defaultPtyHostSocketPath(),ptyLog=defaultPtyHostLogPath(),canonicalTasks=join2(roveStateDir(),"tasks.json"),legacyTasks=join2(preRenameStateDir(homeDir()),"tasks.json"),readableLegacy=readableLegacyIndexPath(canonicalTasks,legacyTasks),usingLegacyTasks=!existsSync(canonicalTasks)&&readableLegacy!==void 0&&existsSync(readableLegacy),tasksPath=usingLegacyTasks?legacyTasks:canonicalTasks,statePath=kvStatePath(),fixes=[],git=await probeGit();if(!git.found)fixes.push(humanOnlyFix("git"));let engines=await probeEngines();if(!engines.anyUsable)fixes.push(noEngineFix(engines.signedOut));let install=describeInstall();if(!install.ok)fixes.push(reinstallManualFix());let staleBun=!isBunAtLeast(Bun.version);if(staleBun)fixes.push(humanOnlyFix("staleBun"));let out=["Rove doctor",` build: v${CURRENT_VERSION} (${process.platform} ${process.arch}, bun ${Bun.version})`,...staleBun?[` \u26A0 bun ${Bun.version} is below the ${MIN_BUN_VERSION} Rove needs \u2014 terminals will not paint`]:[],` home: ${homeDir()}`,"",...await terminalDoctorLines(),git.line,"",...engines.lines,"",install.line,""],daemon=await requestIfReachable(daemonSocket,"daemon.status");if(daemon){let pid=typeof daemon.daemonPid==="number"?daemon.daemonPid:"?",uptime=typeof daemon.uptimeMs==="number"?fmtDuration(daemon.uptimeMs):"?",tasks=typeof daemon.taskCount==="number"?daemon.taskCount:"?",clients=typeof daemon.attachedClients==="number"?daemon.attachedClients:"?";out.push(`daemon: \u2713 running (pid ${pid}, up ${uptime}, ${tasks} task(s), ${clients} client(s))`);let version=typeof daemon.roveVersion==="string"?daemon.roveVersion:void 0;if(version&&version!==CURRENT_VERSION)out.push(` \u26A0 stale build: daemon is v${version}, you launched v${CURRENT_VERSION}`),out.push(` \u2192 run \`${CLI_NAME} daemon restart\`, then relaunch Rove`),fixes.push(daemonRestartFix(CLI_NAME,"daemonStale"));else if(version)out.push(` build: v${version}`);if(isForeignDaemonHome(typeof daemon.homeDir==="string"?daemon.homeDir:void 0,homeDir()))out.push(` \u26A0 foreign home: daemon serves ${String(daemon.homeDir)}, you are reading ${homeDir()}`),out.push(` \u2192 clear ROVE_HOME_DIR/ROVE_HOME_DIR, then \`${CLI_NAME} daemon restart\``);let tabs=(await requestIfReachable(daemonSocket,"debug.inspect"))?.activity?.tabs;if(tabs){let hookInput={socketPath:daemonSocket,configIssues:hookConfigIssues()},verdict=classifyHookChannel({tabs,...hookInput});if(out.push("",...hookChannelDoctorLines(verdict,hookInput,CLI_NAME)),verdict.kind==="down")fixes.push(daemonRestartFix(CLI_NAME,"hooksDown"),engineTabsManualFix())}else out.push("","hooks: ? could not read the daemon's activity registry (debug.inspect unavailable)"),fixes.push(daemonRestartFix(CLI_NAME,"inspectStale"))}else{let state=await appendUnavailableProcess(out,"daemon ",defaultDaemonPidPath(),daemonSocket);fixes.push(state==="wedged"?resetManualFix(CLI_NAME,"resetDaemonWedged"):daemonRestartFix(CLI_NAME,"daemonDown"));let tail=tailFile(daemonLog,8);if(tail){out.push(" last lines of daemon.log:");for(let line of tail.split(`
9
9
  `))out.push(` \u2502 ${line}`)}}out.push("");let inventory=await requestIfReachable(ptySocket,"pty.list");if(inventory){let sessions=inventory.sessions??[],parked=inventory.stats?.parkedSessions??sessions.filter((session)=>session.parked).length;if(out.push(`pty host: \u2713 running (${sessions.length} session(s), ${sessions.filter((session)=>session.alive).length} live, ${parked} parked)`),typeof inventory.pid==="number"&&typeof inventory.rssBytes==="number")out.push(` pid ${inventory.pid}, ${formatBytes(inventory.rssBytes)} RSS`);let hostVersion=typeof inventory.version==="string"?inventory.version:void 0;if(hostVersion===void 0)out.push(" build: unknown \u2014 this host predates the version check, so it is at least that old"),out.push(` \u2192 \`${CLI_NAME} reset\` replaces it (ends every live terminal and engine session)`);else if(hostVersion!==CURRENT_VERSION)out.push(` \u26A0 stale build: pty host is v${hostVersion}, you launched v${CURRENT_VERSION}`),out.push(` \u2192 \`${CLI_NAME} reset\` replaces it (ends every live terminal and engine session)`),fixes.push(resetManualFix(CLI_NAME,"resetPtyStale"));else out.push(` build: v${hostVersion}`);let stats=inventory.stats;if(stats&&typeof stats.ringBytes==="number"&&typeof stats.ringCapacityBytes==="number")out.push(` ring: ${formatBytes(stats.ringBytes)} / ${formatBytes(stats.ringCapacityBytes)}`);if(stats&&typeof stats.parkedScreenBytes==="number")out.push(` parked screens: ${formatBytes(stats.parkedScreenBytes)}`);if(stats&&typeof stats.parkRestoreDeltas==="number"&&typeof stats.parkRestoreFallbacks==="number")out.push(` park wakes: ${stats.parkRestoreDeltas} delta, ${stats.parkRestoreFallbacks} full replay fallback`)}else if(await appendUnavailableProcess(out,"pty host",defaultPtyHostPidPath(),ptySocket)==="wedged")fixes.push(resetManualFix(CLI_NAME,"resetPty"));else out.push(" starts on demand \u2014 the first task tab launches it; nothing to fix");if(process.platform==="win32"){let node=resolveNodeBinary();if(out.push(node?` node: \u2713 ${node} (the Windows PTY host runs under it)`:` node: \u2717 not found on PATH \u2014 the Windows PTY host cannot start
10
- \u2192 install Node.js from https://nodejs.org`),!node)fixes.push(humanOnlyFix("windowsNode"))}if(process.platform==="darwin"){let helpers=spawnHelperDoctorLines(installedSpawnHelpers());if(out.push(...helpers.lines),helpers.broken.length>0)fixes.push(spawnHelperFix(helpers.broken))}out.push("");let liveSessionPids=new Set;for(let session of inventory?.sessions??[])if(session.alive&&typeof session.pid==="number")liveSessionPids.add(session.pid);let orphaned=await collectOrphans(liveSessionPids);if(out.push(...orphanDoctorLines(orphaned.orphans,orphaned.error,CLI_NAME),""),orphaned.orphans.length>0)fixes.push(killOrphansManualFix(CLI_NAME,orphaned.orphans.length));let legacy=await inspectLegacyTmux();if(out.push(...legacyTmuxDoctorLines(legacy),""),legacy.sessions.length>0)fixes.push(resetManualFix(CLI_NAME,"resetLegacy"));let skill=roveSkillState(),installCommand=skillInstallCommand();if(!skill.installed)out.push("skill: \u2717 Rove agent skill not installed",` \u2192 ${installCommand}`),fixes.push(skillInstallFix(installCommand,!1));else if(skill.stale){let installed=skill.installedVersion===null?"unstamped":`v${skill.installedVersion}`;out.push(`skill: \u26A0 Rove agent skill out of date (${installed}; this Rove wants v${skill.currentVersion})`),out.push(` \u2192 ${installCommand}`),fixes.push(skillInstallFix(installCommand,!0))}else out.push(`skill: \u2713 Rove agent skill installed (v${skill.installedVersion})`);out.push("");let count=taskCount(tasksPath);return out.push(`tasks.json: ${describeFile(tasksPath)}${count===null?"":` \u2014 ${count} task(s)`}${usingLegacyTasks?` (legacy ${tasksPath}, not yet migrated)`:""}`),out.push(`state.json: ${describeFile(statePath)}`),out.push(`daemon.log: ${describeFile(daemonLog)}`),out.push(`pty.log: ${describeFile(ptyLog)}`),{lines:out,fixes,orphans:orphaned.orphans}}async function sweepOrphans(orphans){if(orphans.length===0)return["orphans: nothing to kill"];let{groups,survivors}=await killOrphanGroups(orphans),lines=[`orphans: signalled ${groups.length} process group(s) covering ${orphans.length} process(es)`];if(survivors.length>0)lines.push(` \u2717 still alive after SIGKILL: group(s) ${survivors.join(", ")} \u2014 inspect with \`ps -g <pgid>\``);else lines.push(" \u2713 all of them are gone");return lines}async function runDoctorSubcommand(argv=[]){if(argv.some((arg)=>arg==="--help"||arg==="-h"||arg==="help")){process.stdout.write([`Usage: ${CLI_NAME} doctor [--report] [--fix] [--kill-orphans]`,"","Read-only diagnosis of the daemon / Hosted PTY / engines / git / legacy tmux / state.","","Options:"," --report Also write a bug bundle (diagnosis + recent logs + env) to a file"," --fix Review the fixes one by one: safe ones run after a per-fix y/N,"," risky ones (kill sessions, install software) are printed only"," --kill-orphans End the process groups listed under `orphans:` (SIGTERM, then"," SIGKILL). Not undoable \u2014 run plain `doctor` and read the list first"," -h, --help Print this help",""].join(`
10
+ \u2192 install Node.js from https://nodejs.org`),!node)fixes.push(humanOnlyFix("windowsNode"))}if(process.platform==="darwin"){let helpers=spawnHelperDoctorLines(installedSpawnHelpers());if(out.push(...helpers.lines),helpers.broken.length>0)fixes.push(spawnHelperFix(helpers.broken))}out.push("");let liveSessionPids=new Set;for(let session of inventory?.sessions??[])if(session.alive&&typeof session.pid==="number")liveSessionPids.add(session.pid);let orphaned=await collectOrphans(liveSessionPids);if(out.push(...orphanDoctorLines(orphaned.orphans,orphaned.error,CLI_NAME),""),orphaned.orphans.length>0)fixes.push(killOrphansManualFix(CLI_NAME,orphaned.orphans.length));let legacy=await inspectLegacyTmux();if(out.push(...legacyTmuxDoctorLines(legacy),""),legacy.sessions.length>0)fixes.push(resetManualFix(CLI_NAME,"resetLegacy"));let skill=skillOverview(),installCommand=`${CLI_NAME} skill install`;if(skill.targets.length===0)out.push("skill: \u2013 no coding agent with a known skills dir found");else if(!skill.installed)out.push("skill: \u2717 Rove agent skill not installed",` \u2192 ${installCommand}`),fixes.push(skillInstallFix(installCommand,!1));else if(skill.outdated.length>0)out.push(`skill: \u26A0 Rove agent skill out of date for ${skill.outdated.map((t2)=>t2.displayName).join(", ")}`,` \u2192 ${installCommand}`),fixes.push(skillInstallFix(installCommand,!0));else out.push("skill: \u2713 Rove agent skill installed");out.push("");let count=taskCount(tasksPath);return out.push(`tasks.json: ${describeFile(tasksPath)}${count===null?"":` \u2014 ${count} task(s)`}${usingLegacyTasks?` (legacy ${tasksPath}, not yet migrated)`:""}`),out.push(`state.json: ${describeFile(statePath)}`),out.push(`daemon.log: ${describeFile(daemonLog)}`),out.push(`pty.log: ${describeFile(ptyLog)}`),{lines:out,fixes,orphans:orphaned.orphans}}async function sweepOrphans(orphans){if(orphans.length===0)return["orphans: nothing to kill"];let{groups,survivors}=await killOrphanGroups(orphans),lines=[`orphans: signalled ${groups.length} process group(s) covering ${orphans.length} process(es)`];if(survivors.length>0)lines.push(` \u2717 still alive after SIGKILL: group(s) ${survivors.join(", ")} \u2014 inspect with \`ps -g <pgid>\``);else lines.push(" \u2713 all of them are gone");return lines}async function runDoctorSubcommand(argv=[]){if(argv.some((arg)=>arg==="--help"||arg==="-h"||arg==="help")){process.stdout.write([`Usage: ${CLI_NAME} doctor [--report] [--fix] [--kill-orphans]`,"","Read-only diagnosis of the daemon / Hosted PTY / engines / git / legacy tmux / state.","","Options:"," --report Also write a bug bundle (diagnosis + recent logs + env) to a file"," --fix Review the fixes one by one: safe ones run after a per-fix y/N,"," risky ones (kill sessions, install software) are printed only"," --kill-orphans End the process groups listed under `orphans:` (SIGTERM, then"," SIGKILL). Not undoable \u2014 run plain `doctor` and read the list first"," -h, --help Print this help",""].join(`
11
11
  `));return}let report=argv.some((arg)=>arg==="--report"),fix=argv.some((arg)=>arg==="--fix"),kill=argv.some((arg)=>arg==="--kill-orphans"),known=new Set(["--report","--fix","--kill-orphans"]),unknown=argv.find((arg)=>arg.length>0&&!known.has(arg));if(unknown!==void 0)process.stderr.write(`${CLI_NAME} doctor: unexpected argument "${unknown}"
12
12
 
13
13
  Usage: ${CLI_NAME} doctor [--report] [--fix] [--kill-orphans]