@sma1lboy/rove 0.9.108 → 0.9.147

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 (194) hide show
  1. package/README.md +0 -1
  2. package/dist/cli/chunk-003tvywc.js +3 -0
  3. package/dist/cli/chunk-0m9j3yap.js +7 -0
  4. package/dist/cli/chunk-0r8333z3.js +3 -0
  5. package/dist/cli/chunk-0sm2k04y.js +3 -0
  6. package/dist/cli/chunk-0vmrteyg.js +3 -0
  7. package/dist/cli/chunk-0vy8351p.js +18 -0
  8. package/dist/cli/chunk-13s8rnk5.js +3 -0
  9. package/dist/cli/chunk-1kktfmtg.js +4 -0
  10. package/dist/cli/chunk-1rkb0j1j.js +3 -0
  11. package/dist/cli/chunk-1tx1s5v6.js +2 -0
  12. package/dist/cli/chunk-20pt9yqh.js +4 -0
  13. package/dist/cli/chunk-2brn8e1y.js +3 -0
  14. package/dist/cli/chunk-2fypr41w.js +3 -0
  15. package/dist/cli/chunk-2jxdzw4r.js +3 -0
  16. package/dist/cli/chunk-2pqqvse3.js +2 -0
  17. package/dist/cli/chunk-3bfm4hrs.js +3 -0
  18. package/dist/cli/chunk-3ry6prwn.js +3 -0
  19. package/dist/cli/chunk-3ztek08w.js +4 -0
  20. package/dist/cli/chunk-49s2zc0h.js +8 -0
  21. package/dist/cli/chunk-4wwx51m5.js +3 -0
  22. package/dist/cli/chunk-5bn91n19.js +3 -0
  23. package/dist/cli/chunk-5c3d1y0r.js +2 -0
  24. package/dist/cli/chunk-5hhvrvgm.js +8 -0
  25. package/dist/cli/chunk-6dn6h640.js +3 -0
  26. package/dist/cli/chunk-6frfschk.js +2 -0
  27. package/dist/cli/chunk-6rkc7efm.js +5 -0
  28. package/dist/cli/chunk-6xppe9bj.js +3 -0
  29. package/dist/cli/chunk-6zwg6me2.js +4 -0
  30. package/dist/cli/chunk-764bsyb0.js +1 -0
  31. package/dist/cli/chunk-79gqh5p2.js +5 -0
  32. package/dist/cli/chunk-7nhdvr5v.js +4 -0
  33. package/dist/cli/chunk-7q67dz4c.js +3 -0
  34. package/dist/cli/chunk-7ydwn358.js +3 -0
  35. package/dist/cli/chunk-86j25g7y.js +7 -0
  36. package/dist/cli/chunk-88qjhytd.js +12 -0
  37. package/dist/cli/chunk-8arm7k43.js +69 -0
  38. package/dist/cli/chunk-8ddjfc2v.js +4 -0
  39. package/dist/cli/chunk-8r1shxz0.js +16 -0
  40. package/dist/cli/chunk-99devyxr.js +2 -0
  41. package/dist/cli/chunk-9c1e5z6a.js +3 -0
  42. package/dist/cli/chunk-9n458sdy.js +2 -0
  43. package/dist/cli/chunk-aq912vvw.js +3 -0
  44. package/dist/cli/chunk-arf294te.js +2 -0
  45. package/dist/cli/chunk-awsawfrm.js +2 -0
  46. package/dist/cli/chunk-aynx3d2a.js +2 -0
  47. package/dist/cli/chunk-b99tf0jr.js +3 -0
  48. package/dist/cli/chunk-bdbgmjt7.js +3 -0
  49. package/dist/cli/chunk-c6mthex1.js +5 -0
  50. package/dist/cli/chunk-cb0pgyq1.js +8 -0
  51. package/dist/cli/chunk-cb2fpajx.js +3 -0
  52. package/dist/cli/chunk-cehhk94g.js +2 -0
  53. package/dist/cli/chunk-d4bqay6d.js +9 -0
  54. package/dist/cli/chunk-dcb59tsn.js +2 -0
  55. package/dist/cli/chunk-df7qe9y7.js +4 -0
  56. package/dist/cli/chunk-dkxhmj9k.js +25 -0
  57. package/dist/cli/chunk-dnb2bmtb.js +3 -0
  58. package/dist/cli/chunk-dqndd97s.js +7 -0
  59. package/dist/cli/chunk-dvcb6mk4.js +3 -0
  60. package/dist/cli/chunk-dw853n4w.js +3 -0
  61. package/dist/cli/chunk-dwsgeq06.js +15 -0
  62. package/dist/cli/chunk-e1g9mvww.js +11 -0
  63. package/dist/cli/chunk-e3ye4kmk.js +2 -0
  64. package/dist/cli/chunk-ef11h2am.js +3 -0
  65. package/dist/cli/chunk-ef39ym8f.js +3 -0
  66. package/dist/cli/chunk-ewdhz3dv.js +2 -0
  67. package/dist/cli/chunk-f6zsej8e.js +3 -0
  68. package/dist/cli/chunk-fe34e0w7.js +28 -0
  69. package/dist/cli/chunk-g1ybdgad.js +25 -0
  70. package/dist/cli/chunk-gbasmvsc.js +4 -0
  71. package/dist/cli/chunk-gjf604bb.js +3 -0
  72. package/dist/cli/chunk-gm3vj0fv.js +5 -0
  73. package/dist/cli/chunk-grh6dvfv.js +5 -0
  74. package/dist/cli/chunk-gwcneg6c.js +2 -0
  75. package/dist/cli/chunk-h5j8b87f.js +2 -0
  76. package/dist/cli/chunk-h79zfebh.js +7 -0
  77. package/dist/cli/chunk-h82kzdsn.js +3 -0
  78. package/dist/cli/chunk-hape5vwj.js +3 -0
  79. package/dist/cli/chunk-hg5x2wr0.js +3 -0
  80. package/dist/cli/chunk-hgq2gtxx.js +4 -0
  81. package/dist/cli/chunk-j4xfsn9g.js +5 -0
  82. package/dist/cli/chunk-j9g1m4dy.js +2 -0
  83. package/dist/cli/chunk-jdbfawrm.js +3 -0
  84. package/dist/cli/chunk-jsss3ze7.js +11 -0
  85. package/dist/cli/chunk-jvssy49v.js +2 -0
  86. package/dist/cli/chunk-jvxh93nz.js +3 -0
  87. package/dist/cli/chunk-jyv82gf0.js +258 -0
  88. package/dist/cli/chunk-k3ksts6g.js +3 -0
  89. package/dist/cli/chunk-kdrrw9tm.js +2 -0
  90. package/dist/cli/chunk-kg11c1py.js +3 -0
  91. package/dist/cli/chunk-kwe61yx7.js +3 -0
  92. package/dist/cli/chunk-mb5m7ex7.js +2 -0
  93. package/dist/cli/chunk-mfqjdpd8.js +2 -0
  94. package/dist/cli/chunk-mjvq39gf.js +4 -0
  95. package/dist/cli/chunk-mrwee8sj.js +3 -0
  96. package/dist/cli/chunk-my20q579.js +3 -0
  97. package/dist/cli/chunk-myfjt6dw.js +7 -0
  98. package/dist/cli/chunk-nceh1q3d.js +12 -0
  99. package/dist/cli/chunk-ncsgawg7.js +2 -0
  100. package/dist/cli/chunk-nm6adny4.js +4 -0
  101. package/dist/cli/chunk-np07kccr.js +4 -0
  102. package/dist/cli/chunk-p56s3ekm.js +3 -0
  103. package/dist/cli/chunk-p5spmf7e.js +2 -0
  104. package/dist/cli/chunk-p7kztgsd.js +4 -0
  105. package/dist/cli/chunk-pdh5w4ht.js +3 -0
  106. package/dist/cli/chunk-pdj8kqa1.js +74 -0
  107. package/dist/cli/chunk-psx9tk3x.js +4 -0
  108. package/dist/cli/chunk-pw6yfj10.js +3 -0
  109. package/dist/cli/chunk-q6579rbz.js +3 -0
  110. package/dist/cli/chunk-q7dr9eh6.js +3 -0
  111. package/dist/cli/chunk-q9x6d0k6.js +3 -0
  112. package/dist/cli/chunk-qkehg2c1.js +3 -0
  113. package/dist/cli/chunk-qtke4x42.js +3 -0
  114. package/dist/cli/chunk-rgcv1wcs.js +4 -0
  115. package/dist/cli/chunk-rxvbm4vt.js +7 -0
  116. package/dist/cli/chunk-ryhrw647.js +3 -0
  117. package/dist/cli/chunk-s76r56rj.js +3 -0
  118. package/dist/cli/chunk-sdyzxayr.js +3 -0
  119. package/dist/cli/chunk-svpn3av1.js +3 -0
  120. package/dist/cli/chunk-v5893dx3.js +2 -0
  121. package/dist/cli/chunk-vapjtyv9.js +7 -0
  122. package/dist/cli/chunk-vkch2spv.js +33 -0
  123. package/dist/cli/chunk-vpzvcxc1.js +3 -0
  124. package/dist/cli/chunk-vws0j65e.js +4 -0
  125. package/dist/cli/chunk-vyb5a2rh.js +4 -0
  126. package/dist/cli/chunk-w298ayjc.js +3 -0
  127. package/dist/cli/chunk-w48zjgxv.js +9 -0
  128. package/dist/cli/chunk-w5xy83ze.js +2 -0
  129. package/dist/cli/chunk-wpgmq5z6.js +106 -0
  130. package/dist/cli/chunk-wqfp8d9w.js +3 -0
  131. package/dist/cli/chunk-x760j10f.js +3 -0
  132. package/dist/cli/chunk-xbc3gcry.js +2 -0
  133. package/dist/cli/chunk-xy8be792.js +3 -0
  134. package/dist/cli/chunk-yhcz2d2r.js +34 -0
  135. package/dist/cli/chunk-yk2ha5yj.js +3 -0
  136. package/dist/cli/chunk-ykvk2546.js +3 -0
  137. package/dist/cli/chunk-ympakh8w.js +6 -0
  138. package/dist/cli/chunk-zb56ck5f.js +3 -0
  139. package/dist/cli/chunk-zwzkve1e.js +2 -0
  140. package/dist/cli/chunk-zy6vgjdp.js +19 -0
  141. package/dist/cli/index.js +15 -845
  142. package/dist/cli/kobe-run.js +1 -853
  143. package/dist/cli/kobe.js +6 -6
  144. package/dist/cli/pty-host-node.mjs +190 -52
  145. package/dist/cli/rove-run.js +1 -853
  146. package/dist/cli/rove.js +6 -6
  147. package/dist/skills/rove/SKILL.md +29 -10
  148. package/dist/skills/rove/references/api-flags.md +35 -13
  149. package/dist/web-ui/assets/{ChatTerminal-BshL3M8G.js → harness-CYGJ4uoR.js} +19 -20
  150. package/dist/web-ui/assets/index-BTJ-X_4s.js +10 -0
  151. package/dist/web-ui/assets/index-Cs2vPLNB.css +1 -0
  152. package/dist/web-ui/index.html +2 -9
  153. package/dist/web-ui/pty-server.mjs +4 -5
  154. package/package.json +2 -2
  155. package/dist/web-ui/assets/AppShell-BGRIs5hW.js +0 -5
  156. package/dist/web-ui/assets/AppShell-HiyATJse.css +0 -1
  157. package/dist/web-ui/assets/Board-Bt3cwp25.js +0 -1
  158. package/dist/web-ui/assets/BoardPeek-BKR-tpS2.js +0 -2
  159. package/dist/web-ui/assets/ChatTranscript-B67_nnd6.js +0 -1
  160. package/dist/web-ui/assets/ConfirmDialog-kyA624OF.js +0 -1
  161. package/dist/web-ui/assets/IssueIntakePanel-BMP8Vc3E.js +0 -1
  162. package/dist/web-ui/assets/IssuePeek-C7afOYax.js +0 -1
  163. package/dist/web-ui/assets/IssuesPage-DwRaBB-m.js +0 -1
  164. package/dist/web-ui/assets/SettingsPage-CC1sDI8j.js +0 -2
  165. package/dist/web-ui/assets/SlideOver-B4sEOPyN.css +0 -1
  166. package/dist/web-ui/assets/SlideOver-Dq0ifiEm.js +0 -173
  167. package/dist/web-ui/assets/ViewToggle-mNsDLJp8.js +0 -1
  168. package/dist/web-ui/assets/WorkspaceTabs-DLzL-Tad.css +0 -1
  169. package/dist/web-ui/assets/WorkspaceTabs-ifAIZ5Fj.js +0 -3
  170. package/dist/web-ui/assets/active-task-gVYiAkLv.js +0 -1
  171. package/dist/web-ui/assets/arrow-left-CavMh90a.js +0 -1
  172. package/dist/web-ui/assets/board-DoArj55z.js +0 -1
  173. package/dist/web-ui/assets/chips-CS9PLtWy.js +0 -1
  174. package/dist/web-ui/assets/createLucideIcon-CuIQtyYV.js +0 -1
  175. package/dist/web-ui/assets/external-link-Du2dMe8S.js +0 -1
  176. package/dist/web-ui/assets/external-store-BCBJewGi.js +0 -1
  177. package/dist/web-ui/assets/harness-ClZMF1wx.js +0 -1
  178. package/dist/web-ui/assets/index-B4xJZEqf.js +0 -10
  179. package/dist/web-ui/assets/index-BnjD9Q-3.css +0 -1
  180. package/dist/web-ui/assets/issues-DwrKXp9c.js +0 -4
  181. package/dist/web-ui/assets/issues-ISAZBras.js +0 -1
  182. package/dist/web-ui/assets/lazy-issue-panels-DvXQJhKy.js +0 -6
  183. package/dist/web-ui/assets/rotate-cw-BXdpzm3v.js +0 -1
  184. package/dist/web-ui/assets/routes-DEEkL5gG.js +0 -1
  185. package/dist/web-ui/assets/store-BLM6nh6E.js +0 -2
  186. package/dist/web-ui/assets/tabs-CMZJhcSB.js +0 -1
  187. package/dist/web-ui/assets/task._taskId-BCIhg4IQ.js +0 -1
  188. package/dist/web-ui/assets/terminal-DOp1a9g6.js +0 -1
  189. package/dist/web-ui/assets/text-match-DW3sD-Rt.js +0 -1
  190. package/dist/web-ui/assets/time-kviT26Tm.js +0 -1
  191. package/dist/web-ui/assets/toast-C4yXq6hM.js +0 -1
  192. package/dist/web-ui/assets/web-transport-Beqz2mQ8.js +0 -1
  193. package/dist/web-ui/assets/worktrees-BGvJOG2b.js +0 -1
  194. /package/dist/web-ui/assets/{ChatTerminal-BrP-ENHg.css → harness-BrP-ENHg.css} +0 -0
@@ -0,0 +1,25 @@
1
+ // @bun
2
+ import{getPersistedString,setPersistedString}from"./chunk-k3ksts6g.js";import{activeCliName}from"./chunk-ef11h2am.js";import{ROVE_PRODUCT_NAME}from"./chunk-cb2fpajx.js";import{__require}from"./chunk-wqfp8d9w.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 KOBE_SKILL_VERSION=42,ROVE_SKILL_REL_PATHS=[".agents/skills/rove/SKILL.md",".claude/skills/rove/SKILL.md"],LEGACY_SKILL_REL_PATHS=[".agents/skills/kobe/SKILL.md",".claude/skills/kobe/SKILL.md"],SKILL_REL_PATHS=[...ROVE_SKILL_REL_PATHS,...LEGACY_SKILL_REL_PATHS];function skillInstallCommand(env=process.env){return`${activeCliName(env)} skill install`}var SKILL_SOURCE_SLUG="Sma1lboy/rove";function bundledSkillDir(){let here=fileURLToPath(import.meta.url);return[resolve(here,"../../../../../.agents/skills/kobe"),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`${activeCliName()} 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 kobeSkillPaths(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|kobe)-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 kobeSkillState(opts={}){let roots=[opts.home??homedir(),opts.cwd??process.cwd()],roveCopies=distinctSkillFiles(roots,ROVE_SKILL_REL_PATHS).map((path)=>({path,version:skillVersionAt(path)})),legacy=distinctSkillFiles(roots,LEGACY_SKILL_REL_PATHS).map((path)=>({path,version:skillVersionAt(path)})),best=[...roveCopies].sort((a,b)=>(b.version??-1)-(a.version??-1))[0]??legacy[0];if(!best)return{installed:!1,installedVersion:null,currentVersion:KOBE_SKILL_VERSION,stale:!1,legacyCopies:[]};let stale=best.version===null||best.version<KOBE_SKILL_VERSION;return{installed:!0,installedVersion:best.version,currentVersion:KOBE_SKILL_VERSION,stale,legacyCopies:legacy.filter((copy)=>copy.path!==best.path)}}function describeLegacyCopies(copies){return copies.map((c)=>`${c.path}${c.version===null?"":` (v${c.version})`}`).join(", ")}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-vws0j65e.js");if(isRovePluginEnabled())return;let cliName=activeCliName(),installCommand=skillInstallCommand(),state=kobeSkillState();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}`,duplicates=state.legacyCopies;if(!state.stale){if(duplicates.length===0)return;if(getPersistedString(key)==="1")return;setPersistedString(key,"1"),process.stderr.write(`
12
+ ${cliName}: your Rove agent skill is current, but a stale duplicate is still installed:
13
+ ${describeLegacyCopies(duplicates)}
14
+ Remove that directory \u2014 your agent loads both.
15
+
16
+ `);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(`
17
+ ${cliName}: your Rove agent skill is out of date (${was}; this Rove wants v${state.currentVersion}) \u2014 refresh it so \`${cliName} api\` guidance matches:
18
+ ${installCommand}
19
+
20
+ `);return}process.stderr.write(`
21
+ ${cliName}: a new version of the Rove agent skill is available (${was} \u2192 v${state.currentVersion}).
22
+ 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.
23
+ `);else process.stderr.write(`${cliName}: skill update failed (exit ${code}) \u2014 run \`${installCommand}\` manually.
24
+ `)}else if(answer.startsWith("d"))setPersistedString(key,"1")}
25
+ export{skillInstallCommand,bundledSkillDir,npxSkillsArgv,npxSkillsCommand,NPX_MISSING_EXIT,isNpxMissing,runNpxSkillsInstall,markSkillHintSeen,kobeSkillPaths,installedSkillDirs,kobeSkillState,maybeHintSkillInstall};
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{engineEntry,identifiableEngineIds}from"./chunk-yhcz2d2r.js";import{basename}from"path";var WRAPPERS=new Set(["node","bun","npx","deno","sh","zsh","bash","env","script"]);function binaryName(token){return basename(token).replace(/\.(exe|js|mjs|cjs)$/,"")}function executableNameFromArgv(argv){for(let token of argv.slice(0,8)){if(/^[A-Za-z_][A-Za-z0-9_]*=/.test(token))continue;let name=binaryName(token);if(WRAPPERS.has(name))continue;return name||null}return null}function vendorFromArgv(commandLine){let name=executableNameFromArgv(commandLine.trim().split(/\s+/));if(!name)return null;return identifiableEngineIds().find((v)=>{let entry=engineEntry(v);return entry.defaultCommand[0]===name||entry.processNames?.includes(name)===!0})??null}function parsePsSnapshot(text){let rows=[];for(let line of text.split(`
3
+ `)){let m=/^\s*(\d+)\s+(\d+)\s+(\S.*)$/.exec(line);if(m)rows.push({pid:Number(m[1]),ppid:Number(m[2]),args:m[3]})}return rows}function childrenIndex(rows){let kids=new Map;for(let row of rows){let list=kids.get(row.ppid);if(list)list.push(row);else kids.set(row.ppid,[row])}return kids}function hasAncestor(rows,pid,ancestorPid){let parents=new Map(rows.map((r)=>[r.pid,r.ppid])),cur=pid;for(let hops=0;hops<=rows.length;hops++){if(cur===ancestorPid)return!0;let next=parents.get(cur);if(next===void 0||next<=1)return!1;cur=next}return!1}function foregroundEngineIn(rows,rootPid){let kids=childrenIndex(rows),queue=[...kids.get(rootPid)??[]];while(queue.length>0){let row=queue.shift();if(!row)break;let vendor=vendorFromArgv(row.args);if(vendor)return{vendor,argv:row.args,pid:row.pid};queue.push(...kids.get(row.pid)??[])}return null}function engineProcessIn(rows,rootPid,extraLaunch){if(foregroundEngineIn(rows,rootPid))return!0;let expected=extraLaunch?executableNameFromArgv(typeof extraLaunch==="string"?[extraLaunch]:extraLaunch):null;if(!expected)return!1;let kids=childrenIndex(rows),queue=[...kids.get(rootPid)??[]];while(queue.length>0){let row=queue.shift();if(!row)break;if(executableNameFromArgv(row.args.trim().split(/\s+/))===expected)return!0;queue.push(...kids.get(row.pid)??[])}return!1}var psSnapshot=async()=>{let proc=Bun.spawn(["ps","-A","-o","pid=,ppid=,args="],{stdout:"pipe",stderr:"ignore"});return await new Response(proc.stdout).text()};async function foregroundEngine(rootPid,snapshot=psSnapshot){try{return foregroundEngineIn(parsePsSnapshot(await snapshot()),rootPid)}catch{return null}}
4
+ export{vendorFromArgv,parsePsSnapshot,hasAncestor,foregroundEngineIn,engineProcessIn,psSnapshot,foregroundEngine};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{kvStatePath}from"./chunk-6dn6h640.js";import{mkdirSync,readFileSync,renameSync,writeFileSync}from"fs";import{dirname}from"path";var corruptWarned=!1;function readSavedRepos(state){let raw=state.savedRepos;if(!Array.isArray(raw))return[];return raw.filter((entry)=>typeof entry==="string")}function loadStateFile(){let path=kvStatePath(),text;try{text=readFileSync(path,"utf8")}catch{return{}}try{let parsed=JSON.parse(text);if(parsed&&typeof parsed==="object"&&!Array.isArray(parsed))return parsed}catch{}try{if(renameSync(path,`${path}.corrupt-${Date.now()}`),!corruptWarned)corruptWarned=!0,console.error(`[rove] ${path} is corrupted; backed up and starting fresh.`)}catch{}return{}}function writeStateFile(state){let path=kvStatePath();mkdirSync(dirname(path),{recursive:!0});let nonce=Math.random().toString(36).slice(2),tmp=`${path}.${process.pid}.${nonce}.tmp`;writeFileSync(tmp,JSON.stringify(state),{encoding:"utf8",mode:384}),renameSync(tmp,path)}function updateStateFile(mutate){let state=loadStateFile();if(mutate(state)!==!1)writeStateFile(state);return state}function patchStateFile(patch){return updateStateFile((state)=>{for(let[key,value]of Object.entries(patch))if(value===void 0)delete state[key];else state[key]=value;return})}function getPersistedBool(key,defaultValue){let value=loadStateFile()[key];return typeof value==="boolean"?value:defaultValue}function setPersistedBool(key,value){patchStateFile({[key]:value})}function replaceStateFile(snapshot){writeStateFile(snapshot)}
3
+ export{readSavedRepos,loadStateFile,updateStateFile,patchStateFile,getPersistedBool,setPersistedBool,replaceStateFile};
@@ -0,0 +1,5 @@
1
+ // @bun
2
+ import{canonPath,normalizeMainRepo,randomDirTaskSuffix,repoWorkingDir,titleFromRepo}from"./chunk-003tvywc.js";import{readLastActiveTaskId,writeLastActiveTaskId}from"./chunk-zb56ck5f.js";import{GitWorktreeManager,defaultExecDeps}from"./chunk-5hhvrvgm.js";import{canonicalize,listWorktreeDirNames}from"./chunk-2jxdzw4r.js";import{resolvePreferredVendor}from"./chunk-f6zsej8e.js";import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{CannotDeleteMainTaskError,DirtyWorktreeError,EmptyBranchDirtyWorktreeError,EmptyBranchError,GitCommandFailedError,IllegalTransitionError,LandConflictError,MainCheckoutDirtyError,MissingRefError,PLACEHOLDER_TASK_TITLE,TaskDeletingError,TaskNotFoundError,WorktreeRemoveFailedError,isPlaceholderDerivedBranch}from"./chunk-aq912vvw.js";import{detectLanguage}from"./chunk-hape5vwj.js";import{createStateCell}from"./chunk-sdyzxayr.js";import{applyJitter,exponentialBackoff}from"./chunk-gwcneg6c.js";import{addSavedRepo,getSavedRepos,isGitRepo,removeSavedRepo,resolveRepoRoot}from"./chunk-k3ksts6g.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{projectRejection,rejectionReason}from"./chunk-9c1e5z6a.js";async function createTaskRow(deps,input){if(!input.repo)throw Error("createTask: repo is required");let repo=(await deps.mainTasks.ensureIfEligible(input.repo,input.projectIntent??"explicit"))?.repo??normalizeMainRepo(input.repo).repo,title=(input.title??PLACEHOLDER_TASK_TITLE).trim()||PLACEHOLDER_TASK_TITLE;return await deps.store.create({repo,title,branch:input.branch??"",worktreePath:"",status:"backlog",kind:"task",vendor:input.vendor??DEFAULT_TASK_VENDOR,...input.command?.trim()?{command:input.command.trim()}:{},...input.modelEffort?{modelEffort:input.modelEffort}:{},...input.groupId?{groupId:input.groupId}:{},...input.dispatcher?{dispatcher:input.dispatcher}:{},...input.routine?{routine:input.routine}:{},...input.baseRef?.trim()?{baseRef:input.baseRef.trim()}:{}})}async function openDirectoryTaskRow(deps,input){if(!input.dir)throw Error("openDirectoryTask: dir is required");let dir=canonPath(input.dir);return deps.store.create({repo:dir,title:input.scratch?"":`${titleFromRepo(dir)}-${randomDirTaskSuffix()}`,branch:"",worktreePath:dir,status:"backlog",kind:"dir",...input.scratch?{scratch:!0}:{},vendor:input.vendor??resolvePreferredVendor()})}async function adoptScratchRepoRow(deps,id,repo){let task=deps.store.get(id);if(!task||task.kind!=="dir"||task.scratch!==!0)return;let dir=canonPath(repo);await deps.store.update(id,{repo:dir,worktreePath:dir,scratch:!1,title:titleFromRepo(dir)})}function parseDirtyPaths(stdout){return stdout.split(`
3
+ `).filter((line)=>line.length>3).map((line)=>line.slice(3).trim()).filter((line)=>line.length>0)}function baseRepoCtx(repo,deps){let basePath=deps.remoteBasePath(repo);return{exec:deps.execForRepo(repo),dir:basePath??repo}}async function landGit(exec,dir,args,opts){let r=await exec.run(["git",...args],{cwd:dir,env:opts?.readOnly?READ_ONLY_GIT_ENV:void 0});return{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode}}async function isDirty(exec,dir){return(await landGit(exec,dir,["status","--porcelain"],{readOnly:!0})).stdout.trim().length>0}async function landPreflight(task,deps=defaultExecDeps){let refuse=(pf,refusal)=>{let refused={...pf,refusal};return{...refused,message:landRefusalError(task,refused).message}},branch=task.branch.trim();if(!branch)throw Error(`landPreflight: task ${task.id} has no branch to land (never materialised)`);let{exec,dir}=baseRepoCtx(task.repo,deps),headOut=await landGit(exec,dir,["symbolic-ref","--short","HEAD"],{readOnly:!0}),landedOn=headOut.stdout.trim();if(headOut.exitCode!==0||!landedOn){let headCommit=await landGit(exec,dir,["rev-parse","--verify","--quiet","HEAD"],{readOnly:!0}),detached=headCommit.exitCode===0&&headCommit.stdout.trim().length>0;return refuse({branch,landedOn:"",baseDir:dir},detached?"DETACHED_HEAD":"UNREADABLE_BASE")}if(landedOn===branch)return refuse({branch,landedOn,baseDir:dir},"SAME_BRANCH");let baseDirty=await isDirty(exec,dir),aheadOut=await landGit(exec,dir,["rev-list","--count",`${landedOn}..${branch}`],{readOnly:!0});if(aheadOut.exitCode!==0){let baseHead=await landGit(exec,dir,["rev-parse","--verify","--quiet","HEAD"],{readOnly:!0});if(baseHead.exitCode!==0||!baseHead.stdout.trim())return refuse({branch,landedOn,baseDirty,baseDir:dir},"UNBORN_BASE");return refuse({branch,landedOn,baseDirty,baseDir:dir},baseDirty?"MAIN_CHECKOUT_DIRTY":"MISSING_REF")}let parsed=Number.parseInt(aheadOut.stdout.trim(),10),base={branch,landedOn,baseDirty,baseDir:dir,...Number.isFinite(parsed)?{ahead:parsed}:{}};if(baseDirty)return refuse(base,"MAIN_CHECKOUT_DIRTY");if(base.ahead!==0)return base;let worktreePath=task.worktreePath.trim();if(worktreePath){let manager=new GitWorktreeManager(deps),dirty=!1;try{dirty=await manager.isDirty(worktreePath)}catch{dirty=!1}if(dirty){let wtExec=deps.execForPath(worktreePath),files=parseDirtyPaths((await landGit(wtExec,worktreePath,["status","--porcelain"],{readOnly:!0})).stdout);return refuse({...base,dirtyFiles:files},"EMPTY_BRANCH_DIRTY_WORKTREE")}}return refuse(base,"EMPTY_BRANCH")}function landRefusalError(task,pf){switch(pf.refusal){case"DETACHED_HEAD":return Error(`landTask: base checkout at ${pf.baseDir} is in detached-HEAD state; check out a branch first`);case"UNREADABLE_BASE":return Error(`landTask: could not read HEAD of the base checkout at ${pf.baseDir} \u2014 is it still a git repo?`);case"UNBORN_BASE":return Error(`landTask: base checkout at ${pf.baseDir} is on '${pf.landedOn}' but has no commits yet, so there is nothing to merge '${pf.branch}' into; make the first commit there (or \`git merge --ff-only ${pf.branch}\`) and land again`);case"SAME_BRANCH":return Error(`landTask: base checkout is already on '${pf.branch}' \u2014 nothing to land onto`);case"MAIN_CHECKOUT_DIRTY":return new MainCheckoutDirtyError(task.repo,pf.baseDir);case"MISSING_REF":return new MissingRefError(pf.branch,pf.landedOn,pf.baseDir);case"EMPTY_BRANCH_DIRTY_WORKTREE":return new EmptyBranchDirtyWorktreeError(pf.branch,pf.landedOn,task.worktreePath.trim(),[...pf.dirtyFiles??[]]);case"EMPTY_BRANCH":return new EmptyBranchError(pf.branch,pf.landedOn)}}import path from"path";async function landTaskWithCleanup(task,opts,deps){if(task.kind==="main")throw Error("landTask: a main task has no branch to land");if(task.kind==="dir")throw Error("landTask: a directory task has no Rove-managed branch to land");let result=await landTask(task,{strategy:opts.strategy}),worktree=opts.removeWorktree===!1?void 0:await removeLandedWorktree(task,opts.callerCwd,deps),branchAnchor=null,branchKept,worktreeGone=!task.worktreePath.trim()||worktree?.removed===!0;if(opts.deleteBranch&&!worktreeGone)branchKept={reason:worktree?.reason??`worktree ${task.worktreePath} was kept, and still has the branch checked out`};else if(opts.deleteBranch)await deps.worktrees.deleteBranch(task.repo,result.branch,{force:!0,onAnchor:(record)=>{branchAnchor=record}});return{...result,...worktree?{worktree}:{},...branchAnchor?{branchAnchor}:{},...branchKept?{branchKept}:{}}}async function removeLandedWorktree(task,callerCwd,deps){let worktreePath=task.worktreePath.trim();if(!worktreePath)return{removed:!1,reason:"task has no worktree on disk (never materialised)"};let wt=canonicalize(worktreePath);if(wt===canonicalize(task.repo))return{removed:!1,reason:"refusing to remove the base checkout"};if(callerCwd){let rel=path.relative(wt,canonicalize(callerCwd));if(rel===""||!rel.startsWith("..")&&!path.isAbsolute(rel))return{removed:!1,reason:`refusing to remove the caller's own worktree (${worktreePath}) \u2014 re-run from outside it`}}if(deps.tearDownSession)try{await deps.tearDownSession(task.id)}catch{}let residue;try{await deps.worktrees.remove(worktreePath,{onResidue:(r)=>{residue=r}})}catch(err){return{removed:!1,reason:errText(err)}}try{await deps.clearWorktreePath(task.id)}catch(err){return{removed:!0,reason:`worktree removed, but clearing the task's worktree path failed: ${errText(err)}`,...residue?{residue}:{}}}return{removed:!0,...residue?{residue}:{}}}function errText(err){return err instanceof Error?err.message:String(err)}async function conflictedFiles(exec,dir){return(await landGit(exec,dir,["diff","--name-only","--diff-filter=U"],{readOnly:!0})).stdout.split(`
4
+ `).map((l)=>l.trim()).filter((l)=>l.length>0)}async function landTask(task,input={},deps=defaultExecDeps){let strategy=input.strategy??"merge",preflight=await landPreflight(task,deps);if(preflight.refusal)throw landRefusalError(task,{...preflight,refusal:preflight.refusal});let{branch,landedOn}=preflight,{exec,dir}=baseRepoCtx(task.repo,deps);if(strategy==="squash"){if((await landGit(exec,dir,["merge","--squash",branch])).exitCode!==0){let files=await conflictedFiles(exec,dir);throw await landGit(exec,dir,["merge","--abort"]).catch(()=>{}),await landGit(exec,dir,["reset","--hard","HEAD"]).catch(()=>{}),new LandConflictError(task.id,branch,files)}let commit=await landGit(exec,dir,["commit","--no-edit","-m",`Land ${branch} (squash)`]);if(commit.exitCode!==0){if((await landGit(exec,dir,["diff","--cached","--quiet"],{readOnly:!0})).exitCode===0)throw await landGit(exec,dir,["reset","--hard","HEAD"]).catch(()=>{}),Error(`landTask: '${branch}' has nothing to land onto '${landedOn}' (already merged or empty)`);throw new GitCommandFailedError(`commit (squash-landing '${branch}' onto '${landedOn}')`,commit.stderr,"the squashed merge is left STAGED in the base checkout \u2014 fix the cause and `git commit` it, or `git reset --hard HEAD` to discard")}}else{let before=(await landGit(exec,dir,["rev-parse","HEAD"],{readOnly:!0})).stdout.trim(),merge=await landGit(exec,dir,["merge","--no-ff","-m",`Land ${branch}`,branch]);if(merge.exitCode!==0){let files=await conflictedFiles(exec,dir);if(await landGit(exec,dir,["merge","--abort"]).catch(()=>{}),files.length===0)throw new GitCommandFailedError(`merge --no-ff (landing '${branch}' onto '${landedOn}')`,merge.stderr,"the merge was aborted, so the base checkout is unchanged");throw new LandConflictError(task.id,branch,files)}let after=(await landGit(exec,dir,["rev-parse","HEAD"],{readOnly:!0})).stdout.trim();if(before===after)throw Error(`landTask: '${branch}' has nothing to land onto '${landedOn}' (already merged or empty)`)}let shaOut=await landGit(exec,dir,["rev-parse","--short","HEAD"],{readOnly:!0});return{branch,strategy,landedOn,commit:shaOut.stdout.trim()}}class MainTaskCoordinator{store;forgetWorktree;locks=new Map;constructor(store,forgetWorktree){this.store=store;this.forgetWorktree=forgetWorktree}async ensure(repo){let task=await this.ensureIfEligible(repo,"explicit");if(task)return task;let{repo:normalizedRepo}=normalizeMainRepo(repo),rejected=projectRejection(normalizedRepo,isGitRepo,"explicit")??"notGitRepo";throw Error(`cannot add ${normalizedRepo} as a project: ${rejectionReason(rejected)}`)}async ensureIfEligible(repo,intent="derived"){let{repo:normalizedRepo,key}=normalizeMainRepo(repo),onThisRoot=(task)=>normalizeMainRepo(task.repo).key===key,existing=this.store.list().find((task)=>task.kind==="main"&&onThisRoot(task));if(existing)return existing;if(projectRejection(normalizedRepo,isGitRepo,intent))return null;let inflight=this.locks.get(key);if(inflight)return inflight;let promise=(async()=>{addSavedRepo(normalizedRepo,{intent:"explicit"});let adoptable=this.store.list().find((task)=>task.kind==="dir"&&task.scratch!==!0&&onThisRoot(task));if(adoptable)return await this.store.update(adoptable.id,this.mainShape(normalizedRepo));return await this.store.create({...this.mainShape(normalizedRepo),status:"backlog",vendor:resolvePreferredVendor(normalizedRepo)})})();this.locks.set(key,promise);try{return await promise}finally{this.locks.delete(key)}}mainShape(normalizedRepo){return{kind:"main",title:titleFromRepo(normalizedRepo),repo:normalizedRepo,branch:"",worktreePath:repoWorkingDir(normalizedRepo)}}async forget(repo){if(!repo)throw Error("forgetProject: repo is required");let key=normalizeMainRepo(repo).key;for(let saved of getSavedRepos())if(normalizeMainRepo(saved).key===key)removeSavedRepo(saved);for(let task of this.store.list()){if(task.kind!=="main")continue;if(normalizeMainRepo(task.repo).key!==key)continue;await this.store.remove(task.id),this.forgetWorktree(task.id)}}}function promotableDirTasks(deps){let claimed=new Set(deps.tasks.filter((task)=>task.kind==="main").map((task)=>task.repo)),seen=new Set,out=[];for(let task of deps.tasks){if(task.kind!=="dir"||task.scratch===!0)continue;let path2=task.repo;if(!path2||claimed.has(path2)||seen.has(path2))continue;if(!deps.isRepoRoot(path2))continue;seen.add(path2),out.push(task)}return out}class TaskDeletionCoordinator{store;worktrees;forgetTask;onSalvage;onResidue;constructor(store,worktrees,forgetTask,onSalvage,onResidue){this.store=store;this.worktrees=worktrees;this.forgetTask=forgetTask;this.onSalvage=onSalvage;this.onResidue=onResidue}async prepare(id,opts){let task=this.store.get(id);if(!task)return!1;if(task.kind==="main")throw new CannotDeleteMainTaskError;if(task.deletion?.phase==="queued"||task.deletion?.phase==="running")return!0;let force=opts?.force===!0;if(task.worktreePath&&!force&&task.kind!=="dir"){let dirty=!1,ignored=[];try{if(dirty=await this.worktrees.isDirty(task.worktreePath),!dirty)ignored=await this.worktrees.ignoredWork(task.worktreePath)}catch{}if(dirty||ignored.length>0)throw new DirtyWorktreeError(task.id,ignored)}return await this.store.update(task.id,{deletion:{phase:"queued",force,deleteBranch:opts?.deleteBranch===!0,requestedAt:new Date().toISOString()}}),!0}async begin(id){let task=this.store.get(id);if(!task||!task.deletion||task.deletion.phase==="error")return!1;if(task.deletion.phase!=="running")await this.store.update(task.id,{deletion:{...task.deletion,phase:"running"}});return!0}async finish(id){let task=this.store.get(id);if(!task?.deletion||task.deletion.phase!=="running")return;try{if(task.worktreePath&&task.kind!=="dir")await this.worktrees.remove(task.worktreePath,{force:task.deletion.force,deleteBranch:task.deletion.deleteBranch===!0,repo:task.repo,branch:task.branch,onSalvage:(record)=>{if(record)this.onSalvage?.(task.id,record)},onResidue:(residue)=>this.onResidue?.(task.id,residue)})}catch(cause){let failure=new WorktreeRemoveFailedError(task.id,cause);throw await this.store.update(task.id,{deletion:{...task.deletion,phase:"error",error:errorMessage(failure)}}),failure}await this.store.remove(task.id),this.forgetTask(task.id)}async deleteNow(id,opts){if(!await this.prepare(id,opts))return;if(!await this.begin(id))return;await this.finish(id)}}var GH_PR_VIEW_FIELDS="number,url,title,state,baseRefName,headRefName,reviewDecision,mergeable,statusCheckRollup";function lifecycleFromState(state,reviewDecision){switch((state??"").toUpperCase()){case"MERGED":return"merged";case"CLOSED":return"closed";case"OPEN":return(reviewDecision??"").toUpperCase()==="APPROVED"?"ready_to_merge":"open";default:return"unknown"}}function entryCheckState(entry){let status=(entry.status??"").toUpperCase(),conclusion=(entry.conclusion??"").toUpperCase(),contextState=(entry.state??"").toUpperCase();if(status&&status!=="COMPLETED")return"pending";if(conclusion){if(conclusion==="SUCCESS"||conclusion==="NEUTRAL"||conclusion==="SKIPPED")return"passing";return"failing"}if(contextState==="SUCCESS")return"passing";if(contextState==="PENDING"||contextState==="EXPECTED")return"pending";if(contextState==="FAILURE"||contextState==="ERROR")return"failing";return"unknown"}function checkStateFromRollup(rollup){if(!rollup||rollup.length===0)return"none";let sawPending=!1,sawPassing=!1;for(let entry of rollup){let s=entryCheckState(entry);if(s==="failing")return"failing";if(s==="pending")sawPending=!0;else if(s==="passing")sawPassing=!0}if(sawPending)return"pending";if(sawPassing)return"passing";return"unknown"}function mapGhPrView(view,at){if(!view||typeof view.number!=="number")return null;return{provider:"github",lifecycle:lifecycleFromState(view.state,view.reviewDecision),checkState:checkStateFromRollup(view.statusCheckRollup),number:view.number,url:view.url,title:view.title,baseRef:view.baseRefName,headRef:view.headRefName,reviewDecision:view.reviewDecision||void 0,mergeable:view.mergeable||void 0,lastCheckedAt:at}}function samePrStatus(a,b){if(a===b)return!0;if(!a||!b)return!1;return a.provider===b.provider&&a.lifecycle===b.lifecycle&&a.checkState===b.checkState&&a.number===b.number&&a.url===b.url&&a.title===b.title&&a.baseRef===b.baseRef&&a.headRef===b.headRef&&a.reviewDecision===b.reviewDecision&&a.mergeable===b.mergeable}var NO_REMOTE_PATTERNS=["none of the git remotes","no git remote","to use github cli in a github repository","not a github repository"],AUTH_PATTERNS=["gh auth login","authentication required","not logged in","http 401","bad credentials","requires authentication"],NETWORK_PATTERNS=["could not resolve host","no such host","dial tcp","connection refused","connection reset","network is unreachable","i/o timeout","timeout","tls handshake","http 5","rate limit","try again"];function matchesAny(haystack,needles){return needles.some((n)=>haystack.includes(n))}function classifyGhFailure(s){if(s.parseError)return{kind:"error",error:"parse"};if(s.timedOut)return{kind:"error",error:"timeout"};if(s.spawnError)return{kind:"error",error:"missing-binary"};let err=(s.stderr??"").toLowerCase();if(matchesAny(err,NO_REMOTE_PATTERNS))return{kind:"error",error:"no-remote"};if(matchesAny(err,AUTH_PATTERNS))return{kind:"error",error:"auth"};if(matchesAny(err,NETWORK_PATTERNS))return{kind:"error",error:"network"};return{kind:"error",error:"unknown"}}function nextPrPoll(outcome,prevFailures,now,cfg,rand=Math.random){let at=(delay)=>now+applyJitter(delay,cfg.jitterRatio,rand);if(outcome.kind==="pr")return{nextAllowedAt:at(outcome.settled?cfg.settledMs:cfg.tickMs),failures:0};if(outcome.kind==="empty")return{nextAllowedAt:at(cfg.noPrMs),failures:0};if(outcome.error==="no-remote")return{nextAllowedAt:at(cfg.noRemoteMs),failures:0};let failures=prevFailures+1;return{nextAllowedAt:at(exponentialBackoff(cfg.failureBaseMs,failures-1,cfg.failureCapMs)),failures}}var TYPE_PREFIXES=new Set(["feat","feature","fix","bugfix","hotfix","chore","docs","doc","refactor","test","tests","ci","build","perf","style","revert","release"]),BRAND_TOKENS=new Set(["rove","kobe"]);function inferBranchStyle(names){let typed=new Map,bare=0;for(let raw of new Set(names)){let name=raw.trim();if(!name||name==="HEAD")continue;let slash=name.indexOf("/");if(slash===-1){bare+=1;continue}let prefix=name.slice(0,slash);if(TYPE_PREFIXES.has(prefix))typed.set(prefix,(typed.get(prefix)??0)+1)}let typedTotal=0;for(let n of typed.values())typedTotal+=n;if(typedTotal===0||typedTotal<bare)return{kind:"bare"};let best="",bestN=0;for(let[prefix,n]of typed)if(n>bestN||n===bestN&&(best===""||prefix<best))best=prefix,bestN=n;return{kind:"typed",defaultPrefix:best}}function slugTokens(title){return title.toLowerCase().replace(/[^a-z0-9]+/g,"-").split("-").filter((t)=>t.length>0&&!BRAND_TOKENS.has(t))}function capSlug(tokens){return tokens.join("-").slice(0,32).replace(/-+$/,"")}function deriveConventionBranch(title,style){let tokens=slugTokens(title);if(style.kind==="typed"){let first=tokens[0];return`${first!==void 0&&TYPE_PREFIXES.has(first)?tokens.shift():style.defaultPrefix}/${capSlug(tokens)||"task"}`}return capSlug(tokens)||"task"}function uniqueBranchName(base,taken,taskId){if(!taken.has(base))return base;for(let n=2;n<=99;n+=1){let candidate=`${base}-${n}`;if(!taken.has(candidate))return candidate}return`${base}-${taskId.slice(-6).toLowerCase()}`}class TaskEditor{store;worktrees;constructor(store,worktrees){this.store=store,this.worktrees=worktrees}requireTask(id){let task=this.store.get(id);if(!task)throw new TaskNotFoundError(String(id));return task}async setTitle(id,title){let trimmed=title.trim();if(!trimmed)throw Error("setTitle: title is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.title===trimmed&&task.scratch!==!0)return;await this.store.update(task.id,{title:trimmed,...task.scratch===!0?{scratch:!1}:{}}),await this.followBranchToTitle(task,trimmed)}async followBranchToTitle(taskBefore,newTitle){if(taskBefore.kind==="main"||!taskBefore.worktreePath)return;if(!isPlaceholderDerivedBranch(taskBefore.branch,taskBefore.id))return;try{let names=await this.worktrees.listBranchNames(taskBefore.repo),base=deriveConventionBranch(newTitle,inferBranchStyle(names));if(base===taskBefore.branch)return;if(await this.worktrees.branchHasUpstream(taskBefore.worktreePath,taskBefore.branch))return;let taken=new Set(names.filter((n)=>n!==taskBefore.branch)),nextBranch=uniqueBranchName(base,taken,taskBefore.id);await this.setBranch(taskBefore.id,nextBranch)}catch(err){console.error(`[rove] follow-branch-to-title failed for ${taskBefore.id}:`,err)}}async setBranch(id,branch){let trimmed=branch.trim();if(!trimmed)throw Error("setBranch: branch is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.kind==="main")throw Error("setBranch: a main task tracks the repo's own branch; rename it with git directly");if(task.kind==="dir")throw Error("setBranch: a directory task tracks its own checkout; rename branches with git directly");if(task.branch===trimmed)return;if(task.worktreePath)await this.worktrees.renameBranch(task.worktreePath,task.branch,trimmed);await this.store.update(task.id,{branch:trimmed})}async observeLanguage(id,text){let observed=detectLanguage(text);if(!observed)return;let task=this.requireTask(id);if(task.observedLanguage===observed)return;await this.store.update(task.id,{observedLanguage:observed})}async setVendor(id,vendor,effort){let task=this.requireTask(id),nextEffort=effort?.trim()?effort.trim():void 0,effortChanges=effort!==void 0&&task.modelEffort!==nextEffort;if(task.vendor===vendor&&!effortChanges)return;await this.store.update(task.id,{vendor,...effort!==void 0?{modelEffort:nextEffort}:{}})}async setCommand(id,command,vendor){let trimmed=command.trim();if(!trimmed)throw Error("setCommand: command is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.command===trimmed&&(vendor===void 0||task.vendor===vendor))return;await this.store.update(task.id,{command:trimmed,...vendor?{vendor}:{}})}async setPinned(id,pinned){let task=this.requireTask(id);if(task.kind==="main")return;let next=pinned??!task.pinned;if((task.pinned??!1)===next)return;await this.store.update(task.id,{pinned:next})}async moveTask(id,delta){let task=this.requireTask(id),isMain=task.kind==="main",groupIds=this.store.list().filter((t)=>isMain?(t.kind??"task")==="main":(t.kind??"task")!=="main"&&t.repo===task.repo&&(t.pinned??!1)===(task.pinned??!1)).map((t)=>String(t.id));await this.store.move(task.id,delta,groupIds)}async setStatus(id,status){let task=this.requireTask(id);if(task.status===status)return;if(task.status==="done"&&status==="error"||task.status==="error"&&status==="done")throw new IllegalTransitionError(task.status,status,task.id);await this.store.update(task.id,{status})}async setPRStatus(id,prStatus){let task=this.requireTask(id);if((task.prStatus?.lastError??null)===(prStatus?.lastError??null)&&samePrStatus(task.prStatus,prStatus??void 0))return;await this.store.update(task.id,{prStatus:prStatus??void 0})}async setQuotaResume(id,state){let task=this.requireTask(id);if((task.quotaResume?.resumeAt??null)===(state?.resumeAt??null))return;await this.store.update(task.id,{quotaResume:state??void 0})}async setLinkedWorkItem(id,item){let task=this.requireTask(id);if((task.linkedWorkItem?.url??null)===(item?.url??null))return;await this.store.update(task.id,{linkedWorkItem:item??void 0})}async setPrompt(id,prompt){if(prompt.trim().length===0)throw Error("setPrompt: prompt is required (empty or whitespace-only rejected)");let task=this.requireTask(id);if(task.prompt===prompt)return;await this.store.update(task.id,{prompt})}}import{basename}from"path";var ANIMAL_NAMES=["aardvark","addax","adder","agouti","albatross","alpaca","anaconda","anchovy","anglerfish","anole","anteater","antelope","ape","argali","armadillo","avocet","axolotl","baboon","badger","banteng","barracuda","basilisk","bass","bat","beagle","bear","beaver","bee","beetle","beluga","betta","bison","blackbird","blenny","bluebird","bluegill","boar","bobcat","bonito","bovid","buffalo","bullfrog","bunting","bushbuck","butterfly","buzzard","caiman","camel","canary","capybara","caracal","cardinal","caribou","carp","cassowary","caterpillar","catfish","chameleon","chamois","char","cheetah","chickadee","chimp","chinchilla","chipmunk","chough","cicada","civet","clam","clownfish","cobra","cockatoo","condor","coot","copperhead","coral","cormorant","cougar","coyote","crab","crane","crawfish","crayfish","cricket","crocodile","crow","cuckoo","curlew","cuttlefish","deer","dikdik","dingo","dolphin","donkey","dormouse","dotterel","dove","dragonfly","dromedary","duck","dugong","dunlin","eagle","echidna","eel","egret","eider","eland","elephant","elk","emu","ermine","falcon","fawn","ferret","finch","firefly","flamingo","flounder","fox","frog","gadwall","gannet","gaur","gazelle","gecko","gemsbok","gerbil","gharial","gibbon","gnu","goat","goby","godwit","goldfish","goose","gopher","goral","gorilla","goshawk","grackle","grasshopper","grayling","grebe","grouse","guanaco","guillemot","guineafowl","guppy","halibut","hammerhead","hamster","hare","harrier","hartebeest","hawk","hedgehog","heron","herring","hippo","hornbill","hornet","horse","hummingbird","hyena","ibex","ibis","iguana","impala","indri","jacana","jackal","jaguar","jay","jellyfish","jerboa","junco","kakapo","kangaroo","kestrel","killdeer","kingfisher","kinglet","kite","kiwi","koala","kookaburra","krait","krill","kudu","ladybug","lamprey","langur","lapwing","lark","lemming","lemur","leopard","limpet","lion","lionfish","lizard","llama","lobster","locust","loon","lorikeet","loris","lynx","macaque","macaw","mackerel","magpie","mallard","mamba","mammoth","manatee","mandrill","manta","mantis","marlin","marmoset","marmot","marten","meerkat","merganser","mink","minnow","mole","mongoose","monitor","monkey","moose","moth","mouflon","mouse","mudpuppy","mule","muntjac","musk","muskox","muskrat","mussel","mustang","narwhal","newt","nightingale","numbat","nuthatch","nyala","ocelot","octopus","okapi","opossum","orangutan","orca","oriole","oryx","osprey","ostrich","otter","owl","oyster","oystercatcher","paca","panda","pangolin","panther","parakeet","parrot","parrotfish","partridge","peafowl","pelican","penguin","perch","petrel","pheasant","pigeon","pika","pike","pintail","pipefish","platypus","plover","pollock","pony","porcupine","porpoise","possum","ptarmigan","puffin","puma","pupfish","python","quail","quetzal","quokka","quoll","rabbit","raccoon","rail","rat","rattler","raven","ray","redpoll","reindeer","remora","rhino","roadrunner","robin","rook","sable","sailfish","salamander","salmon","sandpiper","sardine","scallop","scaup","scorpion","seahorse","seal","serval","shark","shearwater","shrew","shrike","shrimp","siskin","sitatunga","skate","skink","skua","skunk","sloth","smelt","snail","snipe","solenodon","sparrow","spider","springbok","squid","squirrel","starfish","starling","stilt","stingray","stoat","stork","sunbird","sunfish","swallow","swan","swift","swordfish","tahr","takin","tamarin","tanager","tapir","tarantula","tarpon","tarsier","teal","tenrec","terrapin","tern","tetra","thrasher","thrush","tiger","toad","tortoise","toucan","treecreeper","treefrog","trout","tuatara","tuna","turkey","turtle","urchin","urial","vicuna","viper","vole","vulture","wagtail","wallaby","walleye","walrus","warbler","warthog","waterbuck","weasel","wildebeest","wolf","wolverine","wombat","woodcock","woodpecker","wrasse","wren","yak","zebra","zebu","zorilla"];class SlugAllocator{activeSlugs;random;pool;pendingByRepo=new Map;chain=Promise.resolve();constructor(activeSlugs,options={}){this.activeSlugs=activeSlugs;if(this.random=options.random??Math.random,this.pool=options.pool??ANIMAL_NAMES,this.pool.length===0)throw Error("SlugAllocator: animal pool cannot be empty")}async allocate(repo){let previous=this.chain,release;this.chain=new Promise((resolve)=>{release=resolve}),await previous;try{return await this.pickLocked(repo)}finally{release()}}commit(repo,slug){this.deletePending(repo,slug)}cancel(repo,slug){this.deletePending(repo,slug)}async pickLocked(repo){let occupied=await this.occupiedSlugs(repo),candidates=this.pool.filter((n)=>!occupied.has(n));if(candidates.length>0){let pick=candidates[Math.floor(this.random()*candidates.length)];return this.addPending(repo,pick),pick}let base=this.pool[Math.floor(this.random()*this.pool.length)];for(let v=2;;v++){let candidate=`${base}-v${v}`;if(!occupied.has(candidate))return this.addPending(repo,candidate),candidate}}async occupiedSlugs(repo){let set=new Set(this.pendingByRepo.get(repo)??[]);for(let slug of this.activeSlugs(repo))if(slug)set.add(slug);for(let dir of await listWorktreeDirNames(repo))set.add(dir);return set}addPending(repo,slug){let pending=this.pendingByRepo.get(repo);if(!pending)pending=new Set,this.pendingByRepo.set(repo,pending);pending.add(slug)}deletePending(repo,slug){let pending=this.pendingByRepo.get(repo);if(!pending)return;if(pending.delete(slug),pending.size===0)this.pendingByRepo.delete(repo)}}class WorktreeCoordinator{store;worktrees;canonPath;ensureProject;slugs;worktreeLocks=new Map;adoptLocks=new Map;reservedBranches=new Set;constructor(store,worktrees,canonPath2,ensureProject){this.store=store,this.worktrees=worktrees,this.canonPath=canonPath2,this.ensureProject=ensureProject,this.slugs=new SlugAllocator((repo)=>this.store.list().filter((t)=>t.repo===repo&&t.kind!=="main").map((t)=>{return t.worktreePath.match(/([^/\\]+)[/\\]*$/)?.[1]??""}).filter((s)=>s.length>0))}forget(id){this.worktreeLocks.delete(id)}async ensure(task){let inflight=this.worktreeLocks.get(task.id);if(inflight)return inflight;let work=this.createWorktree(task);this.worktreeLocks.set(task.id,work);try{return await work}finally{this.worktreeLocks.delete(task.id)}}async createWorktree(task){let slug=await this.slugs.allocate(task.repo),branch=task.branch||await this.deriveAutoBranch(task),baseRef=task.baseRef,info;try{info=await this.worktrees.createForTask({repo:task.repo,slug,branch,baseRef})}catch(err){throw this.slugs.cancel(task.repo,slug),err}finally{this.reservedBranches.delete(branch)}try{await this.store.update(task.id,{worktreePath:info.path,branch})}catch(err){throw await this.rollbackWorktree(info.path),this.slugs.cancel(task.repo,slug),err}return this.slugs.commit(task.repo,slug),info.path}async deriveAutoBranch(task){let names=await this.worktrees.listBranchNames(task.repo),base=deriveConventionBranch(task.title,inferBranchStyle(names)),taken=new Set([...names,...this.reservedBranches]),branch=uniqueBranchName(base,taken,task.id);return this.reservedBranches.add(branch),branch}async rollbackWorktree(worktreePath){try{await this.worktrees.remove(worktreePath,{force:!0})}catch(err){console.error(`[rove] ensureWorktree rollback failed for ${worktreePath}:`,err)}}async discoverAdoptable(repo){let all=await this.worktrees.listAll(repo),linked=new Set(this.store.list().filter((t)=>t.worktreePath).map((t)=>this.canonPath(t.worktreePath)));return all.filter((wt)=>!linked.has(this.canonPath(wt.path)))}async adopt(input){let target=this.canonPath(input.worktreePath),inflight=this.adoptLocks.get(target);if(inflight)return inflight;let work=this.adoptLocked(input,target);this.adoptLocks.set(target,work);try{return await work}finally{this.adoptLocks.delete(target)}}async adoptLocked(input,target){let existing=this.store.list().find((t)=>t.worktreePath&&this.canonPath(t.worktreePath)===target);if(existing){if(input.ifExists==="return")return existing;throw Error(`adoptWorktree: ${input.worktreePath} is already adopted as a task`)}let match=(await this.worktrees.listAdoptablePaths(input.repo)).find((wt)=>this.canonPath(wt.path)===target);if(!match)throw Error(`adoptWorktree: ${input.worktreePath} is not an adoptable git worktree of ${input.repo} (unknown, detached, or the main checkout)`);let branch=input.branch?.trim()||match.branch,title=(input.title??basename(match.path)).trim()||PLACEHOLDER_TASK_TITLE;return await this.ensureProject(input.repo),this.store.create({repo:input.repo,title,branch,worktreePath:match.path,status:"backlog",kind:"task",vendor:input.vendor??DEFAULT_TASK_VENDOR})}}class Orchestrator{store;worktrees;worktreeCoordinator;editor;deletions;tasksAcc;activeTaskAcc;unsubscribeStore;mainTasks;tearDownSession;constructor(deps){this.store=deps.store,this.worktrees=deps.worktrees,this.tearDownSession=deps.tearDownSession,this.worktreeCoordinator=new WorktreeCoordinator(this.store,this.worktrees,canonPath,(repo)=>this.mainTasks.ensureIfEligible(repo)),this.mainTasks=new MainTaskCoordinator(this.store,(id)=>this.worktreeCoordinator.forget(id)),this.editor=new TaskEditor(this.store,this.worktrees),this.deletions=new TaskDeletionCoordinator(this.store,this.worktrees,(id)=>this.worktreeCoordinator.forget(id),deps.onSalvage,deps.onWorktreeResidue),this.tasksAcc=createStateCell(this.store.list());let persistedFocus=readLastActiveTaskId();this.activeTaskAcc=createStateCell(persistedFocus&&this.store.get(persistedFocus)?persistedFocus:null),this.unsubscribeStore=this.store.subscribe((snapshot)=>{this.tasksAcc.set(snapshot.slice())})}async init(){try{let promotable=promotableDirTasks({tasks:this.store.list(),isRepoRoot:(path2)=>isGitRepo(path2)&&resolveRepoRoot(path2)===path2});for(let task of promotable)await this.mainTasks.ensureIfEligible(task.repo,"explicit")}catch{}}activeTaskSignal(){return this.activeTaskAcc}async setActiveTask(id){let next=id===null?null:String(id);if(next&&this.store.get(next)?.deletion)throw new TaskDeletingError(next);if(this.activeTaskAcc.set(next),next&&this.store.get(next))writeLastActiveTaskId(next),this.store.touchRecency(next)}tasksSignal(){return this.tasksAcc}subscribeTasks(listener){return this.store.subscribe(listener)}dispose(){this.unsubscribeStore()}listTasks(){return this.store.list()}getTask(id){return this.store.get(id)}createTask=(input)=>createTaskRow({store:this.store,mainTasks:this.mainTasks},input);openDirectoryTask=(input)=>openDirectoryTaskRow({store:this.store},input);adoptScratchRepo=(id,repo)=>adoptScratchRepoRow({store:this.store},id,repo);async ensureMainTask(repo){return await this.mainTasks.ensure(repo)}async ensureWorktree(id){let task=this.requireTask(id);if(task.deletion)throw new TaskDeletingError(String(task.id));if(task.kind==="main")return repoWorkingDir(task.repo);if(task.kind==="dir")return task.worktreePath;if(task.worktreePath){if(await this.worktrees.pathExists(task.worktreePath))return task.worktreePath;return await this.worktrees.pruneWorktrees(task.repo),await this.store.update(task.id,{worktreePath:""}),this.worktreeCoordinator.ensure({...task,worktreePath:""})}return this.worktreeCoordinator.ensure(task)}async clearWorktreePath(id){let task=this.store.get(id);if(!task||!task.worktreePath)return;if(task.kind==="main"||task.kind==="dir")return;await this.store.update(task.id,{worktreePath:""}),this.worktreeCoordinator.forget(task.id)}setTitle=(id,title)=>this.editor.setTitle(id,title);setBranch=(id,branch)=>this.editor.setBranch(id,branch);observeLanguage=(id,text)=>this.editor.observeLanguage(id,text);setVendor=(id,vendor,effort)=>this.editor.setVendor(id,vendor,effort);setCommand=(id,command,vendor)=>this.editor.setCommand(id,command,vendor);setPinned=(id,pinned)=>this.editor.setPinned(id,pinned);moveTask=(id,delta)=>this.editor.moveTask(id,delta);setStatus=(id,status)=>this.editor.setStatus(id,status);setPRStatus=(id,prStatus)=>this.editor.setPRStatus(id,prStatus);setLinkedWorkItem=(id,item)=>this.editor.setLinkedWorkItem(id,item);setQuotaResume=(id,state)=>this.editor.setQuotaResume(id,state);setPrompt=(id,prompt)=>this.editor.setPrompt(id,prompt);async deleteTask(id,opts){await this.deletions.deleteNow(id,opts)}async prepareTaskDeletion(id,opts){return this.deletions.prepare(id,opts)}async beginTaskDeletion(id){return this.deletions.begin(id)}async finishTaskDeletion(id){return this.deletions.finish(id)}async landPreflight(id){let task=this.requireTask(id);if(task.kind==="main")throw Error("landTask: a main task has no branch to land");if(task.kind==="dir")throw Error("landTask: a directory task has no Rove-managed branch to land");if(task.deletion)throw new TaskDeletingError(String(task.id));return landPreflight(task)}async landTask(id,opts){let task=this.requireTask(id);if(task.deletion)throw new TaskDeletingError(String(task.id));return landTaskWithCleanup(task,opts??{},{worktrees:this.worktrees,clearWorktreePath:(tid)=>this.clearWorktreePath(tid),tearDownSession:this.tearDownSession})}async forgetProject(repo){await this.mainTasks.forget(repo)}async discoverAdoptableWorktrees(repo){if(!repo)throw Error("discoverAdoptableWorktrees: repo is required");return this.worktreeCoordinator.discoverAdoptable(repo)}async adoptWorktree(input){if(!input.repo)throw Error("adoptWorktree: repo is required");if(!input.worktreePath)throw Error("adoptWorktree: worktreePath is required");return this.worktreeCoordinator.adopt(input)}requireTask(id){let task=this.store.get(id);if(!task)throw new TaskNotFoundError(String(id));return task}}
5
+ export{GH_PR_VIEW_FIELDS,mapGhPrView,samePrStatus,classifyGhFailure,nextPrPoll,parseDirtyPaths,Orchestrator};
@@ -0,0 +1,5 @@
1
+ // @bun
2
+ import{DEFAULT_LOG_ROTATE_CAP_BYTES,shouldRotateLog}from"./chunk-pw6yfj10.js";import{defaultClientLogPath}from"./chunk-x760j10f.js";import{appendFile,mkdir,rename,stat}from"fs/promises";import{dirname}from"path";var context="client";function setClientLogContext(ctx){context=ctx}function coerceError(err){if(err instanceof Error)return{message:err.message,stack:err.stack};let text;try{text=typeof err==="string"?err:JSON.stringify(err)}catch{text=String(err)}return{message:text}}function formatClientEntry(subsystem,message,now=new Date){return`[${now.toISOString()}] client ${context} [${subsystem}] pid=${process.pid}: ${message}
3
+ `}var warnedOnce=!1;function warnOnce(){if(warnedOnce)return;warnedOnce=!0;try{process.stderr.write(`[rove] client log write failed; continuing without it
4
+ `)}catch{}}var writeChain=Promise.resolve();async function rotateClientLogIfNeeded(path){try{let{size}=await stat(path);if(!shouldRotateLog(size,DEFAULT_LOG_ROTATE_CAP_BYTES))return;await rename(path,`${path}.old`)}catch{}}function append(line,logPath){let path=logPath??defaultClientLogPath();writeChain=writeChain.then(async()=>{await rotateClientLogIfNeeded(path);try{await appendFile(path,line)}catch(err){if(err?.code==="ENOENT")await mkdir(dirname(path),{recursive:!0}),await appendFile(path,line);else throw err}}).catch(()=>warnOnce())}function logClient(subsystem,message,logPath){append(formatClientEntry(subsystem,message),logPath)}function logClientError(subsystem,err){let e=coerceError(err);append(formatClientEntry(subsystem,e.stack??e.message))}var onRejection,onException;function installClientCrashHandlers(){if(onRejection||onException)return;onRejection=(reason)=>logClientError("crash-net",reason),onException=(err)=>logClientError("crash-net",err),process.on("unhandledRejection",onRejection),process.on("uncaughtException",onException)}
5
+ export{setClientLogContext,logClient,logClientError,installClientCrashHandlers};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{spawn}from"child_process";function computeNextAllowedAt(startedAt,finishedAt,timedOut,cfg){if(timedOut)return startedAt+cfg.slowRetryMs;return finishedAt+Math.max(cfg.minIntervalMs,(finishedAt-startedAt)*5)}function shouldPoll(state,now){return!state.inFlight&&now>=state.nextAllowedAt}function applyJitter(delayMs,ratio,rand=Math.random){let r=Math.max(0,Math.min(1,ratio)),offset=(rand()*2-1)*delayMs*r;return Math.max(0,delayMs+offset)}function exponentialBackoff(baseMs,attempt,capMs){if(attempt<=0)return Math.min(baseMs,capMs);return Math.min(baseMs*2**attempt,capMs)}function maybeStartScheduledRun(state,cfg,run,onValue){let startedAt=Date.now();if(!shouldPoll(state,startedAt))return!1;state.inFlight=!0;let controller=new AbortController,timer=setTimeout(()=>controller.abort(),cfg.timeoutMs);return(async()=>{let value,ok=!1;try{value=await run(controller.signal),ok=!0}catch{}clearTimeout(timer);let timedOut=controller.signal.aborted;if(state.nextAllowedAt=computeNextAllowedAt(startedAt,Date.now(),timedOut,cfg),state.inFlight=!1,ok&&!timedOut)onValue(value)})(),!0}function decodeCapturedChunks(chunks){return Buffer.concat(chunks.map((c)=>typeof c==="string"?Buffer.from(c):c)).toString("utf8")}function spawnCapture(cmd,args,opts){return new Promise((resolve)=>{let chunks=[],errChunks=[],settled=!1,finish=(status)=>{if(settled)return;settled=!0,resolve({status,stdout:decodeCapturedChunks(chunks),stderr:decodeCapturedChunks(errChunks)})},child=spawn(cmd,args.slice(),{cwd:opts.cwd,stdio:["ignore","pipe","pipe"],env:opts.env,signal:opts.signal,killSignal:"SIGKILL"});child.stdout?.on("data",(chunk)=>{chunks.push(chunk)}),child.stderr?.on("data",(chunk)=>{errChunks.push(chunk)}),child.on("error",()=>finish(null)),child.on("close",(code)=>finish(code))})}export{applyJitter,exponentialBackoff,maybeStartScheduledRun,spawnCapture};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{ensureGlobalKobeHooks,readTextWithTimeout,runHookSubcommand}from"./chunk-49s2zc0h.js";import"./chunk-3ry6prwn.js";import"./chunk-hg5x2wr0.js";import"./chunk-jyv82gf0.js";import"./chunk-jvxh93nz.js";import"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-yhcz2d2r.js";import"./chunk-df7qe9y7.js";import"./chunk-gwcneg6c.js";import"./chunk-7nhdvr5v.js";import"./chunk-2fypr41w.js";import"./chunk-k3ksts6g.js";import"./chunk-gjf604bb.js";import"./chunk-qtke4x42.js";import"./chunk-xy8be792.js";import"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import"./chunk-6dn6h640.js";import"./chunk-h82kzdsn.js";import"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{runHookSubcommand,readTextWithTimeout,ensureGlobalKobeHooks};
@@ -0,0 +1,7 @@
1
+ // @bun
2
+ import{binaryAvailable,resolveEditorCommand}from"./chunk-p7kztgsd.js";import"./chunk-6xppe9bj.js";import"./chunk-2fypr41w.js";import"./chunk-k3ksts6g.js";import"./chunk-gjf604bb.js";import"./chunk-9c1e5z6a.js";import{kvStatePath}from"./chunk-6dn6h640.js";import{activeCliName}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";import{existsSync,mkdirSync,writeFileSync}from"fs";import{dirname}from"path";var CLI_NAME=activeCliName();function printUsage(out){out.write([`Usage: ${CLI_NAME} config [--path]`,"","Open Rove's user config (state.json \u2014 theme, locale, engine + editor prefs)","in your editor. The editor is your configured one (Settings \u2192 General \u2192","Editor); left on Auto it is $VISUAL / $EDITOR, else the first of","nvim / vim / emacs / nano.","Rove re-reads the file on its next launch.","","Options:"," --path Print the config file path and exit (don't open an editor)"," -h, --help Print this help",""].join(`
3
+ `))}async function runConfigSubcommand(argv=[]){if(argv.some((a)=>a==="-h"||a==="--help"||a==="help")){printUsage(process.stdout);return}let path=kvStatePath();if(argv.some((a)=>a==="--path"||a==="path")){console.log(path);return}let unknown=argv.find((a)=>a.length>0);if(unknown!==void 0)process.stderr.write(`${CLI_NAME} config: unexpected argument "${unknown}"
4
+ `),printUsage(process.stderr),process.exit(2);if(!existsSync(path))mkdirSync(dirname(path),{recursive:!0}),writeFileSync(path,`{}
5
+ `);let resolved=await resolveEditorCommand(path);if(!resolved||!await binaryAvailable(resolved.bin))process.stderr.write(`${CLI_NAME} config: no editor found \u2014 set $EDITOR (or Settings \u2192 General \u2192 Editor), or edit directly:
6
+ ${path}
7
+ `),process.exit(1);let proc=Bun.spawn(["sh","-c",resolved.command],{stdin:"inherit",stdout:"inherit",stderr:"inherit"});process.exit(await proc.exited)}export{runConfigSubcommand};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ var BUILTIN_VENDORS=["claude","codex","copilot","kimi"],DEFAULT_VENDOR=BUILTIN_VENDORS[0],ALL_VENDORS=[...BUILTIN_VENDORS];function isBuiltinVendor(id){return id!==void 0&&BUILTIN_VENDORS.includes(id)}function nextVendorWithin(list,current){if(list.length===0)return current;let i=list.indexOf(current);return list[(i+1)%list.length]??list[0]??current}function prevVendorWithin(list,current){if(list.length===0)return current;let i=list.indexOf(current);if(i<0)return list[list.length-1]??current;return list[(i-1+list.length)%list.length]??current}function coerceVendorId(value){let v=value?.trim();return v&&v.length>0?v:"claude"}
3
+ export{BUILTIN_VENDORS,DEFAULT_VENDOR,ALL_VENDORS,isBuiltinVendor,nextVendorWithin,prevVendorWithin,coerceVendorId};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ var CJK=/[\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]/u,ALPHA=/[a-zA-Z\u00C0-\u024F\u0370-\u03FF\u0400-\u04FF]/u;function detectLanguage(text){let cjk=0,alpha=0;for(let ch of text)if(CJK.test(ch))cjk+=1;else if(ALPHA.test(ch))alpha+=1;if(cjk===0&&alpha===0)return null;return cjk*10>alpha?"zh":"en"}
3
+ export{detectLanguage};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ function reduceActivity(previous,kind,detail){switch(kind){case"session-start":case"session-end":case"turn-interrupted":return"idle";case"turn-start":return"running";case"turn-complete":return previous==="running"||previous==="permission_needed"||previous===void 0?"turn_complete":previous;case"turn-failed":return detail?.failure==="rate_limit"||detail?.failure==="billing"?"rate_limited":"error";case"awaiting-input":return"permission_needed";default:return previous??"idle"}}var DEFAULT_ENGINE_STATE_TTL_MS=600000,STICKY_STATES=new Set(["turn_complete","permission_needed","error","rate_limited","dead"]);function resolveEngineStateTtlMs(){let raw=process.env.KOBE_ENGINE_STATE_TTL_MS;if(raw===void 0)return DEFAULT_ENGINE_STATE_TTL_MS;let n=Number(raw);return Number.isFinite(n)&&n>0?n:DEFAULT_ENGINE_STATE_TTL_MS}
3
+ export{reduceActivity,STICKY_STATES,resolveEngineStateTtlMs};
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{BREAKING_VERSIONS,CURRENT_VERSION,compareSemver}from"./chunk-dnb2bmtb.js";import{loadStateFile,patchStateFile}from"./chunk-gjf604bb.js";import{activeCliName}from"./chunk-ef11h2am.js";var LAST_RUN_VERSION_KEY="app.lastRunVersion";function resetGateBlockers(lastRun,current=CURRENT_VERSION,breaking=BREAKING_VERSIONS){if(typeof lastRun!=="string"||lastRun.length===0)return[];let[lo,hi]=compareSemver(lastRun,current)<=0?[lastRun,current]:[current,lastRun];return breaking.filter((b)=>compareSemver(b,lo)>0&&compareSemver(b,hi)<=0)}function enforceResetGate(){let cliName=activeCliName(),lastRun=loadStateFile()[LAST_RUN_VERSION_KEY],blockers=resetGateBlockers(lastRun);if(blockers.length>0){let from=typeof lastRun==="string"?lastRun:"unknown";console.error([`${cliName} ${CURRENT_VERSION}: cannot start \u2014 version ${blockers.join(", ")} introduced breaking changes`,`(last run: ${from}). Your daemon/session state may be incompatible.`,"","Run:",` ${cliName} reset # stop daemon + PTY host + sessions (tasks kept)`,` ${cliName} reset --hard # additionally wipe the task index + UI state`,"","Then relaunch Rove. Worktrees are never touched."].join(`
3
+ `)),process.exit(1)}if(lastRun!==CURRENT_VERSION)stampResetGate()}function stampResetGate(){try{patchStateFile({[LAST_RUN_VERSION_KEY]:CURRENT_VERSION})}catch{}}
4
+ export{LAST_RUN_VERSION_KEY,enforceResetGate,stampResetGate};
@@ -0,0 +1,5 @@
1
+ // @bun
2
+ import{DEFAULT_BASE_REF_CANDIDATES}from"./chunk-vyb5a2rh.js";import{readOnlyGitProcessEnv}from"./chunk-6xppe9bj.js";import"./chunk-wqfp8d9w.js";import{spawnSync}from"child_process";var NONE={baseRef:null,ahead:null,behind:null,diff:null};function git(cwd,args){try{let out=spawnSync("git",[...args],{cwd,encoding:"utf8",stdio:["ignore","pipe","pipe"],env:readOnlyGitProcessEnv()});return out.status===0?out.stdout.trim():null}catch{return null}}function sharesHistory(worktreePath,ref){return git(worktreePath,["merge-base",ref,"HEAD"])!==null}function baseCheckoutBranch(worktreePath){let out=git(worktreePath,["worktree","list","--porcelain"]);if(!out)return null;let line=(out.split(`
3
+
4
+ `,1)[0]??"").split(`
5
+ `).find((l)=>l.startsWith("branch "));if(!line)return null;return line.slice(7).trim().replace(/^refs\/heads\//,"")||null}function resolveBaseRef(worktreePath){let head=git(worktreePath,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);for(let guess of[...head?[head]:[],...DEFAULT_BASE_REF_CANDIDATES]){if(git(worktreePath,["rev-parse","--verify","--quiet",guess])===null)continue;if(sharesHistory(worktreePath,guess))return guess}let base=baseCheckoutBranch(worktreePath);return base&&sharesHistory(worktreePath,base)?base:null}function resolveMeasureBase(worktreePath,recordedBaseRef){if(recordedBaseRef&&git(worktreePath,["rev-parse","--verify","--quiet",recordedBaseRef])!==null)return recordedBaseRef;return resolveBaseRef(worktreePath)}function parseShortstat(text){let num=(re)=>{let m=text.match(re);return m?Number.parseInt(m[1]??"0",10):0};return{files:num(/(\d+) files? changed/),insertions:num(/(\d+) insertions?\(\+\)/),deletions:num(/(\d+) deletions?\(-\)/)}}function readBranchSignals(worktreePath,recordedBaseRef){if(!worktreePath)return NONE;let baseRef=resolveMeasureBase(worktreePath,recordedBaseRef);if(!baseRef)return NONE;let count=(range)=>{let out=git(worktreePath,["rev-list","--count",range]);if(out===null)return null;let n=Number.parseInt(out,10);return Number.isNaN(n)?null:n},ahead=count(`${baseRef}..HEAD`),behind=count(`HEAD..${baseRef}`),statOut=git(worktreePath,["diff","--shortstat",`${baseRef}...HEAD`]),diff=statOut===null?null:parseShortstat(statOut);return{baseRef,ahead,behind,diff}}export{resolveBaseRef,readBranchSignals,parseShortstat};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{ENGINE_NOT_OBSERVED_REASON,ENGINE_START_POLL_MS,ENGINE_START_PROBE_MS,deferOrThrow,deliverHostedPrompt,deliverToKey,ensurePtyHost,findEngineKey,isTaskKey,killTaskSessions,listSessions,listSessionsOrNull,openPtyHost,outcomeFields,resolveComposerManifest,taskKeys}from"./chunk-7ydwn358.js";import"./chunk-p56s3ekm.js";import"./chunk-8arm7k43.js";import"./chunk-hape5vwj.js";import"./chunk-20pt9yqh.js";import"./chunk-q7dr9eh6.js";import"./chunk-jvxh93nz.js";import"./chunk-7q67dz4c.js";import"./chunk-b99tf0jr.js";import"./chunk-jdbfawrm.js";import"./chunk-q9x6d0k6.js";import"./chunk-w298ayjc.js";import"./chunk-sdyzxayr.js";import"./chunk-0sm2k04y.js";import"./chunk-5bn91n19.js";import"./chunk-pdh5w4ht.js";import"./chunk-4wwx51m5.js";import"./chunk-79gqh5p2.js";import"./chunk-3ztek08w.js";import"./chunk-kwe61yx7.js";import"./chunk-gbasmvsc.js";import"./chunk-yhcz2d2r.js";import"./chunk-df7qe9y7.js";import"./chunk-gwcneg6c.js";import"./chunk-7nhdvr5v.js";import"./chunk-2fypr41w.js";import"./chunk-k3ksts6g.js";import"./chunk-gjf604bb.js";import"./chunk-qtke4x42.js";import"./chunk-xy8be792.js";import"./chunk-2brn8e1y.js";import"./chunk-9c1e5z6a.js";import"./chunk-6dn6h640.js";import"./chunk-h82kzdsn.js";import"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-grh6dvfv.js";import"./chunk-pw6yfj10.js";import"./chunk-x760j10f.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{taskKeys,resolveComposerManifest,outcomeFields,openPtyHost,listSessionsOrNull,listSessions,killTaskSessions,isTaskKey,findEngineKey,ensurePtyHost,deliverToKey,deliverHostedPrompt,deferOrThrow,ENGINE_START_PROBE_MS,ENGINE_START_POLL_MS,ENGINE_NOT_OBSERVED_REASON};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{DEFAULT_LOCALE,isLocaleId}from"./chunk-w298ayjc.js";import{BUNDLED_THEME_JSONS}from"./chunk-0sm2k04y.js";import{kvStatePath}from"./chunk-6dn6h640.js";import{RGBA as RGBA2}from"@opentui/core";import{RGBA}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 RGBA.fromInts(r,g,b,fgInts[3])}var BUNDLED_THEMES=BUNDLED_THEME_JSONS,DEFAULT_THEME="claude";function hasBundledTheme(name){return Boolean(BUNDLED_THEMES[name])}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 RGBA2.fromInts(0,0,0,0);if(c.startsWith("#"))return RGBA2.fromHex(c);if(chain.includes(c))return RGBA2.fromInts(0,0,0);let next=defs[c]??theme.theme[c];if(next===void 0)return RGBA2.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??RGBA2.fromHex("#ffffff"),background=out.background??RGBA2.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:RGBA2.fromInts(backgroundR,backgroundG,backgroundB,0),backgroundPanel:RGBA2.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)}}import{readFileSync}from"fs";var LOCALE_KEY="locale";function readPersistedUiPrefs(fallbackTheme,isKnownTheme=hasBundledTheme){try{let parsed=JSON.parse(readFileSync(kvStatePath(),"utf8")),theme=typeof parsed.activeTheme==="string"&&isKnownTheme(parsed.activeTheme)?parsed.activeTheme:fallbackTheme,transparent=parsed.transparentBackground!==!1,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,transparent,focusAccent,locale}}catch{return{theme:fallbackTheme,transparent:!0,focusAccent:null,locale:DEFAULT_LOCALE}}}
3
+ export{BUNDLED_THEMES,DEFAULT_THEME,FOCUS_ACCENT_SLOTS,resolveTheme,applyDisplayOverlay,LOCALE_KEY,readPersistedUiPrefs};
@@ -0,0 +1,11 @@
1
+ // @bun
2
+ import{SUBCOMMAND_VERBS}from"./chunk-s76r56rj.js";import{expandTilde}from"./chunk-0vmrteyg.js";import{BUNDLED_THEME_JSONS,userThemesDir,validateTheme}from"./chunk-0sm2k04y.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-6dn6h640.js";import{activeCliName}from"./chunk-ef11h2am.js";import"./chunk-8ddjfc2v.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";import{existsSync,mkdirSync,readFileSync,readdirSync,unlinkSync,writeFileSync}from"fs";import{basename,join,resolve}from"path";var CLI_NAME=activeCliName(),THEME_VERB_ALIASES={ls:"list",rm:"remove"},BUNDLED_NAMES=Object.keys(BUNDLED_THEME_JSONS);function fail(message){process.stderr.write(`${CLI_NAME} theme: ${message}
3
+ `),process.exit(1)}function failUsage(message){process.stderr.write(`${CLI_NAME} theme: ${message}
4
+
5
+ `),printUsage(),process.exit(2)}function listThemes(){let lines=[];lines.push("bundled:");for(let name of[...BUNDLED_NAMES].sort())lines.push(` ${name} [built-in]`);let dir=userThemesDir(),userFiles=[];try{userFiles=readdirSync(dir).filter((f)=>f.endsWith(".json")).sort()}catch{}if(lines.push(""),lines.push(`user (${dir}):`),userFiles.length===0)lines.push(" (none)");else for(let f of userFiles){let name=f.slice(0,-5),path=join(dir,f),overridesBundled=BUNDLED_NAMES.includes(name)?" (overrides built-in)":"";lines.push(` ${name}${overridesBundled} ${path}`)}process.stdout.write(`${lines.join(`
6
+ `)}
7
+ `)}async function readSource(source){if(/^https?:\/\//i.test(source)){let res;try{res=await fetch(source)}catch(err){fail(`failed to fetch ${source}: ${errorMessage(err)}`)}if(!res.ok)fail(`failed to fetch ${source}: HTTP ${res.status} ${res.statusText}`);let text2=await res.text(),cleanPath=source.split(/[?#]/)[0]??source,file2=basename(cleanPath)||"theme.json",defaultName2=file2.endsWith(".json")?file2.slice(0,-5):file2;return{text:text2,defaultName:defaultName2}}let abs=resolve(process.cwd(),expandTilde(source)),text;try{text=readFileSync(abs,"utf8")}catch(err){fail(`failed to read ${abs}: ${errorMessage(err)}`)}let file=basename(abs),defaultName=file.endsWith(".json")?file.slice(0,-5):file;return{text,defaultName}}function parseAddArgs(args){let source=null,name,force=!1;for(let i=0;i<args.length;i+=1){let a=args[i];if(a==="--force"||a==="-f"){force=!0;continue}if(a==="--name"||a==="-n"){let next=args[i+1];if(next===void 0)failUsage("--name requires a value");name=next,i+=1;continue}if(a.startsWith("--name=")){name=a.slice(7);continue}if(a.startsWith("--"))failUsage(`unknown flag: ${a}`);if(source===null){source=a;continue}failUsage(`unexpected positional argument: ${a}`)}if(source===null)failUsage("missing <source> (URL or path to theme JSON)");return{source,opts:{name,force}}}async function addTheme(args){let{source,opts}=parseAddArgs(args),{text,defaultName}=await readSource(source),parsed;try{parsed=JSON.parse(text)}catch(err){fail(`source is not valid JSON: ${errorMessage(err)}`)}let result=validateTheme(parsed);if(!result.ok)fail(`source is not a valid Rove theme: ${result.reason}`);let name=opts.name??defaultName;if(!name||!/^[a-zA-Z0-9._-]+$/.test(name))fail(`invalid theme name "${name}" (use letters, digits, '.', '_', '-')`);let dir=userThemesDir();mkdirSync(dir,{recursive:!0});let dest=join(dir,`${name}.json`);if(existsSync(dest)&&!opts.force)fail(`${dest} already exists (pass --force to overwrite)`);writeFileSync(dest,`${JSON.stringify(result.theme,null,2)}
8
+ `,"utf8"),process.stdout.write(`installed theme "${name}" -> ${dest}
9
+ `)}function removeTheme(args){let name=args[0];if(!name)failUsage("missing <name>");if(args.length>1)failUsage(`unexpected extra arguments after "${name}"`);if(BUNDLED_NAMES.includes(name))fail(`"${name}" is a built-in theme and cannot be removed`);let dest=join(userThemesDir(),`${name}.json`);if(!existsSync(dest))fail(`no user theme named "${name}" (looked for ${dest})`);unlinkSync(dest),process.stdout.write(`removed theme "${name}" (${dest})
10
+ `)}function printUsage(out=process.stderr){out.write([`Usage: ${CLI_NAME} theme <command> [args]`,"","Commands:"," list List bundled and user-installed themes"," add <source> [--name <name>] Install a theme from a URL or local path"," Pass --force to overwrite an existing user theme"," remove <name> Remove a user-installed theme","",`User themes live under: ${userThemesDir()}`,"Schema: https://raw.githubusercontent.com/sma1lboy/rove/main/packages/kobe/src/tui/context/theme/theme.schema.json",""].join(`
11
+ `))}async function runThemeSubcommand(args){let[action,...rest]=args;if(!action||action==="--help"||action==="-h"||action==="help"){if(printUsage(action?process.stdout:process.stderr),!action)process.exit(2);return}let verb=THEME_VERB_ALIASES[action]??action;if(!SUBCOMMAND_VERBS.theme.includes(verb))failUsage(`unknown action "${action}" (try ${SUBCOMMAND_VERBS.theme.map((v)=>`"${v}"`).join(", ")})`);if(verb==="list"){if(rest.length>0)failUsage(`"${action}" takes no arguments`);listThemes();return}if(verb==="add"){await addTheme(rest);return}if(verb==="remove"){removeTheme(rest);return}failUsage(`unknown action "${action}"`)}export{runThemeSubcommand};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{BREAKING_VERSIONS,CURRENT_VERSION,DEFAULT_RELEASE_CHANNEL,PACKAGE_NAME,RELEASE_CHANNELS,UPDATE_COMMAND,UPDATE_SCRIPT_URL,breakingVersionsCrossed,channelOf,checkLatestVersion,compareSemver,fetchReleaseNotes,fetchReleaseNotesRange,fetchReleaseSummaries,isNewerSemver,owningNpmPrefix,recommendedGlobalInstallCommand,releasePageUrl,repoSlug}from"./chunk-dnb2bmtb.js";import"./chunk-6dn6h640.js";import"./chunk-cb2fpajx.js";import"./chunk-3bfm4hrs.js";import"./chunk-wqfp8d9w.js";export{repoSlug,releasePageUrl,recommendedGlobalInstallCommand,owningNpmPrefix,isNewerSemver,fetchReleaseSummaries,fetchReleaseNotesRange,fetchReleaseNotes,compareSemver,checkLatestVersion,channelOf,breakingVersionsCrossed,UPDATE_SCRIPT_URL,UPDATE_COMMAND,RELEASE_CHANNELS,PACKAGE_NAME,DEFAULT_RELEASE_CHANNEL,CURRENT_VERSION,BREAKING_VERSIONS};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ function argvHasFlag(argv,flag){return argv.some((a)=>a===flag||a.startsWith(`${flag}=`))}function flagValue(argv,flag){for(let i=0;i<argv.length;i++){if(argv[i]===flag)return argv[i+1];if(argv[i].startsWith(`${flag}=`))return argv[i].slice(flag.length+1)}return}
3
+ export{argvHasFlag,flagValue};