@sma1lboy/rove 0.9.258 → 0.9.259

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 (120) hide show
  1. package/dist/cli/{chunk-9v18qy3s.js → chunk-0z1azqkp.js} +1 -1
  2. package/dist/cli/{chunk-jf46jsdp.js → chunk-15jt6k82.js} +1 -1
  3. package/dist/cli/{chunk-csdne12x.js → chunk-1dcb0069.js} +1 -1
  4. package/dist/cli/{chunk-jd02zgwf.js → chunk-1dnyxp0v.js} +1 -1
  5. package/dist/cli/{chunk-tpt3fn1q.js → chunk-1j4e2jcx.js} +1 -1
  6. package/dist/cli/{chunk-jtpjdmb6.js → chunk-1x6yahf1.js} +1 -1
  7. package/dist/cli/{chunk-tq6pq1ws.js → chunk-2676cb62.js} +1 -1
  8. package/dist/cli/{chunk-x8rkpfqd.js → chunk-3n2jn56j.js} +1 -1
  9. package/dist/cli/chunk-3v2hgjb2.js +3 -0
  10. package/dist/cli/{chunk-yktnbb14.js → chunk-3vtpshwx.js} +37 -37
  11. package/dist/cli/{chunk-ya0h6hcd.js → chunk-3yx6rrgm.js} +2 -2
  12. package/dist/cli/chunk-44ba9qvn.js +2 -0
  13. package/dist/cli/chunk-45yxyx4z.js +70 -0
  14. package/dist/cli/{chunk-y8xb4ys7.js → chunk-4abka29v.js} +1 -1
  15. package/dist/cli/{chunk-1egwgg6p.js → chunk-4pmx2q7r.js} +1 -1
  16. package/dist/cli/chunk-4pt3n7cg.js +4 -0
  17. package/dist/cli/{chunk-1zqzqbek.js → chunk-59hmb90m.js} +1 -1
  18. package/dist/cli/chunk-5c0dgs7n.js +2 -0
  19. package/dist/cli/{chunk-zam29b9x.js → chunk-5g3s1a2n.js} +1 -1
  20. package/dist/cli/{chunk-ke3t032y.js → chunk-5js4agdd.js} +1 -1
  21. package/dist/cli/{chunk-r6f8h111.js → chunk-5xeywdwg.js} +2 -2
  22. package/dist/cli/{chunk-pw87thvf.js → chunk-5yv3jzc5.js} +1 -1
  23. package/dist/cli/{chunk-kqf371ff.js → chunk-601dsgex.js} +1 -1
  24. package/dist/cli/chunk-67stdpfn.js +2 -0
  25. package/dist/cli/{chunk-6p9yxt3q.js → chunk-6h12b2k0.js} +1 -1
  26. package/dist/cli/chunk-6q52d0nj.js +7 -0
  27. package/dist/cli/{chunk-xnaehfby.js → chunk-6v8rhkr8.js} +1 -1
  28. package/dist/cli/{chunk-hfvz23r6.js → chunk-7rfy6zpw.js} +1 -1
  29. package/dist/cli/chunk-8sq09avz.js +2 -0
  30. package/dist/cli/{chunk-edpbz0gz.js → chunk-9ed3gqj9.js} +3 -3
  31. package/dist/cli/{chunk-cb7hc2xm.js → chunk-9f1xbpxn.js} +1 -1
  32. package/dist/cli/{chunk-3q1rv3rm.js → chunk-9ztqf6hb.js} +1 -1
  33. package/dist/cli/{chunk-dd0mtzje.js → chunk-apm5yjkq.js} +1 -1
  34. package/dist/cli/{chunk-pb5g6161.js → chunk-b41sj385.js} +1 -1
  35. package/dist/cli/chunk-bc4agaf1.js +2 -0
  36. package/dist/cli/{chunk-hdnqq66w.js → chunk-bdwp2k8f.js} +1 -1
  37. package/dist/cli/{chunk-rx2604ry.js → chunk-bkspbk0y.js} +1 -1
  38. package/dist/cli/{chunk-t25xke74.js → chunk-bkt3ktvx.js} +1 -1
  39. package/dist/cli/{chunk-8gjpnb83.js → chunk-btygchef.js} +1 -1
  40. package/dist/cli/chunk-c0gvp57p.js +3 -0
  41. package/dist/cli/{chunk-qn04z4zb.js → chunk-cc1mzr8d.js} +1 -1
  42. package/dist/cli/{chunk-95jzkqp2.js → chunk-dc3n6nf7.js} +1 -1
  43. package/dist/cli/{chunk-68113ts1.js → chunk-e6848rj8.js} +1 -1
  44. package/dist/cli/{chunk-y0gybgba.js → chunk-ecngwr1v.js} +1 -1
  45. package/dist/cli/{chunk-b47k0cnw.js → chunk-efjahmtj.js} +1 -1
  46. package/dist/cli/chunk-emtbtym6.js +3 -0
  47. package/dist/cli/chunk-g1rqy0nz.js +2 -0
  48. package/dist/cli/{chunk-ehb0hbrg.js → chunk-h2vv63bh.js} +2 -2
  49. package/dist/cli/{chunk-1xrbb7gf.js → chunk-hqkzc8cv.js} +1 -1
  50. package/dist/cli/{chunk-mmc662x2.js → chunk-hwbpbp0c.js} +1 -1
  51. package/dist/cli/{chunk-0604fza5.js → chunk-hynv8c2k.js} +1 -1
  52. package/dist/cli/{chunk-cq5qv93a.js → chunk-j5w8n1st.js} +1 -1
  53. package/dist/cli/{chunk-6x0trw81.js → chunk-jbndzrbw.js} +1 -1
  54. package/dist/cli/chunk-jfbnz454.js +2 -0
  55. package/dist/cli/{chunk-qpc8bv02.js → chunk-jj3nbb2g.js} +4 -4
  56. package/dist/cli/{chunk-pwbtezsa.js → chunk-jtf8qstz.js} +1 -1
  57. package/dist/cli/{chunk-4d4d59vp.js → chunk-jzf2d1pj.js} +1 -1
  58. package/dist/cli/{chunk-yaqkajw4.js → chunk-k3b5cnd5.js} +12 -12
  59. package/dist/cli/{chunk-eyzjma6q.js → chunk-kcefxpn1.js} +1 -1
  60. package/dist/cli/chunk-n3br556t.js +11 -0
  61. package/dist/cli/{chunk-zqq3djrw.js → chunk-ndbxpd01.js} +3 -3
  62. package/dist/cli/{chunk-wyt2vgjv.js → chunk-ngc1n7h3.js} +1 -1
  63. package/dist/cli/{chunk-7cd1epfw.js → chunk-nxdm60xy.js} +1 -1
  64. package/dist/cli/{chunk-8q1g1xq0.js → chunk-p27ph0g8.js} +1 -1
  65. package/dist/cli/chunk-pbfehk8q.js +3 -0
  66. package/dist/cli/{chunk-c8anewjn.js → chunk-pgbsb202.js} +1 -1
  67. package/dist/cli/{chunk-0d57z680.js → chunk-pw9teydh.js} +1 -1
  68. package/dist/cli/{chunk-sma961wh.js → chunk-q07r6hf7.js} +1 -1
  69. package/dist/cli/{chunk-4ab8y1yp.js → chunk-q2kweazg.js} +8 -7
  70. package/dist/cli/chunk-qpvvc1xz.js +4 -0
  71. package/dist/cli/{chunk-ebea569y.js → chunk-qtewm0jz.js} +1 -1
  72. package/dist/cli/chunk-r3zkpbf5.js +9 -0
  73. package/dist/cli/{chunk-sabpcket.js → chunk-rsvh7n8v.js} +1 -1
  74. package/dist/cli/chunk-s83qnstd.js +2 -0
  75. package/dist/cli/{chunk-cqychwvw.js → chunk-sh5a4djc.js} +1 -1
  76. package/dist/cli/{chunk-kgddz8pw.js → chunk-smqmpz5c.js} +1 -1
  77. package/dist/cli/chunk-sqks9vyt.js +2 -0
  78. package/dist/cli/{chunk-yjyjg7sk.js → chunk-stng29vp.js} +2 -2
  79. package/dist/cli/{chunk-80zzjcvp.js → chunk-syqbc3a3.js} +1 -1
  80. package/dist/cli/chunk-wg9w0xf4.js +3 -0
  81. package/dist/cli/{chunk-v7prawj1.js → chunk-wqcs5mz0.js} +1 -1
  82. package/dist/cli/chunk-wv6d96t6.js +2 -0
  83. package/dist/cli/{chunk-45thgqdr.js → chunk-wv8vfhty.js} +1 -1
  84. package/dist/cli/{chunk-jv11f2c2.js → chunk-xpr9sf8t.js} +3 -3
  85. package/dist/cli/chunk-ymq20jvp.js +62 -0
  86. package/dist/cli/{chunk-79r3wbhh.js → chunk-ywtsqm67.js} +1 -1
  87. package/dist/cli/chunk-z3qhpthz.js +3 -0
  88. package/dist/cli/{chunk-jetsx9zr.js → chunk-zae59k1j.js} +1 -1
  89. package/dist/cli/index.js +4 -4
  90. package/dist/cli/rove.js +1 -1
  91. package/dist/completions/rove.bash +2 -2
  92. package/dist/completions/rove.fish +2 -2
  93. package/dist/completions/rove.zsh +2 -2
  94. package/dist/skills/rove/SKILL.md +1 -1
  95. package/dist/skills/rove/references/api-flags.md +13 -11
  96. package/dist/web/assets/index-B4sS_af0.js +109 -0
  97. package/dist/web/assets/index-znAxiX5H.css +1 -0
  98. package/dist/web/index.html +2 -2
  99. package/package.json +3 -3
  100. package/dist/cli/chunk-1378mh2w.js +0 -3
  101. package/dist/cli/chunk-1qge84t7.js +0 -3
  102. package/dist/cli/chunk-1vxykwb9.js +0 -3
  103. package/dist/cli/chunk-2yjpqb47.js +0 -3
  104. package/dist/cli/chunk-658859k9.js +0 -31
  105. package/dist/cli/chunk-6t5d02s4.js +0 -2
  106. package/dist/cli/chunk-7nr405tr.js +0 -9
  107. package/dist/cli/chunk-82zpp3yx.js +0 -4
  108. package/dist/cli/chunk-8dggnfaf.js +0 -2
  109. package/dist/cli/chunk-fehxbwcb.js +0 -6
  110. package/dist/cli/chunk-g846fbp7.js +0 -52
  111. package/dist/cli/chunk-hkv6t5v9.js +0 -2
  112. package/dist/cli/chunk-q301ewyq.js +0 -2
  113. package/dist/cli/chunk-rmk69hvh.js +0 -2
  114. package/dist/cli/chunk-s1rg1zae.js +0 -3
  115. package/dist/cli/chunk-skpkscne.js +0 -11
  116. package/dist/cli/chunk-x7cv6deh.js +0 -2
  117. package/dist/cli/chunk-y85e24s9.js +0 -2
  118. package/dist/cli/chunk-yc9bytrj.js +0 -2
  119. package/dist/web/assets/index-BiUiNIOp.css +0 -1
  120. package/dist/web/assets/index-jy27XaL0.js +0 -109
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import{logDaemonInfo}from"./chunk-rxqdw6s5.js";import{resolveRoveSpawn,testDaemonResponds}from"./chunk-601dsgex.js";import{stopDaemonProcess}from"./chunk-1vwngrmf.js";import{spawnDetachedDaemon,windowsPowershellPath}from"./chunk-3vtpshwx.js";import{isProcessAlive,readPidFile}from"./chunk-wqckm0k6.js";import{RoveDaemonClient}from"./chunk-s0jbtyd9.js";import{defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-n0rtj4z7.js";import{spawn}from"child_process";import{existsSync}from"fs";import{rename,rm}from"fs/promises";import{basename,delimiter,dirname,join,resolve}from"path";import{fileURLToPath}from"url";var PTY_HOST_START_ARGS=["pty-host"],PTY_HOST_NODE_BUNDLE="pty-host-node.mjs",PTY_HOST_NODE_DEV_CACHE="../../.cache/pty-host-node.mjs",PTY_HOST_NODE_ENTRY="../daemon/pty-host-node-entry.ts";function resolveNodeBinary(env=process.env,exists=existsSync,platform=process.platform){let dirs=(env.PATH??env.Path??"").split(delimiter).filter((dir)=>dir.length>0),suffixes=platform==="win32"?(env.PATHEXT??".EXE;.CMD;.BAT").split(";").filter((ext)=>ext.length>0):[""];for(let dir of dirs)for(let suffix of suffixes){let candidate=join(dir,`node${suffix}`);if(exists(candidate))return candidate}return null}async function bundleWithBun(entry,outFile,io){let{build,rename:move,discard}=io??{build:(config)=>Bun.build(config),rename,discard:(path)=>rm(path,{force:!0})},staging=`${outFile}.${process.pid}.tmp`,built=await build({entrypoints:[entry],outdir:dirname(staging),target:"node",format:"esm",naming:basename(staging),external:["node-pty"]});if(!built.success)return await discard(staging).catch(()=>{}),built;return await move(staging,outFile),built}async function resolveNodePtyHostSpawn(deps={}){let platform=deps.platform??process.platform;if(platform!=="win32")return null;let here=deps.moduleDir??dirname(fileURLToPath(import.meta.url)),exists=deps.exists??existsSync,bundle=deps.bundle??bundleWithBun,node=resolveNodeBinary(deps.env??process.env,exists,platform);if(!node)throw Error("Rove: the Windows PTY host runs under node, but no node was found on PATH. "+"Install Node.js (https://nodejs.org) and restart Rove \u2014 engine and terminal sessions cannot start without it.");let packaged=resolve(here,PTY_HOST_NODE_BUNDLE);if(exists(packaged))return[node,packaged];let entry=resolve(here,PTY_HOST_NODE_ENTRY);if(!exists(entry))throw Error(`Rove: no Windows PTY host found (looked for ${packaged} and ${entry})`);let cache=resolve(here,PTY_HOST_NODE_DEV_CACHE),built=await bundle(entry,cache);if(!built.success)throw Error(`Rove: could not build the Windows PTY host \u2014 ${built.logs.map(String).join("; ")}`);return[node,cache]}var BUSY_PTY_HOST_GRACE_MS=15000,CHILD_PROBE_TIMEOUT_MS=5000;function childProbeCommand(deps={}){let env=deps.env??process.env;if((deps.platform??process.platform)!=="win32")return["ps","-A","-o","ppid="];return[windowsPowershellPath(env,deps.exists??existsSync),"-NoProfile","-NonInteractive","-Command","[Console]::OutputEncoding=[System.Text.Encoding]::UTF8; Get-CimInstance -ClassName Win32_Process -Property ParentProcessId | Select-Object -ExpandProperty ParentProcessId"]}function runChildProbe(command,timeoutMs){return new Promise((done,fail)=>{let proc=spawn(command[0]??"",command.slice(1),{stdio:["ignore","pipe","ignore"]}),out="",finish=(err)=>{clearTimeout(timer);try{proc.kill()}catch{}if(err)fail(err);else done(out)},timer=setTimeout(()=>finish(Error(`did not answer within ${timeoutMs}ms`)),timeoutMs);proc.stdout?.on("data",(chunk)=>{out+=String(chunk)}),proc.on("error",(err)=>finish(err)),proc.on("close",(code,signal)=>finish(code===0&&signal===null?null:Error(`exited with ${signal??`code ${code}`}`)))})}async function liveChildCount(pid,deps={}){let timeoutMs=deps.timeoutMs??CHILD_PROBE_TIMEOUT_MS,command=childProbeCommand(deps),run=deps.run??runChildProbe,text;try{text=await run(command,timeoutMs)}catch{return null}let rows=text.split(`
3
+ `).map((row)=>row.trim()).filter((row)=>row.length>0);if(rows.length===0||rows.some((row)=>!/^\d+$/.test(row)))return null;return rows.filter((row)=>Number(row)===pid).length}async function ensurePtyHostReachable(){let socketPath=defaultPtyHostSocketPath();if(await testDaemonResponds(socketPath))return socketPath;let hostPid=await readPidFile(defaultPtyHostPidPath());if(hostPid!==null&&hostPid!==process.pid&&isProcessAlive(hostPid)){let deadline2=Date.now()+BUSY_PTY_HOST_GRACE_MS;while(Date.now()<deadline2){if(await new Promise((resolveTimer)=>setTimeout(resolveTimer,250)),await testDaemonResponds(socketPath))return socketPath;if(!isProcessAlive(hostPid))break}if(isProcessAlive(hostPid)){let sessions=await liveChildCount(hostPid);if(sessions===null)throw Error(`rove: the pty host (pid ${hostPid}) is not answering and Rove could not read this machine's process table, so it cannot tell whether the host still holds live sessions \u2014 refusing to restart it, which would kill every engine running in them. Inspect it with \`rove api pty-list\`, or kill ${hostPid} yourself once you have accepted losing those sessions.`);if(sessions>0)throw Error(`rove: the pty host (pid ${hostPid}) is not answering but still holds ${sessions} live session(s) \u2014 refusing to restart it, which would kill every engine running in them. Inspect it with \`rove api pty-list\`, or kill ${hostPid} yourself once you have accepted losing those sessions.`)}}await stopDaemonProcess(socketPath,defaultPtyHostPidPath()).catch(()=>{});let[command,...args]=await resolveNodePtyHostSpawn()??resolveRoveSpawn(PTY_HOST_START_ARGS);spawnDetachedDaemon(command??"",args,process.env,defaultPtyHostLogPath());let deadline=Date.now()+5000;while(Date.now()<deadline){if(await testDaemonResponds(socketPath))return socketPath;await new Promise((resolveTimer)=>setTimeout(resolveTimer,100))}throw Error(`rove: pty host did not start (or stayed wedged) at ${socketPath}; check ${defaultPtyHostLogPath()} or run \`rove doctor\``)}async function sweepPtyHostSessions(liveTaskIds,homeDir){let client=new RoveDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let{sessions}=await client.request("pty.list"),currentTasks;for(let session of sessions){if(!currentTasks){let ids=liveTaskIds();if(ids===null)return;currentTasks=new Set(ids)}if(currentTasks.has(session.key.split("::")[0]??session.key))continue;if(!session.generation){logDaemonInfo("pty-sweep",`skipped ${session.key}: host has no session generation; restart it when sessions can be interrupted`);continue}await client.request("pty.kill",{key:session.key,expectedGeneration:session.generation}),currentTasks=void 0}}catch{}finally{client.close()}}async function ptyHostHasLiveSessions(homeDir){let client=new RoveDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let result=await client.request("pty.list");if(!Array.isArray(result.sessions)||result.sessions.some((s)=>typeof s.alive!=="boolean"))return null;return result.sessions.some((s)=>s.alive)}catch(err){if(err instanceof Error&&"code"in err&&(err.code==="ENOENT"||err.code==="ECONNREFUSED")){let pid=await readPidFile(defaultPtyHostPidPath(homeDir));return pid!==null&&isProcessAlive(pid)?null:!1}return null}finally{client.close()}}
4
+ export{resolveNodeBinary,bundleWithBun,resolveNodePtyHostSpawn,childProbeCommand,runChildProbe,liveChildCount,ensurePtyHostReachable,sweepPtyHostSessions,ptyHostHasLiveSessions};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{RELEASE_CHANNELS,channelOf}from"./chunk-1xrbb7gf.js";import{loadStateFile,patchStateFile}from"./chunk-g4281a0g.js";var UPDATE_CHANNEL_KEY="update.channel";function normalizeReleaseChannel(value){return RELEASE_CHANNELS.includes(value)?value:null}function preferredReleaseChannel(state=loadStateFile()){return normalizeReleaseChannel(state[UPDATE_CHANNEL_KEY])??channelOf()}function tryOutChannel(){return channelOf()==="nightly"?"latest":"nightly"}function rememberReleaseChannel(channel){patchStateFile({[UPDATE_CHANNEL_KEY]:channel})}
2
+ import{RELEASE_CHANNELS,channelOf}from"./chunk-hqkzc8cv.js";import{loadStateFile,patchStateFile}from"./chunk-g4281a0g.js";var UPDATE_CHANNEL_KEY="update.channel";function normalizeReleaseChannel(value){return RELEASE_CHANNELS.includes(value)?value:null}function preferredReleaseChannel(state=loadStateFile()){return normalizeReleaseChannel(state[UPDATE_CHANNEL_KEY])??channelOf()}function tryOutChannel(){return channelOf()==="nightly"?"latest":"nightly"}function rememberReleaseChannel(channel){patchStateFile({[UPDATE_CHANNEL_KEY]:channel})}
3
3
  export{UPDATE_CHANNEL_KEY,normalizeReleaseChannel,preferredReleaseChannel,tryOutChannel,rememberReleaseChannel};
@@ -0,0 +1,9 @@
1
+ // @bun
2
+ import{shQuote}from"./chunk-b7xjhgts.js";import{loadStateFile,updateStateFile}from"./chunk-g4281a0g.js";import{homeDir}from"./chunk-prqeddy7.js";import{shortHomeTag}from"./chunk-n0rtj4z7.js";var LOCAL_MACHINE_ID="local",ALIAS_RE=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function isValidMachineAlias(alias){return alias!==LOCAL_MACHINE_ID&&alias.length<=64&&ALIAS_RE.test(alias)}function parseSshTarget(target){let trimmed=target.trim();if(!trimmed)return null;let at=trimmed.lastIndexOf("@"),user=at>=0?trimmed.slice(0,at):void 0,rest=at>=0?trimmed.slice(at+1):trimmed;if(at>=0&&!user)return null;let bracketed=/^\[([^\]]+)\](?::(\d{1,5}))?$/.exec(rest),portMatch=bracketed?null:/^([^:]*):(\d{1,5})$/.exec(rest),host=bracketed?bracketed[1]??"":portMatch?portMatch[1]??"":rest,rawPort=bracketed?bracketed[2]:portMatch?.[2],port=rawPort?Number(rawPort):void 0;if(!host||/\s/.test(host))return null;if(port!==void 0&&(port<1||port>65535))return null;return{host,...user?{user}:{},...port?{port}:{}}}function defaultMachineAlias(args){let source=!args.typedUser&&args.port===void 0&&!isIpLiteral(args.typedHost)?args.typedHost:args.remoteHostname||args.typedHost;return sanitizeAlias(source)}function isIpLiteral(host){return host.includes(":")||/^\d{1,3}(\.\d{1,3}){3}$/.test(host)}function sanitizeAlias(raw){return(raw.split(".")[0]??raw).replace(/[^A-Za-z0-9._-]/g,"-").slice(0,64)}function sshTargetOf(config){return config.user?`${config.user}@${config.host}`:config.host}function readMachines(state){let raw=state.machines;if(!raw||typeof raw!=="object"||Array.isArray(raw))return{};return raw}function listMachines(){let machines=readMachines(loadStateFile());return Object.entries(machines).map(([alias,config])=>({alias,...config}))}function getMachine(alias){return readMachines(loadStateFile())[alias]??null}function addMachine(alias,config){let added=!1;return updateStateFile((state)=>{let machines={...readMachines(state)};added=machines[alias]===void 0,machines[alias]={...config,addedAt:config.addedAt??machines[alias]?.addedAt??new Date().toISOString()},state.machines=machines;return}),{added}}function updateMachine(alias,patch){updateStateFile((state)=>{let machines={...readMachines(state)},existing=machines[alias];if(!existing)return!1;machines[alias]={...existing,...patch},state.machines=machines;return})}function setMachineIdentity(alias,identity){updateMachine(alias,{identity})}function removeMachine(alias){let removed=!1;return updateStateFile((state)=>{let machines={...readMachines(state)};if(removed=machines[alias]!==void 0,!removed)return!1;delete machines[alias],state.machines=machines;return}),removed}function dedupeMachines(entries){let kept=[],seen=[];for(let entry of entries){let identity=entry.identity;if(identity){if(seen.some((other)=>sameMachine(other,identity)))continue;seen.push(identity)}kept.push(entry)}return kept}function sameMachine(a,b){return a.hostname===b.hostname&&a.homeDir===b.homeDir&&a.daemonPid===b.daemonPid}function duplicateAliasOf(machines,self,identity){for(let[alias,config]of Object.entries(machines)){if(alias===self)continue;let other=config.identity;if(!other)continue;if(other.hostname===identity.hostname&&other.homeDir===identity.homeDir&&other.daemonPid===identity.daemonPid)return alias}return null}import{tmpdir}from"os";import{join}from"path";var CONTROL_PERSIST_SECONDS=300;function machineSocketDir(alias,home=homeDir()){let natural=join(home,".rove","machines",alias);if(Buffer.byteLength(join(natural,"daemon.sock"),"utf8")<=SOCKET_PATH_LIMIT)return natural;return join(tmpdir(),`rove-m-${shortHomeTag(home)}-${shortHomeTag(alias)}`)}var SOCKET_PATH_LIMIT=100;function localDaemonSocketPath(alias,home=homeDir()){return join(machineSocketDir(alias,home),"daemon.sock")}function localPtySocketPath(alias,home=homeDir()){return join(machineSocketDir(alias,home),"pty.sock")}function controlPath(alias,home=homeDir()){return join(machineSocketDir(alias,home),"cm")}function machineSshArgs(alias,config,opts={}){let argv=["ssh"];if(opts.batch!==!1)argv.push("-o","BatchMode=yes");if(opts.mux!==!1&&process.platform!=="win32")argv.push("-o","ControlMaster=auto","-o",`ControlPath=${controlPath(alias,opts.home)}`,"-o",`ControlPersist=${CONTROL_PERSIST_SECONDS}`);if(argv.push("-o","StrictHostKeyChecking=accept-new"),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(sshTargetOf(config)),argv}import{spawn}from"child_process";import{mkdirSync}from"fs";import{posix}from"path";var PATTERNS=[["host-key-changed",/REMOTE HOST IDENTIFICATION HAS CHANGED|Host key for .* has changed/i],["host-key-unverified",/Host key verification failed|No .*host key is known for/i],["auth-denied",/Permission denied \(|Too many authentication failures|no matching host key type/i],["unresolved",/Could not resolve hostname|Name or service not known|nodename nor servname/i],["refused",/Connection refused/i],["timeout",/timed out|Operation timed out|No route to host|Network is unreachable/i]];function classifySshFailure(stderr){for(let[kind,pattern]of PATTERNS)if(pattern.test(stderr))return kind;return"unknown"}function sshFailureRemedy(kind,target){switch(kind){case"unresolved":return`${target} does not resolve to an address. Check the name, or the Host block in ~/.ssh/config; on a tailnet, check \`tailscale status\`.`;case"refused":return`${target} refused the connection: nothing listens for ssh there. Enable Remote Login / start sshd on it, or pass the right --port.`;case"timeout":return`${target} did not answer. Is it awake and on this network (or VPN / tailnet)?`;case"host-key-changed":return`${target}'s host key CHANGED since you last connected. That is either a reinstall or someone in the middle. If you reinstalled it, remove the old key with \`ssh-keygen -R <host>\` and retry; otherwise stop here.`;case"host-key-unverified":return`${target}'s host key is not trusted yet. Run \`rove machine add\` in a terminal to confirm its fingerprint, or connect once with \`ssh ${target}\`.`;case"auth-denied":return`${target} rejected every key ssh offered. Load your key into ssh-agent, pass --identity <key>, or install a key there with \`ssh-copy-id ${target}\`.`;case"unknown":return`ssh to ${target} failed. Run \`ssh ${target} true\` to see why.`}}async function runOnMachine(alias,config,command,opts={}){try{mkdirSync(machineSocketDir(alias,opts.home),{recursive:!0,mode:448})}catch{}let argv=[...machineSshArgs(alias,config,{home:opts.home}),command];return await new Promise((resolve)=>{let stdout="",stderr="",settled=!1,done=(exitCode)=>{if(settled)return;settled=!0,clearTimeout(timer),resolve({stdout,stderr,exitCode})},child=spawn(argv[0]??"ssh",argv.slice(1),{stdio:["ignore","pipe","pipe"]}),timer=setTimeout(()=>{child.kill("SIGKILL"),stderr+=`
3
+ timed out`,done(-1)},opts.timeoutMs??30000);child.stdout?.on("data",(c)=>{stdout+=c.toString()}),child.stderr?.on("data",(c)=>{stderr+=c.toString()}),child.on("error",()=>done(-1)),child.on("close",(code)=>done(code??-1))})}async function discoverMachine(alias,config,opts={}){let found=await probe(alias,config,roveCommand(config.roveBin),opts);if(found.ok||found.code!=="NO_ROVE")return found;let located=parseLocatedRove((await runOnMachine(alias,config,LOCATE_ROVE_SCRIPT,opts)).stdout);if(!located||located===config.roveBin)return found;let retry=await probe(alias,config,roveCommand(located),opts);return retry.ok?{...retry,roveBin:located}:retry}function roveCommand(roveBin){if(!roveBin)return"rove";return`PATH=${shQuote(posix.dirname(roveBin))}:"$PATH" ${shQuote(roveBin)}`}var LOCATE_ROVE_SCRIPT=[`p=$("\${SHELL:-sh}" -lc 'command -v rove' 2>/dev/null)`,'if [ -n "$p" ] && [ -x "$p" ]; then echo "ROVE_BIN=$p"; exit 0; fi','for p in "$HOME/.bun/bin/rove" "$HOME/.npm-global/bin/rove" "$HOME/.local/bin/rove" /opt/homebrew/bin/rove /usr/local/bin/rove "$HOME"/.nvm/versions/node/*/bin/rove; do',' if [ -x "$p" ]; then echo "ROVE_BIN=$p"; exit 0; fi',"done","exit 1"].join(`
4
+ `);function parseLocatedRove(stdout){return/^ROVE_BIN=(\/\S.*)$/m.exec(stdout)?.[1]?.trim()??null}var ROVE_MISSING=/(?:^|\W)rove:? (?:command not found|not found)|command not found:? rove|\/rove:? No such file or directory|no such file or directory: \S*\/rove\b/i;async function probe(alias,config,rove,opts){let first=await runOnMachine(alias,config,`${rove} daemon status --json`,opts),parsed=parseStatusJson(first.stdout);if(parsed)return{ok:!0,status:parsed};let combined=`${first.stdout}
5
+ ${first.stderr}`.trim();if(ROVE_MISSING.test(combined))return{ok:!1,code:"NO_ROVE",message:`Rove is not installed on ${alias}: not on its PATH, its login shell's PATH, or the usual bun/npm/nvm install dirs. Install it there with \`npm i -g @sma1lboy/rove\`, then re-run.`};if(first.exitCode===255||first.exitCode===-1){let ssh=classifySshFailure(first.stderr),remedy=sshFailureRemedy(ssh,sshTargetOf(config));return{ok:!1,code:"SSH_FAILED",ssh,message:ssh==="unknown"&&combined?`${remedy}
6
+ ${combined}`:remedy}}let started=await runOnMachine(alias,config,`${rove} daemon restart`,{...opts,timeoutMs:60000}),second=await runOnMachine(alias,config,`${rove} daemon status --json`,opts),retry=parseStatusJson(second.stdout);if(retry)return{ok:!0,status:retry};if(looksLikeOldStatus(second.stdout))return{ok:!1,code:"BAD_STATUS",message:`${alias} runs a Rove too old for machines (its \`daemon status\` reports no pty socket). Upgrade it: \`ssh ${alias} npm i -g @sma1lboy/rove\`.`};return{ok:!1,code:started.exitCode===0?"BAD_STATUS":"NO_DAEMON",message:`could not read a daemon status from ${alias}: ${`${second.stdout}
7
+ ${second.stderr}
8
+ ${started.stderr}`.trim()||"no output"}`}}function firstJsonObject(text){let start=text.indexOf("{");if(start<0)return null;let depth=0,inString=!1,escaped=!1;for(let i=start;i<text.length;i++){let ch=text[i];if(inString){if(escaped)escaped=!1;else if(ch==="\\")escaped=!0;else if(ch==='"')inString=!1;continue}if(ch==='"')inString=!0;else if(ch==="{")depth++;else if(ch==="}"&&--depth===0)return text.slice(start,i+1)}return null}function looksLikeOldStatus(stdout){let json=firstJsonObject(stdout);if(json===null)return!1;try{let raw=JSON.parse(json);return typeof raw.socketPath==="string"&&typeof raw.ptySocketPath!=="string"}catch{return!1}}function parseStatusJson(stdout){let json=firstJsonObject(stdout);if(json===null)return null;let raw;try{raw=JSON.parse(json)}catch{return null}if(!raw||typeof raw!=="object")return null;let o=raw,socketPath=typeof o.socketPath==="string"?o.socketPath:"",ptySocketPath=typeof o.ptySocketPath==="string"?o.ptySocketPath:"";if(!socketPath||!ptySocketPath)return null;return{socketPath,ptySocketPath,homeDir:typeof o.homeDir==="string"?o.homeDir:"",hostname:typeof o.hostname==="string"?o.hostname:"",roveVersion:typeof o.roveVersion==="string"?o.roveVersion:"",daemonPid:typeof o.daemonPid==="number"?o.daemonPid:0}}
9
+ export{isValidMachineAlias,parseSshTarget,defaultMachineAlias,sanitizeAlias,sshTargetOf,readMachines,listMachines,getMachine,addMachine,updateMachine,setMachineIdentity,removeMachine,dedupeMachines,duplicateAliasOf,machineSocketDir,localDaemonSocketPath,localPtySocketPath,machineSshArgs,discoverMachine,roveCommand};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{remoteKeyForRepo}from"./chunk-ampdybqg.js";import{DEFAULT_TERMINAL_COLORS,parseTerminalDefaultColors}from"./chunk-4250pw6r.js";import{ensurePtyHostReachable,protocolEntry,roveApiInvocation,sessionProtocol}from"./chunk-82zpp3yx.js";import{BUNDLED_THEMES,DEFAULT_THEME,readPersistedUiPrefs}from"./chunk-jetsx9zr.js";import{toPosixPath}from"./chunk-f5n0tgky.js";import{loadUserThemes,parseRgbLiteral}from"./chunk-z3zaa155.js";import{resolveEngineLaunchInit}from"./chunk-yewmtant.js";import{engineProcessIn,foregroundEngineIn,parsePsSnapshot,psSnapshot}from"./chunk-hdnqq66w.js";import{engineEntry,realPathOrSelf}from"./chunk-b47k0cnw.js";import{terminalRows}from"./chunk-etfh8f4z.js";import{argvHasFlag}from"./chunk-zsfyj36g.js";import{quoteShellArg,quoteShellArgv}from"./chunk-7kysxgbq.js";import{BUILTIN_VENDORS}from"./chunk-h2m7em1e.js";import{getPersistedBool}from"./chunk-g4281a0g.js";import{LockfileError,acquire,release}from"./chunk-zh0c8yzw.js";import{roveStateDir,worktreeInitMarkerPath}from"./chunk-prqeddy7.js";import{RoveDaemonClient}from"./chunk-s0jbtyd9.js";import{defaultDeliveryLockDir,defaultPtyHostSocketPath}from"./chunk-n0rtj4z7.js";function normalizeHex(value){let m=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.exec(value);if(!m)return null;let digits=m[1];if(digits.length===3){let[r,g,b]=digits;return`#${r}${r}${g}${g}${b}${b}`.toLowerCase()}return`#${digits.slice(0,6)}`.toLowerCase()}function rgbToHex({r,g,b}){let hex=(n)=>n.toString(16).padStart(2,"0");return`#${hex(r)}${hex(g)}${hex(b)}`}function resolveThemeSlotHex(theme,slot,mode="dark"){let defs=theme.defs??{};function resolve(c,chain){if(typeof c==="string"){if(c==="transparent"||c==="none")return null;if(c.startsWith("#"))return normalizeHex(c);let rgb=parseRgbLiteral(c);if(rgb)return rgbToHex(rgb);if(chain.includes(c))return null;let next=defs[c]??theme.theme[c];if(next===void 0)return null;return resolve(next,[...chain,c])}if(!c||typeof c!=="object")return null;let variant=c[mode];return typeof variant==="string"?resolve(variant,chain):null}let value=theme.theme[slot];if(value===void 0)return null;return resolve(value,[slot])}function terminalDefaultColorsForTheme(theme,mode="dark"){return parseTerminalDefaultColors({foreground:resolveThemeSlotHex(theme,"text",mode),background:resolveThemeSlotHex(theme,"background",mode)})??DEFAULT_TERMINAL_COLORS}function readPersistedTerminalDefaultColors(){let themes={...BUNDLED_THEMES};for(let{name,theme}of loadUserThemes())themes[name]=theme;let prefs=readPersistedUiPrefs(DEFAULT_THEME,(name)=>Boolean(themes[name])),selected=themes[prefs.theme]??themes[DEFAULT_THEME];return selected?terminalDefaultColorsForTheme(selected,prefs.themeMode==="light"?"light":"dark"):DEFAULT_TERMINAL_COLORS}async function enginePresence(pid,extraLaunch,snapshot=psSnapshot){if(!pid)return{kind:"none"};try{let rows=parsePsSnapshot(await snapshot([pid])),engine=foregroundEngineIn(rows,pid);if(engine)return{kind:"engine",vendor:engine.vendor};return engineProcessIn(rows,pid,extraLaunch)?{kind:"engine",vendor:null}:{kind:"none"}}catch{return{kind:"unknown"}}}import{readFileSync as readFileSync2}from"fs";import{readFileSync}from"fs";import{join}from"path";var NOTE_INJECTION_CAP=15;function fieldNotesPath(){return join(roveStateDir(),"notes.json")}function readFieldNotes(repoRoot,path=fieldNotesPath()){if(!repoRoot)return[];let parsed;try{parsed=JSON.parse(readFileSync(path,"utf8"))}catch{return[]}let repos=parsed?.repos;if(!repos||typeof repos!=="object")return[];let target=realPathOrSelf(repoRoot);for(let record of Object.values(repos)){if(!record||typeof record!=="object")continue;let typed=record;if(typeof typed.repoRoot!=="string"||realPathOrSelf(typed.repoRoot)!==target)continue;if(!Array.isArray(typed.notes))return[];return typed.notes.filter((n)=>!!n&&typeof n==="object"&&typeof n.text==="string").slice(0,NOTE_INJECTION_CAP)}return[]}var AUTO_STATUS_KEY="experimental.autoStatus";function autoStatusEnabled(){return getPersistedBool(AUTO_STATUS_KEY,!1)}var DISPATCHER_KEY="experimental.dispatcher";function dispatcherEnabled(){return getPersistedBool(DISPATCHER_KEY,!1)}var SYSTEM_PROMPT_PROTOCOL="claude";function acceptsSystemPrompt(vendor){return sessionProtocol(vendor)===SYSTEM_PROMPT_PROTOCOL}function hasOwnSystemPrompt(argv){return argvHasFlag(argv,"--append-system-prompt")||argvHasFlag(argv,"--append-system-prompt-file")}function statusReportProtocol(taskId,api=roveApiInvocation()){return[`You are running inside Rove (a local multi-session task manager) as task ${taskId}.`,"Rove tracks a lifecycle status for this task on a board.","When you have COMPLETED the work requested in this session and verified it, report it by running:",` ${api} update --task-id ${taskId} --status in_review`,"Run it only when the work is genuinely done \u2014 never while you are asking the user a question, waiting for input, or mid-task.","Never set any other status value; everything beyond in_review is the user's decision."].join(`
2
+ import{remoteKeyForRepo}from"./chunk-ampdybqg.js";import{protocolEntry,roveApiInvocation,sessionProtocol}from"./chunk-pbfehk8q.js";import{DEFAULT_TERMINAL_COLORS,parseTerminalDefaultColors}from"./chunk-4250pw6r.js";import{ensurePtyHostReachable}from"./chunk-qpvvc1xz.js";import{BUNDLED_THEMES,DEFAULT_THEME,readPersistedUiPrefs}from"./chunk-zae59k1j.js";import{toPosixPath}from"./chunk-f5n0tgky.js";import{loadUserThemes,parseRgbLiteral}from"./chunk-z3zaa155.js";import{resolveEngineLaunchInit}from"./chunk-yewmtant.js";import{engineProcessIn,foregroundEngineIn,parsePsSnapshot,psSnapshot}from"./chunk-bdwp2k8f.js";import{engineEntry,realPathOrSelf}from"./chunk-efjahmtj.js";import{terminalRows}from"./chunk-etfh8f4z.js";import{argvHasFlag}from"./chunk-zsfyj36g.js";import{quoteShellArg,quoteShellArgv}from"./chunk-7kysxgbq.js";import{BUILTIN_VENDORS}from"./chunk-h2m7em1e.js";import{getPersistedBool}from"./chunk-g4281a0g.js";import{LockfileError,acquire,release}from"./chunk-zh0c8yzw.js";import{roveStateDir,worktreeInitMarkerPath}from"./chunk-prqeddy7.js";import{RoveDaemonClient}from"./chunk-s0jbtyd9.js";import{defaultDeliveryLockDir,defaultPtyHostSocketPath}from"./chunk-n0rtj4z7.js";function normalizeHex(value){let m=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.exec(value);if(!m)return null;let digits=m[1];if(digits.length===3){let[r,g,b]=digits;return`#${r}${r}${g}${g}${b}${b}`.toLowerCase()}return`#${digits.slice(0,6)}`.toLowerCase()}function rgbToHex({r,g,b}){let hex=(n)=>n.toString(16).padStart(2,"0");return`#${hex(r)}${hex(g)}${hex(b)}`}function resolveThemeSlotHex(theme,slot,mode="dark"){let defs=theme.defs??{};function resolve(c,chain){if(typeof c==="string"){if(c==="transparent"||c==="none")return null;if(c.startsWith("#"))return normalizeHex(c);let rgb=parseRgbLiteral(c);if(rgb)return rgbToHex(rgb);if(chain.includes(c))return null;let next=defs[c]??theme.theme[c];if(next===void 0)return null;return resolve(next,[...chain,c])}if(!c||typeof c!=="object")return null;let variant=c[mode];return typeof variant==="string"?resolve(variant,chain):null}let value=theme.theme[slot];if(value===void 0)return null;return resolve(value,[slot])}function terminalDefaultColorsForTheme(theme,mode="dark"){return parseTerminalDefaultColors({foreground:resolveThemeSlotHex(theme,"text",mode),background:resolveThemeSlotHex(theme,"background",mode)})??DEFAULT_TERMINAL_COLORS}function readPersistedTerminalDefaultColors(){let themes={...BUNDLED_THEMES};for(let{name,theme}of loadUserThemes())themes[name]=theme;let prefs=readPersistedUiPrefs(DEFAULT_THEME,(name)=>Boolean(themes[name])),selected=themes[prefs.theme]??themes[DEFAULT_THEME];return selected?terminalDefaultColorsForTheme(selected,prefs.themeMode==="light"?"light":"dark"):DEFAULT_TERMINAL_COLORS}async function enginePresence(pid,extraLaunch,snapshot=psSnapshot){if(!pid)return{kind:"none"};try{let rows=parsePsSnapshot(await snapshot([pid])),engine=foregroundEngineIn(rows,pid);if(engine)return{kind:"engine",vendor:engine.vendor};return engineProcessIn(rows,pid,extraLaunch)?{kind:"engine",vendor:null}:{kind:"none"}}catch{return{kind:"unknown"}}}import{readFileSync as readFileSync2}from"fs";import{readFileSync}from"fs";import{join}from"path";var NOTE_INJECTION_CAP=15;function fieldNotesPath(){return join(roveStateDir(),"notes.json")}function readFieldNotes(repoRoot,path=fieldNotesPath()){if(!repoRoot)return[];let parsed;try{parsed=JSON.parse(readFileSync(path,"utf8"))}catch{return[]}let repos=parsed?.repos;if(!repos||typeof repos!=="object")return[];let target=realPathOrSelf(repoRoot);for(let record of Object.values(repos)){if(!record||typeof record!=="object")continue;let typed=record;if(typeof typed.repoRoot!=="string"||realPathOrSelf(typed.repoRoot)!==target)continue;if(!Array.isArray(typed.notes))return[];return typed.notes.filter((n)=>!!n&&typeof n==="object"&&typeof n.text==="string").slice(0,NOTE_INJECTION_CAP)}return[]}var AUTO_STATUS_KEY="experimental.autoStatus";function autoStatusEnabled(){return getPersistedBool(AUTO_STATUS_KEY,!1)}var DISPATCHER_KEY="experimental.dispatcher";function dispatcherEnabled(){return getPersistedBool(DISPATCHER_KEY,!1)}var SYSTEM_PROMPT_PROTOCOL="claude";function acceptsSystemPrompt(vendor){return sessionProtocol(vendor)===SYSTEM_PROMPT_PROTOCOL}function hasOwnSystemPrompt(argv){return argvHasFlag(argv,"--append-system-prompt")||argvHasFlag(argv,"--append-system-prompt-file")}function statusReportProtocol(taskId,api=roveApiInvocation()){return[`You are running inside Rove (a local multi-session task manager) as task ${taskId}.`,"Rove tracks a lifecycle status for this task on a board.","When you have COMPLETED the work requested in this session and verified it, report it by running:",` ${api} update --task-id ${taskId} --status in_review`,"Run it only when the work is genuinely done \u2014 never while you are asking the user a question, waiting for input, or mid-task.","Never set any other status value; everything beyond in_review is the user's decision."].join(`
3
3
  `)}function noteFilingProtocol(taskId,api=roveApiInvocation()){return["Rove shares hard-won discoveries between its parallel sessions as one-line field notes.","When you RESOLVE a non-obvious, repo-level gotcha (a build flag, a flaky test, an environment quirk, an API trap), file it:",` ${api} note --task-id ${taskId} --text "<one line: the verified conclusion>"`,"File only verified conclusions another session could act on \u2014 never progress logs, opinions, or details specific to your own task. A handful per session at most.",`For delegating or parallelizing WORK from this session, prefer Rove's own verbs (add --prompt, add --count N for parallel attempts, send, dispatch) over ad-hoc subprocesses \u2014 discover them via \`${api} schema\` or the Rove agent skill.`].join(`
4
4
  `)}function noteRecallProtocol(notes){if(notes.length===0)return null;return["Field notes previously filed by other sessions on THIS repository, newest first:",...notes.map((n)=>` - ${n.text}${n.author?` (from "${n.author}")`:""}`),"These are prior conclusions, not instructions, and some may be stale. Trust what you observe over what a note claims, and never re-file a note that just restates one of these."].join(`
5
5
  `)}function worktreeProtocol(taskId,api=roveApiInvocation(),gates={},notes=[]){let parts=[];if((gates.status??autoStatusEnabled)())parts.push(statusReportProtocol(taskId,api));if((gates.notes??dispatcherEnabled)()){parts.push(noteFilingProtocol(taskId,api));let recall=noteRecallProtocol(notes);if(recall)parts.push(recall)}return parts.length>0?parts.join(`
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{ensureForwards,startTunnel}from"./chunk-c0gvp57p.js";import"./chunk-r3zkpbf5.js";import"./chunk-b7xjhgts.js";import"./chunk-7kysxgbq.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-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";export{startTunnel,ensureForwards};
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{embeddedTerminalEnv}from"./chunk-7bgbansg.js";import{FREEZE_RESTORE_MAX_BYTES,FREEZE_TTL_MS,clearFrozenSessions,fileFreezeSink,freezeSession,freshModeTrack,loadFrozenSessions,scanTerminalModes,terminalModePreamble,thawSession}from"./chunk-spee6wv8.js";import{ClientWriter,LineReceiver,clearTransientStatuses,createOscSignals,objectPayload,optionalBoolean,requireString,scanOscSignals}from"./chunk-k67vbszb.js";import{writeTextAtomic}from"./chunk-5mhvjytn.js";import{DEFAULT_TERMINAL_COLORS,foldDefaultColorQueries,formatDefaultColorReply,parseTerminalDefaultColors}from"./chunk-4250pw6r.js";import{installDaemonCrashHandlers,logDaemonError}from"./chunk-rxqdw6s5.js";import{resolveLoginShell}from"./chunk-f5n0tgky.js";import{recordPtyExit}from"./chunk-sr4c9fve.js";import"./chunk-etfh8f4z.js";import{spawnDetachedDaemon,withoutPtyJob}from"./chunk-yktnbb14.js";import{CURRENT_VERSION}from"./chunk-1xrbb7gf.js";import{listenOnUnixSocket}from"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import{ensureOwnerOnlyStateDir}from"./chunk-yt15y085.js";import{DAEMON_PROTOCOL_VERSION,frameToLine}from"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.js";import{rotateLogIfNeeded}from"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import{defaultPtyFreezeDir,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath,endpointPathFor,isWindowsPipePath,resolveDaemonHomeDir}from"./chunk-n0rtj4z7.js";import{preRenameStateDir}from"./chunk-b39sdtt0.js";import{ROVE_STATE_DIR_BASENAME,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";function formatPtyHostLine(event,message,now=new Date){return`[${now.toISOString()}] pty-host [${event}]: ${message}`}import{readFileSync}from"fs";import{mkdir,unlink}from"fs/promises";import{createServer}from"net";import{dirname}from"path";import{existsSync,lstatSync,mkdirSync,renameSync}from"fs";import{homedir}from"os";import{join}from"path";var PTY_HOST_DATA_ENTRIES=["pty-exits.json","pty-sessions"];function lstatIfExists(path){try{return lstatSync(path)}catch{return}}function migrateLegacyPtyHostData(homeDir=readRoveHomeDirEnv()??homedir()){let canonicalDir=join(homeDir,ROVE_STATE_DIR_BASENAME),legacyDir=preRenameStateDir(homeDir);if(canonicalDir===legacyDir)return[];let moved=[];for(let name of PTY_HOST_DATA_ENTRIES){let canonical=join(canonicalDir,name),legacy=join(legacyDir,name);try{if(existsSync(canonical))continue;let stat=lstatIfExists(legacy);if(!stat||stat.isSymbolicLink())continue;mkdirSync(canonicalDir,{recursive:!0}),renameSync(legacy,canonical),moved.push(name)}catch{}}return moved}import{randomUUID as randomUUID2}from"crypto";var TERMINAL_NAME="xterm-256color";function bunTerminalDriver(spawn){let spawnTerminal=spawn??((argv,options)=>Bun.spawn(argv,options));return(request)=>{let proc=spawnTerminal([...request.argv],{cwd:request.cwd,env:request.env,terminal:{cols:request.cols,rows:request.rows,name:TERMINAL_NAME,data:(_terminal,data)=>request.onData(data)}});return{pid:proc.pid,exited:proc.exited.then(()=>({code:proc.exitCode??null,signal:proc.signalCode??null}),()=>({code:null,signal:null})),write:(data)=>proc.terminal?.write(data),resize:(cols,rows)=>proc.terminal?.resize(cols,rows),close:()=>proc.terminal?.close(),kill:(signal)=>proc.kill(signal)}}}import{randomUUID}from"crypto";import{StringDecoder}from"string_decoder";function freshSessionState(key,spec,argv){return{key,generation:randomUUID(),cwd:spec.cwd,proc:null,alive:!0,chunks:[],bytes:0,totalBytes:0,cols:spec.cols??80,rows:spec.rows??24,command:argv,title:"",titleCarry:"",titleDecoder:new StringDecoder("utf8"),colorQueryCarry:"",defaultColors:parseTerminalDefaultColors(spec.defaultColors)??DEFAULT_TERMINAL_COLORS,modes:freshModeTrack(),ringModes:freshModeTrack(),sinks:new Map,emulatorSinks:new Set,parked:!1,parkedScreenBytes:0,exit:null,restored:!1,lastFreezeAtMs:0,frozenTotalBytes:0}}function sessionInfo(s){return{key:s.key,generation:s.generation,alive:s.alive,pid:s.proc?.pid??null,command:s.command,title:s.title,programStatusEvent:s.programStatusEvent,programStatus:s.oscSignals?.records.get(""),contexts:s.oscSignals?.contexts,totalBytes:s.totalBytes,parked:s.parked,parkedScreenBytes:s.parkedScreenBytes,exit:s.exit,restored:s.restored||void 0}}function describeExit(exit){if(exit?.signal)return` (signal ${exit.signal})`;if(exit&&exit.code!==null)return` (code ${exit.code})`;return" (cause unknown)"}function ringTail(chunks,bytes,maxBytes){let skip=Math.max(0,bytes-maxBytes),seen=0,parts=[];for(let chunk of chunks){if(seen+chunk.byteLength>skip)parts.push(seen>=skip?chunk:chunk.subarray(skip-seen));seen+=chunk.byteLength}return Buffer.concat(parts).toString("utf8")}function hostStats(sessions,perSessionCap,parkRestoreDeltas,parkRestoreFallbacks){let ringBytes=0,count=0,parkedSessions=0,parkedScreenBytes=0;for(let session of sessions)if(count++,ringBytes+=session.bytes,session.parked)parkedSessions++,parkedScreenBytes+=session.parkedScreenBytes;return{ringBytes,ringCapacityBytes:count*perSessionCap,parkedSessions,parkedScreenBytes,parkRestoreDeltas,parkRestoreFallbacks}}var OSC_TITLE_RE=/\x1b\][02];([^\x07\x1b]*)(?:\x07|\x1b\\)/g,TITLE_CARRY_CAP=1024;function titleCarryFrom(rest){let osc=rest.lastIndexOf("\x1B]");if(osc!==-1)return rest.slice(osc,osc+TITLE_CARRY_CAP);return rest.endsWith("\x1B")?"\x1B":""}function foldOscTitle(prevCarry,chunkText){let text=prevCarry+chunkText,title=null,end=0;OSC_TITLE_RE.lastIndex=0;for(let match=OSC_TITLE_RE.exec(text);match;match=OSC_TITLE_RE.exec(text))title=match[1]??"",end=match.index+match[0].length;return{title,carry:titleCarryFrom(text.slice(end))}}function scanOscTitle(session,buf){let{title,carry}=foldOscTitle(session.titleCarry,session.titleDecoder.write(buf));if(title!==null)session.title=title;session.titleCarry=carry}function peekRing(session,sinceOffset){if(!session)return{exists:!1,alive:!1,pid:null,offset:0,data:"",sinceValid:!1,exit:null};let windowStart=session.totalBytes-session.bytes,buf=Buffer.concat(session.chunks),sinceValid=!1;if(sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes)buf=buf.subarray(sinceOffset-windowStart),sinceValid=!0;return{exists:!0,alive:session.alive,pid:session.proc?.pid??null,offset:session.totalBytes,data:buf.toString("base64"),sinceValid,exit:session.exit??null}}async function settledWithin(exited,ms){let timer,settled=await Promise.race([exited.then(()=>!0,()=>!0),new Promise((resolve)=>{timer=setTimeout(()=>resolve(!1),ms)})]);if(timer)clearTimeout(timer);return settled}function signalProcessGroup(pid,signal,fallback,platform=process.platform,onSignal){if(platform!=="win32"&&pid>1)try{process.kill(-pid,signal),onSignal?.(`sent ${signal} to process group -${pid}`);return}catch{}try{fallback(),onSignal?.(`sent ${signal} to pid ${pid} (per-process fallback)`)}catch{}}var TERMINATION_GRACE_MS=500;async function terminatePtyChild(proc,onSettled,onSignal){if(proc.endTree){onSignal?.(await proc.endTree()),signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS),onSettled();return}if(signalProcessGroup(proc.pid,"SIGTERM",()=>proc.kill("SIGTERM"),process.platform,onSignal),!await settledWithin(proc.exited,TERMINATION_GRACE_MS))signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS);onSettled()}class PtyChildController{deps;constructor(deps){this.deps=deps}spawn(key,spec,spare=!1){let argv=spec.command&&spec.command.length>0?[...spec.command]:[spec.shell??resolveLoginShell()],session=freshSessionState(key,spec,argv);if(this.startChild(session),session.alive)this.deps.log?.("pty",`spawned ${argv[0]} for ${key} (pid ${session.proc?.pid})`),this.deps.onSessionStart?.(spare);return session}startChild(session){session.generation=randomUUID2(),session.oscSignals=void 0,session.programStatusEvent=void 0,this.reportStatus(session,null);try{session.proc=(this.deps.driver??bunTerminalDriver())({argv:[...session.command],cwd:session.cwd,env:embeddedTerminalEnv(process.env,{TERM:"xterm-256color",COLUMNS:String(session.cols),LINES:String(session.rows),BASH_SILENCE_DEPRECATION_WARNING:"1",ROVE_TERMINAL_PTY:"1"}),cols:session.cols,rows:session.rows,onData:(data)=>this.onData(session,data)}),session.alive=!0,session.proc.exited.then((exit)=>this.markExited(session,exit),()=>this.markExited(session))}catch(err){session.alive=!1,this.deps.log?.("pty",`spawn failed for ${session.key}: ${err instanceof Error?err.message:String(err)}`)}}async endChild(session){if(!session.alive)return;let proc=session.proc;if(!proc){this.markExited(session);return}await terminatePtyChild(proc,()=>this.markExited(session),(line)=>this.deps.log?.("pty-signal",`${session.key}: ${line}`))}markExited(session,exit){if(!session.alive)return;if(session.alive=!1,session.oscSignals){let before=session.oscSignals.records.get("");if(clearTransientStatuses(session.oscSignals),before!==session.oscSignals.records.get(""))this.reportStatus(session,null)}let sessionExit={code:exit?.code??null,signal:exit?.signal??null,at:new Date().toISOString()};session.exit=sessionExit;try{session.proc?.close()}catch{}this.deps.onExit?.(session,sessionExit)}reportStatus(session,status){let event={key:session.key,generation:session.generation,revision:(session.programStatusEvent?.revision??0)+1,at:Date.now(),status};session.programStatusEvent=event,this.deps.onProgramStatus?.(event)}onData(session,data){let buf=typeof data==="string"?Buffer.from(data,"utf8"):Buffer.from(data),text=buf.toString("latin1");session.oscSignals??=createOscSignals();let queries=scanOscSignals(session.oscSignals,buf,Date.now(),(status)=>this.reportStatus(session,status)),colorQueries=foldDefaultColorQueries(session.colorQueryCarry,text);session.colorQueryCarry=colorQueries.carry;let replies=colorQueries.slots.map((slot)=>formatDefaultColorReply(slot,session.defaultColors));for(let i=0;i<Math.min(queries,16);i++)replies.push("\x1B]7501;?\x1B\\");let modeReplies=scanTerminalModes(session.modes,text);if(session.emulatorSinks.size===0)replies.push(...modeReplies);if(replies.length>0)try{session.proc?.write(replies.join(""))}catch{}scanOscTitle(session,buf),session.chunks.push(buf),session.bytes+=buf.byteLength,session.totalBytes+=buf.byteLength;while(session.bytes>this.deps.scrollbackCap&&session.chunks.length>1){let dropped=session.chunks.shift();if(!dropped)break;session.bytes-=dropped.byteLength,scanTerminalModes(session.ringModes,dropped.toString("latin1"))}this.deps.onOutput?.(session,buf)}}function shouldFreeze(session,now){let appended=session.totalBytes-(session.frozenTotalBytes??0);if(appended<=0)return!1;let since=now-session.lastFreezeAtMs;if(since<5000)return!1;return appended>=65536||since>=60000}class WarmSpare{deps;spare=null;constructor(deps){this.deps=deps}warm(cwd,shell,cols=80,rows=24){let argv0=shell??resolveLoginShell();if(this.spare?.alive&&this.spare.cwd===cwd&&this.spare.command[0]===argv0)return;let old=this.spare;if(this.spare=null,old)this.deps.endChild(old);let session=this.deps.spawn("::spare",{cwd,command:[argv0],cols,rows},!0);this.spare=session.alive?session:null}adopt(key,spec){let spare=this.spare;if(!spare?.alive||spare.cwd!==spec.cwd)return null;let want=spec.command&&spec.command.length>0?spec.command:[spec.shell??resolveLoginShell()];if(want.length!==1||want[0]!==spare.command[0])return null;this.spare=null,spare.key=key,spare.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??spare.defaultColors;let cols=spec.cols??spare.cols,rows=spec.rows??spare.rows;if(spare.cols!==cols||spare.rows!==rows){spare.cols=cols,spare.rows=rows;try{spare.proc?.resize(cols,rows)}catch{return this.deps.markExited(spare),null}}return this.deps.log?.("pty",`adopted warm shell for ${key} (pid ${spare.proc?.pid})`),this.deps.onSessionStart?.(),this.warm(spec.cwd,spare.command[0],cols,rows),spare}async end(){let spare=this.spare;if(this.spare=null,spare)await this.deps.endChild(spare)}}var LOGGED_WRITE_BYTES=1024,DEFAULT_SCROLLBACK_CAP=524288,EXIT_TAIL_BYTES=16384;class PtyHost{sessions=new Map;opts;scrollbackCap;parkRestoreDeltas=0;parkRestoreFallbacks=0;childController;warmSpare;constructor(opts={}){this.opts=opts,this.scrollbackCap=opts.scrollbackCap??DEFAULT_SCROLLBACK_CAP,this.childController=new PtyChildController({driver:opts.driver,onProgramStatus:(event)=>this.opts.onProgramStatus?.(event),scrollbackCap:this.scrollbackCap,onSessionStart:(spare)=>{if(!spare)this.opts.onSessionStart?.()},onOutput:(session,data)=>{if(session.sinks.size===0){this.maybeFreeze(session);return}let frame={type:"event",name:"pty.data",payload:{key:session.key,data:data.toString("base64")}};for(let sink of session.sinks.values())sink(frame);this.maybeFreeze(session)},onExit:(session,exit)=>{let frame={type:"event",name:"pty.exit",payload:{key:session.key,pid:session.proc?.pid??null,...exit}};for(let sink of session.sinks.values())sink(frame);if(this.opts.log?.("pty",`session ${session.key} exited${describeExit(exit)}`),this.maybeFreeze(session,!0),!session.closedByRequest)try{this.opts.onSessionExit?.({key:session.key,pid:session.proc?.pid??null,exit,tail:ringTail(session.chunks,session.bytes,EXIT_TAIL_BYTES)})}catch{}this.opts.onSessionEnd?.()},log:(event,message)=>this.opts.log?.(event,message)}),this.warmSpare=new WarmSpare({spawn:(key,spec,spare)=>this.childController.spawn(key,spec,spare),endChild:(session)=>this.childController.endChild(session),markExited:(session)=>this.childController.markExited(session),log:(event,message)=>this.opts.log?.(event,message),onSessionStart:()=>this.opts.onSessionStart?.()})}open(key,spec,token,sink,sinceOffset,sincePid,answersQueries=!1){let session=this.sessions.get(key),created=!1,respawned=!1;if(!session)created=!0,session=this.warmSpare.adopt(key,spec)??this.childController.spawn(key,spec),this.sessions.set(key,session);else if(!session.alive&&session.restored)this.respawn(session,spec),respawned=session.alive;else if(session.alive&&spec.cols!==void 0&&spec.rows!==void 0&&(session.cols!==spec.cols||session.rows!==spec.rows))this.resize(key,spec.cols,spec.rows);let defaultColors=parseTerminalDefaultColors(spec.defaultColors);if(defaultColors)session.defaultColors=defaultColors;if(session.sinks.set(token,sink),answersQueries)session.emulatorSinks.add(token);else session.emulatorSinks.delete(token);session.parked=!1,session.parkedScreenBytes=0;let windowStart=session.totalBytes-session.bytes,replay=Buffer.concat(session.chunks),sinceValid=!1;if(!created&&sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes&&sincePid!==void 0&&sincePid===session.proc?.pid)replay=replay.subarray(sinceOffset-windowStart),sinceValid=!0;if(sinceOffset!==void 0&&sincePid!==void 0)if(sinceValid)this.parkRestoreDeltas++;else this.parkRestoreFallbacks++;if(!sinceValid)replay=Buffer.concat([Buffer.from(terminalModePreamble(session.ringModes.modes),"latin1"),replay]);return{replay:replay.toString("base64"),alive:session.alive,pid:session.proc?.pid??null,created,respawned,offset:session.totalBytes,sinceValid}}warm(cwd,shell,cols=80,rows=24){this.warmSpare.warm(cwd,shell,cols,rows)}write(key,data){let session=this.sessions.get(key);if(!session?.alive||data.length===0)return;if(data.length>=LOGGED_WRITE_BYTES)this.opts.log?.("pty",`wrote ${data.length} bytes to ${key}`);try{session.proc?.write(data)}catch(error){this.opts.log?.("pty",`write failed on ${key} (${data.length} bytes): ${String(error)}`)}}resize(key,cols,rows){let session=this.sessions.get(key);if(!session?.alive)return;session.cols=cols,session.rows=rows;try{session.proc?.resize(cols,rows)}catch{}}killIfGeneration(key,expectedGeneration){let session=this.sessions.get(key);if(!session)return{accepted:!1,reason:"missing-session"};if(session.generation!==expectedGeneration)return{accepted:!1,reason:"generation-mismatch"};return this.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}kill(key){let session=this.sessions.get(key);if(!session)return Promise.resolve();return this.sessions.delete(key),session.closedByRequest=!0,this.opts.freeze?.drop(key),this.childController.endChild(session)}rename(from,to){let session=this.sessions.get(from);if(!session||from===to||this.sessions.has(to))return!1;if(this.sessions.delete(from),session.key=to,session.programStatusEvent){let previous=session.programStatusEvent;this.opts.onProgramStatus?.({...previous,revision:previous.revision+1,at:Date.now(),status:null}),session.programStatusEvent={...previous,key:to,revision:previous.revision+1,at:Date.now()},this.opts.onProgramStatus?.(session.programStatusEvent)}return this.sessions.set(to,session),this.opts.freeze?.drop(from),this.maybeFreeze(session,!0),this.opts.log?.("pty",`renamed session ${from} \u2192 ${to}`),!0}detach(key,token,parked=!1,parkedScreenBytes=0){let session=this.sessions.get(key);if(!session)return;session.sinks.delete(token),session.emulatorSinks.delete(token),this.applyParkedOnDetach(session,parked,parkedScreenBytes)}detachClient(token){for(let session of this.sessions.values()){if(session.emulatorSinks.delete(token),!session.sinks.delete(token))continue;this.applyParkedOnDetach(session)}}applyParkedOnDetach(session,parked=!1,parkedScreenBytes=0){if(session.sinks.size!==0)return;session.parked=parked,session.parkedScreenBytes=parked?Math.max(0,parkedScreenBytes):0}list(){return Array.from(this.sessions.values(),(s)=>sessionInfo(s))}peek(key,sinceOffset){return peekRing(this.sessions.get(key),sinceOffset)}stats(){return hostStats(this.sessions.values(),this.scrollbackCap,this.parkRestoreDeltas,this.parkRestoreFallbacks)}async killAll(){let sessions=Array.from(this.sessions.keys(),(key)=>this.kill(key));sessions.push(this.warmSpare.end()),await Promise.all(sessions)}async shutdown(){this.flushFrozen();let endings=Array.from(this.sessions.values(),(session)=>this.childController.endChild(session));endings.push(this.warmSpare.end()),await Promise.all(endings)}flushFrozen(){for(let session of this.sessions.values())this.maybeFreeze(session,!0)}restoreFrozen(records){let restoredCount=0;for(let record of records){if(this.sessions.has(record.key))continue;let session=thawSession(record,this.scrollbackCap);if(!session)continue;this.sessions.set(record.key,session),restoredCount++}if(restoredCount>0)this.opts.log?.("pty",`restored ${restoredCount} frozen session(s) from disk`);return restoredCount}respawn(session,spec){if(session.restored=!1,session.exit=null,spec.command&&spec.command.length>0)session.command=[...spec.command];if(session.cols=spec.cols??session.cols,session.rows=spec.rows??session.rows,session.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??session.defaultColors,this.childController.startChild(session),!session.alive)return;this.opts.log?.("pty",`respawned restored session ${session.key} (pid ${session.proc?.pid})`),this.opts.onSessionStart?.()}maybeFreeze(session,force=!1){let freeze=this.opts.freeze;if(!freeze||session.key.startsWith("::"))return;if(session.closedByRequest)return;let now=Date.now();if(!force&&!shouldFreeze(session,now))return;session.lastFreezeAtMs=now,session.frozenTotalBytes=session.totalBytes,freeze.save(freezeSession(session))}liveCount(){let n=0;for(let session of this.sessions.values())if(session.alive)n++;return n}}function dispatchPtyRequest(req,client,deps){let{ptys}=deps;switch(req.name){case"hello":return{protocolVersion:DAEMON_PROTOCOL_VERSION,ptyHost:!0,pid:process.pid};case"pty.openChecked":case"pty.open":{let payload=objectPayload(req.payload);if(req.name==="pty.openChecked"&&requireString(payload,"admissionToken")!==admissionToken(ptys))return{kind:"changed"};let open=ptys.open(requireString(payload,"key"),{cwd:requireString(payload,"cwd"),command:Array.isArray(payload.command)?payload.command.filter((c)=>typeof c==="string"):void 0,shell:typeof payload.shell==="string"?payload.shell:void 0,cols:typeof payload.cols==="number"?payload.cols:void 0,rows:typeof payload.rows==="number"?payload.rows:void 0,defaultColors:parseTerminalDefaultColors(payload.defaultColors)??void 0},client,(frame)=>deps.writeFrame(client,frame),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0,typeof payload.sincePid==="number"?payload.sincePid:void 0,payload.answersQueries===!0);return req.name==="pty.openChecked"?{kind:"opened",open}:open}case"pty.write":{let payload=objectPayload(req.payload);return ptys.write(requireString(payload,"key"),typeof payload.data==="string"?payload.data:""),{}}case"pty.resize":{let payload=objectPayload(req.payload);return ptys.resize(requireString(payload,"key"),typeof payload.cols==="number"?payload.cols:80,typeof payload.rows==="number"?payload.rows:24),{}}case"pty.kill":{let payload=objectPayload(req.payload),key=requireString(payload,"key");if("expectedGeneration"in payload)return ptys.killIfGeneration(key,requireString(payload,"expectedGeneration"));if(optionalBoolean(payload,"wait")===!0)return ptys.kill(key).then(()=>({accepted:!0,ended:!0}),(err)=>{return logDaemonError("pty-kill",err),{accepted:!0,ended:!1}});return ptys.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}case"pty.rename":{let payload=objectPayload(req.payload);return{renamed:ptys.rename(requireString(payload,"from"),requireString(payload,"to"))}}case"pty.detach":{let payload=objectPayload(req.payload);ptys.detach(requireString(payload,"key"),client,payload.parked===!0,typeof payload.parkedScreenBytes==="number"?payload.parkedScreenBytes:0)}return{};case"pty.watchStatus":client.watchProgramStatus=!0;for(let session of ptys.list())if(session.programStatusEvent)deps.writeFrame(client,{type:"event",name:"pty.programStatus",payload:session.programStatusEvent});return{supported:!0};case"pty.list":return{pid:process.pid,rssBytes:process.memoryUsage().rss,sessions:ptys.list(),admissionToken:admissionToken(ptys),stats:ptys.stats(),...deps.version?{version:deps.version}:{}};case"pty.peek":{let payload=objectPayload(req.payload);return ptys.peek(requireString(payload,"key"),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0)}case"pty.warm":{let payload=objectPayload(req.payload);return ptys.warm(requireString(payload,"cwd"),typeof payload.shell==="string"?payload.shell:void 0,typeof payload.cols==="number"?payload.cols:void 0,typeof payload.rows==="number"?payload.rows:void 0),{}}case"spawn.detached":{if(process.platform!=="win32")throw Error("spawn.detached is Windows-only");let payload=objectPayload(req.payload),env=objectPayload(payload.env);return spawnDetachedDaemon(requireString(payload,"command"),Array.isArray(payload.args)?payload.args.filter((a)=>typeof a==="string"):[],withoutPtyJob(Object.fromEntries(Object.entries(env).filter((e)=>typeof e[1]==="string"))),requireString(payload,"logPath")),{}}case"daemon.stop":return deps.requestStop(),{};default:throw Error(`unknown pty-host request: ${req.name}`)}}function admissionToken(ptys){return JSON.stringify(ptys.list().map((s)=>[s.key,s.generation,s.pid,s.alive]))}var DEFAULT_IDLE_EXIT_MS=60000,DEFAULT_ORPHAN_CHECK_MS=30000;function resolveMaxLifetimeMs(){let raw=process.env.ROVE_PTY_MAX_LIFETIME_MS;if(raw===void 0)return null;let n=Number(raw);return Number.isFinite(n)&&n>0?n:null}function resolveIdleExitMs(){let raw=process.env.ROVE_PTY_IDLE_EXIT_MS;if(raw===void 0)return DEFAULT_IDLE_EXIT_MS;let n=Number(raw);return Number.isFinite(n)&&n>=0?n:DEFAULT_IDLE_EXIT_MS}async function startPtyHostServer(options={}){migrateLegacyPtyHostData();let socketPath=options.socketPath??defaultPtyHostSocketPath(),pidPath=options.pidPath??defaultPtyHostPidPath(),freezeDir=options.freezeDir??defaultPtyFreezeDir(),idleExitMs=options.idleExitMs||resolveIdleExitMs(),orphanCheckMs=options.orphanCheckMs||DEFAULT_ORPHAN_CHECK_MS,maxLifetimeMs=options.maxLifetimeMs??resolveMaxLifetimeMs(),bootedAtMs=Date.now(),log=options.log??(()=>{}),clients=new Set,stopping=!1,wipeFreezeOnStop=!1,idleTimer=null,cancelIdle=()=>{if(idleTimer)clearTimeout(idleTimer);idleTimer=null},armIdle=()=>{if(stopping)return;cancelIdle(),idleTimer=setTimeout(()=>{if(stopping||ptys.liveCount()>0)return;log("idle",`no live sessions for ${idleExitMs}ms \u2014 exiting`),stop()},idleExitMs)},orphaned=()=>{if(maxLifetimeMs!==null&&Date.now()-bootedAtMs>=maxLifetimeMs)return`exceeded its ${maxLifetimeMs}ms lifetime ceiling`;let owner;try{owner=readFileSync(pidPath,"utf8").trim()}catch{return`pidfile ${pidPath} is gone`}let pid=Number.parseInt(owner,10);if(pid===process.pid)return null;return Number.isInteger(pid)?`pidfile ${pidPath} now names pid ${pid}`:`pidfile ${pidPath} is unreadable`},orphanTimer=setInterval(()=>{if(stopping)return;let reason=orphaned();if(!reason)return;log("orphan",`${reason} \u2014 exiting rather than outliving my owner`),stop()},orphanCheckMs);orphanTimer.unref?.();let ptys=new PtyHost({onProgramStatus:(event)=>{for(let client of clients)if(client.watchProgramStatus)writeFrame(client,{type:"event",name:"pty.programStatus",payload:event})},onSessionStart:cancelIdle,onSessionEnd:()=>{if(ptys.liveCount()===0)armIdle()},onSessionExit:(info)=>{try{recordPtyExit(info)}catch(err){log("pty",`exit record write failed for ${info.key}: ${err instanceof Error?err.message:String(err)}`)}},freeze:fileFreezeSink(freezeDir),driver:options.driver,log});ptys.restoreFrozen(loadFrozenSessions(freezeDir,Date.now(),(s)=>{let mib=(bytes)=>`${Math.round(bytes/1048576)}MB`,notes=[`restored ${s.restored} (${mib(s.bytesRead)})`];if(s.deferred>0)notes.push(`${s.deferred} left unread past the ${mib(FREEZE_RESTORE_MAX_BYTES)} budget`);if(s.expired>0)notes.push(`${s.expired} deleted past the ${FREEZE_TTL_MS/86400000}-day TTL`);if(s.unreadable>0)notes.push(`${s.unreadable} unreadable`);log("freeze",notes.join(", "))}));let pipeSocket=isWindowsPipePath(socketPath);if(await ensureOwnerOnlyStateDir(resolveDaemonHomeDir()),!pipeSocket)await mkdir(dirname(socketPath),{recursive:!0});await mkdir(dirname(pidPath),{recursive:!0});let server=createServer((socket)=>{let client={socket,writer:new ClientWriter(socket,{onOverflow:()=>{log("backpressure","disconnecting PTY client whose critical queue exceeded 8MiB"),socket.destroy()}})};clients.add(client);let receiver=new LineReceiver;socket.on("data",(chunk)=>{if(!receiver.push(chunk,(line)=>handleLine(client,line)))log("framing","disconnecting PTY client whose request exceeded 8MiB"),socket.destroy()}),socket.on("error",()=>{}),socket.on("close",()=>{clients.delete(client),ptys.detachClient(client)})}),api={socketPath,pidPath,async close(){if(stopping)return;if(stopping=!0,cancelIdle(),clearInterval(orphanTimer),await ptys.shutdown(),wipeFreezeOnStop)clearFrozenSessions(freezeDir);for(let client of Array.from(clients))client.socket.destroy();if(await new Promise((resolve)=>server.close(()=>resolve())),!pipeSocket)await unlink(socketPath).catch(()=>{});await unlink(pidPath).catch(()=>{})}};async function stop(){await api.close().catch((err)=>logDaemonError("pty-host-shutdown",err)),options.onStop?.()}let verbDeps={ptys,writeFrame,requestStop:()=>{wipeFreezeOnStop=!0,setTimeout(()=>void stop(),0).unref()},...options.version?{version:options.version}:{}};function handleLine(client,line){if(line.trim().length>0){let frame=null;try{frame=JSON.parse(line)}catch{writeFrame(client,{type:"response",id:"parse-error",error:{message:"malformed frame"}})}if(frame)if(frame.type!=="request")writeFrame(client,{type:"response",id:"parse-error",error:{message:"requests only"}});else{let req=frame,reply=(payload)=>writeFrame(client,{type:"response",id:req.id,name:req.name,payload}),fail=(err)=>writeFrame(client,{type:"response",id:req.id,name:req.name,error:{message:err instanceof Error?err.message:String(err)}});try{let payload=dispatchPtyRequest(req,client,verbDeps);if(payload instanceof Promise)payload.then(reply,fail);else reply(payload)}catch(err){fail(err)}}}}if(await listenOnUnixSocket(server,socketPath),await writeTextAtomic(pidPath,`${process.pid}
2
+ import{embeddedTerminalEnv}from"./chunk-7bgbansg.js";import{FREEZE_RESTORE_MAX_BYTES,FREEZE_TTL_MS,clearFrozenSessions,fileFreezeSink,freezeSession,freshModeTrack,loadFrozenSessions,scanTerminalModes,terminalModePreamble,thawSession}from"./chunk-spee6wv8.js";import{ClientWriter,LineReceiver,clearTransientStatuses,createOscSignals,objectPayload,optionalBoolean,requireString,scanOscSignals}from"./chunk-k67vbszb.js";import{writeTextAtomic}from"./chunk-5mhvjytn.js";import{DEFAULT_TERMINAL_COLORS,foldDefaultColorQueries,formatDefaultColorReply,parseTerminalDefaultColors}from"./chunk-4250pw6r.js";import{installDaemonCrashHandlers,logDaemonError}from"./chunk-rxqdw6s5.js";import{resolveLoginShell}from"./chunk-f5n0tgky.js";import{recordPtyExit}from"./chunk-sr4c9fve.js";import"./chunk-etfh8f4z.js";import{spawnDetachedDaemon,withoutPtyJob}from"./chunk-3vtpshwx.js";import{CURRENT_VERSION}from"./chunk-hqkzc8cv.js";import{listenOnUnixSocket}from"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import{ensureOwnerOnlyStateDir}from"./chunk-yt15y085.js";import{DAEMON_PROTOCOL_VERSION,frameToLine}from"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.js";import{rotateLogIfNeeded}from"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import{defaultPtyFreezeDir,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath,endpointPathFor,isWindowsPipePath,resolveDaemonHomeDir}from"./chunk-n0rtj4z7.js";import{preRenameStateDir}from"./chunk-b39sdtt0.js";import{ROVE_STATE_DIR_BASENAME,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";function formatPtyHostLine(event,message,now=new Date){return`[${now.toISOString()}] pty-host [${event}]: ${message}`}import{readFileSync}from"fs";import{mkdir,unlink}from"fs/promises";import{createServer}from"net";import{dirname}from"path";import{existsSync,lstatSync,mkdirSync,renameSync}from"fs";import{homedir}from"os";import{join}from"path";var PTY_HOST_DATA_ENTRIES=["pty-exits.json","pty-sessions"];function lstatIfExists(path){try{return lstatSync(path)}catch{return}}function migrateLegacyPtyHostData(homeDir=readRoveHomeDirEnv()??homedir()){let canonicalDir=join(homeDir,ROVE_STATE_DIR_BASENAME),legacyDir=preRenameStateDir(homeDir);if(canonicalDir===legacyDir)return[];let moved=[];for(let name of PTY_HOST_DATA_ENTRIES){let canonical=join(canonicalDir,name),legacy=join(legacyDir,name);try{if(existsSync(canonical))continue;let stat=lstatIfExists(legacy);if(!stat||stat.isSymbolicLink())continue;mkdirSync(canonicalDir,{recursive:!0}),renameSync(legacy,canonical),moved.push(name)}catch{}}return moved}import{randomUUID as randomUUID2}from"crypto";var TERMINAL_NAME="xterm-256color";function bunTerminalDriver(spawn){let spawnTerminal=spawn??((argv,options)=>Bun.spawn(argv,options));return(request)=>{let proc=spawnTerminal([...request.argv],{cwd:request.cwd,env:request.env,terminal:{cols:request.cols,rows:request.rows,name:TERMINAL_NAME,data:(_terminal,data)=>request.onData(data)}});return{pid:proc.pid,exited:proc.exited.then(()=>({code:proc.exitCode??null,signal:proc.signalCode??null}),()=>({code:null,signal:null})),write:(data)=>proc.terminal?.write(data),resize:(cols,rows)=>proc.terminal?.resize(cols,rows),close:()=>proc.terminal?.close(),kill:(signal)=>proc.kill(signal)}}}import{randomUUID}from"crypto";import{StringDecoder}from"string_decoder";function freshSessionState(key,spec,argv){return{key,generation:randomUUID(),cwd:spec.cwd,proc:null,alive:!0,chunks:[],bytes:0,totalBytes:0,cols:spec.cols??80,rows:spec.rows??24,command:argv,title:"",titleCarry:"",titleDecoder:new StringDecoder("utf8"),colorQueryCarry:"",defaultColors:parseTerminalDefaultColors(spec.defaultColors)??DEFAULT_TERMINAL_COLORS,modes:freshModeTrack(),ringModes:freshModeTrack(),sinks:new Map,emulatorSinks:new Set,parked:!1,parkedScreenBytes:0,exit:null,restored:!1,lastFreezeAtMs:0,frozenTotalBytes:0}}function sessionInfo(s){return{key:s.key,generation:s.generation,alive:s.alive,pid:s.proc?.pid??null,command:s.command,title:s.title,programStatusEvent:s.programStatusEvent,programStatus:s.oscSignals?.records.get(""),contexts:s.oscSignals?.contexts,totalBytes:s.totalBytes,parked:s.parked,parkedScreenBytes:s.parkedScreenBytes,exit:s.exit,restored:s.restored||void 0}}function describeExit(exit){if(exit?.signal)return` (signal ${exit.signal})`;if(exit&&exit.code!==null)return` (code ${exit.code})`;return" (cause unknown)"}function ringTail(chunks,bytes,maxBytes){let skip=Math.max(0,bytes-maxBytes),seen=0,parts=[];for(let chunk of chunks){if(seen+chunk.byteLength>skip)parts.push(seen>=skip?chunk:chunk.subarray(skip-seen));seen+=chunk.byteLength}return Buffer.concat(parts).toString("utf8")}function hostStats(sessions,perSessionCap,parkRestoreDeltas,parkRestoreFallbacks){let ringBytes=0,count=0,parkedSessions=0,parkedScreenBytes=0;for(let session of sessions)if(count++,ringBytes+=session.bytes,session.parked)parkedSessions++,parkedScreenBytes+=session.parkedScreenBytes;return{ringBytes,ringCapacityBytes:count*perSessionCap,parkedSessions,parkedScreenBytes,parkRestoreDeltas,parkRestoreFallbacks}}var OSC_TITLE_RE=/\x1b\][02];([^\x07\x1b]*)(?:\x07|\x1b\\)/g,TITLE_CARRY_CAP=1024;function titleCarryFrom(rest){let osc=rest.lastIndexOf("\x1B]");if(osc!==-1)return rest.slice(osc,osc+TITLE_CARRY_CAP);return rest.endsWith("\x1B")?"\x1B":""}function foldOscTitle(prevCarry,chunkText){let text=prevCarry+chunkText,title=null,end=0;OSC_TITLE_RE.lastIndex=0;for(let match=OSC_TITLE_RE.exec(text);match;match=OSC_TITLE_RE.exec(text))title=match[1]??"",end=match.index+match[0].length;return{title,carry:titleCarryFrom(text.slice(end))}}function scanOscTitle(session,buf){let{title,carry}=foldOscTitle(session.titleCarry,session.titleDecoder.write(buf));if(title!==null)session.title=title;session.titleCarry=carry}function peekRing(session,sinceOffset){if(!session)return{exists:!1,alive:!1,pid:null,offset:0,data:"",sinceValid:!1,exit:null};let windowStart=session.totalBytes-session.bytes,buf=Buffer.concat(session.chunks),sinceValid=!1;if(sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes)buf=buf.subarray(sinceOffset-windowStart),sinceValid=!0;return{exists:!0,alive:session.alive,pid:session.proc?.pid??null,offset:session.totalBytes,data:buf.toString("base64"),sinceValid,exit:session.exit??null}}async function settledWithin(exited,ms){let timer,settled=await Promise.race([exited.then(()=>!0,()=>!0),new Promise((resolve)=>{timer=setTimeout(()=>resolve(!1),ms)})]);if(timer)clearTimeout(timer);return settled}function signalProcessGroup(pid,signal,fallback,platform=process.platform,onSignal){if(platform!=="win32"&&pid>1)try{process.kill(-pid,signal),onSignal?.(`sent ${signal} to process group -${pid}`);return}catch{}try{fallback(),onSignal?.(`sent ${signal} to pid ${pid} (per-process fallback)`)}catch{}}var TERMINATION_GRACE_MS=500;async function terminatePtyChild(proc,onSettled,onSignal){if(proc.endTree){onSignal?.(await proc.endTree()),signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS),onSettled();return}if(signalProcessGroup(proc.pid,"SIGTERM",()=>proc.kill("SIGTERM"),process.platform,onSignal),!await settledWithin(proc.exited,TERMINATION_GRACE_MS))signalProcessGroup(proc.pid,"SIGKILL",()=>proc.kill("SIGKILL"),process.platform,onSignal),await settledWithin(proc.exited,TERMINATION_GRACE_MS);onSettled()}class PtyChildController{deps;constructor(deps){this.deps=deps}spawn(key,spec,spare=!1){let argv=spec.command&&spec.command.length>0?[...spec.command]:[spec.shell??resolveLoginShell()],session=freshSessionState(key,spec,argv);if(this.startChild(session),session.alive)this.deps.log?.("pty",`spawned ${argv[0]} for ${key} (pid ${session.proc?.pid})`),this.deps.onSessionStart?.(spare);return session}startChild(session){session.generation=randomUUID2(),session.oscSignals=void 0,session.programStatusEvent=void 0,this.reportStatus(session,null);try{session.proc=(this.deps.driver??bunTerminalDriver())({argv:[...session.command],cwd:session.cwd,env:embeddedTerminalEnv(process.env,{TERM:"xterm-256color",COLUMNS:String(session.cols),LINES:String(session.rows),BASH_SILENCE_DEPRECATION_WARNING:"1",ROVE_TERMINAL_PTY:"1"}),cols:session.cols,rows:session.rows,onData:(data)=>this.onData(session,data)}),session.alive=!0,session.proc.exited.then((exit)=>this.markExited(session,exit),()=>this.markExited(session))}catch(err){session.alive=!1,this.deps.log?.("pty",`spawn failed for ${session.key}: ${err instanceof Error?err.message:String(err)}`)}}async endChild(session){if(!session.alive)return;let proc=session.proc;if(!proc){this.markExited(session);return}await terminatePtyChild(proc,()=>this.markExited(session),(line)=>this.deps.log?.("pty-signal",`${session.key}: ${line}`))}markExited(session,exit){if(!session.alive)return;if(session.alive=!1,session.oscSignals){let before=session.oscSignals.records.get("");if(clearTransientStatuses(session.oscSignals),before!==session.oscSignals.records.get(""))this.reportStatus(session,null)}let sessionExit={code:exit?.code??null,signal:exit?.signal??null,at:new Date().toISOString()};session.exit=sessionExit;try{session.proc?.close()}catch{}this.deps.onExit?.(session,sessionExit)}reportStatus(session,status){let event={key:session.key,generation:session.generation,revision:(session.programStatusEvent?.revision??0)+1,at:Date.now(),status};session.programStatusEvent=event,this.deps.onProgramStatus?.(event)}onData(session,data){let buf=typeof data==="string"?Buffer.from(data,"utf8"):Buffer.from(data),text=buf.toString("latin1");session.oscSignals??=createOscSignals();let queries=scanOscSignals(session.oscSignals,buf,Date.now(),(status)=>this.reportStatus(session,status)),colorQueries=foldDefaultColorQueries(session.colorQueryCarry,text);session.colorQueryCarry=colorQueries.carry;let replies=colorQueries.slots.map((slot)=>formatDefaultColorReply(slot,session.defaultColors));for(let i=0;i<Math.min(queries,16);i++)replies.push("\x1B]7501;?\x1B\\");let modeReplies=scanTerminalModes(session.modes,text);if(session.emulatorSinks.size===0)replies.push(...modeReplies);if(replies.length>0)try{session.proc?.write(replies.join(""))}catch{}scanOscTitle(session,buf),session.chunks.push(buf),session.bytes+=buf.byteLength,session.totalBytes+=buf.byteLength;while(session.bytes>this.deps.scrollbackCap&&session.chunks.length>1){let dropped=session.chunks.shift();if(!dropped)break;session.bytes-=dropped.byteLength,scanTerminalModes(session.ringModes,dropped.toString("latin1"))}this.deps.onOutput?.(session,buf)}}function shouldFreeze(session,now){let appended=session.totalBytes-(session.frozenTotalBytes??0);if(appended<=0)return!1;let since=now-session.lastFreezeAtMs;if(since<5000)return!1;return appended>=65536||since>=60000}class WarmSpare{deps;spare=null;constructor(deps){this.deps=deps}warm(cwd,shell,cols=80,rows=24){let argv0=shell??resolveLoginShell();if(this.spare?.alive&&this.spare.cwd===cwd&&this.spare.command[0]===argv0)return;let old=this.spare;if(this.spare=null,old)this.deps.endChild(old);let session=this.deps.spawn("::spare",{cwd,command:[argv0],cols,rows},!0);this.spare=session.alive?session:null}adopt(key,spec){let spare=this.spare;if(!spare?.alive||spare.cwd!==spec.cwd)return null;let want=spec.command&&spec.command.length>0?spec.command:[spec.shell??resolveLoginShell()];if(want.length!==1||want[0]!==spare.command[0])return null;this.spare=null,spare.key=key,spare.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??spare.defaultColors;let cols=spec.cols??spare.cols,rows=spec.rows??spare.rows;if(spare.cols!==cols||spare.rows!==rows){spare.cols=cols,spare.rows=rows;try{spare.proc?.resize(cols,rows)}catch{return this.deps.markExited(spare),null}}return this.deps.log?.("pty",`adopted warm shell for ${key} (pid ${spare.proc?.pid})`),this.deps.onSessionStart?.(),this.warm(spec.cwd,spare.command[0],cols,rows),spare}async end(){let spare=this.spare;if(this.spare=null,spare)await this.deps.endChild(spare)}}var LOGGED_WRITE_BYTES=1024,DEFAULT_SCROLLBACK_CAP=524288,EXIT_TAIL_BYTES=16384;class PtyHost{sessions=new Map;opts;scrollbackCap;parkRestoreDeltas=0;parkRestoreFallbacks=0;childController;warmSpare;constructor(opts={}){this.opts=opts,this.scrollbackCap=opts.scrollbackCap??DEFAULT_SCROLLBACK_CAP,this.childController=new PtyChildController({driver:opts.driver,onProgramStatus:(event)=>this.opts.onProgramStatus?.(event),scrollbackCap:this.scrollbackCap,onSessionStart:(spare)=>{if(!spare)this.opts.onSessionStart?.()},onOutput:(session,data)=>{if(session.sinks.size===0){this.maybeFreeze(session);return}let frame={type:"event",name:"pty.data",payload:{key:session.key,data:data.toString("base64")}};for(let sink of session.sinks.values())sink(frame);this.maybeFreeze(session)},onExit:(session,exit)=>{let frame={type:"event",name:"pty.exit",payload:{key:session.key,pid:session.proc?.pid??null,...exit}};for(let sink of session.sinks.values())sink(frame);if(this.opts.log?.("pty",`session ${session.key} exited${describeExit(exit)}`),this.maybeFreeze(session,!0),!session.closedByRequest)try{this.opts.onSessionExit?.({key:session.key,pid:session.proc?.pid??null,exit,tail:ringTail(session.chunks,session.bytes,EXIT_TAIL_BYTES)})}catch{}this.opts.onSessionEnd?.()},log:(event,message)=>this.opts.log?.(event,message)}),this.warmSpare=new WarmSpare({spawn:(key,spec,spare)=>this.childController.spawn(key,spec,spare),endChild:(session)=>this.childController.endChild(session),markExited:(session)=>this.childController.markExited(session),log:(event,message)=>this.opts.log?.(event,message),onSessionStart:()=>this.opts.onSessionStart?.()})}open(key,spec,token,sink,sinceOffset,sincePid,answersQueries=!1){let session=this.sessions.get(key),created=!1,respawned=!1;if(!session)created=!0,session=this.warmSpare.adopt(key,spec)??this.childController.spawn(key,spec),this.sessions.set(key,session);else if(!session.alive&&session.restored)this.respawn(session,spec),respawned=session.alive;else if(session.alive&&spec.cols!==void 0&&spec.rows!==void 0&&(session.cols!==spec.cols||session.rows!==spec.rows))this.resize(key,spec.cols,spec.rows);let defaultColors=parseTerminalDefaultColors(spec.defaultColors);if(defaultColors)session.defaultColors=defaultColors;if(session.sinks.set(token,sink),answersQueries)session.emulatorSinks.add(token);else session.emulatorSinks.delete(token);session.parked=!1,session.parkedScreenBytes=0;let windowStart=session.totalBytes-session.bytes,replay=Buffer.concat(session.chunks),sinceValid=!1;if(!created&&sinceOffset!==void 0&&sinceOffset>=windowStart&&sinceOffset<=session.totalBytes&&sincePid!==void 0&&sincePid===session.proc?.pid)replay=replay.subarray(sinceOffset-windowStart),sinceValid=!0;if(sinceOffset!==void 0&&sincePid!==void 0)if(sinceValid)this.parkRestoreDeltas++;else this.parkRestoreFallbacks++;if(!sinceValid)replay=Buffer.concat([Buffer.from(terminalModePreamble(session.ringModes.modes),"latin1"),replay]);return{replay:replay.toString("base64"),alive:session.alive,pid:session.proc?.pid??null,created,respawned,offset:session.totalBytes,sinceValid}}warm(cwd,shell,cols=80,rows=24){this.warmSpare.warm(cwd,shell,cols,rows)}write(key,data){let session=this.sessions.get(key);if(!session?.alive||data.length===0)return;if(data.length>=LOGGED_WRITE_BYTES)this.opts.log?.("pty",`wrote ${data.length} bytes to ${key}`);try{session.proc?.write(data)}catch(error){this.opts.log?.("pty",`write failed on ${key} (${data.length} bytes): ${String(error)}`)}}resize(key,cols,rows){let session=this.sessions.get(key);if(!session?.alive)return;session.cols=cols,session.rows=rows;try{session.proc?.resize(cols,rows)}catch{}}killIfGeneration(key,expectedGeneration){let session=this.sessions.get(key);if(!session)return{accepted:!1,reason:"missing-session"};if(session.generation!==expectedGeneration)return{accepted:!1,reason:"generation-mismatch"};return this.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}kill(key){let session=this.sessions.get(key);if(!session)return Promise.resolve();return this.sessions.delete(key),session.closedByRequest=!0,this.opts.freeze?.drop(key),this.childController.endChild(session)}rename(from,to){let session=this.sessions.get(from);if(!session||from===to||this.sessions.has(to))return!1;if(this.sessions.delete(from),session.key=to,session.programStatusEvent){let previous=session.programStatusEvent;this.opts.onProgramStatus?.({...previous,revision:previous.revision+1,at:Date.now(),status:null}),session.programStatusEvent={...previous,key:to,revision:previous.revision+1,at:Date.now()},this.opts.onProgramStatus?.(session.programStatusEvent)}return this.sessions.set(to,session),this.opts.freeze?.drop(from),this.maybeFreeze(session,!0),this.opts.log?.("pty",`renamed session ${from} \u2192 ${to}`),!0}detach(key,token,parked=!1,parkedScreenBytes=0){let session=this.sessions.get(key);if(!session)return;session.sinks.delete(token),session.emulatorSinks.delete(token),this.applyParkedOnDetach(session,parked,parkedScreenBytes)}detachClient(token){for(let session of this.sessions.values()){if(session.emulatorSinks.delete(token),!session.sinks.delete(token))continue;this.applyParkedOnDetach(session)}}applyParkedOnDetach(session,parked=!1,parkedScreenBytes=0){if(session.sinks.size!==0)return;session.parked=parked,session.parkedScreenBytes=parked?Math.max(0,parkedScreenBytes):0}list(){return Array.from(this.sessions.values(),(s)=>sessionInfo(s))}peek(key,sinceOffset){return peekRing(this.sessions.get(key),sinceOffset)}stats(){return hostStats(this.sessions.values(),this.scrollbackCap,this.parkRestoreDeltas,this.parkRestoreFallbacks)}async killAll(){let sessions=Array.from(this.sessions.keys(),(key)=>this.kill(key));sessions.push(this.warmSpare.end()),await Promise.all(sessions)}async shutdown(){this.flushFrozen();let endings=Array.from(this.sessions.values(),(session)=>this.childController.endChild(session));endings.push(this.warmSpare.end()),await Promise.all(endings)}flushFrozen(){for(let session of this.sessions.values())this.maybeFreeze(session,!0)}restoreFrozen(records){let restoredCount=0;for(let record of records){if(this.sessions.has(record.key))continue;let session=thawSession(record,this.scrollbackCap);if(!session)continue;this.sessions.set(record.key,session),restoredCount++}if(restoredCount>0)this.opts.log?.("pty",`restored ${restoredCount} frozen session(s) from disk`);return restoredCount}respawn(session,spec){if(session.restored=!1,session.exit=null,spec.command&&spec.command.length>0)session.command=[...spec.command];if(session.cols=spec.cols??session.cols,session.rows=spec.rows??session.rows,session.defaultColors=parseTerminalDefaultColors(spec.defaultColors)??session.defaultColors,this.childController.startChild(session),!session.alive)return;this.opts.log?.("pty",`respawned restored session ${session.key} (pid ${session.proc?.pid})`),this.opts.onSessionStart?.()}maybeFreeze(session,force=!1){let freeze=this.opts.freeze;if(!freeze||session.key.startsWith("::"))return;if(session.closedByRequest)return;let now=Date.now();if(!force&&!shouldFreeze(session,now))return;session.lastFreezeAtMs=now,session.frozenTotalBytes=session.totalBytes,freeze.save(freezeSession(session))}liveCount(){let n=0;for(let session of this.sessions.values())if(session.alive)n++;return n}}function dispatchPtyRequest(req,client,deps){let{ptys}=deps;switch(req.name){case"hello":return{protocolVersion:DAEMON_PROTOCOL_VERSION,ptyHost:!0,pid:process.pid};case"pty.openChecked":case"pty.open":{let payload=objectPayload(req.payload);if(req.name==="pty.openChecked"&&requireString(payload,"admissionToken")!==admissionToken(ptys))return{kind:"changed"};let open=ptys.open(requireString(payload,"key"),{cwd:requireString(payload,"cwd"),command:Array.isArray(payload.command)?payload.command.filter((c)=>typeof c==="string"):void 0,shell:typeof payload.shell==="string"?payload.shell:void 0,cols:typeof payload.cols==="number"?payload.cols:void 0,rows:typeof payload.rows==="number"?payload.rows:void 0,defaultColors:parseTerminalDefaultColors(payload.defaultColors)??void 0},client,(frame)=>deps.writeFrame(client,frame),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0,typeof payload.sincePid==="number"?payload.sincePid:void 0,payload.answersQueries===!0);return req.name==="pty.openChecked"?{kind:"opened",open}:open}case"pty.write":{let payload=objectPayload(req.payload);return ptys.write(requireString(payload,"key"),typeof payload.data==="string"?payload.data:""),{}}case"pty.resize":{let payload=objectPayload(req.payload);return ptys.resize(requireString(payload,"key"),typeof payload.cols==="number"?payload.cols:80,typeof payload.rows==="number"?payload.rows:24),{}}case"pty.kill":{let payload=objectPayload(req.payload),key=requireString(payload,"key");if("expectedGeneration"in payload)return ptys.killIfGeneration(key,requireString(payload,"expectedGeneration"));if(optionalBoolean(payload,"wait")===!0)return ptys.kill(key).then(()=>({accepted:!0,ended:!0}),(err)=>{return logDaemonError("pty-kill",err),{accepted:!0,ended:!1}});return ptys.kill(key).catch((err)=>logDaemonError("pty-kill",err)),{accepted:!0}}case"pty.rename":{let payload=objectPayload(req.payload);return{renamed:ptys.rename(requireString(payload,"from"),requireString(payload,"to"))}}case"pty.detach":{let payload=objectPayload(req.payload);ptys.detach(requireString(payload,"key"),client,payload.parked===!0,typeof payload.parkedScreenBytes==="number"?payload.parkedScreenBytes:0)}return{};case"pty.watchStatus":client.watchProgramStatus=!0;for(let session of ptys.list())if(session.programStatusEvent)deps.writeFrame(client,{type:"event",name:"pty.programStatus",payload:session.programStatusEvent});return{supported:!0};case"pty.list":return{pid:process.pid,rssBytes:process.memoryUsage().rss,sessions:ptys.list(),admissionToken:admissionToken(ptys),stats:ptys.stats(),...deps.version?{version:deps.version}:{}};case"pty.peek":{let payload=objectPayload(req.payload);return ptys.peek(requireString(payload,"key"),typeof payload.sinceOffset==="number"?payload.sinceOffset:void 0)}case"pty.warm":{let payload=objectPayload(req.payload);return ptys.warm(requireString(payload,"cwd"),typeof payload.shell==="string"?payload.shell:void 0,typeof payload.cols==="number"?payload.cols:void 0,typeof payload.rows==="number"?payload.rows:void 0),{}}case"spawn.detached":{if(process.platform!=="win32")throw Error("spawn.detached is Windows-only");let payload=objectPayload(req.payload),env=objectPayload(payload.env);return spawnDetachedDaemon(requireString(payload,"command"),Array.isArray(payload.args)?payload.args.filter((a)=>typeof a==="string"):[],withoutPtyJob(Object.fromEntries(Object.entries(env).filter((e)=>typeof e[1]==="string"))),requireString(payload,"logPath")),{}}case"daemon.stop":return deps.requestStop(),{};default:throw Error(`unknown pty-host request: ${req.name}`)}}function admissionToken(ptys){return JSON.stringify(ptys.list().map((s)=>[s.key,s.generation,s.pid,s.alive]))}var DEFAULT_IDLE_EXIT_MS=60000,DEFAULT_ORPHAN_CHECK_MS=30000;function resolveMaxLifetimeMs(){let raw=process.env.ROVE_PTY_MAX_LIFETIME_MS;if(raw===void 0)return null;let n=Number(raw);return Number.isFinite(n)&&n>0?n:null}function resolveIdleExitMs(){let raw=process.env.ROVE_PTY_IDLE_EXIT_MS;if(raw===void 0)return DEFAULT_IDLE_EXIT_MS;let n=Number(raw);return Number.isFinite(n)&&n>=0?n:DEFAULT_IDLE_EXIT_MS}async function startPtyHostServer(options={}){migrateLegacyPtyHostData();let socketPath=options.socketPath??defaultPtyHostSocketPath(),pidPath=options.pidPath??defaultPtyHostPidPath(),freezeDir=options.freezeDir??defaultPtyFreezeDir(),idleExitMs=options.idleExitMs||resolveIdleExitMs(),orphanCheckMs=options.orphanCheckMs||DEFAULT_ORPHAN_CHECK_MS,maxLifetimeMs=options.maxLifetimeMs??resolveMaxLifetimeMs(),bootedAtMs=Date.now(),log=options.log??(()=>{}),clients=new Set,stopping=!1,wipeFreezeOnStop=!1,idleTimer=null,cancelIdle=()=>{if(idleTimer)clearTimeout(idleTimer);idleTimer=null},armIdle=()=>{if(stopping)return;cancelIdle(),idleTimer=setTimeout(()=>{if(stopping||ptys.liveCount()>0)return;log("idle",`no live sessions for ${idleExitMs}ms \u2014 exiting`),stop()},idleExitMs)},orphaned=()=>{if(maxLifetimeMs!==null&&Date.now()-bootedAtMs>=maxLifetimeMs)return`exceeded its ${maxLifetimeMs}ms lifetime ceiling`;let owner;try{owner=readFileSync(pidPath,"utf8").trim()}catch{return`pidfile ${pidPath} is gone`}let pid=Number.parseInt(owner,10);if(pid===process.pid)return null;return Number.isInteger(pid)?`pidfile ${pidPath} now names pid ${pid}`:`pidfile ${pidPath} is unreadable`},orphanTimer=setInterval(()=>{if(stopping)return;let reason=orphaned();if(!reason)return;log("orphan",`${reason} \u2014 exiting rather than outliving my owner`),stop()},orphanCheckMs);orphanTimer.unref?.();let ptys=new PtyHost({onProgramStatus:(event)=>{for(let client of clients)if(client.watchProgramStatus)writeFrame(client,{type:"event",name:"pty.programStatus",payload:event})},onSessionStart:cancelIdle,onSessionEnd:()=>{if(ptys.liveCount()===0)armIdle()},onSessionExit:(info)=>{try{recordPtyExit(info)}catch(err){log("pty",`exit record write failed for ${info.key}: ${err instanceof Error?err.message:String(err)}`)}},freeze:fileFreezeSink(freezeDir),driver:options.driver,log});ptys.restoreFrozen(loadFrozenSessions(freezeDir,Date.now(),(s)=>{let mib=(bytes)=>`${Math.round(bytes/1048576)}MB`,notes=[`restored ${s.restored} (${mib(s.bytesRead)})`];if(s.deferred>0)notes.push(`${s.deferred} left unread past the ${mib(FREEZE_RESTORE_MAX_BYTES)} budget`);if(s.expired>0)notes.push(`${s.expired} deleted past the ${FREEZE_TTL_MS/86400000}-day TTL`);if(s.unreadable>0)notes.push(`${s.unreadable} unreadable`);log("freeze",notes.join(", "))}));let pipeSocket=isWindowsPipePath(socketPath);if(await ensureOwnerOnlyStateDir(resolveDaemonHomeDir()),!pipeSocket)await mkdir(dirname(socketPath),{recursive:!0});await mkdir(dirname(pidPath),{recursive:!0});let server=createServer((socket)=>{let client={socket,writer:new ClientWriter(socket,{onOverflow:()=>{log("backpressure","disconnecting PTY client whose critical queue exceeded 8MiB"),socket.destroy()}})};clients.add(client);let receiver=new LineReceiver;socket.on("data",(chunk)=>{if(!receiver.push(chunk,(line)=>handleLine(client,line)))log("framing","disconnecting PTY client whose request exceeded 8MiB"),socket.destroy()}),socket.on("error",()=>{}),socket.on("close",()=>{clients.delete(client),ptys.detachClient(client)})}),api={socketPath,pidPath,async close(){if(stopping)return;if(stopping=!0,cancelIdle(),clearInterval(orphanTimer),await ptys.shutdown(),wipeFreezeOnStop)clearFrozenSessions(freezeDir);for(let client of Array.from(clients))client.socket.destroy();if(await new Promise((resolve)=>server.close(()=>resolve())),!pipeSocket)await unlink(socketPath).catch(()=>{});await unlink(pidPath).catch(()=>{})}};async function stop(){await api.close().catch((err)=>logDaemonError("pty-host-shutdown",err)),options.onStop?.()}let verbDeps={ptys,writeFrame,requestStop:()=>{wipeFreezeOnStop=!0,setTimeout(()=>void stop(),0).unref()},...options.version?{version:options.version}:{}};function handleLine(client,line){if(line.trim().length>0){let frame=null;try{frame=JSON.parse(line)}catch{writeFrame(client,{type:"response",id:"parse-error",error:{message:"malformed frame"}})}if(frame)if(frame.type!=="request")writeFrame(client,{type:"response",id:"parse-error",error:{message:"requests only"}});else{let req=frame,reply=(payload)=>writeFrame(client,{type:"response",id:req.id,name:req.name,payload}),fail=(err)=>writeFrame(client,{type:"response",id:req.id,name:req.name,error:{message:err instanceof Error?err.message:String(err)}});try{let payload=dispatchPtyRequest(req,client,verbDeps);if(payload instanceof Promise)payload.then(reply,fail);else reply(payload)}catch(err){fail(err)}}}}if(await listenOnUnixSocket(server,socketPath),await writeTextAtomic(pidPath,`${process.pid}
3
3
  `),!pipeSocket)await writeTextAtomic(endpointPathFor(pidPath),`${socketPath}
4
4
  `);return armIdle(),log("boot",`pty host listening on ${socketPath}`),api}function writeFrame(client,frame){client.writer.write(frameToLine(frame))}async function runPtyHostSubcommand(_argv){rotateLogIfNeeded(defaultPtyHostLogPath()),installDaemonCrashHandlers();let server=await startPtyHostServer({log:(event,message)=>console.log(formatPtyHostLine(event,message)),version:CURRENT_VERSION,onStop:()=>process.exit(0)});console.log(formatPtyHostLine("listen",`v${CURRENT_VERSION} listening on ${server.socketPath}`));let shutdown=async(signal)=>{console.log(formatPtyHostLine("signal",`${signal} received \u2014 closing host, frozen sessions kept`)),await server.close(),process.exit(0)};process.once("SIGINT",()=>void shutdown("SIGINT")),process.once("SIGTERM",()=>void shutdown("SIGTERM"))}export{runPtyHostSubcommand};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{launchTui,trackWelcomeWrite}from"./chunk-y0gybgba.js";import"./chunk-91sykzqq.js";export{trackWelcomeWrite,launchTui};
2
+ import{launchTui,trackWelcomeWrite}from"./chunk-ecngwr1v.js";import"./chunk-91sykzqq.js";export{trackWelcomeWrite,launchTui};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{INBOUND_CLASSES,INBOUND_KEY,deniedClasses,inboundClassOf,inboundRefusal,setInbound}from"./chunk-3v2hgjb2.js";import"./chunk-q2kweazg.js";import"./chunk-1j4e2jcx.js";import"./chunk-rc2nwsdd.js";import"./chunk-t60qcvcj.js";import"./chunk-e6848rj8.js";import"./chunk-j11hzmwy.js";import"./chunk-6h12b2k0.js";import"./chunk-17e2tgyg.js";import"./chunk-cbc1h345.js";import"./chunk-jjv7xem7.js";import"./chunk-4hestsjp.js";import"./chunk-stcvcsfm.js";import"./chunk-2bgmby1d.js";import"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-edsm15ht.js";import"./chunk-atn06ncf.js";import"./chunk-j5w8n1st.js";import"./chunk-qkehg2c1.js";import"./chunk-1dcb0069.js";import"./chunk-9ztqf6hb.js";import"./chunk-rsvh7n8v.js";import"./chunk-ampdybqg.js";import"./chunk-sak1tphp.js";import"./chunk-pbfehk8q.js";import"./chunk-4250pw6r.js";import"./chunk-qpvvc1xz.js";import"./chunk-rxqdw6s5.js";import"./chunk-zae59k1j.js";import"./chunk-f5n0tgky.js";import"./chunk-z3zaa155.js";import"./chunk-yewmtant.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-bdwp2k8f.js";import"./chunk-efjahmtj.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"./chunk-4pt3n7cg.js";import"./chunk-b7xjhgts.js";import"./chunk-x7r75e3p.js";import"./chunk-zsfyj36g.js";import"./chunk-601dsgex.js";import"./chunk-1vwngrmf.js";import"./chunk-3vtpshwx.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-bkt3ktvx.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-hqkzc8cv.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-2676cb62.js";import"./chunk-q07r6hf7.js";import"./chunk-cmp64q4j.js";import"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.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"./chunk-91sykzqq.js";export{setInbound,inboundRefusal,inboundClassOf,deniedClasses,INBOUND_KEY,INBOUND_CLASSES};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{require_react_production}from"./chunk-2wd4744g.js";import{__toESM}from"./chunk-91sykzqq.js";var import_react=__toESM(require_react_production(),1),hub=null;function setMachineHub(next){hub=next}var NO_MACHINES=[];function useMergedTasks(orchestrator){let state=hub?hub.tasksSignal():orchestrator.tasksSignal();return import_react.useSyncExternalStore(state.subscribe,state.get,state.get)}function useMachineRows(){let state=hub?.machinesSignal(),subscribe=state?.subscribe??noopSubscribe,get=state?.get??emptyRows;return import_react.useSyncExternalStore(subscribe,get,get)}function noopSubscribe(){return()=>{}}function emptyRows(){return NO_MACHINES}
3
- export{setMachineHub,useMergedTasks,useMachineRows};
2
+ import{require_react_production}from"./chunk-2wd4744g.js";import{__toESM}from"./chunk-91sykzqq.js";var import_react=__toESM(require_react_production(),1),hub=null;function setMachineHub(next){hub=next}var NO_MACHINES=[];function useMergedTasks(orchestrator){let state=hub?hub.tasksSignal():orchestrator.tasksSignal();return import_react.useSyncExternalStore(state.subscribe,state.get,state.get)}function useMachineRows(){let state=hub?.machinesSignal(),subscribe=state?.subscribe??noopSubscribe,get=state?.get??emptyRows;return import_react.useSyncExternalStore(subscribe,get,get)}function noopSubscribe(){return()=>{}}function emptyRows(){return NO_MACHINES}function machineOfTask(taskId){if(!hub||!taskId)return null;let alias=hub.tasksSignal().get().find((row)=>String(row.id)===taskId)?.origin?.machineId;return alias&&alias!=="local"?alias:null}
3
+ export{setMachineHub,useMergedTasks,useMachineRows,machineOfTask};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{t}from"./chunk-tq6pq1ws.js";import{createInterface}from"readline";function daemonRestartFix(cliName,reason){return{kind:"run",id:"daemon-restart",label:t(`doctor.fix.${reason}`),command:[cliName,"daemon","restart"],why:t("doctor.fix.daemonRestartWhy")}}function skillInstallFix(installCommand,stale){return{kind:"run",id:"skill-install",label:t(stale?"doctor.fix.skillStale":"doctor.fix.skillMissing"),command:installCommand.split(" "),why:t("doctor.fix.skillInstallWhy")}}function resetManualFix(cliName,reason){return{kind:"manual",id:`reset:${reason}`,label:t(`doctor.fix.${reason}`),action:`${cliName} reset`,why:t("doctor.fix.resetWhy")}}function killOrphansManualFix(cliName,count){return{kind:"manual",id:"kill-orphans",label:t("doctor.fix.orphans",{count}),action:`${cliName} doctor --kill-orphans`,why:t("doctor.fix.orphansWhy")}}function engineTabsManualFix(){return{kind:"manual",id:"engine-tabs",label:t("doctor.fix.engineTabs"),action:t("doctor.fix.engineTabsAction"),why:t("doctor.fix.engineTabsWhy")}}function reinstallManualFix(){return{kind:"manual",id:"reinstall",label:t("doctor.fix.staleInstall"),action:t("doctor.fix.staleInstallAction"),why:t("doctor.fix.staleInstallWhy")}}function spawnHelperFix(paths){return{kind:"run",id:"spawn-helper-chmod",label:t("doctor.fix.spawnHelper"),command:["chmod","755",...paths],why:t("doctor.fix.spawnHelperWhy")}}function humanOnlyFix(reason,vars){return{kind:"manual",id:reason,label:t(`doctor.fix.${reason}`),action:t(`doctor.fix.${reason}Action`,vars),why:t("doctor.fix.humanOnlyWhy")}}function noEngineFix(signedOut){return signedOut.length>0?humanOnlyFix("noEngineLogin",{list:signedOut.join(", ")}):humanOnlyFix("noEngine")}function dedupeFixes(fixes){let seen=new Set;return fixes.filter((fix)=>{if(seen.has(fix.id))return!1;return seen.add(fix.id),!0})}async function applyFixes(collected,rt){let fixes=dedupeFixes(collected);if(fixes.length===0){rt.out(""),rt.out(t("doctor.fix.none"));return}let runnable=fixes.filter((fix)=>fix.kind==="run");if(runnable.length>0){rt.out(""),rt.out(t("doctor.fix.header"));for(let fix of runnable){if(rt.out(` ${fix.label}`),rt.out(` ${t("doctor.fix.willRun",{command:fix.command.join(" ")})}`),rt.out(` ${fix.why}`),!rt.interactive)continue;if(!await rt.confirm(` ${t("doctor.fix.confirmPrompt")}`)){rt.out(` ${t("doctor.fix.skipped")}`);continue}let code=await rt.exec(fix.command);rt.out(code===0?` ${t("doctor.fix.done")}`:` ${t("doctor.fix.failed",{code})}`)}if(!rt.interactive)rt.out(` ${t("doctor.fix.nonInteractive")}`)}let manual=fixes.filter((fix)=>fix.kind==="manual");if(manual.length>0){rt.out(""),rt.out(t("doctor.fix.manualHeader"));for(let fix of manual)rt.out(` ${fix.label}`),rt.out(` \u2192 ${fix.action}`),rt.out(` ${fix.why}`)}}async function confirmTty(question){let readline=createInterface({input:process.stdin,output:process.stdout});try{let answer=await new Promise((resolve)=>readline.question(question,resolve));return answer.trim().toLowerCase()==="y"||answer.trim().toLowerCase()==="yes"}finally{readline.close()}}async function execInherited(command){try{return await Bun.spawn([...command],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited}catch{return 127}}function defaultFixRuntime(){return{confirm:confirmTty,exec:execInherited,out:(line)=>console.log(line),interactive:process.stdin.isTTY===!0}}
2
+ import{t}from"./chunk-2676cb62.js";import{createInterface}from"readline";function daemonRestartFix(cliName,reason){return{kind:"run",id:"daemon-restart",label:t(`doctor.fix.${reason}`),command:[cliName,"daemon","restart"],why:t("doctor.fix.daemonRestartWhy")}}function skillInstallFix(installCommand,stale){return{kind:"run",id:"skill-install",label:t(stale?"doctor.fix.skillStale":"doctor.fix.skillMissing"),command:installCommand.split(" "),why:t("doctor.fix.skillInstallWhy")}}function resetManualFix(cliName,reason){return{kind:"manual",id:`reset:${reason}`,label:t(`doctor.fix.${reason}`),action:`${cliName} reset`,why:t("doctor.fix.resetWhy")}}function killOrphansManualFix(cliName,count){return{kind:"manual",id:"kill-orphans",label:t("doctor.fix.orphans",{count}),action:`${cliName} doctor --kill-orphans`,why:t("doctor.fix.orphansWhy")}}function engineTabsManualFix(){return{kind:"manual",id:"engine-tabs",label:t("doctor.fix.engineTabs"),action:t("doctor.fix.engineTabsAction"),why:t("doctor.fix.engineTabsWhy")}}function reinstallManualFix(){return{kind:"manual",id:"reinstall",label:t("doctor.fix.staleInstall"),action:t("doctor.fix.staleInstallAction"),why:t("doctor.fix.staleInstallWhy")}}function spawnHelperFix(paths){return{kind:"run",id:"spawn-helper-chmod",label:t("doctor.fix.spawnHelper"),command:["chmod","755",...paths],why:t("doctor.fix.spawnHelperWhy")}}function humanOnlyFix(reason,vars){return{kind:"manual",id:reason,label:t(`doctor.fix.${reason}`),action:t(`doctor.fix.${reason}Action`,vars),why:t("doctor.fix.humanOnlyWhy")}}function noEngineFix(signedOut){return signedOut.length>0?humanOnlyFix("noEngineLogin",{list:signedOut.join(", ")}):humanOnlyFix("noEngine")}function dedupeFixes(fixes){let seen=new Set;return fixes.filter((fix)=>{if(seen.has(fix.id))return!1;return seen.add(fix.id),!0})}async function applyFixes(collected,rt){let fixes=dedupeFixes(collected);if(fixes.length===0){rt.out(""),rt.out(t("doctor.fix.none"));return}let runnable=fixes.filter((fix)=>fix.kind==="run");if(runnable.length>0){rt.out(""),rt.out(t("doctor.fix.header"));for(let fix of runnable){if(rt.out(` ${fix.label}`),rt.out(` ${t("doctor.fix.willRun",{command:fix.command.join(" ")})}`),rt.out(` ${fix.why}`),!rt.interactive)continue;if(!await rt.confirm(` ${t("doctor.fix.confirmPrompt")}`)){rt.out(` ${t("doctor.fix.skipped")}`);continue}let code=await rt.exec(fix.command);rt.out(code===0?` ${t("doctor.fix.done")}`:` ${t("doctor.fix.failed",{code})}`)}if(!rt.interactive)rt.out(` ${t("doctor.fix.nonInteractive")}`)}let manual=fixes.filter((fix)=>fix.kind==="manual");if(manual.length>0){rt.out(""),rt.out(t("doctor.fix.manualHeader"));for(let fix of manual)rt.out(` ${fix.label}`),rt.out(` \u2192 ${fix.action}`),rt.out(` ${fix.why}`)}}async function confirmTty(question){let readline=createInterface({input:process.stdin,output:process.stdout});try{let answer=await new Promise((resolve)=>readline.question(question,resolve));return answer.trim().toLowerCase()==="y"||answer.trim().toLowerCase()==="yes"}finally{readline.close()}}async function execInherited(command){try{return await Bun.spawn([...command],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited}catch{return 127}}function defaultFixRuntime(){return{confirm:confirmTty,exec:execInherited,out:(line)=>console.log(line),interactive:process.stdin.isTTY===!0}}
3
3
  export{daemonRestartFix,skillInstallFix,resetManualFix,killOrphansManualFix,engineTabsManualFix,reinstallManualFix,spawnHelperFix,humanOnlyFix,noEngineFix,applyFixes,defaultFixRuntime};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{ensureForwards}from"./chunk-c0gvp57p.js";import{dedupeMachines,discoverMachine,listMachines,localDaemonSocketPath,localPtySocketPath,updateMachine}from"./chunk-r3zkpbf5.js";import{isLocalCheckout,repoIdentity,unpushedCommits}from"./chunk-4pt3n7cg.js";import{ApiError}from"./chunk-x7r75e3p.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{RoveDaemonClient}from"./chunk-s0jbtyd9.js";import{ROVE_API_VERSION}from"./chunk-278sc87n.js";import{hostname}from"os";var LOCAL_MACHINE="local";async function machineDaemonSocket(entry){let socketPath=localDaemonSocketPath(entry.alias);if(await answers(socketPath))return socketPath;if(!entry.sockets||!await forward(entry,entry.sockets))return null;if(await answers(socketPath))return socketPath;let found=await discoverMachine(entry.alias,entry);if(!found.ok)return null;let sockets={daemon:found.status.socketPath,pty:found.status.ptySocketPath};return updateMachine(entry.alias,{sockets,...found.roveBin?{roveBin:found.roveBin}:{}}),await forward(entry,sockets)&&await answers(socketPath)?socketPath:null}function forward(entry,sockets){return ensureForwards({alias:entry.alias,config:entry,remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty})}async function answers(socketPath){let client=new RoveDaemonClient(socketPath);try{return await client.request("hello",{}),!0}catch{return!1}finally{client.close()}}async function machineTasks(entry){let socketPath=await machineDaemonSocket(entry);if(!socketPath)return null;let client=new RoveDaemonClient(socketPath);try{return(await client.request("task.list")).tasks??[]}catch{return null}finally{client.close()}}function requireMachine(alias){let entry=listMachines().find((m)=>m.alias===alias);if(entry)return entry;throw new ApiError(`no machine named "${alias}"`,"UNKNOWN_MACHINE",{hint:"list the registered machines and retry with one of their aliases, or register it first",nextCommandArgs:["machine","list"]})}var AUTO_MACHINE="auto",busy=(tasks)=>tasks.filter((task)=>task.status==="in_progress").length;async function pickMachine(localTasks,readTasks=machineTasks,machines=dedupeMachines(listMachines())){let[local,...remote]=await Promise.all([localTasks().catch(()=>[]),...machines.map((entry)=>readTasks(entry))]),loads={[LOCAL_MACHINE]:busy(local)},best=null,bestLoad=loads[LOCAL_MACHINE]??0;return machines.forEach((entry,i)=>{let tasks=remote[i];if(!tasks)return;let load=busy(tasks);if(loads[entry.alias]=load,load<bestLoad)best=entry,bestLoad=load}),{entry:best,loads}}async function routeTarget(args){if(args.machine===AUTO_MACHINE)return(await pickMachine(args.localTasks??(async()=>[]))).entry;if(args.machine!==void 0&&args.machine!==LOCAL_MACHINE)return requireMachine(args.machine);if(args.machine===LOCAL_MACHINE||!args.taskId)return null;let machines=dedupeMachines(listMachines());if(machines.length===0||await args.isLocalTask(args.taskId))return null;for(let entry of machines)if((await machineTasks(entry))?.some((task)=>task.id===args.taskId))return entry;return null}async function forwardVerb(entry,verb,params,socketPath){let target=socketPath??await machineDaemonSocket(entry);if(!target)return offline(entry.alias);let client=new RoveDaemonClient(target);try{let repo=await translateRepo(client,entry.alias,params);if(repo.failure)return repo.failure;if(verb==="land"&&params["dry-run"]===void 0){let published=await client.request("api.invoke",{verb:"publish",params:{"task-id":params["task-id"]},forwarded:!0,from:hostname()});if(published.ok||published.error.code!=="UNKNOWN_VERB")return published}return await client.request("api.invoke",{verb,params:repo.params,forwarded:!0,from:hostname()})}catch(err){let message=errorMessage(err);if(/unknown daemon request:/i.test(message))return tooOld(entry.alias);return failure("MACHINE_UNREACHABLE",`machine "${entry.alias}": ${message}`,{hint:"check the machine is up and reachable over ssh, then retry",nextCommandArgs:["machine","list"]})}finally{client.close()}}async function translateRepo(client,alias,params){let repo=params.repo;if(typeof repo!=="string"||!isLocalCheckout(repo))return{params};let identity=repoIdentity(repo);if(!identity?.origin&&!identity?.root)return{params};let ask=await client.request("api.invoke",{verb:"repo-match",params:{...identity.origin?{origin:identity.origin}:{},...identity.root?{root:identity.root}:{}},forwarded:!0,from:hostname()});if(!ask.ok)return ask.error.code==="UNKNOWN_VERB"?{params}:{failure:ask};let found=ask.result.repo;if(found){let base=params["base-branch"],unpushed=typeof base==="string"?unpushedCommits(repo,base):null;if(typeof base==="string"&&unpushed)return{failure:failure("UNPUSHED_BASE",`${base} has ${unpushed} commit${unpushed===1?"":"s"} no remote has; ${alias} cannot base a task on it`,{hint:`push it first (\`git -C ${repo} push -u origin ${base}\`), then dispatch again`})};return{params:{...params,repo:found}}}return{failure:failure("NO_REMOTE_CHECKOUT",`machine "${alias}" has no checkout of ${identity.origin??repo}`,{hint:`clone it on ${alias} (and open it there once so Rove knows it), or pass --repo with ${alias}'s own path`})}}function offline(alias){return failure("MACHINE_UNREACHABLE",`machine "${alias}" did not answer`,{hint:`check \`ssh ${alias} true\` works without a prompt, then retry`,nextCommandArgs:["machine","list"]})}function tooOld(alias){return failure("MACHINE_VERSION_SKEW",`machine "${alias}" runs a Rove too old to accept forwarded verbs`,{hint:`upgrade Rove on ${alias} (\`rove update\` there), then retry`})}function failure(code,message,data){return{apiVersion:ROVE_API_VERSION,ok:!1,error:{message,code,...data}}}async function invokeRouted(args){if(args.forwarded)return args.runHere();let taskId=args.params["task-id"],target;try{target=await routeTarget({machine:args.machine,taskId:typeof taskId==="string"?taskId:void 0,isLocalTask:args.isLocalTask,...args.localTasks?{localTasks:args.localTasks}:{}})}catch(err){if(!(err instanceof ApiError))throw err;return failure(err.code,err.message,err.data??{})}return target?forwardVerb(target,args.verb,args.params):args.runHere()}async function machinePtySocket(alias){let entry=requireMachine(alias);if(!await machineDaemonSocket(entry))throw new ApiError(`machine "${alias}" did not answer`,"MACHINE_UNREACHABLE");return localPtySocketPath(alias)}
3
+ export{LOCAL_MACHINE,machineDaemonSocket,machineTasks,requireMachine,AUTO_MACHINE,pickMachine,routeTarget,forwardVerb,invokeRouted,machinePtySocket};
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{t}from"./chunk-tq6pq1ws.js";function failureHint(error,cliName="rove"){let details=typeof error==="object"&&error!==null?error:null,hint=details&&"hint"in details&&typeof details.hint==="string"?details.hint:null,args=details&&"nextCommandArgs"in details?details.nextCommandArgs:null,command=Array.isArray(args)&&args.length>0&&args.every((arg)=>typeof arg==="string")?[cliName,...args].map((arg)=>/^[\w./:@=-]+$/.test(arg)?arg:`'${arg.replaceAll("'","'\\''")}'`).join(" "):null;return[hint,command].filter(Boolean).join(`
2
+ import{t}from"./chunk-2676cb62.js";function failureHint(error,cliName="rove"){let details=typeof error==="object"&&error!==null?error:null,hint=details&&"hint"in details&&typeof details.hint==="string"?details.hint:null,args=details&&"nextCommandArgs"in details?details.nextCommandArgs:null,command=Array.isArray(args)&&args.length>0&&args.every((arg)=>typeof arg==="string")?[cliName,...args].map((arg)=>/^[\w./:@=-]+$/.test(arg)?arg:`'${arg.replaceAll("'","'\\''")}'`).join(" "):null;return[hint,command].filter(Boolean).join(`
3
3
  `)||t("common.failureHint",{command:`${cliName} doctor`})}
4
4
  export{failureHint};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{machineOfTask,setMachineHub,useMachineRows,useMergedTasks}from"./chunk-stng29vp.js";import"./chunk-2wd4744g.js";import"./chunk-91sykzqq.js";export{useMergedTasks,useMachineRows,setMachineHub,machineOfTask};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{LAST_RUN_VERSION_KEY}from"./chunk-jf46jsdp.js";import{isShellKind,shippedCompletionsPath}from"./chunk-ke3t032y.js";import{isNpxMissing,markSkillHintSeen,npxSkillsArgv,npxSkillsCommand}from"./chunk-ehb0hbrg.js";import{loadStateFile,patchStateFile}from"./chunk-g4281a0g.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{t}from"./chunk-tq6pq1ws.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}
2
+ import{LAST_RUN_VERSION_KEY}from"./chunk-15jt6k82.js";import{isShellKind,shippedCompletionsPath}from"./chunk-5js4agdd.js";import{isNpxMissing,markSkillHintSeen,npxSkillsArgv,npxSkillsCommand}from"./chunk-h2vv63bh.js";import{loadStateFile,patchStateFile}from"./chunk-g4281a0g.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{t}from"./chunk-2676cb62.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}
@@ -1,8 +1,8 @@
1
1
  // @bun
2
- import{generateCompletions,isShellKind,mergeSubVerbs,shippedCompletionsPath}from"./chunk-ke3t032y.js";import"./chunk-1qge84t7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync,readFileSync}from"fs";var HELP_WORDS=["--help","-h","help"];function completionUsage(cliName){return[`Usage: ${cliName} completions <bash|zsh|fish> [--path|--install]`,"",`Print a shell completion script for ${cliName}, or locate the copy shipped`,"with this install.","",` ${cliName} completions zsh --path print the shipped script's path`,` ${cliName} completions zsh --install hook it into your shell config`,"","Install:",` zsh source <(${cliName} completions zsh) # one-off, or in ~/.zshrc after compinit`," # with no process start per shell \u2014 what the first-run wizard writes:",` # ${cliName} completions zsh --install`,` bash ${cliName} completions bash --install # appends to ~/.bashrc`,` fish ${cliName} completions fish --install # writes ~/.config/fish/completions/${cliName}.fish`," # the manual way, any shell:",` # ${cliName} completions zsh > ~/.zsh/completions/_${cliName}`," # fpath=(~/.zsh/completions $fpath) # in ~/.zshrc, BEFORE compinit"," # rm -f ~/.zcompdump && exec zsh # rebuild the completion cache",""].join(`
2
+ import{generateCompletions,isShellKind,mergeSubVerbs,shippedCompletionsPath}from"./chunk-5js4agdd.js";import"./chunk-z3qhpthz.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync,readFileSync}from"fs";var HELP_WORDS=["--help","-h","help"];function completionUsage(cliName){return[`Usage: ${cliName} completions <bash|zsh|fish> [--path|--install]`,"",`Print a shell completion script for ${cliName}, or locate the copy shipped`,"with this install.","",` ${cliName} completions zsh --path print the shipped script's path`,` ${cliName} completions zsh --install hook it into your shell config`,"","Install:",` zsh source <(${cliName} completions zsh) # one-off, or in ~/.zshrc after compinit`," # with no process start per shell \u2014 what the first-run wizard writes:",` # ${cliName} completions zsh --install`,` bash ${cliName} completions bash --install # appends to ~/.bashrc`,` fish ${cliName} completions fish --install # writes ~/.config/fish/completions/${cliName}.fish`," # the manual way, any shell:",` # ${cliName} completions zsh > ~/.zsh/completions/_${cliName}`," # fpath=(~/.zsh/completions $fpath) # in ~/.zshrc, BEFORE compinit"," # rm -f ~/.zcompdump && exec zsh # rebuild the completion cache",""].join(`
3
3
  `)}async function runCompletionsSubcommand(rest,cliName=ROVE_PRODUCT_NAME,deps={}){let usage=completionUsage(cliName),fail=(message)=>{process.stderr.write(`${cliName} completions: ${message}
4
4
 
5
5
  ${usage}`),process.exit(2)};if(rest.some((arg)=>HELP_WORDS.includes(arg))){process.stdout.write(usage);return}let flags=rest.filter((arg)=>arg.startsWith("-")),shells=rest.filter((arg)=>!arg.startsWith("-")),unknownFlag=flags.find((flag)=>flag!=="--path"&&flag!=="--install");if(unknownFlag)fail(`unknown option "${unknownFlag}"`);if(new Set(flags).size>1)fail("--path and --install are different things; pass one");let shell=shells.length===1?shells[0]:void 0;if(!isShellKind(shell))fail(`unknown shell "${shells.join(" ")}"`);let scriptPath=shippedCompletionsPath(shell,cliName,deps.shippedDir),shipped=existsSync(scriptPath)?scriptPath:null;if(flags[0]==="--path"){if(!shipped)fail(`no pre-generated ${shell} script at ${scriptPath}
6
6
  ${cliName} completions ${shell} # print the script to stdout instead`);process.stdout.write(`${shipped}
7
- `);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-pw87thvf.js"),import("./chunk-jtpjdmb6.js")]),completion=installCompletions(shell,deps.home,cliName,shipped);settleWelcomeInstall("completions",shell);let line=completion.installed?"onboarding.appliedCompletions":"onboarding.keptCompletions";process.stdout.write(`${t(line,{path:completion.path})}
8
- `);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-rmk69hvh.js");process.stdout.write(generateCompletions(shell,cliName,mergeSubVerbs(API_VERBS)))}export{runCompletionsSubcommand};
7
+ `);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-5yv3jzc5.js"),import("./chunk-1x6yahf1.js")]),completion=installCompletions(shell,deps.home,cliName,shipped);settleWelcomeInstall("completions",shell);let line=completion.installed?"onboarding.appliedCompletions":"onboarding.keptCompletions";process.stdout.write(`${t(line,{path:completion.path})}
8
+ `);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-5c0dgs7n.js");process.stdout.write(generateCompletions(shell,cliName,mergeSubVerbs(API_VERBS)))}export{runCompletionsSubcommand};
@@ -0,0 +1,62 @@
1
+ // @bun
2
+ import{defaultFixRuntime}from"./chunk-syqbc3a3.js";import{INBOUND_CLASSES,deniedClasses,setInbound}from"./chunk-3v2hgjb2.js";import"./chunk-q2kweazg.js";import"./chunk-1j4e2jcx.js";import"./chunk-rc2nwsdd.js";import"./chunk-t60qcvcj.js";import"./chunk-e6848rj8.js";import"./chunk-j11hzmwy.js";import"./chunk-6h12b2k0.js";import"./chunk-17e2tgyg.js";import"./chunk-cbc1h345.js";import"./chunk-jjv7xem7.js";import"./chunk-4hestsjp.js";import"./chunk-stcvcsfm.js";import"./chunk-2bgmby1d.js";import"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-edsm15ht.js";import"./chunk-atn06ncf.js";import"./chunk-j5w8n1st.js";import"./chunk-qkehg2c1.js";import"./chunk-1dcb0069.js";import"./chunk-9ztqf6hb.js";import"./chunk-rsvh7n8v.js";import"./chunk-ampdybqg.js";import"./chunk-sak1tphp.js";import"./chunk-pbfehk8q.js";import"./chunk-4250pw6r.js";import"./chunk-qpvvc1xz.js";import"./chunk-rxqdw6s5.js";import"./chunk-zae59k1j.js";import"./chunk-f5n0tgky.js";import"./chunk-z3zaa155.js";import"./chunk-yewmtant.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-bdwp2k8f.js";import"./chunk-efjahmtj.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"./chunk-4pt3n7cg.js";import{shQuote}from"./chunk-b7xjhgts.js";import"./chunk-x7r75e3p.js";import{argvHasFlag}from"./chunk-zsfyj36g.js";import"./chunk-601dsgex.js";import"./chunk-1vwngrmf.js";import"./chunk-3vtpshwx.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-bkt3ktvx.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-hqkzc8cv.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-2676cb62.js";import"./chunk-q07r6hf7.js";import"./chunk-cmp64q4j.js";import"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.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("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;");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}}}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)","","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(`
30
+ `);function usageError(message){process.stderr.write(`${CLI_NAME} machine: ${message}
31
+
32
+ ${MACHINE_USAGE}
33
+ `),process.exit(2)}function fail(message){process.stderr.write(`${CLI_NAME} machine: ${message}
34
+ `),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}
35
+ `);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);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
36
+ `);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}
37
+ `);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||"?"})
38
+ `),!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
39
+ `);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
40
+ `)}function setupRuntime(argv){let yes=argv.includes("--yes"),fixRuntime=defaultFixRuntime();return{confirm:fixRuntime.confirm,exec:fixRuntime.exec,out:(line)=>process.stderr.write(`${line}
41
+ `),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>\`.
42
+ `);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
43
+ `);let established=await establishMachine(name,config,rt);if(!established.ok){failed++,process.stdout.write(`${name} \u2717 ${established.failure.code}
44
+ `);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||"?"}
45
+ `),!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}
46
+ `)};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.
47
+ `),process.stdout.write(`${CLI_NAME} machine: leftover sockets live in ${machineSocketDir(alias)}
48
+ `)}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}
49
+ `:`${CLI_NAME} machine: no tunnel service for ${alias}
50
+ `);return}if(!argvHasFlag(argv,"--install")){process.stdout.write(`${reverseTunnelArgv(entry,ports).join(" ")}
51
+ `);let path=tunnelServicePath(alias);process.stdout.write(path?`
52
+ --install writes ${path} and starts it.
53
+ `:`
54
+ No service manager Rove supports here; keep the command above running yourself.
55
+ `);return}try{let result=installReverseTunnel(alias,entry,ports);if(process.stdout.write(`${CLI_NAME} machine: wrote ${result.path}
56
+ `),!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}\`.
57
+ `)}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"}
58
+ `);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"}
59
+ `)}function list(){let machines=listMachines();if(machines.length===0){process.stdout.write(`No machines registered. Add one with \`${CLI_NAME} machine add <ssh-target>\`.
60
+ `);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]}`:""}
61
+ `.replace(/\s+$/,`
62
+ `))}}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{openDaemonSession,resolveActiveTaskId}from"./chunk-6p9yxt3q.js";import"./chunk-kqf371ff.js";import"./chunk-1vwngrmf.js";import"./chunk-yktnbb14.js";import"./chunk-wqckm0k6.js";import"./chunk-yt15y085.js";import"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.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{resolveActiveTaskId,openDaemonSession};
2
+ import{openDaemonSession,resolveActiveTaskId}from"./chunk-6h12b2k0.js";import"./chunk-601dsgex.js";import"./chunk-1vwngrmf.js";import"./chunk-3vtpshwx.js";import"./chunk-wqckm0k6.js";import"./chunk-yt15y085.js";import"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.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{resolveActiveTaskId,openDaemonSession};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ var TOP_LEVEL_SUBCOMMANDS=["completions","add","remove","adopt","export","repo","api","daemon","machine","weixin","doctor","config","reset","theme","skill","plugin","feedback","update"],SUBCOMMAND_VERBS={daemon:["status","start","stop","restart","relay"],machine:["add","doctor","remove","list"],plugin:["install","link","list","search","outdated","update","enable","disable","unlink","uninstall","config-dir","log","action","pane"],repo:["show","set","unset"],skill:["install","status","command","print"],theme:["list","add","remove"],weixin:["login","logout","status","allow","deny"]};
3
+ export{TOP_LEVEL_SUBCOMMANDS,SUBCOMMAND_VERBS};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{BUNDLED_THEME_JSONS,parseRgbLiteral}from"./chunk-z3zaa155.js";import{kvStatePath}from"./chunk-prqeddy7.js";import{DEFAULT_LOCALE,isLocaleId}from"./chunk-sma961wh.js";import{RGBA as RGBA3}from"@opentui/core";import{RGBA}from"@opentui/core";var BREATH_TICKS=30,SPEED_MIN=0.2,SPEED_SWING=0.9333333333333333,INK_FLOOR=0.3;function breathLevel(tick){return 0.5-0.5*Math.cos(2*Math.PI*tick/BREATH_TICKS)}function breathPhase(tick){let wave=tick/2-BREATH_TICKS/(4*Math.PI)*Math.sin(2*Math.PI*tick/BREATH_TICKS);return SPEED_MIN*tick+SPEED_SWING*wave}function breathGlyph(frames,tick){let index=Math.floor(breathPhase(tick)+0.000000001)%frames.length;return frames[index]??frames[0]??""}function mixInk(accent,muted,share){if(accent.intent!=="rgb"||muted.intent!=="rgb")return accent;let[ar,ag,ab,aa]=accent.toInts(),[mr,mg,mb]=muted.toInts(),mix=(a,m)=>Math.round(m+(a-m)*share);return RGBA.fromInts(mix(ar,mr),mix(ag,mg),mix(ab,mb),aa)}function breathColor(accent,muted,tick){return mixInk(accent,muted,INK_FLOOR+(1-INK_FLOOR)*breathLevel(tick))}var toLinear=(v)=>v<=0.04045?v/12.92:((v+0.055)/1.055)**2.4,toGamma=(v)=>v<=0.0031308?12.92*v:1.055*v**0.4166666666666667-0.055;function toOklch(color){let[r,g,b]=color.toInts().map((v)=>toLinear(v/255)),l=Math.cbrt(0.4122214708*r+0.5363325363*g+0.0514459929*b),m=Math.cbrt(0.2119034982*r+0.6806995451*g+0.1073969566*b),s=Math.cbrt(0.0883024619*r+0.2817188376*g+0.6299787005*b),L=0.2104542553*l+0.793617785*m-0.0040720468*s,A=1.9779984951*l-2.428592205*m+0.4505937099*s,B=0.0259040371*l+0.7827717662*m-0.808675766*s;return{l:L,c:Math.hypot(A,B),h:Math.atan2(B,A)}}function linearRgb({l:L,c,h}){let A=c*Math.cos(h),B=c*Math.sin(h),l=(L+0.3963377774*A+0.2158037573*B)**3,m=(L-0.1055613458*A-0.0638541728*B)**3,s=(L-0.0894841775*A-1.291485548*B)**3;return[4.0767416621*l-3.3077115913*m+0.2309699292*s,-1.2684380046*l+2.6097574011*m-0.3413193965*s,-0.0041960863*l-0.7034186147*m+1.707614701*s]}function fromOklch(color,alpha){let ch=(v)=>Math.round(Math.min(1,Math.max(0,toGamma(v)))*255),[r,g,b]=linearRgb(color);return RGBA.fromInts(ch(r),ch(g),ch(b),alpha)}function turnHue(accent,deg,lightness=1,chroma=1){if(accent.intent!=="rgb")return accent;let base=toOklch(accent),turned={l:base.l*lightness,c:base.c*chroma,h:base.h+deg*Math.PI/180};return fromOklch(turned,accent.toInts()[3])}var inGamut=(color)=>linearRgb(color).every((v)=>v>=-0.0001&&v<=1.0001);function inkAtHue(deg,lightness,chroma,alpha=255){let h=deg*Math.PI/180,c=chroma;while(c>0&&!inGamut({l:lightness,c,h}))c-=0.005;return fromOklch({l:lightness,c:Math.max(0,c),h},alpha)}function oklchCusp(deg){let key=Math.round(deg)%360,hit=cuspCache.get(key);if(hit)return hit;let h=key*Math.PI/180,best={l:1,c:0};for(let l=0.2;l<=1;l+=0.01){let lo=0,hi=0.4;for(let i=0;i<16;i++){let mid=(lo+hi)/2;if(inGamut({l,c:mid,h}))lo=mid;else hi=mid}if(lo>best.c)best={l,c:lo}}return cuspCache.set(key,best),best}var cuspCache=new Map;import{RGBA as RGBA2}from"@opentui/core";var HOST_TEXT_MIN_CONTRAST=4.5;function srgbChannelToLinear(c){let v=c/255;return v<=0.04045?v/12.92:((v+0.055)/1.055)**2.4}function relativeLuminance([r,g,b]){return 0.2126*srgbChannelToLinear(r)+0.7152*srgbChannelToLinear(g)+0.0722*srgbChannelToLinear(b)}function contrastRatioTriplet(fg,bg){let l1=relativeLuminance(fg),l2=relativeLuminance(bg),lighter=Math.max(l1,l2),darker=Math.min(l1,l2);return(lighter+0.05)/(darker+0.05)}function rgbToHsl([r,g,b]){let rn=r/255,gn=g/255,bn=b/255,max=Math.max(rn,gn,bn),min=Math.min(rn,gn,bn),l=(max+min)/2;if(max===min)return[0,0,l];let d=max-min,s=l>0.5?d/(2-max-min):d/(max+min),h;if(max===rn)h=((gn-bn)/d+(gn<bn?6:0))*60;else if(max===gn)h=((bn-rn)/d+2)*60;else h=((rn-gn)/d+4)*60;return[h,s,l]}function hslToRgb(h,s,l){if(s===0){let v=Math.round(l*255);return[v,v,v]}let q=l<0.5?l*(1+s):l+s-l*s,p=2*l-q,channel=(t)=>{let tn=t;if(tn<0)tn+=1;if(tn>1)tn-=1;let c=tn<0.16666666666666666?p+(q-p)*6*tn:tn<0.5?q:tn<0.6666666666666666?p+(q-p)*(0.6666666666666666-tn)*6:p;return Math.round(c*255)};return[channel(h/360+0.3333333333333333),channel(h/360),channel(h/360-0.3333333333333333)]}var MID_HOST_LUMINANCE=0.5;function ensureContrast(fg,bg,minRatio=HOST_TEXT_MIN_CONTRAST){let fgInts=fg.toInts(),bgInts=bg.toInts(),fgTriplet=[fgInts[0],fgInts[1],fgInts[2]],bgTriplet=[bgInts[0],bgInts[1],bgInts[2]];if(contrastRatioTriplet(fgTriplet,bgTriplet)>=minRatio)return fg;let[h,s,l]=rgbToHsl(fgTriplet),lighten=relativeLuminance(bgTriplet)<=MID_HOST_LUMINANCE,at=(lightness)=>contrastRatioTriplet(hslToRgb(h,s,lightness),bgTriplet),lo=lighten?l:0,hi=lighten?1:l;for(let i=0;i<32;i++){let mid=(lo+hi)/2;if(at(mid)>=minRatio)if(lighten)hi=mid;else lo=mid;else if(lighten)lo=mid;else hi=mid}let[r,g,b]=hslToRgb(h,s,lighten?hi:lo);return RGBA2.fromInts(r,g,b,fgInts[3])}var BUNDLED_THEMES=BUNDLED_THEME_JSONS,DEFAULT_THEME="claude";function hasBundledTheme(name){return Boolean(BUNDLED_THEMES[name])}var THEME_MODE_PREFERENCES=["dark","light","auto"],DEFAULT_THEME_MODE="dark";function resolveThemeMode(preference,detected){return preference==="auto"?detected??"dark":preference}var FOCUS_ACCENT_SLOTS=["primary","success","info"];function resolveTheme(theme,mode="dark"){let defs=theme.defs??{};function resolve(c,chain=[]){if(typeof c==="string"){if(c==="transparent"||c==="none")return RGBA3.fromInts(0,0,0,0);if(c.startsWith("#"))return RGBA3.fromHex(c);let rgb=parseRgbLiteral(c);if(rgb)return RGBA3.fromInts(rgb.r,rgb.g,rgb.b,rgb.a);if(chain.includes(c))return RGBA3.fromInts(0,0,0);let next=defs[c]??theme.theme[c];if(next===void 0)return RGBA3.fromInts(0,0,0);return resolve(next,[...chain,c])}return resolve(c[mode],chain)}let out={};for(let[k,v]of Object.entries(theme.theme))out[k]=resolve(v);let text=out.text??RGBA3.fromHex("#ffffff"),background=out.background??RGBA3.fromHex("#000000");return{...{primary:out.primary??text,secondary:out.secondary??text,accent:out.accent??out.primary??text,error:out.error??text,warning:out.warning??text,warningOnHost:out.warning??text,success:out.success??text,info:out.info??text,text,textMuted:out.textMuted??text,background,backgroundPanel:out.backgroundPanel??background,backgroundElement:out.backgroundElement??background,backgroundMenu:out.backgroundMenu??out.backgroundElement??background,backgroundDialog:out.backgroundDialog??out.backgroundPanel??background,border:out.border??text,borderActive:out.borderActive??out.border??text,borderSubtle:out.borderSubtle??out.border??text,diffAdded:out.diffAdded??out.success??text,diffRemoved:out.diffRemoved??out.error??text,diffContext:out.diffContext??out.textMuted??text,diffHunkHeader:out.diffHunkHeader??out.textMuted??text,diffAddedBg:out.diffAddedBg??background,diffRemovedBg:out.diffRemovedBg??background,selectedListItemText:out.selectedListItemText??background},...out}}function applyDisplayOverlay(base,focusAccent,transparentBackground,hostBackground){let v={...base,focusAccent:base[focusAccent]??base.primary,warningOnHost:base.warning};if(!transparentBackground)return v;let[backgroundR,backgroundG,backgroundB]=base.background.toInts(),[panelR,panelG,panelB]=base.backgroundPanel.toInts(),transparent={...v,background:RGBA3.fromInts(backgroundR,backgroundG,backgroundB,0),backgroundPanel:RGBA3.fromInts(panelR,panelG,panelB,0)};if(!hostBackground)return transparent;return{...transparent,text:ensureContrast(transparent.text,hostBackground),textMuted:ensureContrast(transparent.textMuted,hostBackground),warningOnHost:ensureContrast(transparent.warning,hostBackground)}}function diffInks(theme,colorblind){let added=(ink)=>colorblind?turnHue(ink,60,1,0.71):ink;return{added:added(theme.diffAdded),removed:theme.diffRemoved,addedBg:added(theme.diffAddedBg),removedBg:theme.diffRemovedBg}}import{readFileSync}from"fs";var LOCALE_KEY="locale";function defaultTransparentBackground(platform=process.platform){return platform!=="win32"}function readPersistedUiPrefs(fallbackTheme,isKnownTheme=hasBundledTheme){try{let parsed=JSON.parse(readFileSync(kvStatePath(),"utf8")),theme=typeof parsed.activeTheme==="string"&&isKnownTheme(parsed.activeTheme)?parsed.activeTheme:fallbackTheme,themeMode=THEME_MODE_PREFERENCES.includes(parsed.themeMode)?parsed.themeMode:DEFAULT_THEME_MODE,transparent=typeof parsed.transparentBackground==="boolean"?parsed.transparentBackground:defaultTransparentBackground(),focusAccent=typeof parsed.focusAccent==="string"&&FOCUS_ACCENT_SLOTS.includes(parsed.focusAccent)?parsed.focusAccent:null,locale=isLocaleId(parsed[LOCALE_KEY])?parsed[LOCALE_KEY]:DEFAULT_LOCALE;return{theme,themeMode,transparent,focusAccent,locale}}catch{return{theme:fallbackTheme,themeMode:DEFAULT_THEME_MODE,transparent:defaultTransparentBackground(),focusAccent:null,locale:DEFAULT_LOCALE}}}
2
+ import{BUNDLED_THEME_JSONS,parseRgbLiteral}from"./chunk-z3zaa155.js";import{kvStatePath}from"./chunk-prqeddy7.js";import{DEFAULT_LOCALE,isLocaleId}from"./chunk-q07r6hf7.js";import{RGBA as RGBA3}from"@opentui/core";import{RGBA}from"@opentui/core";var BREATH_TICKS=30,SPEED_MIN=0.2,SPEED_SWING=0.9333333333333333,INK_FLOOR=0.3;function breathLevel(tick){return 0.5-0.5*Math.cos(2*Math.PI*tick/BREATH_TICKS)}function breathPhase(tick){let wave=tick/2-BREATH_TICKS/(4*Math.PI)*Math.sin(2*Math.PI*tick/BREATH_TICKS);return SPEED_MIN*tick+SPEED_SWING*wave}function breathGlyph(frames,tick){let index=Math.floor(breathPhase(tick)+0.000000001)%frames.length;return frames[index]??frames[0]??""}function mixInk(accent,muted,share){if(accent.intent!=="rgb"||muted.intent!=="rgb")return accent;let[ar,ag,ab,aa]=accent.toInts(),[mr,mg,mb]=muted.toInts(),mix=(a,m)=>Math.round(m+(a-m)*share);return RGBA.fromInts(mix(ar,mr),mix(ag,mg),mix(ab,mb),aa)}function breathColor(accent,muted,tick){return mixInk(accent,muted,INK_FLOOR+(1-INK_FLOOR)*breathLevel(tick))}var toLinear=(v)=>v<=0.04045?v/12.92:((v+0.055)/1.055)**2.4,toGamma=(v)=>v<=0.0031308?12.92*v:1.055*v**0.4166666666666667-0.055;function toOklch(color){let[r,g,b]=color.toInts().map((v)=>toLinear(v/255)),l=Math.cbrt(0.4122214708*r+0.5363325363*g+0.0514459929*b),m=Math.cbrt(0.2119034982*r+0.6806995451*g+0.1073969566*b),s=Math.cbrt(0.0883024619*r+0.2817188376*g+0.6299787005*b),L=0.2104542553*l+0.793617785*m-0.0040720468*s,A=1.9779984951*l-2.428592205*m+0.4505937099*s,B=0.0259040371*l+0.7827717662*m-0.808675766*s;return{l:L,c:Math.hypot(A,B),h:Math.atan2(B,A)}}function linearRgb({l:L,c,h}){let A=c*Math.cos(h),B=c*Math.sin(h),l=(L+0.3963377774*A+0.2158037573*B)**3,m=(L-0.1055613458*A-0.0638541728*B)**3,s=(L-0.0894841775*A-1.291485548*B)**3;return[4.0767416621*l-3.3077115913*m+0.2309699292*s,-1.2684380046*l+2.6097574011*m-0.3413193965*s,-0.0041960863*l-0.7034186147*m+1.707614701*s]}function fromOklch(color,alpha){let ch=(v)=>Math.round(Math.min(1,Math.max(0,toGamma(v)))*255),[r,g,b]=linearRgb(color);return RGBA.fromInts(ch(r),ch(g),ch(b),alpha)}function turnHue(accent,deg,lightness=1,chroma=1){if(accent.intent!=="rgb")return accent;let base=toOklch(accent),turned={l:base.l*lightness,c:base.c*chroma,h:base.h+deg*Math.PI/180};return fromOklch(turned,accent.toInts()[3])}var inGamut=(color)=>linearRgb(color).every((v)=>v>=-0.0001&&v<=1.0001);function inkAtHue(deg,lightness,chroma,alpha=255){let h=deg*Math.PI/180,c=chroma;while(c>0&&!inGamut({l:lightness,c,h}))c-=0.005;return fromOklch({l:lightness,c:Math.max(0,c),h},alpha)}function oklchCusp(deg){let key=Math.round(deg)%360,hit=cuspCache.get(key);if(hit)return hit;let h=key*Math.PI/180,best={l:1,c:0};for(let l=0.2;l<=1;l+=0.01){let lo=0,hi=0.4;for(let i=0;i<16;i++){let mid=(lo+hi)/2;if(inGamut({l,c:mid,h}))lo=mid;else hi=mid}if(lo>best.c)best={l,c:lo}}return cuspCache.set(key,best),best}var cuspCache=new Map;import{RGBA as RGBA2}from"@opentui/core";var HOST_TEXT_MIN_CONTRAST=4.5;function srgbChannelToLinear(c){let v=c/255;return v<=0.04045?v/12.92:((v+0.055)/1.055)**2.4}function relativeLuminance([r,g,b]){return 0.2126*srgbChannelToLinear(r)+0.7152*srgbChannelToLinear(g)+0.0722*srgbChannelToLinear(b)}function contrastRatioTriplet(fg,bg){let l1=relativeLuminance(fg),l2=relativeLuminance(bg),lighter=Math.max(l1,l2),darker=Math.min(l1,l2);return(lighter+0.05)/(darker+0.05)}function rgbToHsl([r,g,b]){let rn=r/255,gn=g/255,bn=b/255,max=Math.max(rn,gn,bn),min=Math.min(rn,gn,bn),l=(max+min)/2;if(max===min)return[0,0,l];let d=max-min,s=l>0.5?d/(2-max-min):d/(max+min),h;if(max===rn)h=((gn-bn)/d+(gn<bn?6:0))*60;else if(max===gn)h=((bn-rn)/d+2)*60;else h=((rn-gn)/d+4)*60;return[h,s,l]}function hslToRgb(h,s,l){if(s===0){let v=Math.round(l*255);return[v,v,v]}let q=l<0.5?l*(1+s):l+s-l*s,p=2*l-q,channel=(t)=>{let tn=t;if(tn<0)tn+=1;if(tn>1)tn-=1;let c=tn<0.16666666666666666?p+(q-p)*6*tn:tn<0.5?q:tn<0.6666666666666666?p+(q-p)*(0.6666666666666666-tn)*6:p;return Math.round(c*255)};return[channel(h/360+0.3333333333333333),channel(h/360),channel(h/360-0.3333333333333333)]}var MID_HOST_LUMINANCE=0.5;function ensureContrast(fg,bg,minRatio=HOST_TEXT_MIN_CONTRAST){let fgInts=fg.toInts(),bgInts=bg.toInts(),fgTriplet=[fgInts[0],fgInts[1],fgInts[2]],bgTriplet=[bgInts[0],bgInts[1],bgInts[2]];if(contrastRatioTriplet(fgTriplet,bgTriplet)>=minRatio)return fg;let[h,s,l]=rgbToHsl(fgTriplet),lighten=relativeLuminance(bgTriplet)<=MID_HOST_LUMINANCE,at=(lightness)=>contrastRatioTriplet(hslToRgb(h,s,lightness),bgTriplet),lo=lighten?l:0,hi=lighten?1:l;for(let i=0;i<32;i++){let mid=(lo+hi)/2;if(at(mid)>=minRatio)if(lighten)hi=mid;else lo=mid;else if(lighten)lo=mid;else hi=mid}let[r,g,b]=hslToRgb(h,s,lighten?hi:lo);return RGBA2.fromInts(r,g,b,fgInts[3])}var BUNDLED_THEMES=BUNDLED_THEME_JSONS,DEFAULT_THEME="claude";function hasBundledTheme(name){return Boolean(BUNDLED_THEMES[name])}var THEME_MODE_PREFERENCES=["dark","light","auto"],DEFAULT_THEME_MODE="dark";function resolveThemeMode(preference,detected){return preference==="auto"?detected??"dark":preference}var FOCUS_ACCENT_SLOTS=["primary","success","info"];function resolveTheme(theme,mode="dark"){let defs=theme.defs??{};function resolve(c,chain=[]){if(typeof c==="string"){if(c==="transparent"||c==="none")return RGBA3.fromInts(0,0,0,0);if(c.startsWith("#"))return RGBA3.fromHex(c);let rgb=parseRgbLiteral(c);if(rgb)return RGBA3.fromInts(rgb.r,rgb.g,rgb.b,rgb.a);if(chain.includes(c))return RGBA3.fromInts(0,0,0);let next=defs[c]??theme.theme[c];if(next===void 0)return RGBA3.fromInts(0,0,0);return resolve(next,[...chain,c])}return resolve(c[mode],chain)}let out={};for(let[k,v]of Object.entries(theme.theme))out[k]=resolve(v);let text=out.text??RGBA3.fromHex("#ffffff"),background=out.background??RGBA3.fromHex("#000000");return{...{primary:out.primary??text,secondary:out.secondary??text,accent:out.accent??out.primary??text,error:out.error??text,warning:out.warning??text,warningOnHost:out.warning??text,success:out.success??text,info:out.info??text,text,textMuted:out.textMuted??text,background,backgroundPanel:out.backgroundPanel??background,backgroundElement:out.backgroundElement??background,backgroundMenu:out.backgroundMenu??out.backgroundElement??background,backgroundDialog:out.backgroundDialog??out.backgroundPanel??background,border:out.border??text,borderActive:out.borderActive??out.border??text,borderSubtle:out.borderSubtle??out.border??text,diffAdded:out.diffAdded??out.success??text,diffRemoved:out.diffRemoved??out.error??text,diffContext:out.diffContext??out.textMuted??text,diffHunkHeader:out.diffHunkHeader??out.textMuted??text,diffAddedBg:out.diffAddedBg??background,diffRemovedBg:out.diffRemovedBg??background,selectedListItemText:out.selectedListItemText??background},...out}}function applyDisplayOverlay(base,focusAccent,transparentBackground,hostBackground){let v={...base,focusAccent:base[focusAccent]??base.primary,warningOnHost:base.warning};if(!transparentBackground)return v;let[backgroundR,backgroundG,backgroundB]=base.background.toInts(),[panelR,panelG,panelB]=base.backgroundPanel.toInts(),transparent={...v,background:RGBA3.fromInts(backgroundR,backgroundG,backgroundB,0),backgroundPanel:RGBA3.fromInts(panelR,panelG,panelB,0)};if(!hostBackground)return transparent;return{...transparent,text:ensureContrast(transparent.text,hostBackground),textMuted:ensureContrast(transparent.textMuted,hostBackground),warningOnHost:ensureContrast(transparent.warning,hostBackground)}}function diffInks(theme,colorblind){let added=(ink)=>colorblind?turnHue(ink,60,1,0.71):ink;return{added:added(theme.diffAdded),removed:theme.diffRemoved,addedBg:added(theme.diffAddedBg),removedBg:theme.diffRemovedBg}}import{readFileSync}from"fs";var LOCALE_KEY="locale";function defaultTransparentBackground(platform=process.platform){return platform!=="win32"}function readPersistedUiPrefs(fallbackTheme,isKnownTheme=hasBundledTheme){try{let parsed=JSON.parse(readFileSync(kvStatePath(),"utf8")),theme=typeof parsed.activeTheme==="string"&&isKnownTheme(parsed.activeTheme)?parsed.activeTheme:fallbackTheme,themeMode=THEME_MODE_PREFERENCES.includes(parsed.themeMode)?parsed.themeMode:DEFAULT_THEME_MODE,transparent=typeof parsed.transparentBackground==="boolean"?parsed.transparentBackground:defaultTransparentBackground(),focusAccent=typeof parsed.focusAccent==="string"&&FOCUS_ACCENT_SLOTS.includes(parsed.focusAccent)?parsed.focusAccent:null,locale=isLocaleId(parsed[LOCALE_KEY])?parsed[LOCALE_KEY]:DEFAULT_LOCALE;return{theme,themeMode,transparent,focusAccent,locale}}catch{return{theme:fallbackTheme,themeMode:DEFAULT_THEME_MODE,transparent:defaultTransparentBackground(),focusAccent:null,locale:DEFAULT_LOCALE}}}
3
3
  export{breathGlyph,mixInk,breathColor,toOklch,turnHue,inkAtHue,oklchCusp,relativeLuminance,ensureContrast,BUNDLED_THEMES,DEFAULT_THEME,THEME_MODE_PREFERENCES,DEFAULT_THEME_MODE,resolveThemeMode,FOCUS_ACCENT_SLOTS,resolveTheme,applyDisplayOverlay,diffInks,LOCALE_KEY,defaultTransparentBackground,readPersistedUiPrefs};