@sma1lboy/rove 0.9.252 → 0.9.254

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 (186) hide show
  1. package/dist/cli/{chunk-r0etyq15.js → chunk-08ycv55d.js} +1 -1
  2. package/dist/cli/chunk-0g1me47p.js +2 -0
  3. package/dist/cli/{chunk-cvrtapqt.js → chunk-13msr643.js} +1 -1
  4. package/dist/cli/chunk-18dpws0y.js +2 -0
  5. package/dist/cli/{chunk-gaf6n1ea.js → chunk-1e6jbj70.js} +1 -1
  6. package/dist/cli/{chunk-07jq0271.js → chunk-1mpheecn.js} +1 -1
  7. package/dist/cli/{chunk-57wm48dh.js → chunk-1yzg4hzy.js} +1 -1
  8. package/dist/cli/{chunk-md094j05.js → chunk-278sc87n.js} +1 -1
  9. package/dist/cli/{chunk-q854fweb.js → chunk-3jnw3ftt.js} +1 -1
  10. package/dist/cli/chunk-3r8v2gza.js +2 -0
  11. package/dist/cli/{chunk-34468esa.js → chunk-4mxn5jg6.js} +1 -1
  12. package/dist/cli/{chunk-2ks86x2d.js → chunk-4myck788.js} +1 -1
  13. package/dist/cli/{chunk-sgegp9x9.js → chunk-4zhmbqt3.js} +1 -1
  14. package/dist/cli/chunk-5a6b4kv9.js +4 -0
  15. package/dist/cli/{chunk-5hhr44fc.js → chunk-5b7pd8j5.js} +1 -1
  16. package/dist/cli/chunk-5d0vb6v9.js +2 -0
  17. package/dist/cli/{chunk-9e21z4gn.js → chunk-5fhrns31.js} +1 -1
  18. package/dist/cli/{chunk-m3bz62v4.js → chunk-5j6z32fh.js} +1 -1
  19. package/dist/cli/chunk-5s4g1bkx.js +2 -0
  20. package/dist/cli/{chunk-q2fnt7gm.js → chunk-68gxqtse.js} +1 -1
  21. package/dist/cli/chunk-68pcd00x.js +2 -0
  22. package/dist/cli/chunk-6d5csfp4.js +2 -0
  23. package/dist/cli/{chunk-pgmv2hwf.js → chunk-6g5wvt5m.js} +2 -2
  24. package/dist/cli/{chunk-36pkmg07.js → chunk-6wxnkz3c.js} +10 -10
  25. package/dist/cli/{chunk-jn7vr075.js → chunk-6zvh002j.js} +1 -1
  26. package/dist/cli/{chunk-axmpjma9.js → chunk-7cd1epfw.js} +1 -1
  27. package/dist/cli/chunk-7ghwdjdc.js +3 -0
  28. package/dist/cli/chunk-7wga6bet.js +8 -0
  29. package/dist/cli/{chunk-jwnhthx9.js → chunk-7zpkyrxy.js} +1 -1
  30. package/dist/cli/{chunk-npb9xz3y.js → chunk-80zzjcvp.js} +1 -1
  31. package/dist/cli/{chunk-namxa4wy.js → chunk-8bd054vx.js} +1 -1
  32. package/dist/cli/{chunk-s5k3g5ra.js → chunk-9dendh71.js} +1 -1
  33. package/dist/cli/chunk-9g0vz9dk.js +209 -0
  34. package/dist/cli/chunk-9vd6fv1k.js +3 -0
  35. package/dist/cli/{chunk-tntdcyra.js → chunk-afwh7as3.js} +1 -1
  36. package/dist/cli/{chunk-9sta3ak4.js → chunk-ant4k6dm.js} +1 -1
  37. package/dist/cli/chunk-avz72132.js +3 -0
  38. package/dist/cli/chunk-ax7wzcam.js +2 -0
  39. package/dist/cli/{chunk-zk5qkkb1.js → chunk-axxf5dkq.js} +1 -1
  40. package/dist/cli/{chunk-a7kq09ke.js → chunk-b31cte10.js} +1 -1
  41. package/dist/cli/{chunk-fktvtdkb.js → chunk-bphs6am4.js} +1 -1
  42. package/dist/cli/chunk-cjxvb9vg.js +2 -0
  43. package/dist/cli/chunk-cm923k09.js +52 -0
  44. package/dist/cli/{chunk-6a4xqzqf.js → chunk-d48g9zzm.js} +3 -3
  45. package/dist/cli/{chunk-zzzm2cfx.js → chunk-d4mvprvq.js} +2 -2
  46. package/dist/cli/{chunk-952aedqm.js → chunk-ddc4t38t.js} +1 -1
  47. package/dist/cli/{chunk-resmnaxq.js → chunk-dehnv06q.js} +1 -1
  48. package/dist/cli/{chunk-y1cb8pj5.js → chunk-dqprpnd6.js} +1 -1
  49. package/dist/cli/chunk-dx72asyw.js +2 -0
  50. package/dist/cli/{chunk-e8pv3b92.js → chunk-e5vnptx5.js} +1 -1
  51. package/dist/cli/chunk-edsm15ht.js +4 -0
  52. package/dist/cli/{chunk-2rfyjb3y.js → chunk-ef7ckm5b.js} +1 -1
  53. package/dist/cli/{chunk-s2t9acrv.js → chunk-f6836h0n.js} +1 -1
  54. package/dist/cli/{chunk-s5a5dyab.js → chunk-fnsch8kr.js} +2 -2
  55. package/dist/cli/chunk-ft6ftksv.js +2 -0
  56. package/dist/cli/{chunk-trjve2xz.js → chunk-fwt0t2h7.js} +1 -1
  57. package/dist/cli/{chunk-ra40m849.js → chunk-gb3qb83h.js} +1 -1
  58. package/dist/cli/chunk-ghyz3fd7.js +4 -0
  59. package/dist/cli/chunk-gqpka00s.js +30 -0
  60. package/dist/cli/{chunk-4ays3krf.js → chunk-hqp8b49k.js} +2 -2
  61. package/dist/cli/{chunk-h3q3r1py.js → chunk-hzzq6pdb.js} +1 -1
  62. package/dist/cli/{chunk-x8pk5cyf.js → chunk-j19gkhzh.js} +1 -1
  63. package/dist/cli/{chunk-b67pjyyg.js → chunk-j26zqrnq.js} +1 -1
  64. package/dist/cli/{chunk-24dryfqb.js → chunk-j7831wcj.js} +1 -1
  65. package/dist/cli/{chunk-t3v57v42.js → chunk-j84zbw79.js} +2 -2
  66. package/dist/cli/chunk-j9c9tdfg.js +2 -0
  67. package/dist/cli/{chunk-zcadc92x.js → chunk-jetsx9zr.js} +1 -1
  68. package/dist/cli/{chunk-5q08srg6.js → chunk-jtpjdmb6.js} +1 -1
  69. package/dist/cli/chunk-jwtqe209.js +2 -0
  70. package/dist/cli/{chunk-w2sp489k.js → chunk-k3wzznqw.js} +1 -1
  71. package/dist/cli/chunk-k7ke95vy.js +5 -0
  72. package/dist/cli/chunk-k9ahks28.js +41 -0
  73. package/dist/cli/{chunk-nz9nmp4v.js → chunk-kwd59v51.js} +1 -1
  74. package/dist/cli/{chunk-j6t7xvm3.js → chunk-m0cbndc2.js} +1 -1
  75. package/dist/cli/{chunk-a7m7w6d1.js → chunk-m6qv5rsv.js} +1 -1
  76. package/dist/cli/{chunk-4e1wcgw7.js → chunk-mpdfhvgs.js} +3 -3
  77. package/dist/cli/chunk-mxkm0snt.js +2 -0
  78. package/dist/cli/chunk-n3wdy4z4.js +2 -0
  79. package/dist/cli/{chunk-tfqrc2v1.js → chunk-n5xj11ps.js} +3 -3
  80. package/dist/cli/{chunk-kda565xs.js → chunk-p5902z3e.js} +1 -1
  81. package/dist/cli/chunk-pahcf9td.js +3 -0
  82. package/dist/cli/{chunk-rc8baevh.js → chunk-pkq8n3gs.js} +2 -2
  83. package/dist/cli/{chunk-2bxts9pp.js → chunk-pvah9q79.js} +1 -1
  84. package/dist/cli/chunk-pyv2ywxr.js +3 -0
  85. package/dist/cli/chunk-qb6ktr8a.js +2 -0
  86. package/dist/cli/{chunk-mw0ysrpd.js → chunk-qk5f6p3e.js} +1 -1
  87. package/dist/cli/{chunk-rxge7bh5.js → chunk-qkd4eweb.js} +1 -1
  88. package/dist/cli/{chunk-h7y9v8k1.js → chunk-r4bn0mtb.js} +1 -1
  89. package/dist/cli/{chunk-ayhkcv0w.js → chunk-r7q7s63y.js} +2 -2
  90. package/dist/cli/{chunk-cbd6y9at.js → chunk-rf4z7b6g.js} +1 -1
  91. package/dist/cli/{chunk-25867jnk.js → chunk-rn97jntv.js} +1 -1
  92. package/dist/cli/{chunk-1tebqkdv.js → chunk-rnxk3587.js} +1 -1
  93. package/dist/cli/chunk-s96qnht3.js +2 -0
  94. package/dist/cli/chunk-sma961wh.js +3 -0
  95. package/dist/cli/{chunk-p2jeq98m.js → chunk-stcvcsfm.js} +1 -1
  96. package/dist/cli/{chunk-qh4y4e27.js → chunk-sxhjvr0w.js} +1 -1
  97. package/dist/cli/{chunk-0gxa04rx.js → chunk-sxt12set.js} +1 -1
  98. package/dist/cli/chunk-tbq3t259.js +2 -0
  99. package/dist/cli/{chunk-jp31bpgp.js → chunk-tewt7vre.js} +1 -1
  100. package/dist/cli/{chunk-1v8y9xtk.js → chunk-tmz0wzq8.js} +1 -1
  101. package/dist/cli/{chunk-zb5d61xa.js → chunk-tnft1xw4.js} +1 -1
  102. package/dist/cli/{chunk-032g0ahy.js → chunk-tq6pq1ws.js} +1 -1
  103. package/dist/cli/{chunk-x0rvg54z.js → chunk-v0jvt60f.js} +1 -1
  104. package/dist/cli/{chunk-qyfmfpjg.js → chunk-v7prawj1.js} +1 -1
  105. package/dist/cli/chunk-v8s0s21v.js +2 -0
  106. package/dist/cli/{chunk-t5qayy7m.js → chunk-v9dcyjmj.js} +1 -1
  107. package/dist/cli/chunk-v9fgdd90.js +3 -0
  108. package/dist/cli/chunk-vfwbgx85.js +2 -0
  109. package/dist/cli/{chunk-a1wjg2cv.js → chunk-vvw1njx5.js} +1 -1
  110. package/dist/cli/chunk-vzn94t0z.js +6 -0
  111. package/dist/cli/{chunk-vgknea9y.js → chunk-wbtebbrv.js} +1 -1
  112. package/dist/cli/{chunk-meyfwc50.js → chunk-wkk63qck.js} +1 -1
  113. package/dist/cli/chunk-wn2w5ar9.js +2 -0
  114. package/dist/cli/{chunk-2s762g8n.js → chunk-wsv6tw1b.js} +1 -1
  115. package/dist/cli/{chunk-2n1n70f2.js → chunk-x40h0f1w.js} +1 -1
  116. package/dist/cli/{chunk-0y4qgnby.js → chunk-x5ymh8ev.js} +1 -1
  117. package/dist/cli/{chunk-568q390y.js → chunk-x7r75e3p.js} +2 -2
  118. package/dist/cli/{chunk-7h7270rz.js → chunk-x7ryv67y.js} +2 -2
  119. package/dist/cli/{chunk-phpt1d3e.js → chunk-x951qvk5.js} +1 -1
  120. package/dist/cli/{chunk-ebhbtvhd.js → chunk-xdhs40fx.js} +1 -1
  121. package/dist/cli/chunk-xg6zg6kz.js +2 -0
  122. package/dist/cli/{chunk-21ek142k.js → chunk-xkr7fwvb.js} +1 -1
  123. package/dist/cli/{chunk-nqtvthqg.js → chunk-xpxxgzw9.js} +1 -1
  124. package/dist/cli/{chunk-7j00hbq5.js → chunk-y330t2bt.js} +2 -2
  125. package/dist/cli/{chunk-hq9tbzqa.js → chunk-y55zpren.js} +1 -1
  126. package/dist/cli/chunk-yebn33mf.js +2 -0
  127. package/dist/cli/chunk-ykdpg0zd.js +15 -0
  128. package/dist/cli/{chunk-qstjfseh.js → chunk-yshp8cmx.js} +1 -1
  129. package/dist/cli/chunk-z3zaa155.js +3 -0
  130. package/dist/cli/{chunk-npwzmmv9.js → chunk-z7zm8h1q.js} +2 -2
  131. package/dist/cli/index.js +8 -8
  132. package/dist/cli/pty-host-node.mjs +3 -0
  133. package/dist/cli/rove-run.js +1 -1
  134. package/dist/cli/rove.js +1 -1
  135. package/dist/completions/rove.bash +1 -1
  136. package/dist/completions/rove.fish +1 -1
  137. package/dist/completions/rove.zsh +1 -1
  138. package/dist/skills/rove/SKILL.md +61 -2
  139. package/dist/skills/rove/references/api-flags.md +75 -29
  140. package/dist/web/assets/{index-DHlgMx7L.js → index-BydepNFM.js} +3 -3
  141. package/dist/web/index.html +1 -1
  142. package/dist/web-ui/assets/{harness-BHiciz5A.js → harness-dYkQBfYz.js} +3 -3
  143. package/dist/web-ui/assets/{index-BkxJISAI.js → index-ByMdqeTv.js} +2 -2
  144. package/dist/web-ui/index.html +1 -1
  145. package/package.json +3 -3
  146. package/dist/cli/chunk-17pg88dq.js +0 -22
  147. package/dist/cli/chunk-1zwp3ase.js +0 -2
  148. package/dist/cli/chunk-2bp01vf2.js +0 -2
  149. package/dist/cli/chunk-2g2w5vvn.js +0 -2
  150. package/dist/cli/chunk-564jgrb3.js +0 -2
  151. package/dist/cli/chunk-5qxp7xx3.js +0 -2
  152. package/dist/cli/chunk-6f01fsje.js +0 -2
  153. package/dist/cli/chunk-7zxf47xb.js +0 -2
  154. package/dist/cli/chunk-8e0nmegv.js +0 -2
  155. package/dist/cli/chunk-9dregrj6.js +0 -5
  156. package/dist/cli/chunk-9h940gnr.js +0 -2
  157. package/dist/cli/chunk-9mcpqrx8.js +0 -2
  158. package/dist/cli/chunk-bhm24ne6.js +0 -9
  159. package/dist/cli/chunk-c0ksxg3z.js +0 -3
  160. package/dist/cli/chunk-cb1dg7nz.js +0 -2
  161. package/dist/cli/chunk-ccn7pq03.js +0 -5
  162. package/dist/cli/chunk-cpv1rpc7.js +0 -2
  163. package/dist/cli/chunk-csdttpme.js +0 -52
  164. package/dist/cli/chunk-fz0xfw86.js +0 -2
  165. package/dist/cli/chunk-h89ghyex.js +0 -2
  166. package/dist/cli/chunk-jnj2kk2h.js +0 -3
  167. package/dist/cli/chunk-kqv7t8jk.js +0 -8
  168. package/dist/cli/chunk-kx0wzjj4.js +0 -2
  169. package/dist/cli/chunk-m2t2n474.js +0 -6
  170. package/dist/cli/chunk-n2xemv4a.js +0 -2
  171. package/dist/cli/chunk-n92fz0hn.js +0 -2
  172. package/dist/cli/chunk-nj53wrzz.js +0 -2
  173. package/dist/cli/chunk-pdvyfz3n.js +0 -3
  174. package/dist/cli/chunk-pj3gnkfr.js +0 -3
  175. package/dist/cli/chunk-q3xt0mqt.js +0 -3
  176. package/dist/cli/chunk-qzsahxd9.js +0 -3
  177. package/dist/cli/chunk-r2c5nbcq.js +0 -4
  178. package/dist/cli/chunk-rf0jrh3q.js +0 -2
  179. package/dist/cli/chunk-rj7fwa30.js +0 -2
  180. package/dist/cli/chunk-sbn5pbz9.js +0 -2
  181. package/dist/cli/chunk-va0n5rwm.js +0 -39
  182. package/dist/cli/chunk-va5am5n6.js +0 -2
  183. package/dist/cli/chunk-vd8qqev9.js +0 -4
  184. package/dist/cli/chunk-vwpcv7j1.js +0 -4
  185. package/dist/cli/chunk-yknavm97.js +0 -3
  186. package/dist/cli/chunk-yt24rrvx.js +0 -2
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{parse}from"./chunk-w7zv47mp.js";import{OWNER_ONLY_FILE_MODE}from"./chunk-yt15y085.js";import{PLUGIN_EVENT_NAMES}from"./chunk-278sc87n.js";import{preRenameStateDir}from"./chunk-b39sdtt0.js";import{ROVE_STATE_DIR_BASENAME,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import{existsSync,readFileSync}from"fs";import{basename,join}from"path";var PLUGIN_PLATFORMS=["macos","linux","windows"];class ManifestError extends Error{}function fail(message){throw new ManifestError(`rove-plugin.toml: ${message}`)}function asString(value,field){if(typeof value!=="string"||value.length===0)fail(`\`${field}\` must be a non-empty string`);return value}function asSettingDefault(value,field){if(value===void 0||value===!1)return;if(value===!0)return"1";if(typeof value==="number"&&Number.isFinite(value))return String(value);return asString(value,field)}var TIMEOUT_MIN_MS=100,TIMEOUT_MAX_MS=600000;function asTimeoutMs(value,field){if(value===void 0)return;if(typeof value!=="number"||!Number.isInteger(value)||value<TIMEOUT_MIN_MS||value>TIMEOUT_MAX_MS)fail(`\`${field}\` must be a whole number of milliseconds between ${TIMEOUT_MIN_MS} and ${TIMEOUT_MAX_MS}`);return value}function asCommand(value,field){if(!Array.isArray(value)||value.length===0||!value.every((v)=>typeof v==="string"&&v.length>0))fail(`\`${field}\` must be a non-empty array of strings (argv form)`);return value}function asPlatforms(value,field){if(value===void 0)return;if(!Array.isArray(value)||!value.every((v)=>PLUGIN_PLATFORMS.includes(v)))fail(`\`${field}\` must be an array drawn from ${PLUGIN_PLATFORMS.join(", ")}`);return value}function asTableArray(value,field){if(value===void 0)return[];if(!Array.isArray(value)||!value.every((v)=>typeof v==="object"&&v!==null&&!Array.isArray(v)))fail(`\`[[${field}]]\` must be an array of tables`);return value}function asStringArray(value,field){if(value===void 0)return;if(!Array.isArray(value)||!value.every((v)=>typeof v==="string"&&v.length>0))fail(`\`${field}\` must be a non-empty array of strings`);return value}import{isAbsolute,normalize,sep}from"path";var DEFAULT_PAGE_ORDER=100;function insidePlugin(entry){if(isAbsolute(entry))return!1;return normalize(entry).split(/[\\/]/)[0]!==".."&&!normalize(entry).startsWith(`..${sep}`)}function parsePages(raw,localId){let pages=asTableArray(raw,"pages").map((t,i)=>{let id=asString(t.id,`pages[${i}].id`);if(!localId.test(id))fail(`page id \`${id}\` may not contain dots`);let entry=asString(t.entry,`pages[${i}].entry`);if(!insidePlugin(entry))fail(`page \`${id}\` entry \`${entry}\` must be a path inside the plugin`);let order=t.order??DEFAULT_PAGE_ORDER;if(typeof order!=="number"||!Number.isInteger(order))fail(`\`pages[${i}].order\` must be an integer`);let action=t.action===void 0?void 0:asString(t.action,`pages[${i}].action`);return{id,title:asString(t.title,`pages[${i}].title`),entry,order,...action?{action}:{}}}),seen=new Set;for(let page of pages){if(seen.has(page.id))fail(`duplicate page id \`${page.id}\``);seen.add(page.id)}return pages}var SETTING_KEY_RE=/^[A-Za-z_][A-Za-z0-9_]*$/,RESERVED_SETTING_KEYS=["PATH","HOME","SHELL","IFS","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","NODE_OPTIONS","BUN_INSPECT","PYTHONPATH","PYTHONSTARTUP","PERL5OPT","PERL5LIB","RUBYOPT","BASH_ENV","ENV","GIT_SSH_COMMAND","GIT_SSH","GIT_EXTERNAL_DIFF","GIT_PAGER","PAGER","EDITOR","VISUAL"];function settingKeyRejection(key){if(!SETTING_KEY_RE.test(key))return`\`${key}\` is not a valid env var name (${SETTING_KEY_RE.source})`;if(RESERVED_SETTING_KEYS.includes(key))return`\`${key}\` is reserved; it steers how the plugin's own process runs`;return null}var PLUGIN_MANIFEST_FILENAME="rove-plugin.toml",PLUGIN_MANIFEST_FILENAMES=[PLUGIN_MANIFEST_FILENAME],RESERVED_ENGINE_IDS=["claude","codex","copilot","kimi","pi","omp","gemini","opencode","cursor","grok","droid","amp","devin","qodercli","cline","kiro","maki","antigravity","bob","hermes","kilo","mastracode"];function pluginManifestPath(root){for(let filename of PLUGIN_MANIFEST_FILENAMES){let path=join(root,filename);if(existsSync(path))return path}return null}function readPluginManifest(root){let path=pluginManifestPath(root);if(!path)throw new ManifestError(`no ${PLUGIN_MANIFEST_FILENAMES.join(" or ")} found at ${root}`);return parsePluginManifest(readFileSync(path,"utf8"),basename(path))}var PLUGIN_ID_RE=/^[A-Za-z0-9][A-Za-z0-9._:-]*$/,LOCAL_ID_RE=/^[A-Za-z0-9][A-Za-z0-9_:-]*$/;function qualifiedActionId(pluginId,actionId){return`${pluginId}.${actionId}`}function currentPluginPlatform(platform=process.platform){if(platform==="darwin")return"macos";if(platform==="linux")return"linux";if(platform==="win32")return"windows";return}function supportsPlatform(item,manifest,platform){let declared=item.platforms??manifest.platforms;if(!declared)return!0;return platform!==void 0&&declared.includes(platform)}function parsePluginManifest(text,filename=PLUGIN_MANIFEST_FILENAME){try{return parseCanonicalPluginManifest(text)}catch(err){if(filename!==PLUGIN_MANIFEST_FILENAME&&err instanceof ManifestError)throw new ManifestError(err.message.replace(/^rove-plugin\.toml:/,`${filename}:`));throw err}}function parseCanonicalPluginManifest(text){let raw;try{raw=parse(text)}catch(err){fail(`invalid TOML \u2014 ${err instanceof Error?err.message:String(err)}`)}let warnings=[],id=asString(raw.id,"id");if(!PLUGIN_ID_RE.test(id))fail(`plugin id \`${id}\` may use ASCII letters, digits, dot, colon, underscore, hyphen`);let name=asString(raw.name,"name"),version=asString(raw.version,"version"),rawMinVersion=raw.min_rove_version,minRoveVersion=asString(rawMinVersion,"min_rove_version"),description=raw.description===void 0?void 0:asString(raw.description,"description"),platforms=asPlatforms(raw.platforms,"platforms");if(!platforms)warnings.push("no top-level `platforms` declared; assuming the plugin runs everywhere");let build=asTableArray(raw.build,"build").map((t,i)=>({command:asCommand(t.command,`build[${i}].command`),platforms:asPlatforms(t.platforms,`build[${i}].platforms`)})),startup=asTableArray(raw.startup,"startup").map((t,i)=>({command:asCommand(t.command,`startup[${i}].command`),platforms:asPlatforms(t.platforms,`startup[${i}].platforms`),timeoutMs:asTimeoutMs(t.timeout_ms,`startup[${i}].timeout_ms`)})),shutdown=asTableArray(raw.shutdown,"shutdown").map((t,i)=>({command:asCommand(t.command,`shutdown[${i}].command`),platforms:asPlatforms(t.platforms,`shutdown[${i}].platforms`),timeoutMs:asTimeoutMs(t.timeout_ms,`shutdown[${i}].timeout_ms`)})),actions=asTableArray(raw.actions,"actions").map((t,i)=>{let actionId=asString(t.id,`actions[${i}].id`);if(t.timeout_ms!==void 0)warnings.push(`actions[${i}] declares \`timeout_ms\`; actions are user-invoked and are never killed on a deadline`);if(!LOCAL_ID_RE.test(actionId))fail(`action id \`${actionId}\` may not contain dots`);return{id:actionId,title:asString(t.title,`actions[${i}].title`),command:asCommand(t.command,`actions[${i}].command`),platforms:asPlatforms(t.platforms,`actions[${i}].platforms`)}}),seen=new Set;for(let a of actions){if(seen.has(a.id))fail(`duplicate action id \`${a.id}\``);seen.add(a.id)}let panes=asTableArray(raw.panes,"panes").map((t,i)=>{let paneId=asString(t.id,`panes[${i}].id`);if(!LOCAL_ID_RE.test(paneId))fail(`pane id \`${paneId}\` may not contain dots`);if(t.timeout_ms!==void 0)warnings.push(`panes[${i}] declares \`timeout_ms\`; a pane is a terminal the user closes, not a bounded hook`);if(t.placement!==void 0&&t.placement!=="tab"&&t.placement!=="split")warnings.push(`pane \`${paneId}\` placement \`${String(t.placement)}\` is not supported yet; opening as a split`);return{id:paneId,title:asString(t.title,`panes[${i}].title`),placement:t.placement==="tab"?"tab":"split",command:asCommand(t.command,`panes[${i}].command`),platforms:asPlatforms(t.platforms,`panes[${i}].platforms`)}}),paneSeen=new Set;for(let p of panes){if(paneSeen.has(p.id))fail(`duplicate pane id \`${p.id}\``);paneSeen.add(p.id)}let pages=parsePages(raw.pages,LOCAL_ID_RE),events=asTableArray(raw.events,"events").flatMap((t,i)=>{let on=asString(t.on,`events[${i}].on`),hook={on,command:asCommand(t.command,`events[${i}].command`),platforms:asPlatforms(t.platforms,`events[${i}].platforms`),timeoutMs:asTimeoutMs(t.timeout_ms,`events[${i}].timeout_ms`)};if(!PLUGIN_EVENT_NAMES.includes(on))warnings.push(`unknown event \`${on}\`; this hook will never fire on this Rove version`);return[hook]}),settings=asTableArray(raw.settings,"settings").map((t,i)=>{let type=asString(t.type,`settings[${i}].type`);if(type!=="string"&&type!=="number"&&type!=="boolean"&&type!=="enum"&&type!=="secret")fail(`settings[${i}].type must be string | number | boolean | enum | secret`);let options=t.options===void 0?void 0:Array.isArray(t.options)&&t.options.every((o)=>typeof o==="string"&&o.length>0)?t.options:fail(`settings[${i}].options must be an array of strings`);if(type==="enum"&&(!options||options.length===0))fail(`settings[${i}] enum needs \`options\``);let settingDefault=asSettingDefault(t.default,`settings[${i}].default`),key=asString(t.key,`settings[${i}].key`),rejection=settingKeyRejection(key);if(rejection)fail(`settings[${i}].key ${rejection}`);return{key,label:asString(t.label,`settings[${i}].label`),type,...options?{options}:{},...settingDefault===void 0?{}:{default:settingDefault}}}),fileHandlers=asTableArray(raw.file_handlers,"file_handlers").map((t,i)=>{let pattern=asString(t.pattern,`file_handlers[${i}].pattern`);try{new RegExp(pattern)}catch{fail(`file_handlers[${i}].pattern is not a valid regex`)}let action=asString(t.action,`file_handlers[${i}].action`);if(!actions.some((a)=>a.id===action))fail(`file_handlers[${i}] names unknown action \`${action}\``);return{pattern,action}}),engines=asTableArray(raw.engines,"engines").map((t,i)=>{let engineId=asString(t.id,`engines[${i}].id`);if(!LOCAL_ID_RE.test(engineId))fail(`engine id \`${engineId}\` may not contain dots`);if(RESERVED_ENGINE_IDS.includes(engineId))fail(`engine id \`${engineId}\` shadows a built-in or shipped engine`);let rules=asTableArray(t.rules,`engines[${i}].rules`).map((r,j)=>{let state=asString(r.state,`engines[${i}].rules[${j}].state`);if(state!=="working"&&state!=="blocked"&&state!=="idle")fail(`engines[${i}].rules[${j}].state must be working | blocked | idle`);let lineRegex=asStringArray(r.line_regex,`engines[${i}].rules[${j}].line_regex`);for(let re of lineRegex??[])try{new RegExp(re)}catch{fail(`engines[${i}].rules[${j}].line_regex \`${re}\` is not a valid regex`)}let all=asStringArray(r.all,`engines[${i}].rules[${j}].all`),any=asStringArray(r.any,`engines[${i}].rules[${j}].any`);if(!all&&!any&&!lineRegex)fail(`engines[${i}].rules[${j}] needs at least one of all/any/line_regex`);return{state,...typeof r.bottom_lines==="number"?{bottomLines:r.bottom_lines}:{},...all?{all}:{},...any?{any}:{},...lineRegex?{lineRegex}:{}}}),identityRaw=t.identity,identity;if(identityRaw!==void 0){if(typeof identityRaw!=="object"||identityRaw===null||Array.isArray(identityRaw))fail(`engines[${i}].identity must be a table`);let idt=identityRaw,shortName=((key)=>idt[key]===void 0?void 0:asString(idt[key],`engines[${i}].identity.${key}`))("short_name");identity={...shortName!==void 0?{shortName}:{}}}let firstMessageDelivery;if(t.first_message_delivery!==void 0){let raw2=asString(t.first_message_delivery,`engines[${i}].first_message_delivery`);if(raw2!=="argv"&&raw2!=="paste")fail(`engines[${i}].first_message_delivery must be argv | paste`);firstMessageDelivery=raw2}return{id:engineId,name:asString(t.name,`engines[${i}].name`),command:asCommand(t.command,`engines[${i}].command`),...t.process_names===void 0?{}:{processNames:asCommand(t.process_names,`engines[${i}].process_names`)},rules,...identity?{identity}:{},...firstMessageDelivery?{firstMessageDelivery}:{}}}),engineSeen=new Set;for(let e of engines){if(engineSeen.has(e.id))fail(`duplicate engine id \`${e.id}\``);engineSeen.add(e.id)}let mod;if(raw.mod!==void 0){if(!raw.mod||typeof raw.mod!=="object"||Array.isArray(raw.mod))fail("`mod` must be a table");let t=raw.mod;if(t.timeout_ms!==void 0)warnings.push("`mod` declares `timeout_ms`; a mod runs until the daemon stops");mod={command:asCommand(t.command,"mod.command"),platforms:asPlatforms(t.platforms,"mod.platforms")}}return{manifest:{id,name,version,minRoveVersion,description,platforms,build,startup,shutdown,actions,events,panes,pages,settings,fileHandlers,engines,...mod?{mod}:{}},warnings}}import{homedir}from"os";import{join as join2}from"path";function stateRoot(homeDir){let home=homeDir??readRoveHomeDirEnv()??homedir();return join2(home,ROVE_STATE_DIR_BASENAME)}function pluginRegistryPath(homeDir){return join2(stateRoot(homeDir),"plugins.json")}function pluginsRootDir(homeDir){return join2(stateRoot(homeDir),"plugins")}function legacyPluginsRootDir(homeDir){let home=homeDir??readRoveHomeDirEnv()??homedir();return join2(preRenameStateDir(home),"plugins")}function pluginDataDir(id,homeDir){return join2(pluginsRootDir(homeDir),id)}function pluginCheckoutDir(id,homeDir){return join2(pluginDataDir(id,homeDir),"checkout")}function pluginConfigDir(id,homeDir){return join2(pluginDataDir(id,homeDir),"config")}function pluginStateDir(id,homeDir){return join2(pluginDataDir(id,homeDir),"state")}function pluginLogPath(id,homeDir){return join2(pluginDataDir(id,homeDir),"log.jsonl")}function pluginsOutdatedCachePath(homeDir){return join2(stateRoot(homeDir),"plugins-outdated.json")}import{mkdirSync,readFileSync as readFileSync2,writeFileSync}from"fs";import{dirname,join as join3,relative}from"path";var EMPTY={plugins:[]};function loadPluginRegistry(homeDir){let text;try{text=readFileSync2(pluginRegistryPath(homeDir),"utf8")}catch{return EMPTY}try{let raw=JSON.parse(text);if(!Array.isArray(raw.plugins))return EMPTY;return{plugins:raw.plugins.filter(isEntry).map((entry)=>withCanonicalRoot(entry,homeDir))}}catch{return EMPTY}}function withCanonicalRoot(entry,homeDir){if(entry.source.kind!=="github")return entry;let legacy=legacyPluginsRootDir(homeDir),canonical=pluginsRootDir(homeDir);if(legacy===canonical)return entry;let inside=relative(legacy,entry.root);if(inside===""||inside.startsWith("..")||inside.startsWith("/"))return entry;return{...entry,root:join3(canonical,inside)}}function isEntry(v){if(typeof v!=="object"||v===null)return!1;let e=v,source=e.source;return typeof e.id==="string"&&typeof e.root==="string"&&typeof e.enabled==="boolean"&&typeof e.version==="string"&&typeof e.installedAt==="number"&&typeof source==="object"&&source!==null&&(source.kind==="link"||source.kind==="github"&&typeof source.spec==="string")}function savePluginRegistry(registry,homeDir){let path=pluginRegistryPath(homeDir);mkdirSync(dirname(path),{recursive:!0}),writeFileSync(path,`${JSON.stringify(registry,null,2)}
3
+ `,{mode:OWNER_ONLY_FILE_MODE})}function upsertPluginEntry(registry,entry){return{plugins:[...registry.plugins.filter((p)=>p.id!==entry.id),entry]}}function removePluginEntry(registry,id){return{plugins:registry.plugins.filter((p)=>p.id!==id)}}
4
+ export{PLUGIN_MANIFEST_FILENAMES,pluginManifestPath,readPluginManifest,qualifiedActionId,currentPluginPlatform,supportsPlatform,parsePluginManifest,pluginRegistryPath,pluginsRootDir,pluginDataDir,pluginCheckoutDir,pluginConfigDir,pluginStateDir,pluginLogPath,pluginsOutdatedCachePath,loadPluginRegistry,savePluginRegistry,upsertPluginEntry,removePluginEntry};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{__require}from"./chunk-91sykzqq.js";var CHANNEL_LOADERS={weixin:async()=>(await import("./chunk-va0n5rwm.js")).default};async function runChannelCli(id,argv){let load=CHANNEL_LOADERS[id];if(!load)throw Error(`no chat channel "${id}"`);await(await load()).runCli(argv)}async function startChatChannels(ctx){let started=[];for(let[id,load]of Object.entries(CHANNEL_LOADERS))try{let channel=(await load()).createChannel();await channel.start(ctx),started.push(channel)}catch(err){ctx.log("channel",`${id} did not start: ${err instanceof Error?err.message:String(err)}`)}return started}
2
+ import{__require}from"./chunk-91sykzqq.js";var CHANNEL_LOADERS={weixin:async()=>(await import("./chunk-k9ahks28.js")).default};async function runChannelCli(id,argv){let load=CHANNEL_LOADERS[id];if(!load)throw Error(`no chat channel "${id}"`);await(await load()).runCli(argv)}async function startChatChannels(ctx){let started=[];for(let[id,load]of Object.entries(CHANNEL_LOADERS))try{let channel=(await load()).createChannel();await channel.start(ctx),started.push(channel)}catch(err){ctx.log("channel",`${id} did not start: ${err instanceof Error?err.message:String(err)}`)}return started}
3
3
  export{runChannelCli,startChatChannels};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{loadStateFile,patchStateFile}from"./chunk-zk5qkkb1.js";var LAST_ACTIVE_TASK_KEY="lastActive.taskId";function readLastActiveTaskId(){let value=loadStateFile()[LAST_ACTIVE_TASK_KEY];return typeof value==="string"&&value?value:null}function writeLastActiveTaskId(id){patchStateFile({[LAST_ACTIVE_TASK_KEY]:id})}
2
+ import{loadStateFile,patchStateFile}from"./chunk-axxf5dkq.js";var LAST_ACTIVE_TASK_KEY="lastActive.taskId";function readLastActiveTaskId(){let value=loadStateFile()[LAST_ACTIVE_TASK_KEY];return typeof value==="string"&&value?value:null}function writeLastActiveTaskId(id){patchStateFile({[LAST_ACTIVE_TASK_KEY]:id})}
3
3
  export{readLastActiveTaskId,writeLastActiveTaskId};
@@ -1,6 +1,6 @@
1
1
  // @bun
2
- import{DAEMON_CHANNELS}from"./chunk-md094j05.js";import{logClientError}from"./chunk-hq9tbzqa.js";import{samePath}from"./chunk-pn5ygqn6.js";import{preRenameRuntimePaths}from"./chunk-b39sdtt0.js";import{readRoveEnv}from"./chunk-nc46gddg.js";import{connect}from"net";import{StringDecoder}from"string_decoder";function automationRunNeedsAttention(status){return status==="dispatch_failed"||status==="skipped_unavailable"}var ROUTINE_RESPONSE_MAX_CHARS=32000,ROUTINE_RESPONSE_WINDOW_MS=7200000;function routineRunResponseState(run,nowMs){if(run.response)return"responded";if(run.status!=="dispatched"&&run.status!=="revived")return null;return nowMs-Date.parse(run.at)>ROUTINE_RESPONSE_WINDOW_MS?"missing":"awaiting"}var ATTENTION_INBOX_STATES=["turn_complete","permission_needed","error","rate_limited","dead","routine_failed","routine_responded"];function isRoutineInboxState(state){return state==="routine_failed"||state==="routine_responded"}function isAttentionInboxState(value){return typeof value==="string"&&ATTENTION_INBOX_STATES.includes(value)}function attentionInboxItemKey(item){if(isRoutineInboxState(item.state)&&item.detail?.routine)return`\x00${item.state}\x00${item.detail.routine.automationId}`;return`${item.taskId}\x00${item.tabId??""}`}var CHANNEL_NAMES=DAEMON_CHANNELS;var CHANNEL_NAME_SET=new Set(CHANNEL_NAMES);function isChannelName(value){return typeof value==="string"&&CHANNEL_NAME_SET.has(value)}function normalizeChannelFilter(value){if(!Array.isArray(value))return null;let set=new Set;for(let name of value)if(isChannelName(name))set.add(name);return set.size>0?set:null}var DAEMON_PROTOCOL_VERSION=5,MIN_COMPATIBLE_PROTOCOL_VERSION=2;function isProtocolCompatible(args){return args.remoteVersion>=args.localMin&&args.localVersion>=args.remoteMin}function isDaemonVersionStale(daemonVersion,clientVersion){if(!daemonVersion)return!1;return daemonVersion!==clientVersion}function isForeignDaemonHome(daemonHome,clientHome){if(!daemonHome)return!1;return!samePath(daemonHome,clientHome)}var BLOCKING_RPCS=new Set(["api.invoke","ui.prompt","task.land","workitem.start","automation.runNow","pr.rerunFailedChecks","task.ensureWorktree","task.ensureMain","worktree.discoverAdoptable","worktree.adopt","worktree.list","worktree.remove"]);function parseDaemonStopReason(value){return value==="restart"||value==="stop"||value==="idle"||value==="socket-lost"?value:void 0}function displayTaskTitle(task){return task.title||task.branch||task.worktreePath||task.repo||"scratch"}function serializeTask(task){return{id:task.id,title:displayTaskTitle(task),repo:task.repo,branch:task.branch,worktreePath:task.worktreePath,kind:task.kind??"task",...task.scratch?{scratch:!0}:{},...task.routine?{routine:task.routine}:{},status:task.status,pinned:task.pinned??!1,vendor:task.vendor,command:task.command,prStatus:task.prStatus,modelEffort:task.modelEffort,model:task.model,tier:task.tier,groupId:task.groupId,observedLanguage:task.observedLanguage,deletion:task.deletion,quotaResume:task.quotaResume,linkedWorkItem:task.linkedWorkItem,dispatcher:task.dispatcher,prompt:task.prompt,baseRef:task.baseRef,worktreeName:task.worktreeName,report:task.report,createdAt:task.createdAt,updatedAt:task.updatedAt}}function frameToLine(frame){return`${JSON.stringify(frame)}
2
+ import{DAEMON_CHANNELS}from"./chunk-278sc87n.js";import{logClientError}from"./chunk-y55zpren.js";import{samePath}from"./chunk-pn5ygqn6.js";import{preRenameRuntimePaths}from"./chunk-b39sdtt0.js";import{readRoveEnv}from"./chunk-nc46gddg.js";import{connect}from"net";import{StringDecoder}from"string_decoder";function automationRunNeedsAttention(status){return status==="dispatch_failed"||status==="skipped_unavailable"}var ROUTINE_RESPONSE_MAX_CHARS=32000,ROUTINE_RESPONSE_WINDOW_MS=7200000;function routineRunResponseState(run,nowMs){if(run.response)return"responded";if(run.status!=="dispatched"&&run.status!=="revived")return null;if(run.deliveryStatus==="missing")return"missing";if(run.deliveryStatus==="awaiting")return"awaiting";return nowMs-Date.parse(run.at)>ROUTINE_RESPONSE_WINDOW_MS?"missing":"awaiting"}var GATE_QUESTION_MAX=500,GATE_CONTEXT_MAX=4000,GATE_OPTIONS_MAX=6;function gateInboxKey(gateId){return`\x00gate\x00${gateId}`}var ATTENTION_INBOX_STATES=["turn_complete","permission_needed","error","rate_limited","dead","routine_failed","routine_responded","report_missing","decision_needed"];function isRoutineInboxState(state){return state==="routine_failed"||state==="routine_responded"}function isAttentionInboxState(value){return typeof value==="string"&&ATTENTION_INBOX_STATES.includes(value)}function attentionInboxItemKey(item){if(isRoutineInboxState(item.state)&&item.detail?.routine)return`\x00${item.state}\x00${item.detail.routine.automationId}`;if(item.state==="report_missing"&&item.detail?.delivery)return`\x00delivery\x00${item.detail.delivery.id}`;if(item.state==="decision_needed"&&item.detail?.gate)return gateInboxKey(item.detail.gate.id);return`${item.taskId}\x00${item.tabId??""}`}var DELIVERY_OUTCOMES=["done","partial","blocked","failed"],DELIVERY_SUMMARY_MAX_CHARS=32000,DELIVERY_EVIDENCE_MAX_ITEMS=50,DELIVERY_EVIDENCE_MAX_CHARS=2000,DELIVERY_NEXT_MAX_CHARS=4000,DELIVERY_PROMPT_HEAD_CHARS=200,MAX_DELIVERIES_PER_TASK=50,DELIVERY_STALL_MS=600000;function deliveryFooter(deliveryId,api){return`[ROVE] When this turn ends, report: ${api} report --delivery ${deliveryId} --outcome done|partial|blocked|failed --summary \u2026 [--evidence \u2026]\u2026 [--next \u2026]`}var SKIP_REASONS=["task-missing","awaiting-owner","report-missing","quota","engine-error","engine-dead","awaiting-permission","busy"],SHOULD_RUN_SKIP_EXIT_CODE=3;function parseSkipVerdict(value){if(!value||typeof value!=="object"||Array.isArray(value))return;let raw=value;if(raw.run!==!1||!SKIP_REASONS.includes(raw.reason))return;let text=(v)=>typeof v==="string"&&v.length>0?v:void 0;return{run:!1,reason:raw.reason,...text(raw.detail)?{detail:raw.detail}:{},...text(raw.until)?{until:raw.until}:{},...Array.isArray(raw.gateIds)?{gateIds:raw.gateIds.filter((g)=>typeof g==="string")}:{}}}var CHANNEL_NAMES=DAEMON_CHANNELS;var CHANNEL_NAME_SET=new Set(CHANNEL_NAMES);function isChannelName(value){return typeof value==="string"&&CHANNEL_NAME_SET.has(value)}function normalizeChannelFilter(value){if(!Array.isArray(value))return null;let set=new Set;for(let name of value)if(isChannelName(name))set.add(name);return set.size>0?set:null}var DAEMON_PROTOCOL_VERSION=5,MIN_COMPATIBLE_PROTOCOL_VERSION=2;function isProtocolCompatible(args){return args.remoteVersion>=args.localMin&&args.localVersion>=args.remoteMin}function isDaemonVersionStale(daemonVersion,clientVersion){if(!daemonVersion)return!1;return daemonVersion!==clientVersion}function isForeignDaemonHome(daemonHome,clientHome){if(!daemonHome)return!1;return!samePath(daemonHome,clientHome)}var BLOCKING_RPCS=new Set(["api.invoke","ui.prompt","task.land","workitem.start","automation.runNow","pr.rerunFailedChecks","task.ensureWorktree","task.ensureMain","worktree.discoverAdoptable","worktree.adopt","worktree.list","worktree.remove"]);function parseDaemonStopReason(value){return value==="restart"||value==="stop"||value==="idle"||value==="socket-lost"?value:void 0}function displayTaskTitle(task){return task.title||task.branch||task.worktreePath||task.repo||"scratch"}function serializeTask(task){return{id:task.id,title:displayTaskTitle(task),repo:task.repo,branch:task.branch,worktreePath:task.worktreePath,kind:task.kind??"task",...task.scratch?{scratch:!0}:{},...task.routine?{routine:task.routine}:{},status:task.status,pinned:task.pinned??!1,vendor:task.vendor,command:task.command,prStatus:task.prStatus,modelEffort:task.modelEffort,model:task.model,tier:task.tier,groupId:task.groupId,observedLanguage:task.observedLanguage,deletion:task.deletion,quotaResume:task.quotaResume,linkedWorkItem:task.linkedWorkItem,dispatcher:task.dispatcher,requireReport:task.requireReport,prompt:task.prompt,baseRef:task.baseRef,worktreeName:task.worktreeName,report:task.report,createdAt:task.createdAt,updatedAt:task.updatedAt}}function frameToLine(frame){return`${JSON.stringify(frame)}
3
3
  `}class RpcTimeoutError extends Error{constructor(name,timeoutMs){super(`daemon rpc "${name}" timed out after ${timeoutMs}ms (daemon wedged?)`);this.name="RpcTimeoutError"}}function rpcTimeoutMs(){let raw=readRoveEnv("RPC_TIMEOUT_MS")?.trim();if(raw){let parsed=Number.parseInt(raw,10);if(Number.isFinite(parsed))return parsed}return 20000}class ConnectTimeoutError extends Error{constructor(socketPath,timeoutMs){super(`connecting to ${socketPath} timed out after ${timeoutMs}ms \u2014 nothing accepted the connection (daemon or PTY host not listening at that address)`);this.name="ConnectTimeoutError"}}function connectTimeoutMs(){let raw=readRoveEnv("CONNECT_TIMEOUT_MS")?.trim();if(raw){let parsed=Number.parseInt(raw,10);if(Number.isFinite(parsed))return parsed}return 5000}class RoveDaemonClient{socketPath;socket=null;buffer="";nextId=1;pending=new Map;handlers=new Map;lifecycleHandlers=new Map;connecting=null;disposed=!1;constructor(socketPath){this.socketPath=socketPath}connect(){if(this.socket)return Promise.resolve();if(this.disposed)return Promise.reject(Error("daemon client disposed"));if(this.connecting)return this.connecting;let p=this.openSocketWithFallback();this.connecting=p;let cleanup=()=>{if(this.connecting===p)this.connecting=null};return p.then(cleanup,cleanup),p}get isDisposed(){return this.disposed}close(){this.disposed=!0,this.socket?.end(),this.socket=null,this.failPending()}forceDisconnect(){let socket=this.socket;if(!socket)return;this.socket=null,socket.destroy(),this.failPending()}failPending(){if(this.pending.size===0)return;let err=Error("daemon connection closed");for(let pending of this.pending.values()){if(pending.timer)clearTimeout(pending.timer);pending.reject(err)}this.pending.clear()}on(name,handler){let set=this.handlers.get(name);if(!set)set=new Set,this.handlers.set(name,set);return set.add(handler),()=>{if(set?.delete(handler),set?.size===0)this.handlers.delete(name)}}onChannel(channel,handler){return this.on(channel,(frame)=>handler(frame.payload))}subscribe(opts={}){let payload={};if(opts.channels)payload.channels=opts.channels;if(opts.role)payload.role=opts.role;if(opts.cellPixelSize)payload.cellPixelWidth=opts.cellPixelSize.width,payload.cellPixelHeight=opts.cellPixelSize.height;return this.request("subscribe",payload)}onLifecycle(name,handler){let set=this.lifecycleHandlers.get(name);if(!set)set=new Set,this.lifecycleHandlers.set(name,set);return set.add(handler),()=>{if(set?.delete(handler),set?.size===0)this.lifecycleHandlers.delete(name)}}async request(name,payload){await this.connect();let socket=this.socket;if(!socket)throw Error("daemon connection is not open");let id=String(this.nextId++),promise=new Promise((resolve,reject)=>{let entry={resolve:(value)=>resolve(value),reject},timeoutMs=rpcTimeoutMs();if(timeoutMs>0&&!BLOCKING_RPCS.has(name))entry.timer=setTimeout(()=>this.onRequestTimeout(id,name,timeoutMs),timeoutMs);this.pending.set(id,entry)});return socket.write(frameToLine({type:"request",id,name,payload})),promise}onRequestTimeout(id,name,timeoutMs){let pending=this.pending.get(id);if(!pending)return;this.pending.delete(id),pending.reject(new RpcTimeoutError(name,timeoutMs)),this.forceDisconnect(),this.emitLifecycle("close")}async openSocketWithFallback(){try{await this.openSocket(this.socketPath);return}catch(err){if(!(err instanceof Error)||!("code"in err)||!["ENOENT","ECONNREFUSED"].includes(String(err.code)))throw err;for(let path of preRenameRuntimePaths(this.socketPath)){if(this.disposed)throw err;try{await this.openSocket(path);return}catch{}}throw err}}openSocket(path){return new Promise((resolve,reject)=>{let socket=connect(path);this.socket=socket;let timeoutMs=connectTimeoutMs(),timer;if(timeoutMs>0)timer=setTimeout(()=>{if(socket.off("connect",onConnect),socket.off("error",onError),socket.destroy(),this.socket===socket)this.socket=null;reject(new ConnectTimeoutError(this.socketPath,timeoutMs))},timeoutMs);let onConnect=()=>{if(timer)clearTimeout(timer);socket.off("error",onError),socket.on("error",()=>socket.destroy()),resolve()},onError=(err)=>{if(timer)clearTimeout(timer);if(socket.off("connect",onConnect),this.socket===socket)this.socket=null;reject(err)};socket.once("connect",onConnect),socket.once("error",onError);let decoder=new StringDecoder("utf8");this.buffer="",socket.on("data",(chunk)=>this.onData(decoder.write(chunk))),socket.on("close",()=>this.onSocketClose(socket))})}onSocketClose(which){if(this.socket!==which)return;this.socket=null,this.failPending(),this.emitLifecycle("close")}emitLifecycle(name){for(let handler of this.lifecycleHandlers.get(name)??[])try{handler()}catch(err){console.error(`[rove] lifecycle handler for "${name}" threw:`,err)}}onData(chunk){this.buffer+=chunk;let nl=this.buffer.indexOf(`
4
4
  `);while(nl!==-1){let line=this.buffer.slice(0,nl);if(this.buffer=this.buffer.slice(nl+1),line.trim().length>0)this.onLine(line);nl=this.buffer.indexOf(`
5
5
  `)}}onLine(line){let frame;try{frame=JSON.parse(line)}catch(err){logClientError("client-frame",err);return}if(frame.type==="event"){this.emit(frame);return}if(frame.type!=="response")return;let pending=this.pending.get(frame.id);if(!pending)return;if(this.pending.delete(frame.id),pending.timer)clearTimeout(pending.timer);if(frame.error){let err=Error(frame.error.message);if(frame.error.name)err.name=frame.error.name;pending.reject(err)}else pending.resolve(frame.payload)}emit(frame){for(let handler of this.handlers.get(frame.name)??[])try{handler(frame)}catch(err){logClientError("client-event",err)}for(let handler of this.handlers.get("*")??[])try{handler(frame)}catch(err){logClientError("client-event",err)}}}
6
- export{automationRunNeedsAttention,ROUTINE_RESPONSE_MAX_CHARS,routineRunResponseState,isRoutineInboxState,isAttentionInboxState,attentionInboxItemKey,CHANNEL_NAMES,normalizeChannelFilter,DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,isProtocolCompatible,isDaemonVersionStale,isForeignDaemonHome,parseDaemonStopReason,displayTaskTitle,serializeTask,frameToLine,RpcTimeoutError,ConnectTimeoutError,RoveDaemonClient};
6
+ export{automationRunNeedsAttention,ROUTINE_RESPONSE_MAX_CHARS,routineRunResponseState,GATE_QUESTION_MAX,GATE_CONTEXT_MAX,GATE_OPTIONS_MAX,isRoutineInboxState,isAttentionInboxState,attentionInboxItemKey,DELIVERY_OUTCOMES,DELIVERY_SUMMARY_MAX_CHARS,DELIVERY_EVIDENCE_MAX_ITEMS,DELIVERY_EVIDENCE_MAX_CHARS,DELIVERY_NEXT_MAX_CHARS,DELIVERY_PROMPT_HEAD_CHARS,MAX_DELIVERIES_PER_TASK,DELIVERY_STALL_MS,deliveryFooter,SKIP_REASONS,SHOULD_RUN_SKIP_EXIT_CODE,parseSkipVerdict,CHANNEL_NAMES,normalizeChannelFilter,DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,isProtocolCompatible,isDaemonVersionStale,isForeignDaemonHome,parseDaemonStopReason,displayTaskTitle,serializeTask,frameToLine,RpcTimeoutError,ConnectTimeoutError,RoveDaemonClient};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{ApiError,REMOTE_CALLER,VERB_GROUP_IDS,cliCaller,helpStep,promptMayHaveLanded,splitDaemonCode}from"./chunk-x7r75e3p.js";import"./chunk-91sykzqq.js";export{splitDaemonCode,promptMayHaveLanded,helpStep,cliCaller,VERB_GROUP_IDS,REMOTE_CALLER,ApiError};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{RemoteOrchestrator}from"./chunk-pj3gnkfr.js";import{startTunnel}from"./chunk-x0rvg54z.js";import{discoverMachine}from"./chunk-t5qayy7m.js";import{dedupeMachines,duplicateAliasOf,listMachines,readMachines,setMachineIdentity,updateMachine}from"./chunk-q854fweb.js";import{loadStateFile}from"./chunk-zk5qkkb1.js";import{createStateCell}from"./chunk-cmp64q4j.js";import{RoveDaemonClient}from"./chunk-s5a5dyab.js";import{logClient,logClientError}from"./chunk-hq9tbzqa.js";class MachineHub{local;slots=new Map;machinesAcc=createStateCell([],"machines.status");mergedAcc=createStateCell([],"machines.tasks");localUnsubscribe=null;disposed=!1;constructor(local){this.local=local}machinesSignal(){return this.machinesAcc}tasksSignal(){if(this.slots.size===0)return this.local.tasksSignal();return this.mergedAcc}remoteTaskIds(){let ids=new Set;for(let slot of this.slots.values())for(let task of slot.tasks)ids.add(String(task.id));return ids}attach(){let entries=dedupeMachines(listMachines());if(entries.length===0)return;for(let entry of entries)this.slots.set(entry.alias,{entry,tasks:[]});this.publishStatuses(),this.localUnsubscribe=this.local.tasksSignal().subscribe(()=>this.republishTasks()),this.republishTasks();for(let entry of entries)this.connect(entry)}async connect(entry){let slot=this.slots.get(entry.alias);if(!slot||this.disposed)return;let found=await discoverMachine(entry.alias,entry);if(this.disposed)return;let sockets=found.ok?{daemon:found.status.socketPath,pty:found.status.ptySocketPath}:entry.sockets;if(!sockets){this.setStatus(entry.alias,{state:"offline",error:found.ok?void 0:found.message});return}if(found.ok)updateMachine(entry.alias,{sockets,...found.roveBin?{roveBin:found.roveBin}:{}});let tunnel=startTunnel({alias:entry.alias,config:entry,remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty});if(slot.tunnel=tunnel,tunnel.state()==="unsupported"){this.setStatus(entry.alias,{state:"unsupported",error:"SSH unix-socket forwarding is not available on Windows"});return}if(tunnel.onState((state)=>{if(state==="online")this.openOrchestrator(entry,tunnel);else if(state==="offline")this.setStatus(entry.alias,{state:"offline"}),this.republishTasks()}),tunnel.state()==="online")await this.openOrchestrator(entry,tunnel)}async openOrchestrator(entry,tunnel){let slot=this.slots.get(entry.alias);if(!slot||this.disposed||slot.orchestrator)return;let client=new RoveDaemonClient(tunnel.daemonSocketPath),orchestrator=new RemoteOrchestrator(client,{role:"gui",expectForeignHome:!0,onPeerIdentity:(peer)=>this.onPeerIdentity(entry.alias,peer)});slot.orchestrator=orchestrator;try{await orchestrator.init()}catch(err){let message=err instanceof Error?err.message:String(err);this.setStatus(entry.alias,{state:classifyHandshakeFailure(message),error:message}),logClientError("machines",err);return}let stopTasks=orchestrator.tasksSignal().subscribe(()=>{slot.tasks=orchestrator.tasksSignal().get(),this.republishTasks()}),stopConnection=orchestrator.connectionStateSignal().subscribe(()=>{let connected=orchestrator.connectionStateSignal().get()==="online";if(this.slots.get(entry.alias)!==slot)return;this.setStatus(entry.alias,{state:connected?"online":"offline"}),this.republishTasks()});slot.unsubscribe=()=>{stopTasks(),stopConnection()},slot.tasks=orchestrator.tasksSignal().get(),this.setStatus(entry.alias,{state:"online",version:orchestrator.daemonVersionSignal().get()??void 0}),this.republishTasks(),logClient("machines",`${entry.alias} online (${slot.tasks.length} tasks)`)}onPeerIdentity(alias,peer){if(!peer.hostname&&!peer.homeDir)return;let identity={hostname:peer.hostname,homeDir:peer.homeDir,daemonPid:peer.daemonPid};setMachineIdentity(alias,identity);let duplicate=duplicateAliasOf(readMachines(loadStateFile()),alias,identity);this.setStatus(alias,{hostname:peer.hostname||void 0,version:peer.roveVersion||void 0,...duplicate?{duplicateOf:duplicate}:{}})}setStatus(alias,patch){let next=this.machinesAcc.get().map((row)=>row.alias===alias?{...row,...patch}:row);this.machinesAcc.set(next)}publishStatuses(){this.machinesAcc.set([...this.slots.values()].map((slot)=>({alias:slot.entry.alias,hostLabel:slot.entry.alias,state:"connecting"})))}republishTasks(){let merged=this.local.tasksSignal().get().map((task)=>stampOrigin(task,"local","local"));for(let slot of this.slots.values()){let status=this.machinesAcc.get().find((row)=>row.alias===slot.entry.alias);if(status?.duplicateOf)continue;let hostLabel=status?.hostLabel||slot.entry.alias,stale=status?.state!=="online";for(let task of slot.tasks)merged.push(stampOrigin(task,slot.entry.alias,hostLabel,stale))}this.mergedAcc.set(merged)}dispose(){this.disposed=!0,this.localUnsubscribe?.();for(let slot of this.slots.values())slot.unsubscribe?.(),slot.orchestrator?.dispose(),slot.tunnel?.stop();this.slots.clear()}}function classifyHandshakeFailure(message){return/protocol v\d/i.test(message)?"mismatch":"offline"}function stampOrigin(task,machineId,hostLabel,stale=!1){return{...task,origin:{machineId,hostLabel,...stale?{stale:!0}:{}}}}
2
+ import{RemoteOrchestrator}from"./chunk-v9fgdd90.js";import{startTunnel}from"./chunk-v0jvt60f.js";import{discoverMachine}from"./chunk-v9dcyjmj.js";import{dedupeMachines,duplicateAliasOf,listMachines,readMachines,setMachineIdentity,updateMachine}from"./chunk-3jnw3ftt.js";import{loadStateFile}from"./chunk-axxf5dkq.js";import{createStateCell}from"./chunk-cmp64q4j.js";import{RoveDaemonClient}from"./chunk-fnsch8kr.js";import{logClient,logClientError}from"./chunk-y55zpren.js";class MachineHub{local;slots=new Map;machinesAcc=createStateCell([],"machines.status");mergedAcc=createStateCell([],"machines.tasks");localUnsubscribe=null;disposed=!1;constructor(local){this.local=local}machinesSignal(){return this.machinesAcc}tasksSignal(){if(this.slots.size===0)return this.local.tasksSignal();return this.mergedAcc}remoteTaskIds(){let ids=new Set;for(let slot of this.slots.values())for(let task of slot.tasks)ids.add(String(task.id));return ids}attach(){let entries=dedupeMachines(listMachines());if(entries.length===0)return;for(let entry of entries)this.slots.set(entry.alias,{entry,tasks:[]});this.publishStatuses(),this.localUnsubscribe=this.local.tasksSignal().subscribe(()=>this.republishTasks()),this.republishTasks();for(let entry of entries)this.connect(entry)}async connect(entry){let slot=this.slots.get(entry.alias);if(!slot||this.disposed)return;let found=await discoverMachine(entry.alias,entry);if(this.disposed)return;let sockets=found.ok?{daemon:found.status.socketPath,pty:found.status.ptySocketPath}:entry.sockets;if(!sockets){this.setStatus(entry.alias,{state:"offline",error:found.ok?void 0:found.message});return}if(found.ok)updateMachine(entry.alias,{sockets,...found.roveBin?{roveBin:found.roveBin}:{}});let tunnel=startTunnel({alias:entry.alias,config:entry,remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty});if(slot.tunnel=tunnel,tunnel.state()==="unsupported"){this.setStatus(entry.alias,{state:"unsupported",error:"SSH unix-socket forwarding is not available on Windows"});return}if(tunnel.onState((state)=>{if(state==="online")this.openOrchestrator(entry,tunnel);else if(state==="offline")this.setStatus(entry.alias,{state:"offline"}),this.republishTasks()}),tunnel.state()==="online")await this.openOrchestrator(entry,tunnel)}async openOrchestrator(entry,tunnel){let slot=this.slots.get(entry.alias);if(!slot||this.disposed||slot.orchestrator)return;let client=new RoveDaemonClient(tunnel.daemonSocketPath),orchestrator=new RemoteOrchestrator(client,{role:"gui",expectForeignHome:!0,onPeerIdentity:(peer)=>this.onPeerIdentity(entry.alias,peer)});slot.orchestrator=orchestrator;try{await orchestrator.init()}catch(err){let message=err instanceof Error?err.message:String(err);this.setStatus(entry.alias,{state:classifyHandshakeFailure(message),error:message}),logClientError("machines",err);return}let stopTasks=orchestrator.tasksSignal().subscribe(()=>{slot.tasks=orchestrator.tasksSignal().get(),this.republishTasks()}),stopConnection=orchestrator.connectionStateSignal().subscribe(()=>{let connected=orchestrator.connectionStateSignal().get()==="online";if(this.slots.get(entry.alias)!==slot)return;this.setStatus(entry.alias,{state:connected?"online":"offline"}),this.republishTasks()});slot.unsubscribe=()=>{stopTasks(),stopConnection()},slot.tasks=orchestrator.tasksSignal().get(),this.setStatus(entry.alias,{state:"online",version:orchestrator.daemonVersionSignal().get()??void 0}),this.republishTasks(),logClient("machines",`${entry.alias} online (${slot.tasks.length} tasks)`)}onPeerIdentity(alias,peer){if(!peer.hostname&&!peer.homeDir)return;let identity={hostname:peer.hostname,homeDir:peer.homeDir,daemonPid:peer.daemonPid};setMachineIdentity(alias,identity);let duplicate=duplicateAliasOf(readMachines(loadStateFile()),alias,identity);this.setStatus(alias,{hostname:peer.hostname||void 0,version:peer.roveVersion||void 0,...duplicate?{duplicateOf:duplicate}:{}})}setStatus(alias,patch){let next=this.machinesAcc.get().map((row)=>row.alias===alias?{...row,...patch}:row);this.machinesAcc.set(next)}publishStatuses(){this.machinesAcc.set([...this.slots.values()].map((slot)=>({alias:slot.entry.alias,hostLabel:slot.entry.alias,state:"connecting"})))}republishTasks(){let merged=this.local.tasksSignal().get().map((task)=>stampOrigin(task,"local","local"));for(let slot of this.slots.values()){let status=this.machinesAcc.get().find((row)=>row.alias===slot.entry.alias);if(status?.duplicateOf)continue;let hostLabel=status?.hostLabel||slot.entry.alias,stale=status?.state!=="online";for(let task of slot.tasks)merged.push(stampOrigin(task,slot.entry.alias,hostLabel,stale))}this.mergedAcc.set(merged)}dispose(){this.disposed=!0,this.localUnsubscribe?.();for(let slot of this.slots.values())slot.unsubscribe?.(),slot.orchestrator?.dispose(),slot.tunnel?.stop();this.slots.clear()}}function classifyHandshakeFailure(message){return/protocol v\d/i.test(message)?"mismatch":"offline"}function stampOrigin(task,machineId,hostLabel,stale=!1){return{...task,origin:{machineId,hostLabel,...stale?{stale:!0}:{}}}}
3
3
  export{MachineHub,classifyHandshakeFailure};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{getGlobalDefaultVendor,getRepoLastActiveVendor,resolvePreferredVendor,setGlobalDefaultVendor,setRepoLastActiveVendor}from"./chunk-a7m7w6d1.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-21ek142k.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-zk5qkkb1.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{setRepoLastActiveVendor,setGlobalDefaultVendor,resolvePreferredVendor,getRepoLastActiveVendor,getGlobalDefaultVendor};
2
+ import{getGlobalDefaultVendor,getRepoLastActiveVendor,resolvePreferredVendor,setGlobalDefaultVendor,setRepoLastActiveVendor}from"./chunk-m6qv5rsv.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-xkr7fwvb.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-axxf5dkq.js";import"./chunk-qk5f6p3e.js";import"./chunk-b31cte10.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-pn5ygqn6.js";import"./chunk-z7zm8h1q.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{setRepoLastActiveVendor,setGlobalDefaultVendor,resolvePreferredVendor,getRepoLastActiveVendor,getGlobalDefaultVendor};
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{readOnlyGitProcessEnv}from"./chunk-6xppe9bj.js";import{quoteShellArg}from"./chunk-7kysxgbq.js";import{getPersistedString}from"./chunk-xkr7fwvb.js";import{recordSpawn}from"./chunk-40dgv828.js";import{pathSyntax,pathWithin}from"./chunk-pn5ygqn6.js";var EDITOR_KINDS=["auto","vim","nvim","nano","emacs","custom"],AUTO_EDITOR_CANDIDATES=["nvim","vim","emacs","nano"],EDITOR_KIND_KEY="editor.kind",EDITOR_CUSTOM_KEY="editor.customCommand",DEFAULT_EDITOR_KIND="auto";function normalizeEditorKind(value){return EDITOR_KINDS.includes(value)?value:"auto"}var FILE_PLACEHOLDER="{file}",LINE_PLACEHOLDER="{line}",PLUS_LINE_EDITORS=new Set(["vi","vim","nvim","nano","emacs","emacsclient","micro","kak","mg","joe"]),SUFFIX_LINE_EDITORS=new Set(["hx","helix"]);function firstToken(cmd){return cmd.trim().split(/\s+/)[0]??""}function buildEditorCommand(kind,customCommand,absPath,envEditor,line){if(kind==="vim"||kind==="nvim"||kind==="nano"||kind==="emacs")return plainEditorCommand(kind,absPath,line);let tmpl=(customCommand.trim()||(envEditor??"").trim()).trim();if(!tmpl)return null;let bin=firstToken(tmpl);if(!bin)return null;let hasLine=tmpl.includes(LINE_PLACEHOLDER),autoPlusLine=!hasLine&&line!==void 0&&PLUS_LINE_EDITORS.has(bin.split("/").pop()??bin),target=hasLine||autoPlusLine?{arg:quoteShellArg(absPath),atLine:!0}:fileArg(bin,absPath,line),withLine=(autoPlusLine?`${bin} +${line}${tmpl.slice(bin.length)}`:tmpl).split(LINE_PLACEHOLDER).join(String(line??1)),command=withLine.includes(FILE_PLACEHOLDER)?withLine.split(FILE_PLACEHOLDER).join(target.arg):`${withLine} ${target.arg}`;return line===void 0?{bin,command}:{bin,command,atLine:target.atLine}}function plainEditorCommand(bin,absPath,line){let target=fileArg(bin,absPath,line),command=`${bin} ${target.arg}`;return line===void 0?{bin,command}:{bin,command,atLine:target.atLine}}function fileArg(bin,absPath,line){let file=quoteShellArg(absPath);if(line===void 0)return{arg:file,atLine:!1};let name=bin.split("/").pop()??bin;if(PLUS_LINE_EDITORS.has(name))return{arg:`+${line} ${file}`,atLine:!0};if(SUFFIX_LINE_EDITORS.has(name))return{arg:`${file}:${line}`,atLine:!0};return{arg:file,atLine:!1}}function buildNvimDiffCommand(bin,absPath,relPath){let file=quoteShellArg(absPath);return["f=$(mktemp 2>/dev/null)",`if [ -n "$f" ] && git show ${quoteShellArg(`HEAD:./${relPath}`)} > "$f" 2>/dev/null; then`,` ${bin} -d "$f" ${file} -c 'setlocal nomodifiable' -c 'wincmd l'; r=$?`,"else",` ${bin} ${file}; r=$?`,"fi",'rm -f "$f" 2>/dev/null; exit $r'].join(`
3
+ `)}function relativeToWorktree(worktree,absPath){return pathWithin(worktree,absPath)||null}async function resolveEditorCommand(absPath,line){let kind=normalizeEditorKind(getPersistedString(EDITOR_KIND_KEY)),custom=getPersistedString(EDITOR_CUSTOM_KEY)??"",env=(process.env.VISUAL??process.env.EDITOR??"").trim();if(kind!=="auto")return buildEditorCommand(kind,custom,absPath,env,line);if(env)return buildEditorCommand("custom","",absPath,env,line);for(let bin of AUTO_EDITOR_CANDIDATES)if(await binaryAvailable(bin))return plainEditorCommand(bin,absPath,line);return null}async function binaryAvailable(bin){try{return await Bun.spawn(["sh","-c",`command -v ${quoteShellArg(bin)} >/dev/null 2>&1`],{stdin:"ignore",stdout:"ignore",stderr:"ignore"}).exited===0}catch{return!1}}async function fileHasDiff(worktree,relPath){try{return recordSpawn("tui.fileHasDiff",["git","diff","--quiet","HEAD","--",relPath],worktree),await Bun.spawn(["git","diff","--quiet","HEAD","--",relPath],{cwd:worktree,stdin:"ignore",stdout:"ignore",stderr:"ignore",env:readOnlyGitProcessEnv()}).exited===1}catch{return!1}}async function resolveEditorLaunch(worktree,absPath,line){let resolved=await resolveEditorCommand(absPath,line);if(!resolved)return null;if(!await binaryAvailable(resolved.bin))return null;let command=await maybeDiffCommand(resolved,worktree,absPath),label=editorWindowLabel(absPath);return resolved.atLine===void 0?{command,label}:{command,label,atLine:resolved.atLine}}async function maybeDiffCommand(resolved,worktree,absPath){let{bin,command}=resolved;if(bin!=="nvim"&&bin!=="vim")return command;if(command!==`${bin} ${quoteShellArg(absPath)}`)return command;let rel=relativeToWorktree(worktree,absPath);if(!rel)return command;if(!await fileHasDiff(worktree,rel))return command;return buildNvimDiffCommand(bin,absPath,rel)}function editorWindowLabel(absPath){let base=pathSyntax(absPath).basename(absPath).trim();return base.length>0?base:"edit"}
4
+ export{EDITOR_KINDS,EDITOR_KIND_KEY,EDITOR_CUSTOM_KEY,DEFAULT_EDITOR_KIND,normalizeEditorKind,resolveEditorCommand,binaryAvailable,resolveEditorLaunch};