@sma1lboy/rove 0.9.258 → 0.9.263
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.
- package/dist/cli/{chunk-x8rkpfqd.js → chunk-0079aw9z.js} +1 -1
- package/dist/cli/{chunk-xnaehfby.js → chunk-02f0matw.js} +1 -1
- package/dist/cli/chunk-09sfrqkr.js +2 -0
- package/dist/cli/{chunk-ke3t032y.js → chunk-0rrmz6k6.js} +1 -1
- package/dist/cli/{chunk-3q1rv3rm.js → chunk-1cmcaarg.js} +2 -2
- package/dist/cli/chunk-1gxb0bd3.js +3 -0
- package/dist/cli/{chunk-ebea569y.js → chunk-1h68wb7r.js} +1 -1
- package/dist/cli/chunk-26mf16v9.js +2 -0
- package/dist/cli/{chunk-1zqzqbek.js → chunk-27k612fg.js} +1 -1
- package/dist/cli/{chunk-jd02zgwf.js → chunk-2cbzp9t1.js} +1 -1
- package/dist/cli/{chunk-stcvcsfm.js → chunk-3ac75tqw.js} +1 -1
- package/dist/cli/{chunk-68113ts1.js → chunk-3zjdbdwy.js} +1 -1
- package/dist/cli/chunk-495kp7gj.js +16 -0
- package/dist/cli/{chunk-cq5qv93a.js → chunk-4gt375ve.js} +1 -1
- package/dist/cli/{chunk-sabpcket.js → chunk-4kzqv6rq.js} +1 -1
- package/dist/cli/{chunk-cewyvr3c.js → chunk-59g5tbc7.js} +1 -1
- package/dist/cli/chunk-5pkyrzfc.js +3 -0
- package/dist/cli/{chunk-yktnbb14.js → chunk-5v02t4pz.js} +37 -37
- package/dist/cli/{chunk-kgddz8pw.js → chunk-60ppphcx.js} +1 -1
- package/dist/cli/chunk-69dz852g.js +2 -0
- package/dist/cli/{chunk-8q1g1xq0.js → chunk-6qyd3ny6.js} +1 -1
- package/dist/cli/chunk-744netc1.js +55 -0
- package/dist/cli/chunk-7kwk5kxn.js +3 -0
- package/dist/cli/{chunk-rnxk3587.js → chunk-7y7v9x3n.js} +1 -1
- package/dist/cli/{chunk-9v18qy3s.js → chunk-87ar2d2r.js} +1 -1
- package/dist/cli/{chunk-r6f8h111.js → chunk-8mx0egn7.js} +2 -2
- package/dist/cli/{chunk-qpc8bv02.js → chunk-8p4ah1m9.js} +4 -4
- package/dist/cli/{chunk-zam29b9x.js → chunk-8vkma6c4.js} +1 -1
- package/dist/cli/chunk-98pfg06f.js +70 -0
- package/dist/cli/{chunk-edsm15ht.js → chunk-a2epp2ad.js} +1 -1
- package/dist/cli/{chunk-wyt2vgjv.js → chunk-a89xzxv2.js} +1 -1
- package/dist/cli/{chunk-0d57z680.js → chunk-aaz3wnp3.js} +1 -1
- package/dist/cli/{chunk-pw87thvf.js → chunk-asez7vm6.js} +1 -1
- package/dist/cli/{chunk-95jzkqp2.js → chunk-ax5c2qmv.js} +1 -1
- package/dist/cli/chunk-b2h6jfrg.js +3 -0
- package/dist/cli/{chunk-t25xke74.js → chunk-b3vz95wb.js} +1 -1
- package/dist/cli/{chunk-k2cnmb5q.js → chunk-bc72rgkm.js} +1 -1
- package/dist/cli/{chunk-eyzjma6q.js → chunk-bmk52w06.js} +1 -1
- package/dist/cli/{chunk-1egwgg6p.js → chunk-bntczetj.js} +1 -1
- package/dist/cli/chunk-bnv1mm5h.js +4 -0
- package/dist/cli/{chunk-hfvz23r6.js → chunk-c09jfhpp.js} +1 -1
- package/dist/cli/chunk-c0gvp57p.js +3 -0
- package/dist/cli/chunk-c6kw0s9a.js +4 -0
- package/dist/cli/{chunk-cqychwvw.js → chunk-ca4dvdj4.js} +1 -1
- package/dist/cli/chunk-cwk568n5.js +2 -0
- package/dist/cli/chunk-dnmq3c4k.js +11 -0
- package/dist/cli/chunk-dx12gkf5.js +2 -0
- package/dist/cli/{chunk-rx2604ry.js → chunk-efr0fy7z.js} +1 -1
- package/dist/cli/{chunk-80zzjcvp.js → chunk-f6tqc1cc.js} +1 -1
- package/dist/cli/{chunk-rc2nwsdd.js → chunk-fdexrh6h.js} +1 -1
- package/dist/cli/{chunk-jf46jsdp.js → chunk-fr4mwfe1.js} +1 -1
- package/dist/cli/{chunk-y0gybgba.js → chunk-gbbx9zpz.js} +1 -1
- package/dist/cli/chunk-gzj9nk7k.js +3 -0
- package/dist/cli/chunk-h8zvgpzd.js +82 -0
- package/dist/cli/{chunk-0604fza5.js → chunk-hk0s2bbn.js} +1 -1
- package/dist/cli/{chunk-y8xb4ys7.js → chunk-jqkzg4dd.js} +1 -1
- package/dist/cli/{chunk-hdnqq66w.js → chunk-jt994bhe.js} +1 -1
- package/dist/cli/chunk-jwqdhbe9.js +3 -0
- package/dist/cli/{chunk-s0jbtyd9.js → chunk-kmgheesn.js} +3 -2
- package/dist/cli/{chunk-jtpjdmb6.js → chunk-mccgj97d.js} +1 -1
- package/dist/cli/{chunk-pwbtezsa.js → chunk-mhbc490p.js} +1 -1
- package/dist/cli/{chunk-jv11f2c2.js → chunk-mqrn27h8.js} +3 -3
- package/dist/cli/{chunk-v7prawj1.js → chunk-n7vtv1rw.js} +1 -1
- package/dist/cli/chunk-ndrcjcv5.js +2 -0
- package/dist/cli/{chunk-t60qcvcj.js → chunk-ns2f9b6r.js} +1 -1
- package/dist/cli/chunk-nze6pmm7.js +2 -0
- package/dist/cli/{chunk-zqq3djrw.js → chunk-pdn1r8rf.js} +3 -3
- package/dist/cli/{chunk-1vwngrmf.js → chunk-qga9xd2f.js} +1 -1
- package/dist/cli/chunk-r1cvs8v1.js +2 -0
- package/dist/cli/chunk-r240tf5j.js +3 -0
- package/dist/cli/chunk-r3zkpbf5.js +9 -0
- package/dist/cli/chunk-r6nmjtze.js +2 -0
- package/dist/cli/{chunk-6p9yxt3q.js → chunk-re15t5r1.js} +1 -1
- package/dist/cli/{chunk-b47k0cnw.js → chunk-rtcevh2t.js} +1 -1
- package/dist/cli/{chunk-tpt3fn1q.js → chunk-s0x0yw8x.js} +1 -1
- package/dist/cli/chunk-s83qnstd.js +2 -0
- package/dist/cli/chunk-sgngkkp3.js +2 -0
- package/dist/cli/chunk-spt9e3zk.js +31 -0
- package/dist/cli/{chunk-yjyjg7sk.js → chunk-stng29vp.js} +2 -2
- package/dist/cli/{chunk-278sc87n.js → chunk-szjgjrar.js} +1 -1
- package/dist/cli/{chunk-6x0trw81.js → chunk-t6txrkad.js} +1 -1
- package/dist/cli/{chunk-kqf371ff.js → chunk-tgfn5ykb.js} +1 -1
- package/dist/cli/chunk-tjj9bt7n.js +3 -0
- package/dist/cli/chunk-tmr45c9p.js +3 -0
- package/dist/cli/chunk-w2d69c89.js +7 -0
- package/dist/cli/{chunk-mmc662x2.js → chunk-wkv4aw6c.js} +1 -1
- package/dist/cli/{chunk-tq6pq1ws.js → chunk-ws4cg819.js} +1 -1
- package/dist/cli/{chunk-ehb0hbrg.js → chunk-wv5hvxcd.js} +2 -2
- package/dist/cli/chunk-wv6d96t6.js +2 -0
- package/dist/cli/chunk-xkyf0ws5.js +20 -0
- package/dist/cli/{chunk-edpbz0gz.js → chunk-xn4494n9.js} +3 -3
- package/dist/cli/{chunk-pb5g6161.js → chunk-xt82hp6y.js} +1 -1
- package/dist/cli/{chunk-1xrbb7gf.js → chunk-xwyp7bvy.js} +1 -1
- package/dist/cli/{chunk-c8anewjn.js → chunk-y5p9wm83.js} +1 -1
- package/dist/cli/chunk-yhcsp07b.js +66 -0
- package/dist/cli/{chunk-cb7hc2xm.js → chunk-ymb3ag9d.js} +1 -1
- package/dist/cli/{chunk-7cd1epfw.js → chunk-yyjskza5.js} +1 -1
- package/dist/cli/{chunk-45thgqdr.js → chunk-zns1zx6s.js} +1 -1
- package/dist/cli/chunk-zr3kwred.js +3 -0
- package/dist/cli/index.js +4 -4
- package/dist/cli/pty-host-node.mjs +5 -0
- package/dist/cli/rove.js +1 -1
- package/dist/completions/rove.bash +3 -3
- package/dist/completions/rove.fish +3 -3
- package/dist/completions/rove.zsh +3 -3
- package/dist/skills/rove/SKILL.md +1 -1
- package/dist/skills/rove/references/api-flags.md +35 -16
- package/dist/web/assets/index-CdjFB6v7.css +1 -0
- package/dist/web/assets/index-bEO8TjwB.js +109 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/cli/chunk-1378mh2w.js +0 -3
- package/dist/cli/chunk-1qge84t7.js +0 -3
- package/dist/cli/chunk-1vxykwb9.js +0 -3
- package/dist/cli/chunk-2yjpqb47.js +0 -3
- package/dist/cli/chunk-4ab8y1yp.js +0 -15
- package/dist/cli/chunk-4d4d59vp.js +0 -20
- package/dist/cli/chunk-658859k9.js +0 -31
- package/dist/cli/chunk-6t5d02s4.js +0 -2
- package/dist/cli/chunk-79r3wbhh.js +0 -2
- package/dist/cli/chunk-7nr405tr.js +0 -9
- package/dist/cli/chunk-82zpp3yx.js +0 -4
- package/dist/cli/chunk-8dggnfaf.js +0 -2
- package/dist/cli/chunk-8gjpnb83.js +0 -41
- package/dist/cli/chunk-csdne12x.js +0 -3
- package/dist/cli/chunk-dd0mtzje.js +0 -3
- package/dist/cli/chunk-dqprpnd6.js +0 -3
- package/dist/cli/chunk-fehxbwcb.js +0 -6
- package/dist/cli/chunk-g846fbp7.js +0 -52
- package/dist/cli/chunk-hkv6t5v9.js +0 -2
- package/dist/cli/chunk-jetsx9zr.js +0 -3
- package/dist/cli/chunk-q301ewyq.js +0 -2
- package/dist/cli/chunk-qn04z4zb.js +0 -2
- package/dist/cli/chunk-rmk69hvh.js +0 -2
- package/dist/cli/chunk-s1rg1zae.js +0 -3
- package/dist/cli/chunk-skpkscne.js +0 -11
- package/dist/cli/chunk-sma961wh.js +0 -3
- package/dist/cli/chunk-x7cv6deh.js +0 -2
- package/dist/cli/chunk-y85e24s9.js +0 -2
- package/dist/cli/chunk-ya0h6hcd.js +0 -31
- package/dist/cli/chunk-yaqkajw4.js +0 -82
- package/dist/cli/chunk-yc9bytrj.js +0 -2
- package/dist/web/assets/index-BiUiNIOp.css +0 -1
- package/dist/web/assets/index-jy27XaL0.js +0 -109
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{isDev}from"./chunk-prqeddy7.js";import{fileURLToPath}from"url";var package_default={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.
|
|
2
|
+
import{isDev}from"./chunk-prqeddy7.js";import{fileURLToPath}from"url";var package_default={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.263",description:"Rove \u2014 the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",keywords:["terminal","tui","cli","multiplexer","ai-agents","coding-agent","ai-coding-assistant","agentic-ai","parallel-agents","git-worktree","claude-code","codex","llm","developer-tools"],type:"module",packageManager:"bun@1.3.13",bin:{rove:"dist/cli/rove.js"},files:["dist/cli","dist/completions","dist/web","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://rove.run",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:mock":"ROVE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:rubric":"bun run scripts/build-tier-rubric.ts",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"ROVE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"ROVE_INCLUDE_SOCKET=1 ROVE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"ROVE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun scripts/render-track.mjs",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build","plugin-sandbox":"bun run scripts/plugin-sandbox.ts"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0",react:"^19.2.8","smol-toml":"^1.7.1",ws:"^8.21.3"},optionalDependencies:{"node-pty":"^1.1.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/rove-daemon":"0.7.22","@tsconfig/bun":"1.0.11","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","react-devtools-core":"^7.0.1","rove-bridge":"0.0.24","rove-weixin":"0.0.24",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]};var CURRENT_VERSION=package_default.version,PACKAGE_NAME=package_default.name;function repoSlug(){let url=package_default.repository?.url;if(!url)return null;let m=url.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!m||!m[1]||!m[2])return null;return`${m[1]}/${m[2]}`}var UPDATE_SCRIPT_URL="https://raw.githubusercontent.com/Sma1lboy/rove/main/scripts/update.sh",UPDATE_COMMAND=`curl -fsSL ${UPDATE_SCRIPT_URL} | sh`;function updateCommandFor(target){return target===void 0||target===DEFAULT_RELEASE_CHANNEL?UPDATE_COMMAND:`${UPDATE_COMMAND} -s -- ${target}`}function owningNpmPrefix(modulePath=fileURLToPath(import.meta.url)){let at=modulePath.indexOf("/lib/node_modules/");if(at<=0)return null;return modulePath.slice(0,at)}function recommendedGlobalInstallCommand(prefix=owningNpmPrefix()){let target=`${PACKAGE_NAME}@latest`;return prefix===null?`npm install -g ${target}`:`npm install -g --prefix ${prefix} ${target}`}var BREAKING_VERSIONS=[];function breakingVersionsCrossed(from,to,breaking=BREAKING_VERSIONS){let[lo,hi]=compareSemver(from,to)<=0?[from,to]:[to,from];return breaking.filter((b)=>compareSemver(b,lo)>0&&compareSemver(b,hi)<=0)}var FETCH_TIMEOUT_MS=3000,RELEASE_CHANNELS=["latest","nightly"],DEFAULT_RELEASE_CHANNEL="latest";function channelOf(version=CURRENT_VERSION){return prereleaseOf(version)?.split(".")[0]==="nightly"?"nightly":DEFAULT_RELEASE_CHANNEL}async function fetchLatestFromRegistry(packageName,channel){let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let encoded=packageName.replace("/","%2F"),res=await fetch(`https://registry.npmjs.org/${encoded}/${channel}`,{signal:ctrl.signal,headers:{accept:"application/json"}});if(!res.ok)return null;let body=await res.json();if(typeof body.version!=="string")return null;return body.version}catch{return null}finally{clearTimeout(timer)}}function isNewerSemver(latest,current){let core=compareSemver(latest,current);if(core!==0)return core>0;return comparePrerelease(prereleaseOf(latest),prereleaseOf(current))>0}function prereleaseOf(version){let dash=version.indexOf("-");return dash===-1?void 0:version.slice(dash+1)||void 0}function comparePrerelease(a,b){if(a===b)return 0;if(a===void 0)return 1;if(b===void 0)return-1;let aParts=a.split("."),bParts=b.split(".");for(let i=0;i<Math.max(aParts.length,bParts.length);i++){let av=aParts[i],bv=bParts[i];if(av===void 0)return-1;if(bv===void 0)return 1;if(av===bv)continue;let an=/^\d+$/.test(av)?Number.parseInt(av,10):null,bn=/^\d+$/.test(bv)?Number.parseInt(bv,10):null;if(an!==null&&bn!==null)return an>bn?1:-1;if(an!==null)return-1;if(bn!==null)return 1;return av>bv?1:-1}return 0}function compareSemver(aVersion,bVersion){let norm=(v)=>v.split("-")[0]??v,a=norm(aVersion).split(".").map((s)=>Number.parseInt(s,10)),b=norm(bVersion).split(".").map((s)=>Number.parseInt(s,10));for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(Number.isNaN(av)||Number.isNaN(bv))return 0;if(av>bv)return 1;if(av<bv)return-1}return 0}async function checkLatestVersion(opts={}){let channel=opts.channel??channelOf(),fake=process.env.ROVE_FAKE_UPDATE;if(fake)return{current:CURRENT_VERSION,latest:fake,hasUpdate:isNewerSemver(fake,CURRENT_VERSION),channel};if(isDev()&&!opts.force)return null;let latest=await fetchLatestFromRegistry(PACKAGE_NAME,channel);if(!latest)return null;return{current:CURRENT_VERSION,latest,hasUpdate:isNewerSemver(latest,CURRENT_VERSION),channel}}function versionFromTagName(tagName){if(typeof tagName!=="string")return null;return tagName.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function fetchReleaseNotes(version){let slug=repoSlug();if(!slug)return null;let tag=`v${version}`,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases/tags/${tag}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return null;let body=await res.json();if(typeof body.body!=="string"||typeof body.html_url!=="string")return null;return{body:body.body,url:body.html_url,version}}catch{return null}finally{clearTimeout(timer)}}async function fetchReleaseNotesRange(args){let slug=repoSlug();if(!slug)return[];let limit=args.limit??100,ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string"||typeof release.body!=="string")return null;if(compareSemver(version,args.current)<=0)return null;if(compareSemver(version,args.latest)>0)return null;return{version,url:release.html_url,body:release.body}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}async function fetchReleaseSummaries(limit=12){let slug=repoSlug();if(!slug)return[];let ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),FETCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/repos/${slug}/releases?per_page=${limit}`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!res.ok)return[];let body=await res.json();if(!Array.isArray(body))return[];return body.map((release)=>{let version=versionFromTagName(release.tag_name);if(!version||typeof release.html_url!=="string")return null;return{version,url:release.html_url}}).filter((release)=>release!==null)}catch{return[]}finally{clearTimeout(timer)}}function releasePageUrl(version){let slug=repoSlug();if(!slug)return null;return`https://github.com/${slug}/releases/tag/v${version}`}
|
|
3
3
|
export{package_default,CURRENT_VERSION,PACKAGE_NAME,repoSlug,UPDATE_SCRIPT_URL,UPDATE_COMMAND,updateCommandFor,owningNpmPrefix,recommendedGlobalInstallCommand,BREAKING_VERSIONS,breakingVersionsCrossed,RELEASE_CHANNELS,DEFAULT_RELEASE_CHANNEL,channelOf,isNewerSemver,compareSemver,checkLatestVersion,fetchReleaseNotes,fetchReleaseNotesRange,fetchReleaseSummaries,releasePageUrl};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{NoopHookAdapter,activityHookAdapters,createEngineHookAdapter}from"./chunk-
|
|
2
|
+
import{NoopHookAdapter,activityHookAdapters,createEngineHookAdapter}from"./chunk-rtcevh2t.js";import"./chunk-2tfnscxk.js";import"./chunk-9ecnsh42.js";import"./chunk-w7zv47mp.js";import"./chunk-2brn8e1y.js";import"./chunk-b3vz95wb.js";import"./chunk-7zyyvc3d.js";import"./chunk-r6k3ve2g.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-tdhk4dz8.js";import"./chunk-22d0yc7m.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-g4281a0g.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{createEngineHookAdapter,activityHookAdapters,NoopHookAdapter};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{defaultFixRuntime}from"./chunk-f6tqc1cc.js";import{INBOUND_CLASSES,deniedClasses,setInbound}from"./chunk-5pkyrzfc.js";import"./chunk-495kp7gj.js";import"./chunk-s0x0yw8x.js";import"./chunk-fdexrh6h.js";import"./chunk-ns2f9b6r.js";import"./chunk-3zjdbdwy.js";import"./chunk-j11hzmwy.js";import"./chunk-re15t5r1.js";import"./chunk-17e2tgyg.js";import"./chunk-cbc1h345.js";import"./chunk-jjv7xem7.js";import"./chunk-4hestsjp.js";import"./chunk-3ac75tqw.js";import"./chunk-2bgmby1d.js";import"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-a2epp2ad.js";import"./chunk-atn06ncf.js";import"./chunk-4gt375ve.js";import"./chunk-qkehg2c1.js";import"./chunk-gzj9nk7k.js";import"./chunk-1cmcaarg.js";import"./chunk-4kzqv6rq.js";import"./chunk-ampdybqg.js";import"./chunk-sak1tphp.js";import"./chunk-1gxb0bd3.js";import"./chunk-4250pw6r.js";import"./chunk-bnv1mm5h.js";import"./chunk-rxqdw6s5.js";import"./chunk-jwqdhbe9.js";import"./chunk-f5n0tgky.js";import"./chunk-z3zaa155.js";import"./chunk-yewmtant.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-jt994bhe.js";import"./chunk-rtcevh2t.js";import"./chunk-2tfnscxk.js";import"./chunk-9ecnsh42.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-kg9kmwt9.js";import"./chunk-6xppe9bj.js";import{addMachine,defaultMachineAlias,discoverMachine,duplicateAliasOf,getMachine,isValidMachineAlias,listMachines,machineSocketDir,machineSshArgs,parseSshTarget,readMachines,removeMachine,roveCommand,sanitizeAlias,setMachineIdentity,sshTargetOf,updateMachine}from"./chunk-r3zkpbf5.js";import{primaryCheckouts,repoIdOf,repoIdentity,setPrimaryCheckout}from"./chunk-c6kw0s9a.js";import{shQuote}from"./chunk-b7xjhgts.js";import"./chunk-x7r75e3p.js";import{argvHasFlag}from"./chunk-zsfyj36g.js";import"./chunk-tgfn5ykb.js";import"./chunk-qga9xd2f.js";import"./chunk-5v02t4pz.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-b3vz95wb.js";import"./chunk-7zyyvc3d.js";import"./chunk-r6k3ve2g.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-tdhk4dz8.js";import{CURRENT_VERSION}from"./chunk-xwyp7bvy.js";import"./chunk-22d0yc7m.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import{loadStateFile}from"./chunk-g4281a0g.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import{homeDir}from"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-ws4cg819.js";import"./chunk-7kwk5kxn.js";import"./chunk-cmp64q4j.js";import"./chunk-kmgheesn.js";import"./chunk-szjgjrar.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__require}from"./chunk-91sykzqq.js";import{spawn}from"child_process";import{appendFileSync,chmodSync,existsSync,mkdirSync}from"fs";import{homedir}from"os";import{dirname}from"path";function parseSshG(stdout,home=homedir()){let values=new Map;for(let line of stdout.split(`
|
|
3
|
+
`)){let space=line.indexOf(" ");if(space>0)values.set(line.slice(0,space).toLowerCase(),line.slice(space+1).trim())}let hostname=values.get("hostname")??"",port=Number(values.get("port")??"22")||22,files=(key)=>(values.get(key)??"").split(/\s+/).filter((f)=>f&&f!=="none").map((f)=>f.startsWith("~/")?`${home}${f.slice(1)}`:f),alias=values.get("hostkeyalias"),proxy=(key)=>{let v=values.get(key);return v!==void 0&&v!=="none"};return{knownHostsName:alias&&alias!=="none"?alias:port===22?hostname:`[${hostname}]:${port}`,hostname,port,userKnownHosts:files("userknownhostsfile"),globalKnownHosts:files("globalknownhostsfile"),proxied:proxy("proxyjump")||proxy("proxycommand")}}async function checkHostKey(config){let target=sshTargetOf(config),resolved=await run(["ssh","-G",...config.port?["-p",String(config.port)]:[],target]);if(resolved.code!==0)return{state:"skipped",reason:"ssh -G failed"};let destination=parseSshG(resolved.stdout);if(!destination.hostname)return{state:"skipped",reason:"ssh -G named no host"};if(destination.proxied)return{state:"skipped",reason:"reached through a proxy"};for(let file of[...destination.userKnownHosts,...destination.globalKnownHosts]){if(!existsSync(file))continue;if((await run(["ssh-keygen","-F",destination.knownHostsName,"-f",file])).code===0)return{state:"known"}}let keys=(await run(["ssh-keyscan","-T","5","-p",String(destination.port),destination.hostname])).stdout.split(`
|
|
4
|
+
`).filter((line)=>line.trim()&&!line.startsWith("#"));if(keys.length===0)return{state:"skipped",reason:"the host offered no key"};let named=keys.map((line)=>line.replace(/^\S+/,destination.knownHostsName)),fingerprints=(await run(["ssh-keygen","-l","-f","-"],`${named.join(`
|
|
5
|
+
`)}
|
|
6
|
+
`)).stdout.split(`
|
|
7
|
+
`).filter((line)=>line.trim());return{state:"unknown",destination,fingerprints,trust(){let file=destination.userKnownHosts[0]??`${homedir()}/.ssh/known_hosts`;mkdirSync(dirname(file),{recursive:!0,mode:448}),appendFileSync(file,`${named.join(`
|
|
8
|
+
`)}
|
|
9
|
+
`,{mode:384});try{chmodSync(file,384)}catch{}}}}function run(argv,stdin){return new Promise((resolve)=>{let stdout="",child=spawn(argv[0]??"ssh",argv.slice(1),{stdio:[stdin===void 0?"ignore":"pipe","pipe","ignore"]}),timer=setTimeout(()=>child.kill("SIGKILL"),15000);if(child.stdout?.on("data",(chunk)=>{stdout+=chunk.toString()}),child.on("error",()=>{clearTimeout(timer),resolve({code:-1,stdout})}),child.on("close",(code)=>{clearTimeout(timer),resolve({code:code??-1,stdout})}),stdin!==void 0)child.stdin?.end(stdin)})}import{spawnSync}from"child_process";import{existsSync as existsSync2,mkdirSync as mkdirSync2,rmSync,writeFileSync}from"fs";import{homedir as homedir2}from"os";import{dirname as dirname2,join}from"path";function reverseTunnelArgv(config,ports){let argv=["ssh","-N","-o","BatchMode=yes","-o","ExitOnForwardFailure=yes","-o","ServerAliveInterval=15","-o","ServerAliveCountMax=3","-o","StrictHostKeyChecking=accept-new"];if(config.port)argv.push("-p",String(config.port));if(config.auth.kind==="key"&&config.auth.keyPath)argv.push("-i",config.auth.keyPath);return argv.push("-R",`127.0.0.1:${ports.remotePort}:127.0.0.1:${ports.localPort}`,sshTargetOf(config)),argv}var unitName=(alias)=>`rove-tunnel-${alias}`;function tunnelServicePath(alias,platform=process.platform){if(platform==="linux")return join(homedir2(),".config","systemd","user",`${unitName(alias)}.service`);if(platform==="darwin")return join(homedir2(),"Library","LaunchAgents",`run.rove.tunnel.${alias}.plist`);return null}function absoluteSsh(argv){let which=spawnSync("sh",["-c","command -v ssh"],{encoding:"utf8"});return[which.status===0?which.stdout.trim():"/usr/bin/ssh",...argv.slice(1)]}var shellQuote=(arg)=>/^[\w@%+=:,./-]+$/.test(arg)?arg:`'${arg.replaceAll("'","'\\''")}'`,xml=(s)=>s.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">");function systemdUnit(alias,argv){return["[Unit]",`Description=Rove reverse tunnel to ${alias}`,"After=network-online.target","","[Service]",`ExecStart=${argv.map(shellQuote).join(" ")}`,"Restart=always","RestartSec=5","","[Install]","WantedBy=default.target",""].join(`
|
|
10
|
+
`)}function launchdPlist(alias,argv){let args=argv.map((a)=>` <string>${xml(a)}</string>`).join(`
|
|
11
|
+
`);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
12
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
13
|
+
<plist version="1.0">
|
|
14
|
+
<dict>
|
|
15
|
+
<key>Label</key>
|
|
16
|
+
<string>run.rove.tunnel.${xml(alias)}</string>
|
|
17
|
+
<key>ProgramArguments</key>
|
|
18
|
+
<array>
|
|
19
|
+
${args}
|
|
20
|
+
</array>
|
|
21
|
+
<key>RunAtLoad</key>
|
|
22
|
+
<true/>
|
|
23
|
+
<key>KeepAlive</key>
|
|
24
|
+
<true/>
|
|
25
|
+
<key>ThrottleInterval</key>
|
|
26
|
+
<integer>5</integer>
|
|
27
|
+
</dict>
|
|
28
|
+
</plist>
|
|
29
|
+
`}function run2(cmd,args){let res=spawnSync(cmd,args,{encoding:"utf8"});return{ok:res.status===0,out:`${res.stdout??""}${res.stderr??""}`.trim()}}function installReverseTunnel(alias,config,ports){let path=tunnelServicePath(alias);if(!path)throw Error(`no supported service manager on ${process.platform}; run \`${reverseTunnelArgv(config,ports).join(" ")}\` yourself`);let argv=absoluteSsh(reverseTunnelArgv(config,ports));if(mkdirSync2(dirname2(path),{recursive:!0}),process.platform==="linux"){writeFileSync(path,systemdUnit(alias,argv));let reload=run2("systemctl",["--user","daemon-reload"]);if(!reload.ok)return{path,started:!1,detail:`systemd user manager unavailable: ${reload.out}`};let start=run2("systemctl",["--user","enable","--now",`${unitName(alias)}.service`]);return{path,started:start.ok,detail:start.out}}writeFileSync(path,launchdPlist(alias,argv)),run2("launchctl",["unload",path]);let load=run2("launchctl",["load","-w",path]);return{path,started:load.ok,detail:load.out}}function uninstallReverseTunnel(alias){let path=tunnelServicePath(alias);if(!path||!existsSync2(path))return null;if(process.platform==="linux")run2("systemctl",["--user","disable","--now",`${unitName(alias)}.service`]),rmSync(path),run2("systemctl",["--user","daemon-reload"]);else run2("launchctl",["unload","-w",path]),rmSync(path);return path}import{existsSync as existsSync3,mkdirSync as mkdirSync3,readFileSync}from"fs";import{hostname}from"os";import{join as join2}from"path";function hubKeyPath(home=homeDir()){return join2(home,".rove","ssh","hub_ed25519")}var INSTALL_SCRIPT="curl -fsSL https://rove.run/install.sh | sh";function fixesFor(failure,alias,config,keyPath=hubKeyPath()){let target=sshTargetOf(config),ssh=(cmd,batch=!0)=>[...machineSshArgs(alias,config,{batch}),cmd];if(failure.code==="SSH_FAILED"&&failure.ssh==="auth-denied"&&config.auth.kind==="key"){let fixes=[];if(!existsSync3(keyPath))fixes.push({kind:"run",id:"hub-key",label:"Create a key this hub logs in with",shown:`ssh-keygen -t ed25519 -N "" -C ${hubKeyComment()} -f ${keyPath}`,why:"A dedicated key revokes this hub alone: delete its one line on the machine. No passphrase, so the hub can reconnect unattended; the file is owner-only.",argv:()=>{return mkdirSync3(join2(keyPath,".."),{recursive:!0,mode:448}),["ssh-keygen","-q","-t","ed25519","-N","","-C",hubKeyComment(),"-f",keyPath]}});return fixes.push({kind:"run",id:"install-hub-key",label:`Authorize that key on ${target}`,shown:`ssh ${target} 'append ${keyPath}.pub to ~/.ssh/authorized_keys'`,why:"The one interactive step: ssh asks for your password on that machine once. Rove never sees it.",argv:()=>ssh(authorizeKeyScript(readFileSync(`${keyPath}.pub`,"utf8").trim()),!1),apply:(c)=>({...c,auth:{kind:"key",keyPath}})}),fixes}if(failure.code==="SSH_FAILED")return[];if(failure.code==="NO_ROVE")return[{kind:"install",id:"install-rove",label:`Install Rove on ${target}`,shown:`ssh ${target} '${INSTALL_SCRIPT}'`,why:"The official install script: sets up Bun if needed, then Rove, for that user only.",argv:()=>ssh(INSTALL_SCRIPT)}];if(failure.code==="BAD_STATUS"&&/too old/.test(failure.message))return[{kind:"install",id:"update-rove",label:`Update Rove on ${target}`,shown:`ssh ${target} 'rove update'`,why:"Its Rove predates machines; `rove update` moves it to the current release.",argv:()=>ssh(`${roveCommand(config.roveBin)} update`)}];return[{kind:"manual",id:"daemon-log",label:`Rove on ${target} would not start its daemon`,action:`ssh ${target} 'tail -n 40 ~/.rove/daemon.log'`}]}function hubKeyComment(){return`rove-hub@${hostname()}`}function authorizeKeyScript(publicKey){let line=shQuote(publicKey);return["umask 077","mkdir -p ~/.ssh","touch ~/.ssh/authorized_keys",`grep -qxF ${line} ~/.ssh/authorized_keys || printf '%s\\n' ${line} >> ~/.ssh/authorized_keys`].join(" && ")}async function establishMachine(alias,initial,rt){let discover=rt.discover??discoverMachine,config=initial,tried=new Set;for(;;){let found=await discover(alias,config);if(found.ok)return{ok:!0,found,config:found.roveBin?{...config,roveBin:found.roveBin}:config};rt.out(found.message);let fixes=fixesFor(found,alias,config),runnable=fixes.filter((f)=>f.kind!=="manual"&&!tried.has(f.id));for(let fix of fixes)if(fix.kind==="manual")rt.out(` \u2192 ${fix.action}`);if(runnable.length===0)return{ok:!1,failure:found};for(let fix of runnable){if(fix.kind==="manual")continue;if(tried.add(fix.id),rt.out(` ${fix.label}`),rt.out(` will run: ${fix.shown}`),rt.out(` ${fix.why}`),rt.planOnly)continue;if(rt.ask&&!await rt.confirm(" Run it? [y/N] "))return{ok:!1,failure:found};let code=await rt.exec(fix.argv());if(code!==0)return rt.out(` failed (exit ${code})`),{ok:!1,failure:found};if(fix.apply)config=fix.apply(config)}if(rt.planOnly)return rt.out(" Not a terminal: nothing was run. Re-run in a terminal, or pass --yes."),{ok:!1,failure:found}}}import{resolve}from"path";function machinePrimary(argv,fail){let clear=argvHasFlag(argv,"--clear"),target=argv.find((a)=>!a.startsWith("--"));if(!target){let marks=Object.entries(primaryCheckouts());if(marks.length===0)process.stdout.write(`No primary checkouts marked.
|
|
30
|
+
`);for(let[id2,path2]of marks)process.stdout.write(`${id2} ${path2}
|
|
31
|
+
`);return}let path=resolve(target),id=repoIdOf(repoIdentity(path));if(!id)fail(`primary: ${path} is not a git checkout`);setPrimaryCheckout(id,clear?null:path),process.stdout.write(clear?`${ROVE_PRODUCT_NAME} machine: ${id} has no primary checkout now
|
|
32
|
+
`:`${ROVE_PRODUCT_NAME} machine: ${id} resolves to ${path} here
|
|
33
|
+
`)}var CLI_NAME=ROVE_PRODUCT_NAME,MACHINE_USAGE=[`Usage: ${CLI_NAME} machine <add|remove|list> [options]`,"","Manage the other computers running Rove. Each one is reached over SSH;","its tasks appear in the sidebar under a row of its own.","","Commands:"," add <ssh-target> Register a machine (verifies it, offering fixes, before saving)"," doctor [alias] Re-check registered machines and offer the same fixes"," remove <alias> Forget a machine (nothing on it is touched)"," list Show registered machines"," tunnel <alias> Keep a reverse tunnel to <alias> so it can reach THIS machine"," inbound [allow|deny <class>] What other machines' hubs may run here (default: everything)"," primary [<path>] [--clear] The checkout a repo id resolves to here when there are several","","Add options:"," --alias <name> Local name for the machine (default: the target you typed)"," --port <n> SSH port (default: whatever ssh_config says)"," --identity <file> SSH private key (default: ssh-agent / ssh_config)"," --yes Run every offered fix without asking (add, doctor)","","Tunnel options (when <alias> cannot reach this machine, e.g. WSL behind Windows NAT):"," --install Run it as a login service (systemd user unit / launchd agent)"," --uninstall Stop and remove that service"," --print Print the ssh command and service file; change nothing (default)"," --remote-port <n> Port on <alias>'s loopback that leads back here (default 2222)"," --local-port <n> This machine's sshd port (default 22)"," Then on <alias>: machine add <you>@127.0.0.1:<remote-port>",""," <ssh-target> is [user@]host[:port] \u2014 usually just an ssh_config Host alias."," In a terminal, a key the machine rejects or a missing Rove is offered as"," a fix (a dedicated hub key, the install script) instead of an error.",""].join(`
|
|
34
|
+
`);function usageError(message){process.stderr.write(`${CLI_NAME} machine: ${message}
|
|
35
|
+
|
|
36
|
+
${MACHINE_USAGE}
|
|
37
|
+
`),process.exit(2)}function fail(message){process.stderr.write(`${CLI_NAME} machine: ${message}
|
|
38
|
+
`),process.exit(1)}function flagValue(argv,name){for(let i=0;i<argv.length;i++){let arg=argv[i];if(arg===void 0)continue;if(arg.startsWith(`--${name}=`))return arg.slice(name.length+3);if(arg!==`--${name}`)continue;let value=argv[i+1];if(value===void 0||value.startsWith("--"))usageError(`--${name} needs a value`);return value}return}async function runMachineSubcommand(argv){let[verb,...rest]=argv;if(!verb||verb==="--help"||verb==="-h"||verb==="help"){process.stdout.write(`${MACHINE_USAGE}
|
|
39
|
+
`);return}if(verb==="list")return list();if(verb==="add")return await add(rest);if(verb==="doctor")return await doctor(rest);if(verb==="remove")return remove(rest);if(verb==="tunnel")return tunnel(rest);if(verb==="inbound")return inbound(rest);if(verb==="primary")return machinePrimary(rest,usageError);usageError(`unknown verb "${verb}"`)}async function add(argv){let target=positionalOf(argv);if(!target)usageError("add needs an ssh target, e.g. `machine add narwhal`");let parsed=parseSshTarget(target);if(!parsed)usageError(`"${target}" is not a valid ssh target ([user@]host[:port])`);let portFlag=flagValue(argv,"port"),port=portFlag?Number(portFlag):parsed.port;if(port!==void 0&&(!Number.isInteger(port)||port<1||port>65535))usageError("--port must be 1-65535");let identity=flagValue(argv,"identity"),requested=flagValue(argv,"alias");if(requested&&!isValidMachineAlias(requested))usageError(`--alias must be letters/digits/._- and cannot be "local" (got "${requested}")`);let probeAlias=requested??sanitizeAlias(parsed.host),config={host:parsed.host,...parsed.user?{user:parsed.user}:{},...port?{port}:{},auth:identity?{kind:"key",keyPath:identity}:{kind:"key"}};await confirmHostKey(config),process.stderr.write(`${CLI_NAME} machine: contacting ${sshTargetOf(config)}\u2026
|
|
40
|
+
`);let established=await establishMachine(probeAlias,config,setupRuntime(argv));if(!established.ok)fail("nothing was saved");let{found,config:settled}=established,alias=requested??defaultMachineAlias({typedHost:parsed.host,typedUser:parsed.user,port,remoteHostname:found.status.hostname});if(!isValidMachineAlias(alias))fail(`could not derive a usable alias from "${found.status.hostname}" \u2014 pass --alias`);let identityTriple={hostname:found.status.hostname,homeDir:found.status.homeDir,daemonPid:found.status.daemonPid},duplicate=duplicateAliasOf(readMachines(loadStateFile()),alias,identityTriple),sockets={daemon:found.status.socketPath,pty:found.status.ptySocketPath};if(found.roveBin)process.stderr.write(`${CLI_NAME} machine: rove is not on ${alias}'s non-interactive PATH; using ${found.roveBin}
|
|
41
|
+
`);addMachine(alias,{...settled,identity:identityTriple,sockets}),setMachineIdentity(alias,identityTriple);let{ensureForwards}=await import("./chunk-s83qnstd.js"),up=await ensureForwards({alias,config:settled,remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty});if(process.stdout.write(`${CLI_NAME} machine: ${alias} \u2192 ${sshTargetOf(settled)} (rove ${found.status.roveVersion||"?"} on ${found.status.hostname||"?"})
|
|
42
|
+
`),!up)process.stderr.write(`${CLI_NAME} machine: registered, but could not forward ${alias}'s socket yet \u2014 it will show as offline until the connection comes up
|
|
43
|
+
`);if(duplicate)process.stdout.write(`${CLI_NAME} machine: ${alias} is the same machine as ${duplicate} (hostname/homeDir/pid match) \u2014 the sidebar shows one row
|
|
44
|
+
`)}function setupRuntime(argv){let yes=argv.includes("--yes"),fixRuntime=defaultFixRuntime();return{confirm:fixRuntime.confirm,exec:fixRuntime.exec,out:(line)=>process.stderr.write(`${line}
|
|
45
|
+
`),ask:!yes,planOnly:!yes&&process.stdin.isTTY!==!0}}async function doctor(argv){let alias=positionalOf(argv),entries=listMachines().filter((m)=>!alias||m.alias===alias);if(alias&&entries.length===0)fail(`no machine named "${alias}" (see \`${CLI_NAME} machine list\`)`);if(entries.length===0){process.stdout.write(`No machines registered. Add one with \`${CLI_NAME} machine add <ssh-target>\`.
|
|
46
|
+
`);return}let rt=setupRuntime(argv),{ensureForwards}=await import("./chunk-s83qnstd.js"),failed=0;for(let{alias:name,...config}of entries){process.stderr.write(`${CLI_NAME} machine: checking ${name} (${sshTargetOf(config)})\u2026
|
|
47
|
+
`);let established=await establishMachine(name,config,rt);if(!established.ok){failed++,process.stdout.write(`${name} \u2717 ${established.failure.code}
|
|
48
|
+
`);continue}let{found,config:settled}=established,sockets={daemon:found.status.socketPath,pty:found.status.ptySocketPath};updateMachine(name,{...settled,sockets});let up=await ensureForwards({alias:name,config:settled,remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty}),version=found.status.roveVersion||"?",skew=version!==CURRENT_VERSION?` (this machine runs ${CURRENT_VERSION})`:"";if(process.stdout.write(`${name} ${up?"\u2713":"\u2717 socket not forwarded"} rove ${version}${skew} on ${found.status.hostname||"?"}
|
|
49
|
+
`),!up)failed++}if(failed>0)process.exitCode=1}async function confirmHostKey(config){let check=await checkHostKey(config);if(check.state!=="unknown")return;let write=(line)=>{process.stderr.write(`${line}
|
|
50
|
+
`)};write(`${CLI_NAME} machine: first connection to ${sshTargetOf(config)} (${check.destination.knownHostsName}). Its host key:`);for(let line of check.fingerprints)write(` ${line}`);if(process.stdin.isTTY!==!0){write(`${CLI_NAME} machine: not a terminal; trusting it on first use, as ssh would`);return}if(write("Compare it with the machine's own `ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub` if you can."),!await defaultFixRuntime().confirm("Trust this host key? [y/N] "))fail("host key not trusted; nothing was saved");check.trust()}function remove(argv){let alias=argv[0];if(!alias)usageError("remove needs an alias, e.g. `machine remove narwhal`");if(!getMachine(alias))fail(`no machine named "${alias}" (see \`${CLI_NAME} machine list\`)`);removeMachine(alias),process.stdout.write(`${CLI_NAME} machine: removed ${alias}. Nothing on that machine was changed \u2014 its daemon, tasks and worktrees are untouched.
|
|
51
|
+
`),process.stdout.write(`${CLI_NAME} machine: leftover sockets live in ${machineSocketDir(alias)}
|
|
52
|
+
`)}function tunnel(argv){let alias=positionalOf(argv);if(!alias)usageError("tunnel needs the alias of the machine to tunnel to, e.g. `machine tunnel mac --install`");let entry=getMachine(alias);if(!entry)fail(`no machine named "${alias}" (see \`${CLI_NAME} machine list\`)`);let port=(name,fallback)=>{let raw=flagValue(argv,name);if(raw===void 0)return fallback;let n=Number.parseInt(raw,10);if(!Number.isInteger(n)||n<1||n>65535)usageError(`--${name} must be a port number`);return n},ports={remotePort:port("remote-port",2222),localPort:port("local-port",22)};if(argvHasFlag(argv,"--uninstall")){let removed=uninstallReverseTunnel(alias);process.stdout.write(removed?`${CLI_NAME} machine: removed the tunnel service ${removed}
|
|
53
|
+
`:`${CLI_NAME} machine: no tunnel service for ${alias}
|
|
54
|
+
`);return}if(!argvHasFlag(argv,"--install")){process.stdout.write(`${reverseTunnelArgv(entry,ports).join(" ")}
|
|
55
|
+
`);let path=tunnelServicePath(alias);process.stdout.write(path?`
|
|
56
|
+
--install writes ${path} and starts it.
|
|
57
|
+
`:`
|
|
58
|
+
No service manager Rove supports here; keep the command above running yourself.
|
|
59
|
+
`);return}try{let result=installReverseTunnel(alias,entry,ports);if(process.stdout.write(`${CLI_NAME} machine: wrote ${result.path}
|
|
60
|
+
`),!result.started)fail(`the service did not start: ${result.detail}`);process.stdout.write(`${CLI_NAME} machine: tunnel to ${alias} is up and restarts on its own. On ${alias}, register this machine with \`${CLI_NAME} machine add <you>@127.0.0.1:${ports.remotePort}\`.
|
|
61
|
+
`)}catch(err){fail(err instanceof Error?err.message:String(err))}}function inbound(argv){let[action,cls]=argv;if(action==="allow"||action==="deny"){if(!cls||!INBOUND_CLASSES.includes(cls))usageError(`inbound ${action} needs one of: ${INBOUND_CLASSES.join(", ")}`);let denied2=setInbound(cls,action==="allow");process.stdout.write(`${CLI_NAME} machine: other machines ${action==="allow"?"may now":"may no longer"} run "${cls}" verbs here. Denied: ${denied2.length?denied2.join(", "):"nothing"}
|
|
62
|
+
`);return}if(action!==void 0)usageError("inbound takes allow|deny <class>, or nothing to show the policy");let denied=new Set(deniedClasses());for(let c of INBOUND_CLASSES)process.stdout.write(`${c.padEnd(11)} ${denied.has(c)?"deny":"allow"}
|
|
63
|
+
`)}function list(){let machines=listMachines();if(machines.length===0){process.stdout.write(`No machines registered. Add one with \`${CLI_NAME} machine add <ssh-target>\`.
|
|
64
|
+
`);return}let all=readMachines(loadStateFile()),rows=machines.map((entry)=>{let duplicate=entry.identity?duplicateAliasOf(all,entry.alias,entry.identity):null;return[entry.alias,sshTargetOf(entry),entry.identity?.hostname??"\u2014",duplicate?`same machine as ${duplicate}`:""]}),widths=[0,1,2].map((i)=>Math.max(...rows.map((row)=>(row[i]??"").length),0));for(let row of rows){let line=[0,1,2].map((i)=>(row[i]??"").padEnd(widths[i]??0)).join(" ");process.stdout.write(`${line}${row[3]?` ${row[3]}`:""}
|
|
65
|
+
`.replace(/\s+$/,`
|
|
66
|
+
`))}}var SWITCHES=new Set(["--yes","--install","--uninstall","--print"]);function positionalOf(argv){for(let i=0;i<argv.length;i++){let arg=argv[i];if(arg===void 0)continue;if(arg.startsWith("--")){if(!arg.includes("=")&&!SWITCHES.has(arg))i++;continue}return arg}return}export{runMachineSubcommand};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{writeOutdatedCache}from"./chunk-
|
|
2
|
+
import{writeOutdatedCache}from"./chunk-7y7v9x3n.js";import{PluginCliError,installPlugin}from"./chunk-bntczetj.js";import{loadPluginRegistry,pluginCheckoutDir,pluginConfigDir,pluginDataDir,pluginStateDir,removePluginEntry,savePluginRegistry}from"./chunk-a2epp2ad.js";import"./chunk-w7zv47mp.js";import"./chunk-xwyp7bvy.js";import"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-szjgjrar.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{execFileSync}from"child_process";import{existsSync,mkdirSync,readdirSync,renameSync}from"fs";import{join}from"path";function gitOut(args,cwd){try{return execFileSync("git",args,{cwd,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return null}}function checkEntry(entry){let repoSpec=entry.source.spec.split("/").slice(0,2).join("/"),localSha=gitOut(["rev-parse","HEAD"],pluginCheckoutDir(entry.id)),remote=gitOut(["ls-remote",`https://github.com/${repoSpec}.git`,"HEAD"]),remoteSha=remote?remote.split(/\s+/)[0]??null:null;return{id:entry.id,spec:entry.source.spec,version:entry.version,localSha,remoteSha,behind:Boolean(localSha&&remoteSha&&localSha!==remoteSha)}}function listOutdated(){let rows=loadPluginRegistry().plugins.filter((p)=>p.source.kind==="github").map(checkEntry);return writeOutdatedCache(rows.filter((r)=>r.behind).map((r)=>r.id)),rows}function printOutdated(){let rows=listOutdated();if(rows.length===0){console.log("no GitHub-installed plugins.");return}for(let r of rows){let status=r.behind?"update available":r.remoteSha===null?"remote unreachable":r.localSha===null?"local sha unreadable":"up to date";console.log(`${r.id} v${r.version} ${status}`)}}function migrateRenamedPlugin(oldId,newId){for(let dirOf of[pluginConfigDir,pluginStateDir]){let from=dirOf(oldId),to=dirOf(newId);if(!existsSync(from))continue;mkdirSync(to,{recursive:!0});for(let entry of readdirSync(from)){if(existsSync(join(to,entry)))continue;renameSync(join(from,entry),join(to,entry))}}savePluginRegistry(removePluginEntry(loadPluginRegistry(),oldId)),console.log(`renamed ${oldId} \u2192 ${newId}: settings and state carried over, old entry unregistered`),console.log(` leftover checkout (safe to remove): ${pluginDataDir(oldId)}`)}async function updatePlugins(ids,opts){let rows=listOutdated(),targets;if(opts.all){if(targets=rows.filter((r)=>r.behind),targets.length===0){console.log("all plugins up to date.");return}}else{if(ids.length===0)throw new PluginCliError("update takes plugin ids or --all");targets=ids.map((id)=>{let row=rows.find((r)=>r.id===id);if(!row)throw new PluginCliError(`\`${id}\` is not a GitHub-installed plugin; see \`${ROVE_PRODUCT_NAME} plugin list\``);return row})}for(let target of targets){if(!target.behind&&!ids.includes(target.id))continue;console.log(`updating ${target.id} (${target.spec})\u2026`);let installedId=await installPlugin(target.spec,{yes:opts.yes});if(installedId!==target.id)migrateRenamedPlugin(target.id,installedId)}listOutdated()}export{updatePlugins,printOutdated};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{BUNDLED_THEME_JSONS,userThemesDir,validateTheme}from"./chunk-z3zaa155.js";import{expandTilde}from"./chunk-ag3txfg2.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-7ghwdjdc.js";import{SUBCOMMAND_VERBS}from"./chunk-
|
|
2
|
+
import{BUNDLED_THEME_JSONS,userThemesDir,validateTheme}from"./chunk-z3zaa155.js";import{expandTilde}from"./chunk-ag3txfg2.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-7ghwdjdc.js";import{SUBCOMMAND_VERBS}from"./chunk-tjj9bt7n.js";import"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-pn5ygqn6.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{existsSync,mkdirSync,readFileSync,readdirSync,unlinkSync,writeFileSync}from"fs";import{basename,join,resolve}from"path";var CLI_NAME=ROVE_PRODUCT_NAME,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
3
|
Run ${CLI_NAME} theme --help for valid names and options.
|
|
4
4
|
`),process.exit(1)}function failUsage(message){process.stderr.write(`${CLI_NAME} theme: ${message}
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{LAST_RUN_VERSION_KEY}from"./chunk-
|
|
2
|
+
import{LAST_RUN_VERSION_KEY}from"./chunk-fr4mwfe1.js";import{isShellKind,shippedCompletionsPath}from"./chunk-0rrmz6k6.js";import{isNpxMissing,markSkillHintSeen,npxSkillsArgv,npxSkillsCommand}from"./chunk-wv5hvxcd.js";import{loadStateFile,patchStateFile}from"./chunk-g4281a0g.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{t}from"./chunk-ws4cg819.js";import{spawnSync}from"child_process";import{appendFileSync,existsSync,mkdirSync,readFileSync,writeFileSync}from"fs";import{homedir}from"os";import{basename,join}from"path";var WELCOMED_KEY="welcomed",PENDING_SKILL_KEY="welcomePendingSkillInstall";function shouldWelcome(state){if(state[WELCOMED_KEY]===!0)return!1;return typeof state[LAST_RUN_VERSION_KEY]!=="string"}function takeWelcome(){if(!shouldWelcome(loadStateFile()))return null;try{patchStateFile({[WELCOMED_KEY]:!0})}catch{}return{shell:detectShell()}}var PENDING_COMPLETIONS_KEY="welcomePendingCompletions";function detectShell(env=process.env){let shell=basename(env.SHELL??"");return shell==="zsh"||shell==="bash"||shell==="fish"?shell:null}function completionHook(shell,cli,shipped){if(shipped===null)return legacyCompletionHook(shell,cli);return shell==="fish"?`test -f "${shipped}"; and source "${shipped}"`:`[ -f "${shipped}" ] && source "${shipped}"`}function legacyCompletionHook(shell,cli){return shell==="fish"?`${cli} completions fish | source`:`command -v ${cli} >/dev/null && source <(${cli} completions ${shell})`}function shippedScriptFor(shell,cli){let path=shippedCompletionsPath(shell,cli);return existsSync(path)?path:null}function installCompletions(shell,home=homedir(),cli=ROVE_PRODUCT_NAME,shipped=shippedScriptFor(shell,cli)){let hook=completionHook(shell,cli,shipped);if(shell==="fish"){let dir=join(home,".config","fish","completions"),path=join(dir,`${cli}.fish`);return mkdirSync(dir,{recursive:!0}),writeFileSync(path,`${hook}
|
|
3
3
|
`),{path,installed:!0}}let rc=join(home,shell==="zsh"?".zshrc":".bashrc"),existing=existsSync(rc)?readFileSync(rc,"utf8"):"";if(existing.includes(hook))return{path:rc,installed:!1};let legacy=legacyCompletionHook(shell,cli);if(existing.includes(legacy))return writeFileSync(rc,existing.replace(legacy,hook)),{path:rc,installed:!0};if(existing.includes(`${cli} completions`))return{path:rc,installed:!1};return appendFileSync(rc,`
|
|
4
4
|
# ${cli} completions
|
|
5
5
|
${hook}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{RemoteOrchestrator}from"./chunk-tmr45c9p.js";import{startTunnel}from"./chunk-c0gvp57p.js";import{dedupeMachines,discoverMachine,duplicateAliasOf,listMachines,readMachines,setMachineIdentity,updateMachine}from"./chunk-r3zkpbf5.js";import{loadStateFile}from"./chunk-g4281a0g.js";import{createStateCell}from"./chunk-cmp64q4j.js";import{RoveDaemonClient}from"./chunk-kmgheesn.js";import{logClient,logClientError}from"./chunk-gskbzgc3.js";var NO_LIVE={activity:new Map,changes:new Map,tokens:new Map};class MachineHub{local;slots=new Map;machinesAcc=createStateCell([],"machines.status");mergedAcc=createStateCell([],"machines.tasks");liveAcc=createStateCell(NO_LIVE,"machines.live");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}liveSignal(){return this.liveAcc}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()}),live=[orchestrator.engineStateSignal(),orchestrator.worktreeChangesSignal(),orchestrator.rowTokensSignal()].map((signal)=>signal.subscribe(()=>this.republishLive()));slot.unsubscribe=()=>{stopTasks(),stopConnection();for(let stop of live)stop()},slot.tasks=orchestrator.tasksSignal().get(),this.setStatus(entry.alias,{state:"online",version:orchestrator.daemonVersionSignal().get()??void 0}),this.republishTasks(),this.republishLive(),logClient("machines",`${entry.alias} online (${slot.tasks.length} tasks)`)}republishLive(){let activity=new Map,changes=new Map,tokens=new Map;for(let slot of this.slots.values()){let o=slot.orchestrator;if(!o)continue;for(let[id,state]of o.engineStateSignal().get())activity.set(id,state);for(let[path,change]of o.worktreeChangesSignal().get()??[])changes.set(path,change);for(let[id,chips]of o.rowTokensSignal().get())tokens.set(id,chips)}this.liveAcc.set({activity,changes,tokens})}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
|
+
export{MachineHub,classifyHandshakeFailure};
|
package/dist/cli/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{matchPathGlob}from"./chunk-kg11c1py.js";import{failureHint}from"./chunk-
|
|
3
|
+
import{matchPathGlob}from"./chunk-kg11c1py.js";import{failureHint}from"./chunk-n7vtv1rw.js";import{switchFlag}from"./chunk-zsfyj36g.js";import{connectIfRunning}from"./chunk-tgfn5ykb.js";import"./chunk-qga9xd2f.js";import"./chunk-5v02t4pz.js";import{expandTilde}from"./chunk-ag3txfg2.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{BUILTIN_VENDORS,coerceVendorId,isBuiltinVendor}from"./chunk-h2m7em1e.js";import{CURRENT_VERSION}from"./chunk-xwyp7bvy.js";import{rejectionReason}from"./chunk-3342qzve.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-ws4cg819.js";import"./chunk-7kwk5kxn.js";import"./chunk-cmp64q4j.js";import"./chunk-kmgheesn.js";import"./chunk-szjgjrar.js";import"./chunk-gskbzgc3.js";import{pathSyntax}from"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{resolve as resolve2}from"path";function debugEnabled(env){return env.ROVE_DEBUG==="1"||env.ROVE_DEBUG==="1"}function failureSubject(cliName,argv){let verb=argv[2];return verb&&!verb.startsWith("-")&&!verb.includes("/")?`${cliName} ${verb}`:cliName}function summarizeCliGitError(message,cwd){if(!/not a git repository/i.test(message))return null;return`${cwd} is not a git repository \u2014 run this inside one, or pass a repo path.`}function formatCliFailure(err,opts){let subject=failureSubject(opts.cliName,opts.argv);if(debugEnabled(opts.env))return`${subject}: ${String(err instanceof Error?err.stack??err:err)}
|
|
4
4
|
${failureHint(err,opts.cliName)}`;let raw=errorMessage(err),git=summarizeCliGitError(raw,opts.cwd);return`${subject}: ${git??`${raw}
|
|
5
|
-
${failureHint(err,opts.cliName)}`}`}var DYNAMIC_COMMANDS=new Map([["completions",async(args)=>{let{runCompletionsSubcommand}=await import("./chunk-
|
|
6
|
-
`),process.exit(1);let projectRoot=await projectRootFor(dir);await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-z6y4cg73.js");writeLastActiveTaskId(String(task.id))}});let{publishRoveTerminalTitle}=await import("./chunk-g8wrdp7n.js");publishRoveTerminalTitle();let{launchTui}=await import("./chunk-
|
|
5
|
+
${failureHint(err,opts.cliName)}`}`}var DYNAMIC_COMMANDS=new Map([["completions",async(args)=>{let{runCompletionsSubcommand}=await import("./chunk-mqrn27h8.js");await runCompletionsSubcommand(args)}],["export",async(args)=>{let{runExportSubcommand}=await import("./chunk-3x0ryj15.js");await runExportSubcommand(args)}],["repo",async(args)=>{let{runRepoSubcommand}=await import("./chunk-ax5c2qmv.js");await runRepoSubcommand(args)}],["api",async(args)=>{let{runApiSubcommand}=await import("./chunk-dx12gkf5.js");await runApiSubcommand(args)}],["update",async(args)=>{let{runUpdateSubcommand}=await import("./chunk-8mx0egn7.js");await runUpdateSubcommand(args)}],["theme",async(args)=>{let{runThemeSubcommand}=await import("./chunk-yyjskza5.js");await runThemeSubcommand(args)}],["feedback",async(args)=>{let{runFeedbackSubcommand}=await import("./chunk-6qyd3ny6.js");await runFeedbackSubcommand(args)}],["daemon",async(args)=>{let{runDaemonSubcommand}=await import("./chunk-dnmq3c4k.js");await runDaemonSubcommand(args)}],["machine",async(args)=>{let{runMachineSubcommand}=await import("./chunk-yhcsp07b.js");await runMachineSubcommand(args)}],["weixin",async(args)=>{let{runChannelCli}=await import("./chunk-c09jfhpp.js");await runChannelCli("weixin",args)}],["doctor",async(args)=>{let{runDoctorSubcommand}=await import("./chunk-xt82hp6y.js");await runDoctorSubcommand(args)}],["config",async(args)=>{let{runConfigSubcommand}=await import("./chunk-wch6y5bd.js");await runConfigSubcommand(args)}],["reset",async(args)=>{let{runResetSubcommand}=await import("./chunk-jqkzg4dd.js");await runResetSubcommand(args)}],["pty-host",async(args)=>{let{runPtyHostSubcommand}=await import("./chunk-ca4dvdj4.js");await runPtyHostSubcommand(args)}],["skill",async(args)=>{let{runSkillSubcommand}=await import("./chunk-xn4494n9.js");await runSkillSubcommand(args)}],["plugin",async(args)=>{let{runPluginSubcommand}=await import("./chunk-pdn1r8rf.js");await runPluginSubcommand(args)}],["hook",async(args)=>{let{runHookSubcommand}=await import("./chunk-2cbzp9t1.js");await runHookSubcommand(args)}]]);import{statSync}from"fs";import{resolve}from"path";async function openLocalOrchestrator(){let{TaskIndexStore}=await import("./chunk-m86qk3za.js"),{GitWorktreeManager}=await import("./chunk-x2xk1hpy.js"),{Orchestrator}=await import("./chunk-rn3cyff1.js"),store=new TaskIndexStore;return await store.load(),new Orchestrator({store,worktrees:new GitWorktreeManager})}async function withDaemonOrLocal(bridge){let client=await connectIfRunning();if(client)try{return await bridge.daemon(client)}finally{client.close()}let orch=await openLocalOrchestrator();return bridge.local(orch)}function isPathLikeArg(arg){return arg==="."||arg===".."||arg.startsWith("./")||arg.startsWith("../")||arg.startsWith(".\\")||arg.startsWith("..\\")||pathSyntax(arg).isAbsolute(arg)||arg.startsWith("/")||arg==="~"||arg.startsWith("~/")||arg.startsWith("~\\")}async function projectRootFor(dir){let{isGitRepo,resolveRepoRoot}=await import("./chunk-zfyf3fdj.js"),{projectRejection}=await import("./chunk-4z01vg3t.js"),top=resolveRepoRoot(dir);if(top!==dir)return null;return projectRejection(top,isGitRepo,"explicit")?null:top}async function runOpenDirectory(arg){let dir=resolve(process.cwd(),expandTilde(arg)),isDir=!1;try{isDir=statSync(dir).isDirectory()}catch{isDir=!1}if(!isDir)process.stderr.write(`${ROVE_PRODUCT_NAME}: "${arg}" is not a directory (resolved to ${dir}).
|
|
6
|
+
`),process.exit(1);let projectRoot=await projectRootFor(dir);await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-z6y4cg73.js");writeLastActiveTaskId(String(task.id))}});let{publishRoveTerminalTitle}=await import("./chunk-g8wrdp7n.js");publishRoveTerminalTitle();let{launchTui}=await import("./chunk-60ppphcx.js");await launchTui()}function topLevelUsage(cliName=ROVE_PRODUCT_NAME){return[`${cliName} ${CURRENT_VERSION}`,"",`Usage: ${cliName} [command] [options]`,"","Run with no command to launch PureTUI.",`Run \`${cliName} .\` (or \`${cliName} <path>\`) to open a directory as a standalone task.`,"","Commands:"," completions <shell> Generate shell completion script (bash/zsh/fish)"," add [path] Save a repo path for the new-task picker"," remove [path] Forget a saved project (inverse of add; non-destructive)"," adopt [glob] Import existing git worktrees as tasks"," export [--csv|--json] Print the task list (json/csv/table; daemon-free)"," repo <verb> Per-repo init script + first prompt (show|set|unset)",` api <verb> Scriptable RPC surface for agents (see \`${cliName} api --help\`)`," daemon <verb> Manage the daemon (start|stop|status|restart)"," machine <verb> Other computers running Rove (add|doctor|remove|list)"," weixin <verb> Talk to Rove from WeChat (login|logout|status|allow|deny|send|agent)"," doctor [--report|--fix] Diagnose daemon/PTY/engines/git; --fix walks the remedies",` config [--path] Open ${cliName}'s config file (state.json) in your editor`," reset [--hard] Stop runtimes; optionally wipe task/UI state"," theme <verb> Manage user themes (list|add|remove)",` skill <verb> Install the ${cliName} agent skill (install|status|command|print)`," plugin <verb> Install and run plugins (install|link|list|action|\u2026)"," feedback Send feedback to GitHub Discussions",` update [version|channel|list] Self-update ${cliName}, switch channel, or list versions`,"","Options:"," -v, --version Print version"," -h, --help Print this help"," --skill Print the agent skill file and exit"," --web [bridge flags] Serve the browser client on 127.0.0.1 and print its link"].join(`
|
|
7
7
|
`)}var CLI_NAME=ROVE_PRODUCT_NAME,ADD_USAGE=[`Usage: ${CLI_NAME} add [path]`,` ${CLI_NAME} add --remote --host <host> --user <user> --path <basePath> [--port N] [--key [path] | --password]`,"","Save a repo for the new-task picker. With --remote, register an SSH-backed","project whose worktrees live on <host>; engine launch over SSH is pending.",""].join(`
|
|
8
8
|
`);async function runAddSubcommand(rest){let arg=rest[0];if(arg==="--help"||arg==="-h"||arg==="help"){process.stdout.write(ADD_USAGE);return}if(arg==="--remote"){let{runAddRemote}=await import("./chunk-vpj3gw8b.js");await runAddRemote(rest.slice(1));return}if(arg?.startsWith("-"))process.stderr.write(`${CLI_NAME} add: unknown flag "${arg}"
|
|
9
9
|
|
|
@@ -26,4 +26,4 @@ ${ADOPT_USAGE}
|
|
|
26
26
|
pass a path glob to adopt, e.g. ${CLI_NAME} adopt '${repo}/*' --yes`);return}let matched=worktrees.filter(isMatch);if(matched.length===0){console.log(`
|
|
27
27
|
no worktrees match glob ${JSON.stringify(glob)}`);return}if(!yes){console.log(`
|
|
28
28
|
${matched.length} worktree(s) match \u2014 re-run with --yes to adopt them`);return}await adoptWorktreesInto(orch,repo,matched,vendor),console.log(`done \u2014 adopted ${matched.length} worktree(s)`)}function printTopLevelUsage(out){out.write(`${topLevelUsage()}
|
|
29
|
-
`)}var COMMANDS=new Map([["add",runAddSubcommand],["remove",runRemoveSubcommand],["adopt",runAdoptSubcommand],...DYNAMIC_COMMANDS]);async function main(){let[,,...rawArgs]=process.argv,[subcommand,...rest]=rawArgs;if(subcommand==="--version"||subcommand==="-v"||subcommand==="version"){let{CURRENT_VERSION:CURRENT_VERSION2}=await import("./chunk-
|
|
29
|
+
`)}var COMMANDS=new Map([["add",runAddSubcommand],["remove",runRemoveSubcommand],["adopt",runAdoptSubcommand],...DYNAMIC_COMMANDS]);async function main(){let[,,...rawArgs]=process.argv,[subcommand,...rest]=rawArgs;if(subcommand==="--version"||subcommand==="-v"||subcommand==="version"){let{CURRENT_VERSION:CURRENT_VERSION2}=await import("./chunk-hk0s2bbn.js");console.log(`${CLI_NAME} ${CURRENT_VERSION2}`);return}if(subcommand==="--help"||subcommand==="-h"||subcommand==="help"){printTopLevelUsage(process.stdout);return}if(subcommand==="--skill"){let{runSkillSubcommand}=await import("./chunk-xn4494n9.js");await runSkillSubcommand(["print"]);return}if(subcommand==="--web"){let{runWebSubcommand}=await import("./chunk-a89xzxv2.js");await runWebSubcommand(rest);return}let handler=subcommand!==void 0?COMMANDS.get(subcommand):void 0;if(handler){await handler(rest);return}if(subcommand!==void 0&&isPathLikeArg(subcommand)){await runOpenDirectory(subcommand);return}if(subcommand!==void 0)console.error(`${CLI_NAME}: unknown command '${subcommand}'`),printTopLevelUsage(process.stderr),process.exit(2);let{publishRoveTerminalTitle}=await import("./chunk-g8wrdp7n.js");publishRoveTerminalTitle();let{launchTui}=await import("./chunk-60ppphcx.js");await launchTui()}main().catch((err)=>{console.error(formatCliFailure(err,{cliName:CLI_NAME,argv:process.argv,cwd:process.cwd(),env:process.env})),process.exit(1)});
|
|
@@ -706,6 +706,9 @@ function ensureOwnerOnlyStateDir(homeDir) {
|
|
|
706
706
|
return ensureOwnerOnlyDir(join5(homeDir, ROVE_STATE_DIR_BASENAME));
|
|
707
707
|
}
|
|
708
708
|
|
|
709
|
+
// ../rove-daemon/src/repo-id.ts
|
|
710
|
+
var memo = new Map;
|
|
711
|
+
|
|
709
712
|
// ../rove-daemon/src/daemon/automation-contracts.ts
|
|
710
713
|
var ROUTINE_RESPONSE_WINDOW_MS = 2 * 60 * 60000;
|
|
711
714
|
// ../rove-daemon/src/daemon/delivery-contracts.ts
|
|
@@ -721,6 +724,8 @@ var ALLOWED = {
|
|
|
721
724
|
var DAEMON_CHANNELS = [
|
|
722
725
|
"task.snapshot",
|
|
723
726
|
"issue.snapshot",
|
|
727
|
+
"tabs.changed",
|
|
728
|
+
"row.status",
|
|
724
729
|
"active-task",
|
|
725
730
|
"update",
|
|
726
731
|
"engine-state",
|
package/dist/cli/rove.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{join as l}from"node:path";import{createInterface as a}from"node:readline/promises";import{pathToFileURL as ss}from"node:url";import{spawnSync as Q}from"node:child_process";import{constants as e,accessSync as V}from"node:fs";import{homedir as R}from"node:os";import{basename as o,delimiter as I,dirname as U,join as y}from"node:path";import{fileURLToPath as T}from"node:url";var H={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.
|
|
2
|
+
import{join as l}from"node:path";import{createInterface as a}from"node:readline/promises";import{pathToFileURL as ss}from"node:url";import{spawnSync as Q}from"node:child_process";import{constants as e,accessSync as V}from"node:fs";import{homedir as R}from"node:os";import{basename as o,delimiter as I,dirname as U,join as y}from"node:path";import{fileURLToPath as T}from"node:url";var H={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.263",description:"Rove — the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",keywords:["terminal","tui","cli","multiplexer","ai-agents","coding-agent","ai-coding-assistant","agentic-ai","parallel-agents","git-worktree","claude-code","codex","llm","developer-tools"],type:"module",packageManager:"bun@1.3.13",bin:{rove:"dist/cli/rove.js"},files:["dist/cli","dist/completions","dist/web","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://rove.run",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:mock":"ROVE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:rubric":"bun run scripts/build-tier-rubric.ts",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"ROVE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"ROVE_INCLUDE_SOCKET=1 ROVE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"ROVE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun scripts/render-track.mjs",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build","plugin-sandbox":"bun run scripts/plugin-sandbox.ts"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0",react:"^19.2.8","smol-toml":"^1.7.1",ws:"^8.21.3"},optionalDependencies:{"node-pty":"^1.1.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/rove-daemon":"0.7.22","@tsconfig/bun":"1.0.11","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","react-devtools-core":"^7.0.1","rove-bridge":"0.0.24","rove-weixin":"0.0.24",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]};var q="rove";var k=q;var z="ROVE_BUN",_="ROVE_NO_BUN_BOOTSTRAP",F="ROVE_SKIP_BUN_CHECK",$=H.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0",L=(s)=>{try{return V(s,e.X_OK),!0}catch{return!1}},B=(s)=>s==="win32"?"bun.exe":"bun",f=(s)=>{let t=Q(s,["--version"],{encoding:"utf8",timeout:5000});if(t.error||t.status!==0)return null;return t.stdout?.split(`
|
|
3
3
|
`)[0]?.trim()??""};function J(s){return s.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function X(s,t=$){let c=J(s),W=J(t);if(!c||!W)return!0;let b=c.split(".").map(Number),g=W.split(".").map(Number);for(let p=0;p<3;p++){let r=b[p]??0,i=g[p]??0;if(r!==i)return r>i}return!0}function Y(s=process.env){return s[F]==="1"}function A(s={}){let t=s.env??process.env,c=s.platform??process.platform,W=s.home??t.HOME??t.USERPROFILE??R(),b=B(c),g=[],p=t[z]?.trim();if(p)g.push(p);for(let G of(t.PATH??t.Path??"").split(I))if(G)g.push(y(G,b));let r=t.BUN_INSTALL?.trim();if(r)g.push(y(r,"bin",b));if(W)g.push(y(W,".bun","bin",b));let i=s.launcherDir;if(i)g.push(y(i,"..","..","node_modules","bun","bin",b)),g.push(y(i,"..","..","..","bun","bin",b));return g}function N(s={}){let t=s.isExecutable??L;return A(s).find((c)=>t(c))??null}function Z(s={}){let t=s.isExecutable??L,c=s.bunVersionOf??f;if(Y(s.env??process.env))return{bun:N(s),stale:null,unusable:null};let W=null,b=null;for(let g of A(s)){if(!t(g))continue;let p=c(g);if(p===null){b??=g;continue}if(X(p))return{bun:g,stale:W,unusable:b};W??={path:g,version:J(p)??p}}return{bun:null,stale:W,unusable:b}}function h(s){return U(T(s))}function C(s){return o(T(s)).replace(/\.[cm]?[jt]s$/,"")}function n(s=process.platform){return s==="win32"?["powershell","-NoProfile","-Command","irm bun.sh/install.ps1 | iex"]:["bash","-c","curl -fsSL https://bun.sh/install | bash"]}function D(s=k,t=process.platform){let c=t==="win32"?'powershell -c "irm bun.sh/install.ps1 | iex"':"curl -fsSL https://bun.sh/install | bash";return[`${s}: Rove runs on the Bun runtime, and no Bun was found on this machine.`,"","Install Bun, then run this command again:",` ${c}`," npm install -g bun # any platform, if you already have npm","","Or install Bun and Rove together in one step:"," curl -fsSL https://rove.run/install.sh | sh","",`Already have Bun somewhere unusual? Point Rove at it: ${z}=/path/to/bun`,""].join(`
|
|
4
4
|
`)}function j(s,t,c=k){return[`${c}: this machine's Bun is too old for Rove — found ${t} at ${s}, need ${$} or newer.`,"","Rove's terminals are built on Bun's PTY API. An older Bun ignores it silently,","so every terminal and engine tab would open empty and stay empty.","","Upgrade Bun, then run this command again:"," bun upgrade # Bun installed itself (~/.bun)"," brew upgrade bun # Homebrew"," npm install -g bun@latest # npm-managed Bun","",`Have a newer Bun elsewhere? Point Rove at it: ${z}=/path/to/bun`,`Run on this one anyway (unsupported, terminals will be blank): ${F}=1`,""].join(`
|
|
5
5
|
`)}function v(s,t=k){return[`${t}: the Bun at ${s} could not be run — \`${s} --version\` failed or never returned.`,"","Rove skipped it rather than starting through it, which would hang or fail","with a message from that binary instead of this one.","","Reinstall Bun, then run this command again:"," curl -fsSL https://bun.sh/install | bash","",`Have a working Bun elsewhere? Point Rove at it: ${z}=/path/to/bun`,""].join(`
|
|
@@ -12,14 +12,14 @@ _rove() {
|
|
|
12
12
|
fi
|
|
13
13
|
if [[ ${COMP_CWORD} -eq 2 ]]; then
|
|
14
14
|
case "${prev}" in
|
|
15
|
-
api) COMPREPLY=( $(compgen -W "schema engine-list list get-task pty-list collect context digest agent-turns inspect read-output watch worktree-files worktree-diff worktree-diff-file deliveries should-run add send dispatch interrupt note note-list note-delete pane-open pane-close pane-graphics tab-close tab-new tab-split notify prompt engine-report row-token set-active report attention-dismiss gate-raise gate-answer gate-withdraw gates feedback issue-list issue-create issue-update issue-delete routine-list routine-create routine-update routine-delete routine-run-now routine-respond routine-runs workitem-list workitem-start update land delete ensure-worktree remove-worktree discover-adoptable adopt" -- "${cur}") ) ;;
|
|
16
|
-
daemon) COMPREPLY=( $(compgen -W "status start stop restart" -- "${cur}") ) ;;
|
|
15
|
+
api) COMPREPLY=( $(compgen -W "schema engine-list list get-task pty-list collect context digest agent-turns inspect read-output watch worktree-files worktree-diff worktree-diff-file repo-match repo-list publish deliveries should-run add send dispatch interrupt note note-list note-delete pane-open pane-close pane-graphics tab-close tab-new tab-split notify prompt engine-report row-token set-active report attention-dismiss gate-raise gate-answer gate-withdraw gates feedback issue-list issue-create issue-update issue-delete routine-list routine-create routine-update routine-delete routine-run-now routine-respond routine-runs workitem-list workitem-start update land delete ensure-worktree remove-worktree discover-adoptable adopt" -- "${cur}") ) ;;
|
|
16
|
+
daemon) COMPREPLY=( $(compgen -W "status start stop restart relay" -- "${cur}") ) ;;
|
|
17
17
|
machine) COMPREPLY=( $(compgen -W "add doctor remove list" -- "${cur}") ) ;;
|
|
18
18
|
plugin) COMPREPLY=( $(compgen -W "install link list search outdated update enable disable unlink uninstall config-dir log action pane" -- "${cur}") ) ;;
|
|
19
19
|
repo) COMPREPLY=( $(compgen -W "show set unset" -- "${cur}") ) ;;
|
|
20
20
|
skill) COMPREPLY=( $(compgen -W "install status command print" -- "${cur}") ) ;;
|
|
21
21
|
theme) COMPREPLY=( $(compgen -W "list add remove" -- "${cur}") ) ;;
|
|
22
|
-
weixin) COMPREPLY=( $(compgen -W "login logout status allow deny" -- "${cur}") ) ;;
|
|
22
|
+
weixin) COMPREPLY=( $(compgen -W "login logout status allow deny send agent" -- "${cur}") ) ;;
|
|
23
23
|
esac
|
|
24
24
|
fi
|
|
25
25
|
}
|
|
@@ -19,11 +19,11 @@ complete -c rove -f -n __fish_use_subcommand -a skill
|
|
|
19
19
|
complete -c rove -f -n __fish_use_subcommand -a plugin
|
|
20
20
|
complete -c rove -f -n __fish_use_subcommand -a feedback
|
|
21
21
|
complete -c rove -f -n __fish_use_subcommand -a update
|
|
22
|
-
complete -c rove -f -n "__fish_seen_subcommand_from api" -a "schema engine-list list get-task pty-list collect context digest agent-turns inspect read-output watch worktree-files worktree-diff worktree-diff-file deliveries should-run add send dispatch interrupt note note-list note-delete pane-open pane-close pane-graphics tab-close tab-new tab-split notify prompt engine-report row-token set-active report attention-dismiss gate-raise gate-answer gate-withdraw gates feedback issue-list issue-create issue-update issue-delete routine-list routine-create routine-update routine-delete routine-run-now routine-respond routine-runs workitem-list workitem-start update land delete ensure-worktree remove-worktree discover-adoptable adopt"
|
|
23
|
-
complete -c rove -f -n "__fish_seen_subcommand_from daemon" -a "status start stop restart"
|
|
22
|
+
complete -c rove -f -n "__fish_seen_subcommand_from api" -a "schema engine-list list get-task pty-list collect context digest agent-turns inspect read-output watch worktree-files worktree-diff worktree-diff-file repo-match repo-list publish deliveries should-run add send dispatch interrupt note note-list note-delete pane-open pane-close pane-graphics tab-close tab-new tab-split notify prompt engine-report row-token set-active report attention-dismiss gate-raise gate-answer gate-withdraw gates feedback issue-list issue-create issue-update issue-delete routine-list routine-create routine-update routine-delete routine-run-now routine-respond routine-runs workitem-list workitem-start update land delete ensure-worktree remove-worktree discover-adoptable adopt"
|
|
23
|
+
complete -c rove -f -n "__fish_seen_subcommand_from daemon" -a "status start stop restart relay"
|
|
24
24
|
complete -c rove -f -n "__fish_seen_subcommand_from machine" -a "add doctor remove list"
|
|
25
25
|
complete -c rove -f -n "__fish_seen_subcommand_from plugin" -a "install link list search outdated update enable disable unlink uninstall config-dir log action pane"
|
|
26
26
|
complete -c rove -f -n "__fish_seen_subcommand_from repo" -a "show set unset"
|
|
27
27
|
complete -c rove -f -n "__fish_seen_subcommand_from skill" -a "install status command print"
|
|
28
28
|
complete -c rove -f -n "__fish_seen_subcommand_from theme" -a "list add remove"
|
|
29
|
-
complete -c rove -f -n "__fish_seen_subcommand_from weixin" -a "login logout status allow deny"
|
|
29
|
+
complete -c rove -f -n "__fish_seen_subcommand_from weixin" -a "login logout status allow deny send agent"
|
|
@@ -13,14 +13,14 @@ _rove() {
|
|
|
13
13
|
|
|
14
14
|
verbs=()
|
|
15
15
|
case "${words[2]}" in
|
|
16
|
-
api) verbs=("schema" "engine-list" "list" "get-task" "pty-list" "collect" "context" "digest" "agent-turns" "inspect" "read-output" "watch" "worktree-files" "worktree-diff" "worktree-diff-file" "deliveries" "should-run" "add" "send" "dispatch" "interrupt" "note" "note-list" "note-delete" "pane-open" "pane-close" "pane-graphics" "tab-close" "tab-new" "tab-split" "notify" "prompt" "engine-report" "row-token" "set-active" "report" "attention-dismiss" "gate-raise" "gate-answer" "gate-withdraw" "gates" "feedback" "issue-list" "issue-create" "issue-update" "issue-delete" "routine-list" "routine-create" "routine-update" "routine-delete" "routine-run-now" "routine-respond" "routine-runs" "workitem-list" "workitem-start" "update" "land" "delete" "ensure-worktree" "remove-worktree" "discover-adoptable" "adopt") ;;
|
|
17
|
-
daemon) verbs=("status" "start" "stop" "restart") ;;
|
|
16
|
+
api) verbs=("schema" "engine-list" "list" "get-task" "pty-list" "collect" "context" "digest" "agent-turns" "inspect" "read-output" "watch" "worktree-files" "worktree-diff" "worktree-diff-file" "repo-match" "repo-list" "publish" "deliveries" "should-run" "add" "send" "dispatch" "interrupt" "note" "note-list" "note-delete" "pane-open" "pane-close" "pane-graphics" "tab-close" "tab-new" "tab-split" "notify" "prompt" "engine-report" "row-token" "set-active" "report" "attention-dismiss" "gate-raise" "gate-answer" "gate-withdraw" "gates" "feedback" "issue-list" "issue-create" "issue-update" "issue-delete" "routine-list" "routine-create" "routine-update" "routine-delete" "routine-run-now" "routine-respond" "routine-runs" "workitem-list" "workitem-start" "update" "land" "delete" "ensure-worktree" "remove-worktree" "discover-adoptable" "adopt") ;;
|
|
17
|
+
daemon) verbs=("status" "start" "stop" "restart" "relay") ;;
|
|
18
18
|
machine) verbs=("add" "doctor" "remove" "list") ;;
|
|
19
19
|
plugin) verbs=("install" "link" "list" "search" "outdated" "update" "enable" "disable" "unlink" "uninstall" "config-dir" "log" "action" "pane") ;;
|
|
20
20
|
repo) verbs=("show" "set" "unset") ;;
|
|
21
21
|
skill) verbs=("install" "status" "command" "print") ;;
|
|
22
22
|
theme) verbs=("list" "add" "remove") ;;
|
|
23
|
-
weixin) verbs=("login" "logout" "status" "allow" "deny") ;;
|
|
23
|
+
weixin) verbs=("login" "logout" "status" "allow" "deny" "send" "agent") ;;
|
|
24
24
|
esac
|
|
25
25
|
if (( CURRENT == 3 && ${#verbs} > 0 )); then
|
|
26
26
|
_describe -t verbs 'verb' verbs
|
|
@@ -3,7 +3,7 @@ name: rove
|
|
|
3
3
|
description: Use when controlling Rove tasks, parallel coding attempts, hosted agent sessions, task lifecycle, or the daemon-owned issue tracker from a shell. Also the ONLY channel for messaging another agent session on this machine — `rove api send`, never a peer/MCP side channel.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- rove-skill-version:
|
|
6
|
+
<!-- rove-skill-version: 70 — bump in lockstep with ROVE_SKILL_VERSION (src/lib/skill-install.ts). -->
|
|
7
7
|
|
|
8
8
|
# Rove shell control
|
|
9
9
|
|
|
@@ -223,17 +223,19 @@ clear the shared active task.
|
|
|
223
223
|
|
|
224
224
|
<!-- generated:begin create,edit,lifecycle -->
|
|
225
225
|
```text
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
226
|
+
publish --task-id(REQ) --remote
|
|
227
|
+
add --repo(REQ) --clone --allow-fork --title --branch --base-branch --worktree-name
|
|
228
|
+
--command --effort --tier{swift|standard|deep|auto} --model --count
|
|
229
|
+
--agents <claude:2,codex:1>
|
|
230
|
+
--status{backlog|in_progress|in_review|done|canceled|error}(backlog) --pin
|
|
231
|
+
--require-report --expect-report --activate(false) --prompt|--prompt-file
|
|
232
|
+
update --task-id(REQ) --title --tab --branch --command --model --effort --pinned
|
|
233
|
+
--require-report{on|off}
|
|
234
|
+
--status{backlog|in_progress|in_review|done|canceled|error} --report-branch
|
|
235
|
+
--report-pr --report-summary
|
|
236
|
+
land --task-id(REQ) --dry-run --strategy{merge|squash}(merge) --delete-branch
|
|
237
|
+
--remove-worktree(true)
|
|
238
|
+
delete --task-id --group --force --delete-branch --delete-remote --wait
|
|
237
239
|
```
|
|
238
240
|
<!-- generated:end -->
|
|
239
241
|
|
|
@@ -314,13 +316,15 @@ it fires with no TUI attached.
|
|
|
314
316
|
<!-- generated:begin routine -->
|
|
315
317
|
```text
|
|
316
318
|
routine-list (none)
|
|
317
|
-
routine-create --repo(REQ) --name(REQ) --prompt|--prompt-file
|
|
319
|
+
routine-create --repo(REQ) --name(REQ) --prompt|--prompt-file --schedule(REQ)
|
|
318
320
|
--vendor{claude|codex|copilot|kimi|pi|omp|bob} --model --effort
|
|
319
|
-
--base-branch --precheck --precheck-timeout(120) --
|
|
320
|
-
--
|
|
321
|
+
--base-branch --precheck --precheck-timeout(120) --script
|
|
322
|
+
--script-timeout(120) --notify --grace(60) --persistent-session
|
|
323
|
+
--target-task --target-tab --disabled
|
|
321
324
|
routine-update --id(REQ) --name --prompt|--prompt-file --schedule --vendor --model
|
|
322
|
-
--effort --base-branch --precheck --precheck-timeout(120) --
|
|
323
|
-
--
|
|
325
|
+
--effort --base-branch --precheck --precheck-timeout(120) --script
|
|
326
|
+
--script-timeout(120) --notify --grace(60) --persistent-session
|
|
327
|
+
--target-task --target-tab --enabled
|
|
324
328
|
routine-delete --id(REQ)
|
|
325
329
|
routine-run-now --id(REQ)
|
|
326
330
|
routine-respond --run(REQ) --text --prompt-file
|
|
@@ -376,6 +380,8 @@ respawned — files kept, conversation did not), `skipped_precheck` (nothing to
|
|
|
376
380
|
```text
|
|
377
381
|
schema --verb --group --all
|
|
378
382
|
engine-list (none)
|
|
383
|
+
repo-match --origin --root --allow-fork
|
|
384
|
+
repo-list (none)
|
|
379
385
|
feedback --title(REQ) --body(REQ) --category(feedback)
|
|
380
386
|
```
|
|
381
387
|
<!-- generated:end -->
|
|
@@ -384,6 +390,17 @@ Bare `schema` is the compact index; `--verb <name>` drills into one verb,
|
|
|
384
390
|
`--group <g>` lists one group, `--all` dumps everything. `engine-list` is the
|
|
385
391
|
ids + RAW launch command + protocol.
|
|
386
392
|
|
|
393
|
+
`--repo` takes a repo id as well as a path: `owner/name` (GitHub),
|
|
394
|
+
`host/owner/name`, or a remote URL. An id resolves to the checkout on the
|
|
395
|
+
machine that runs the verb (its `rove machine primary`, else a clean one).
|
|
396
|
+
`add --repo <id> --clone` clones it into `~/.rove/repos/<host>/<owner>/<name>`
|
|
397
|
+
when that machine has none; `--allow-fork` accepts a checkout there under
|
|
398
|
+
another origin. Forwarded with `--machine`, a missing checkout is
|
|
399
|
+
`NO_REMOTE_CHECKOUT` and a fork-only one is `FORK_MATCH`. `repo-match` answers which checkout an `--origin`/`--root`
|
|
400
|
+
resolves to (`{ repo, fork?, checkouts, searched }`); `repo-list` lists a
|
|
401
|
+
machine's repos by id (`{ repos: [{ id, primary, checkouts }] }`) — pass
|
|
402
|
+
`--machine <alias>` to ask another machine.
|
|
403
|
+
|
|
387
404
|
`feedback` opens a GitHub Discussion in the Rove repo through `gh` — Rove's own
|
|
388
405
|
product feedback channel, not a way to file work for another project (that is
|
|
389
406
|
a `send` to their main task; see SKILL.md).
|
|
@@ -412,6 +429,8 @@ Errors go to stderr as `{"error":{"message","code",...}}`. Most carry `hint`
|
|
|
412
429
|
| `DAEMON_GONE` | the daemon died mid-`watch` | `rove daemon status`, then re-run the watch |
|
|
413
430
|
| `WORKTREE_NAME_TAKEN` | `add --worktree-name` names a directory already in use | pick another name, or omit the flag for a generated one |
|
|
414
431
|
| `INVALID_WORKTREE_NAME` | `--worktree-name` is not one plain path segment | letters/digits/`.`/`_`/`-`, not starting with `.` |
|
|
432
|
+
| `NO_LOCAL_CHECKOUT` | `add --repo <id>`, and this machine has no checkout of it | `--clone`, or `--repo` with a checkout's path |
|
|
433
|
+
| `CLONE_FAILED` | `--clone` could not `git clone` the repo | check `git ls-remote <url>` there, or clone by hand and pass the path |
|
|
415
434
|
|
|
416
435
|
Daemon-side refusals carry their OWN code (`DIRTY_WORKTREE`, `LAND_CONFLICT`,
|
|
417
436
|
`MISSING_REF`, `GIT_COMMAND_FAILED`, …), not `RPC_ERROR`. Match on `code`; the
|