@sma1lboy/rove 0.9.279-next.28 → 0.9.280
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{chunk-p6rh2ptw.js → chunk-02x0ahxk.js} +1 -1
- package/dist/cli/{chunk-k04qvy42.js → chunk-0g1h35mr.js} +1 -1
- package/dist/cli/{chunk-v3yf3gmy.js → chunk-2pfh3zm0.js} +1 -1
- package/dist/cli/{chunk-4a82zjaq.js → chunk-2wrt80ft.js} +1 -1
- package/dist/cli/{chunk-78qmf1cd.js → chunk-3a7x7jg7.js} +2 -2
- package/dist/cli/{chunk-90qathy6.js → chunk-4drm07mp.js} +1 -1
- package/dist/cli/{chunk-cydytp2v.js → chunk-4z1a65bz.js} +1 -1
- package/dist/cli/{chunk-bmw0t79j.js → chunk-5dq0n3h7.js} +1 -1
- package/dist/cli/{chunk-37wbxna9.js → chunk-5g6v6tq5.js} +1 -1
- package/dist/cli/{chunk-cntrqw1e.js → chunk-5kgq379z.js} +1 -1
- package/dist/cli/{chunk-7tbemfgm.js → chunk-6mk6ceb6.js} +2 -2
- package/dist/cli/{chunk-e2zv4b2x.js → chunk-7aaw17vr.js} +1 -1
- package/dist/cli/{chunk-jtf8ag8v.js → chunk-7fya3y0n.js} +1 -1
- package/dist/cli/{chunk-mfp8ax3c.js → chunk-7nnpp89t.js} +1 -1
- package/dist/cli/{chunk-z8eg7tnp.js → chunk-amq030gb.js} +2 -2
- package/dist/cli/{chunk-tkc3621t.js → chunk-azt0c2b5.js} +1 -1
- package/dist/cli/{chunk-2m22fy6d.js → chunk-bw2y7670.js} +1 -1
- package/dist/cli/{chunk-692jsg07.js → chunk-byh32qnx.js} +1 -1
- package/dist/cli/{chunk-ney5fnem.js → chunk-d2wndk4q.js} +1 -1
- package/dist/cli/{chunk-9192at57.js → chunk-f262ywvg.js} +1 -1
- package/dist/cli/{chunk-hqpfg53t.js → chunk-fkgemeww.js} +1 -1
- package/dist/cli/{chunk-bv7z8jsy.js → chunk-gk8efsx0.js} +1 -1
- package/dist/cli/{chunk-1pcqw0x7.js → chunk-hd1szhba.js} +1 -1
- package/dist/cli/{chunk-apgfbg20.js → chunk-j54c5a0a.js} +1 -1
- package/dist/cli/{chunk-5wt8ect1.js → chunk-jk4f0xsh.js} +1 -1
- package/dist/cli/{chunk-tw3hfkbv.js → chunk-jkgp816v.js} +1 -1
- package/dist/cli/{chunk-g2wwgt6t.js → chunk-mey3vksj.js} +1 -1
- package/dist/cli/{chunk-hzqfb00a.js → chunk-mjzjah9d.js} +1 -1
- package/dist/cli/{chunk-np765y1f.js → chunk-q6tsx6zc.js} +1 -1
- package/dist/cli/{chunk-y9rydmhw.js → chunk-qc9sj5wh.js} +1 -1
- package/dist/cli/{chunk-3btnwykt.js → chunk-qzhfs668.js} +1 -1
- package/dist/cli/{chunk-ngq02svt.js → chunk-r98h6b42.js} +2 -2
- package/dist/cli/{chunk-hg8c3ze3.js → chunk-rvjnafyt.js} +1 -1
- package/dist/cli/{chunk-a5dqhn9k.js → chunk-t7dyf50m.js} +1 -1
- package/dist/cli/{chunk-02bcfavz.js → chunk-tqxbbg3k.js} +1 -1
- package/dist/cli/{chunk-q3wzpn85.js → chunk-txvjg1g9.js} +1 -1
- package/dist/cli/{chunk-1pk5genq.js → chunk-w003rpr2.js} +1 -1
- package/dist/cli/{chunk-qg5wexks.js → chunk-wz307hf6.js} +1 -1
- package/dist/cli/{chunk-qd97s6pt.js → chunk-xmjknfy2.js} +1 -1
- package/dist/cli/{chunk-tt47sn82.js → chunk-xy5mrrqk.js} +1 -1
- package/dist/cli/{chunk-phmt9a1k.js → chunk-zkby63ej.js} +1 -1
- package/dist/cli/{chunk-ejrbh8a0.js → chunk-zp0q931y.js} +1 -1
- package/dist/cli/{chunk-56rjpxzc.js → chunk-zv0rrhck.js} +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/rove.js +1 -1
- package/dist/web/assets/{index-CcqHr-Sc.js → index-DIN0Lz5C.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +3 -3
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{parseDaemonStopReason}from"./chunk-6xr1prk6.js";import{isRowTokenTone}from"./chunk-atn06ncf.js";import{ensureDaemonReachable,isStaleInstallError}from"./chunk-e58kj4gm.js";import{sameWorktreeChanges}from"./chunk-0r1jf8m9.js";import{CURRENT_VERSION}from"./chunk-4a82zjaq.js";import{createStateCell,mapReadableState}from"./chunk-cmp64q4j.js";import{DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,isAttentionInboxState,isDaemonVersionStale,isForeignDaemonHome,isProtocolCompatible,isRoutineInboxState}from"./chunk-qzzmd63x.js";import{parseModUiPayload}from"./chunk-96kvwzj8.js";import{toTaskId}from"./chunk-xy8be792.js";import{homeDir}from"./chunk-z1nj22va.js";import{logClient,logClientError}from"./chunk-0g4wc808.js";function parseWorktreeChangesPayload(payload){let changes=payload?.changes;if(!changes||typeof changes!=="object"||Array.isArray(changes))return null;let map=new Map;for(let[path,value]of Object.entries(changes)){let counts=value;if(typeof counts?.added!=="number"||typeof counts.deleted!=="number")return null;map.set(path,{added:counts.added,deleted:counts.deleted,...typeof counts.behind==="number"?{behind:counts.behind}:{},...typeof counts.ahead==="number"?{ahead:counts.ahead}:{}})}let unreadable=payload?.unreadable;if(Array.isArray(unreadable)){for(let path of unreadable)if(typeof path==="string"&&path.length>0)map.set(path,null)}return map}function sameWorktreeChangesMap(a,b){if(a.size!==b.size)return!1;for(let[path,counts]of a){if(!b.has(path))return!1;if(!sameWorktreeChanges(counts,b.get(path)??null))return!1}return!0}function parseToken(raw){if(!raw||typeof raw!=="object")return null;let t=raw;if(typeof t.source!=="string"||typeof t.key!=="string")return null;if(typeof t.text!=="string"||t.text.length===0)return null;if(typeof t.expiresAt!=="number"||!Number.isFinite(t.expiresAt))return null;return{source:t.source,key:t.key,text:t.text,...isRowTokenTone(t.tone)?{tone:t.tone}:{},expiresAt:t.expiresAt}}function parseRowTokensPayload(payload){let tokens=payload?.tokens;if(!tokens||typeof tokens!=="object"||Array.isArray(tokens))return null;let out=new Map;for(let[taskId,list]of Object.entries(tokens)){if(!Array.isArray(list))continue;let parsed=list.map(parseToken).filter((token)=>token!==null);if(parsed.length>0)out.set(taskId,parsed)}return out}function sameRowTokenMap(a,b){if(a.size!==b.size)return!1;for(let[taskId,left]of a){let right=b.get(taskId);if(!right||right.length!==left.length)return!1;for(let[i,token]of left.entries()){let other=right[i];if(!other||other.source!==token.source||other.key!==token.key||other.text!==token.text||other.tone!==token.tone||other.expiresAt!==token.expiresAt)return!1}}return!0}function liveRowTokens(map,taskId,now){let tokens=map?.get(taskId);if(!tokens||tokens.length===0)return[];return tokens.filter((token)=>token.expiresAt>now)}function shouldLogReconnectAttempt(attempt){if(attempt>100)return!1;return attempt===1||attempt%10===0}function describePayload(value){if(value===void 0)return"undefined";if(value===null)return"null";let type=Array.isArray(value)?"array":typeof value,text;try{text=typeof value==="string"?value:JSON.stringify(value)}catch{text=String(value)}if(text.length>120)text=`${text.slice(0,120)}\u2026`;return`${type}:${text}`}function decodeUiPrefsPayload(payload){let p=payload;if(!p||typeof p!=="object"||!("theme"in p))return null;if(p.theme!==null&&typeof p.theme!=="string")return null;return{theme:typeof p.theme==="string"&&p.theme.length>0?p.theme:null,..."themeMode"in p?{themeMode:typeof p.themeMode==="string"?p.themeMode:null}:{},transparentBackground:p.transparentBackground!==!1,focusAccent:typeof p.focusAccent==="string"?p.focusAccent:null,locale:typeof p.locale==="string"?p.locale:"",sortMode:p.sortMode==="recent"||p.sortMode==="attention"||p.sortMode==="name"?p.sortMode:"default",keysCollapsed:p.keysCollapsed===!0,projectFilter:typeof p.projectFilter==="string"&&p.projectFilter.length>0?p.projectFilter:null}}var TOKEN_TOTAL_FIELDS=["inputTokens","outputTokens","cacheReadTokens","cacheCreationTokens"];function parseContextUsagePayload(payload){let context=payload?.context;if(!context||typeof context!=="object"||Array.isArray(context))return null;let map=new Map;for(let[key,value]of Object.entries(context)){let v=value;if(typeof v?.contextTokens!=="number")return null;if(v.contextWindowTokens!==void 0&&typeof v.contextWindowTokens!=="number")return null;let parts=v.parts;if(parts!==void 0&&(!Array.isArray(parts)||!parts.every((p)=>typeof p?.key==="string"&&typeof p?.tokens==="number")))return null;let totals={};for(let field of TOKEN_TOTAL_FIELDS){let raw=v[field];if(raw===void 0)continue;if(typeof raw!=="number")return null;totals[field]=raw}map.set(key,{contextTokens:v.contextTokens,...typeof v.contextWindowTokens==="number"?{contextWindowTokens:v.contextWindowTokens}:{},...v.approximate===!0?{approximate:!0}:{},...totals,...Array.isArray(parts)?{parts:parts.map((p)=>({key:p.key,tokens:p.tokens}))}:{}})}return map}function sameContextUsageMap(a,b){if(a.size!==b.size)return!1;for(let[key,value]of a){let other=b.get(key);if(!other||other.contextTokens!==value.contextTokens||other.contextWindowTokens!==value.contextWindowTokens||other.approximate!==value.approximate||TOKEN_TOTAL_FIELDS.some((field)=>other[field]!==value[field])||JSON.stringify(other.parts)!==JSON.stringify(value.parts))return!1}return!0}function parseUsageSnapshotPayload(payload){let usage=payload?.usage;if(!usage||typeof usage!=="object"||Array.isArray(usage))return null;let map=new Map;for(let[vendor,value]of Object.entries(usage)){let snapshot=value;if(typeof snapshot?.capturedAt!=="number"||!Array.isArray(snapshot.windows))return null;let windows=[];for(let raw of snapshot.windows){let w=raw;if(typeof w?.kind!=="string"||typeof w.label!=="string"||typeof w.percent!=="number")return null;if(w.resetsAt!==null&&typeof w.resetsAt!=="number")return null;windows.push({kind:w.kind,label:w.label,percent:w.percent,resetsAt:w.resetsAt})}map.set(vendor,{windows,capturedAt:snapshot.capturedAt})}return map}function sameUsageSnapshotMap(a,b){if(a.size!==b.size)return!1;for(let[vendor,usage]of a){let other=b.get(vendor);if(!other||other.capturedAt!==usage.capturedAt||other.windows.length!==usage.windows.length)return!1;for(let i=0;i<usage.windows.length;i++){let x=usage.windows[i],y=other.windows[i];if(!x||!y||x.kind!==y.kind||x.label!==y.label||x.percent!==y.percent||x.resetsAt!==y.resetsAt)return!1}}return!0}function parseTranscriptActivityPayload(payload){let activity=payload?.activity;if(!activity||typeof activity!=="object"||Array.isArray(activity))return null;let map=new Map;for(let[path,value]of Object.entries(activity)){let v=value;if(typeof v?.mtimeMs!=="number"||typeof v.completionAt!=="number")return null;if(v.completionId!==null&&typeof v.completionId!=="string")return null;map.set(path,{mtimeMs:v.mtimeMs,completionId:v.completionId,completionAt:v.completionAt})}return map}function sameTranscriptActivityMap(a,b){if(a.size!==b.size)return!1;for(let[path,v]of a){let other=b.get(path);if(!other||other.mtimeMs!==v.mtimeMs||other.completionId!==v.completionId||other.completionAt!==v.completionAt)return!1}return!0}function deserializeTask(s){return{id:toTaskId(s.id),title:s.title,repo:s.repo,branch:s.branch,worktreePath:s.worktreePath,kind:s.kind,...s.scratch?{scratch:!0}:{},...s.noProject?{noProject:!0}:{},...s.routine?{routine:s.routine}:{},status:s.status,pinned:s.pinned,...s.kept?{kept:!0}:{},...s.notes?{notes:s.notes}:{},...s.todos?{todos:s.todos}:{},...s.archived?{archived:!0}:{},vendor:s.vendor,command:s.command,prStatus:s.prStatus,modelEffort:s.modelEffort,model:s.model,tier:s.tier,groupId:s.groupId,observedLanguage:s.observedLanguage,deletion:s.deletion,quotaResume:s.quotaResume,scheduledStart:s.scheduledStart,...s.autoFixCi?{autoFixCi:s.autoFixCi}:{},linkedWorkItem:s.linkedWorkItem,dispatcher:s.dispatcher,...s.parentTaskId?{parentTaskId:toTaskId(s.parentTaskId)}:{},...s.sharesWorkspaceOf?{sharesWorkspaceOf:toTaskId(s.sharesWorkspaceOf)}:{},...s.cwdSubpath?{cwdSubpath:s.cwdSubpath}:{},...s.ptyAlias?{ptyAlias:s.ptyAlias}:{},...s.extraRepos?.length?{extraRepos:s.extraRepos}:{},...s.workspace?{workspace:s.workspace}:{},...s.sessionPrs?.length?{sessionPrs:s.sessionPrs}:{},requireReport:s.requireReport,prompt:s.prompt,baseRef:s.baseRef,worktreeName:s.worktreeName,...s.gitRepo?{gitRepo:s.gitRepo}:{},report:s.report,...s.repoId?{repoId:s.repoId}:{},createdAt:s.createdAt,updatedAt:s.updatedAt}}async function runReconnectLoop(deps){let delayMs=deps.spawnDaemon?Math.floor(Math.random()*400):500,attempt=0;while(!deps.isDisposed()){if(delayMs>0)await new Promise((r)=>setTimeout(r,delayMs));if(deps.isDisposed())break;attempt++;try{if(deps.spawnDaemon)await deps.ensureReachable();await deps.init(),logClient("orch",`reconnected and re-subscribed after ${attempt} attempt(s) \u2014 task list re-synced`);return}catch(err){if(isStaleInstallError(err)){logClientError("orch-reconnect-fatal",err),deps.onFatal?.(err);return}if(deps.shouldLogAttempt(attempt))logClientError("orch-reconnect",err);delayMs=delayMs===0?500:Math.min(delayMs*2,3000)}}}function singleFlightReconnect(deps){let current=null;return(spawnDaemon)=>{if(current)return current;let task=runReconnectLoop({...deps,spawnDaemon});current=task;let clear=()=>{if(current===task)current=null};return task.then(clear,clear),task}}async function performInit(client,opts,signals){let hello=await client.request("hello",{protocolVersion:DAEMON_PROTOCOL_VERSION,minProtocolVersion:MIN_COMPATIBLE_PROTOCOL_VERSION}),daemonVersion=typeof hello.protocolVersion==="number"?hello.protocolVersion:DAEMON_PROTOCOL_VERSION,daemonMin=typeof hello.minProtocolVersion==="number"?hello.minProtocolVersion:daemonVersion;if(!isProtocolCompatible({localVersion:DAEMON_PROTOCOL_VERSION,localMin:MIN_COMPATIBLE_PROTOCOL_VERSION,remoteVersion:daemonVersion,remoteMin:daemonMin}))throw Error(`Rove daemon is protocol v${daemonVersion} (min v${daemonMin}); this client is v${DAEMON_PROTOCOL_VERSION} (min v${MIN_COMPATIBLE_PROTOCOL_VERSION}). Restart the daemon (\`rove daemon restart\`) or upgrade Rove.`);let clientHome=homeDir();if(!opts.expectForeignHome&&isForeignDaemonHome(hello.homeDir,clientHome))throw Error(`Rove daemon on this socket serves ${hello.homeDir}, but this client uses ${clientHome}. A sandbox or dev daemon has taken the production socket \u2014 stop it (\`rove daemon stop\`), or unset ROVE_DAEMON_SOCKET_PATH / ROVE_DAEMON_SOCKET_PATH before starting it.`);if(signals.setDaemonVersionSig(typeof hello.roveVersion==="string"?hello.roveVersion:null),opts.onPeerIdentity?.({hostname:typeof hello.hostname==="string"?hello.hostname:"",homeDir:typeof hello.homeDir==="string"?hello.homeDir:"",daemonPid:typeof hello.daemonPid==="number"?hello.daemonPid:0,roveVersion:typeof hello.roveVersion==="string"?hello.roveVersion:""}),signals.setDaemonRestartingSig(!1),hello.tasks&&opts.subscribesTasks)signals.setTasks(hello.tasks.map(deserializeTask));if(await client.subscribe({role:opts.role,channels:opts.channels,cellPixelSize:opts.cellPixelSize}),hello.capabilities?.includes("worktree.changes")){if(signals.worktreeChangesAcc()===null)signals.setWorktreeChangesSig(new Map)}else signals.setWorktreeChangesSig(null);if(hello.capabilities?.includes("transcript.activity")){if(signals.transcriptActivityAcc()===null)signals.setTranscriptActivitySig(new Map)}else signals.setTranscriptActivitySig(null);signals.setConnectionState("online"),logClient("orch",`subscribed as ${opts.role} (${signals.tasksAcc().length} tasks)`)}function ordinalOf(tabId,fallback){let match=/^tab-(\d+)$/.exec(tabId);return match?Number(match[1]):fallback}function adoptTabs(state,tabIds){let known=new Set(state.tabs.map((tab)=>tab.id)),fresh=[];for(let id of tabIds){if(known.has(id))continue;known.add(id),fresh.push(id)}if(fresh.length===0)return state;let minted=state.nextOrdinal,adopted=fresh.map((id)=>({kind:"engine",id,title:null,ordinal:ordinalOf(id,minted++),spawned:!0}));adopted.sort((a,b)=>a.ordinal-b.ordinal);let tabs=[...state.tabs,...adopted],maxOrdinal=tabs.reduce((max,tab)=>Math.max(max,tab.ordinal),0);return{tabs,activeId:state.activeId,nextOrdinal:Math.max(state.nextOrdinal,maxOrdinal+1)}}function isAddedTab(raw){if(typeof raw!=="object"||raw===null)return!1;if(!("id"in raw)||typeof raw.id!=="string")return!1;if(!("ordinal"in raw)||typeof raw.ordinal!=="number")return!1;if(!("title"in raw)||raw.title!==null&&typeof raw.title!=="string")return!1;if(!("kind"in raw))return!1;if(raw.kind==="engine")return!0;return raw.kind==="command"&&"command"in raw&&Array.isArray(raw.command)}function absorbTab(state,tab){let nextOrdinal=Math.max(state.nextOrdinal,tab.ordinal+1),known=state.tabs.find((t)=>t.id===tab.id);if(known?.kind===tab.kind){if(Object.entries(tab).every(([key,value])=>JSON.stringify(Reflect.get(known,key))===JSON.stringify(value))&&nextOrdinal===state.nextOrdinal)return state}let merged=known?.kind===tab.kind?{...known,...tab,title:known.title}:tab,tabs=known?state.tabs.map((t)=>t===known?merged:t):[...state.tabs,merged];return{...state,tabs,nextOrdinal}}var MAP_CHANNELS={"usage.snapshot":{what:"usage payload",parse:parseUsageSnapshotPayload,same:sameUsageSnapshotMap,read:(signals)=>signals.usageSnapshotAcc(),write:(signals,next)=>signals.setUsageSnapshotSig(next)},"usage.context":{what:"context payload",parse:parseContextUsagePayload,same:sameContextUsageMap,read:(signals)=>signals.contextUsageAcc(),write:(signals,next)=>signals.setContextUsageSig(next)},"worktree.changes":{what:"changes payload",parse:parseWorktreeChangesPayload,same:sameWorktreeChangesMap,read:(signals)=>signals.worktreeChangesAcc(),write:(signals,next)=>signals.setWorktreeChangesSig(next)},"transcript.activity":{what:"activity payload",parse:parseTranscriptActivityPayload,same:sameTranscriptActivityMap,read:(signals)=>signals.transcriptActivityAcc(),write:(signals,next)=>signals.setTranscriptActivitySig(next)},"mod.ui":{what:"mod pane list",parse:parseModUiPayload,same:(a,b)=>JSON.stringify(a)===JSON.stringify(b),read:(signals)=>signals.modPanesAcc(),write:(signals,next)=>signals.setModPanesSig(next)},"task.tokens":{what:"token map",parse:parseRowTokensPayload,same:sameRowTokenMap,read:(signals)=>signals.rowTokensAcc(),write:(signals,next)=>signals.setRowTokensSig(next)}};function handleMapChannel(name,payload,signals){let channel=MAP_CHANNELS[name];if(!channel)return!1;let next=channel.parse(payload);if(!next)return logClientError("orch",`dropped ${name} event: malformed ${channel.what} (${describePayload(payload)})`),!0;let current=channel.read(signals);if(current&&channel.same(current,next))return!0;return channel.write(signals,next),!0}function writeGraphicsToStdout(data){if(!process.stdout.isTTY)return;process.stdout.write(data)}function pruneEngineState(tasks,signals){let live=new Set(tasks.map((t)=>t.id)),current=signals.engineStateAcc();if(current.size>0){let next=null;for(let key of current.keys()){if(live.has(key))continue;if(!next)next=new Map(current);next.delete(key)}if(next)signals.setEngineStateSig(next)}let tabs=signals.engineTabStateAcc();if(tabs.size>0){let nextTabs=null;for(let key of tabs.keys()){if(live.has(key))continue;if(!nextTabs)nextTabs=new Map(tabs);nextTabs.delete(key)}if(nextTabs)signals.setEngineTabStateSig(nextTabs)}let lifecycle=signals.engineLifecycleAcc();if(lifecycle.size>0){let nextLifecycle=null;for(let key of lifecycle.keys()){if(live.has(key))continue;if(!nextLifecycle)nextLifecycle=new Map(lifecycle);nextLifecycle.delete(key)}if(nextLifecycle)signals.setEngineLifecycleSig(nextLifecycle)}}function pruneTaskJobs(tasks,signals){let current=signals.taskJobsAcc();if(current.size===0)return;let live=new Set(tasks.map((t)=>t.id)),next=null;for(let key of current.keys()){if(live.has(key))continue;if(!next)next=new Map(current);next.delete(key)}if(next)signals.setTaskJobsSig(next)}function handleOrchestratorEvent(name,payload,signals){if(name==="task.snapshot"){let value=payload?.tasks;if(Array.isArray(value))signals.setTasks(value.map(deserializeTask)),pruneEngineState(value,signals),pruneTaskJobs(value,signals);else logClientError("orch",`dropped task.snapshot event: tasks is not an array (got ${describePayload(value)})`);return}if(name==="daemon.stopping"){let p=payload;if(typeof p?.roveVersion==="string")signals.setDaemonVersionSig(p.roveVersion);if(parseDaemonStopReason(p?.reason)==="restart")signals.setDaemonRestartingSig(!0);return}if(name==="active-task"){let id=payload?.taskId;signals.setActiveTaskSig(typeof id==="string"?id:null);return}if(name==="update"){let info=payload?.info;signals.setUpdateSig(info??null);return}if(name==="engine-state"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.state!=="string"){logClientError("orch",`dropped engine-state event: taskId/state must be strings (taskId=${describePayload(p?.taskId)}, state=${describePayload(p?.state)})`);return}let tabId=typeof p.tabId==="string"&&p.tabId?p.tabId:void 0,entry={state:p.state,detail:p.detail,...typeof p.sessionId==="string"&&p.sessionId?{sessionId:p.sessionId}:{},...typeof p.transcriptPath==="string"&&p.transcriptPath?{transcriptPath:p.transcriptPath}:{},...tabId?{tabId}:{},at:typeof p.at==="number"?p.at:0},prevTaskState=signals.engineStateAcc().get(p.taskId)?.state;if(!tabId){let next=new Map(signals.engineStateAcc());if(p.state==="idle")next.delete(p.taskId);else next.set(p.taskId,entry);signals.setEngineStateSig(next)}if((p.state==="idle"||p.state==="turn_complete"||p.state==="error"||p.state==="running"&&prevTaskState!=="running")&&signals.engineLifecycleAcc().has(p.taskId)){let lifecycle=new Map(signals.engineLifecycleAcc());lifecycle.delete(p.taskId),signals.setEngineLifecycleSig(lifecycle)}if(tabId){let nextTabs=new Map(signals.engineTabStateAcc()),tabs=new Map(nextTabs.get(p.taskId)??[]);tabs.set(tabId,entry),nextTabs.set(p.taskId,tabs),signals.setEngineTabStateSig(nextTabs)}return}if(name==="attention.inbox"){let items=payload?.items;if(!Array.isArray(items)){logClientError("orch",`dropped attention.inbox event: items is not an array (${describePayload(items)})`);return}let kept=items.filter((item)=>{if(!item||typeof item!=="object"||Array.isArray(item))return!1;let p=item;return(typeof p.taskId==="string"||p.taskId===null&&isRoutineInboxState(p.state))&&(p.tabId===null||typeof p.tabId==="string")&&isAttentionInboxState(p.state)&&(p.unread===void 0||typeof p.unread==="boolean")&&typeof p.at==="number"});if(kept.length!==items.length)logClientError("orch",`dropped ${items.length-kept.length} malformed attention.inbox item(s) of ${items.length} (${describePayload(items)})`);if(kept.length===0&&items.length>0)return;signals.setAttentionInboxSig(kept.map((item)=>({...item,unread:item.unread!==!1})));return}if(name==="gates"){let gates=payload?.gates;if(!Array.isArray(gates)){logClientError("orch",`dropped gates event: gates is not an array (${describePayload(gates)})`);return}let kept=gates.filter((g)=>{if(!g||typeof g!=="object"||Array.isArray(g))return!1;let p=g;return typeof p.id==="string"&&typeof p.taskId==="string"&&typeof p.question==="string"});if(kept.length===0&&gates.length>0)return;signals.setGatesSig(kept.map((g)=>({...g,options:Array.isArray(g.options)?g.options:[]})));return}if(name==="task.jobs"){let p=payload;if(typeof p?.taskId!=="string"||p.kind!=="ensureWorktree"){logClientError("orch",`dropped task.jobs event: expected string taskId + kind "ensureWorktree" (taskId=${describePayload(p?.taskId)}, kind=${describePayload(p?.kind)})`);return}let current=signals.taskJobsAcc();if(p.phase==="running"){let progress=typeof p.progress==="number"&&Number.isFinite(p.progress)?p.progress:current.get(p.taskId)?.progress,next=new Map(current);next.set(p.taskId,progress===void 0?{kind:p.kind}:{kind:p.kind,progress}),signals.setTaskJobsSig(next);return}if((p.phase==="done"||p.phase==="error")&¤t.has(p.taskId)){let next=new Map(current);next.delete(p.taskId),signals.setTaskJobsSig(next)}return}if(handleMapChannel(name,payload,signals))return;if(name==="tab.open"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.at!=="number"||typeof p.title!=="string"||!Array.isArray(p.argv)){logClientError("orch",`dropped tab.open event: malformed payload (${describePayload(payload)})`);return}signals.setTabOpenSig(p);return}if(name==="tab.close"){let p=payload;if(!(p&&"kind"in p&&p.kind==="terminal-tab"?typeof p.taskId==="string"&&typeof p.tabId==="string"&&typeof p.requestId==="string"&&typeof p.at==="number":typeof p?.taskId==="string"&&typeof p.at==="number"&&("title"in p)&&typeof p.title==="string")){logClientError("orch",`dropped tab.close event: malformed payload (${describePayload(payload)})`);return}signals.setTabCloseSig(p);return}if(name==="tab.rename"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.tabId!=="string"||typeof p.title!=="string"||typeof p.at!=="number"){logClientError("orch",`dropped tab.rename event: malformed payload (${describePayload(payload)})`);return}signals.setTabRenameSig(p);return}if(name==="tabs.changed"){let p=payload,state=p?.state;if(typeof p?.taskId!=="string"||typeof p.rev!=="number"||state!==null&&(typeof state!=="object"||!Array.isArray(state?.tabs))){logClientError("orch",`dropped tabs.changed event: malformed payload (${describePayload(payload)})`);return}signals.emitTabsChanged(p);return}if(name==="row.status"){let p=payload;if(typeof p?.rev!=="number"||typeof p.tasks!=="object"||p.tasks===null){logClientError("orch",`dropped row.status event: malformed payload (${describePayload(payload)})`);return}signals.emitRowStatus(p);return}if(name==="tab.add"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.at!=="number"||!isAddedTab(p.tab)){logClientError("orch",`dropped tab.add event: malformed payload (${describePayload(payload)})`);return}signals.setTabAddSig({taskId:p.taskId,tab:p.tab,at:p.at});return}if(name==="ui.prompt"){let p=payload;if(typeof p?.promptId!=="string"||typeof p.title!=="string"||typeof p.at!=="number"){logClientError("orch",`dropped ui.prompt event: malformed payload (${describePayload(payload)})`);return}signals.setUiPromptSig(p);return}if(name==="engine.lifecycle"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.kind!=="string"){logClientError("orch",`dropped engine.lifecycle event: malformed payload (${describePayload(payload)})`);return}let prev=signals.engineLifecycleAcc(),cur=prev.get(p.taskId)??{subagents:0},entry=p.kind==="subagent-start"?{subagents:cur.subagents+1}:p.kind==="subagent-stop"?{subagents:Math.max(0,cur.subagents-1)}:cur;if(entry===cur&&!prev.has(p.taskId))return;let map=new Map(prev);if(entry.subagents===0)map.delete(p.taskId);else map.set(p.taskId,entry);signals.setEngineLifecycleSig(map);return}if(name==="graphics.write"){let p=payload;if(typeof p?.data!=="string"||typeof p.imageId!=="number"||typeof p.at!=="number"){logClientError("orch",`dropped graphics.write event: malformed payload (${describePayload(payload)})`);return}signals.writeGraphics(Buffer.from(p.data,"base64"));return}if(name==="notice.event"){let p=payload;if(typeof p?.title!=="string"||typeof p.at!=="number"||typeof p.kind!=="string"){logClientError("orch",`dropped notice.event: malformed payload (${describePayload(payload)})`);return}signals.setNoticeSig(p);return}if(name==="ui-prefs"){let decoded=decodeUiPrefsPayload(payload);if(!decoded){let theme=payload?.theme;logClientError("orch",`dropped ui-prefs event: theme must be a string (got ${describePayload(theme)})`);return}signals.setUiPrefsSig(decoded);return}if(name==="state"||name==="machines"){signals.setRawSig(name,payload);return}if(name==="keybindings"){let p=payload;if(typeof p?.rev!=="number"){logClientError("orch",`dropped keybindings event: rev must be a number (got ${describePayload(p?.rev)})`);return}signals.setKeybindingsRevSig(p.rev)}}function subscribeTasksOp(tasks,listener){try{listener(tasks())}catch(err){console.error("[rove RemoteOrchestrator] task listener threw on subscribe:",err)}return tasks.subscribe(()=>{try{listener(tasks.get())}catch(err){console.error("[rove RemoteOrchestrator] task listener threw:",err)}})}class RowStatusChannel{client;listeners=new Set;constructor(client){this.client=client}emit=(payload)=>{for(let listener of this.listeners)listener(payload)};onChanged=(listener)=>{return this.listeners.add(listener),()=>this.listeners.delete(listener)};list=()=>this.client.request("status.list");viewing=(taskId,tabId)=>this.client.request("ui.viewing",taskId===null?{taskId:null}:{taskId,...tabId?{tabId}:{}});answered=(taskId,tabId)=>this.client.request("activity.answered",{taskId,tabId})}class TabsChannel{client;listeners=new Set;constructor(client){this.client=client}emit=(event)=>{for(let listener of this.listeners)listener(event)};onChanged=(listener)=>{return this.listeners.add(listener),()=>this.listeners.delete(listener)};apply=(taskId,ops)=>this.client.request("tabs.apply",{taskId,ops});list=()=>this.client.request("tabs.list");reserve=(taskId,count)=>this.client.request("tabs.reserve",{taskId,count});release=(taskId,from,to)=>this.client.request("tabs.release",{taskId,from,to})}async function createTaskOp(client,input){let{modelEffort,...rest}=input,res=await client.request("task.create",{...rest,effort:modelEffort});return deserializeTask(res.task)}async function ensureMainTaskOp(client,repo){let res=await client.request("task.ensureMain",{repo});return deserializeTask(res.task)}async function openDirectoryTaskOp(client,input){let res=await client.request("task.openDir",input);return deserializeTask(res.task)}async function adoptScratchRepoOp(client,id,repo){await client.request("task.adoptScratchRepo",{taskId:String(id),repo})}async function moveTaskToProjectOp(client,id,repo){let res=await client.request("task.moveToProject",{taskId:String(id),repo});return{repo:res.repo,moved:res.moved}}async function ensureWorktreeOp(client,id){return(await client.request("task.ensureWorktree",{taskId:String(id)})).worktreePath}async function forgetProjectOp(client,repo){await client.request("project.forget",{repo})}function reportEngineInterruptOp(client,taskId,tabId){client.request("engine.reportEvent",{kind:"turn-interrupted",taskId,tabId}).catch(()=>{})}async function setTitleOp(client,id,title){await client.request("task.rename",{taskId:String(id),title})}async function setBranchOp(client,id,branch){await client.request("task.setBranch",{taskId:String(id),branch})}async function setVendorOp(client,id,vendor,effort,model){await client.request("task.setVendor",{taskId:String(id),vendor,...effort!==void 0?{effort}:{},...model!==void 0?{model}:{}})}async function setCommandOp(client,id,command,vendor){await client.request("task.setCommand",{taskId:String(id),command,...vendor?{vendor}:{}})}async function setPinnedOp(client,id,pinned){await client.request("task.pin",{taskId:String(id),pinned})}async function archiveTaskOp(client,id,archived,force=!1){await client.request("task.archive",{taskId:String(id),archived,force})}async function moveTaskOp(client,id,delta){await client.request("task.move",{taskId:String(id),direction:delta<0?"up":"down"})}async function moveTaskToTopOp(client,id){await client.request("task.move",{taskId:String(id),direction:"top"})}async function setPromptOp(client,id,prompt){await client.request("task.setPrompt",{taskId:String(id),prompt})}async function setStatusOp(client,id,status){await client.request("task.status",{taskId:String(id),status})}async function deleteTaskOp(client,id,opts){return client.request("task.delete",{taskId:String(id),force:opts?.force,deleteBranch:opts?.deleteBranch,cascade:opts?.cascade})}async function spawnChildTaskOp(client,input){let{dispatcher,...rest}=input,res=await client.request("task.spawn",{...rest,...dispatcher?{dispatcherTaskId:dispatcher.taskId,dispatcherTabId:dispatcher.tabId}:{}});return{task:deserializeTask(res.task),parentDirty:res.parentDirty,sharedLinks:res.sharedLinks}}async function dismissAttentionOp(client,taskId,tabId,at,deliveryId){return(await client.request("attention.dismiss",{taskId:String(taskId),...tabId!==null?{tabId}:{},at,...deliveryId!==void 0?{deliveryId}:{}})).deleted}async function dismissRoutineAttentionOp(client,automationId){return(await client.request("attention.dismissRoutine",{automationId})).deleted}async function answerGateOp(client,gateId,answer){return{delivered:(await client.request("gate.answer",{gateId,...answer,by:"tui"})).delivered}}async function withdrawGateOp(client,gateId){await client.request("gate.withdraw",{gateId})}async function markAttentionReadOp(client,taskId,tabId,at){return(await client.request("attention.read",{taskId:String(taskId),...tabId!==null?{tabId}:{},at})).updated}async function landPreflightOp(client,id){return(await client.request("task.landPreflight",{taskId:String(id)})).result}async function landTaskOp(client,id,opts){return(await client.request("task.land",{taskId:String(id),strategy:opts?.strategy,deleteBranch:opts?.deleteBranch,removeWorktree:opts?.removeWorktree,callerCwd:opts?.callerCwd})).result}async function discoverAdoptableWorktreesOp(client,repo){return(await client.request("worktree.discoverAdoptable",{repo})).worktrees}async function adoptWorktreeOp(client,input){let res=await client.request("worktree.adopt",input);return deserializeTask(res.task)}async function listWorktreesOp(client,opts){return(await client.request("worktree.list",{network:opts?.network!==!1})).projects}async function removeWorktreeOp(client,path,force){return(await client.request("worktree.remove",{path,force})).residue??null}async function syncBaseOp(client,taskId){let res=await client.request("task.syncBase",{taskId}),failed=res.result.repos?.find((r)=>!r.ok);if(failed)throw Error(failed.error??"sync failed");return res.result}async function failingChecksOp(client,taskId){let res=await client.request("pr.failingChecks",{taskId});return{checks:res.checks??[],totalFailing:res.totalFailing??0,...res.unavailable?{unavailable:res.unavailable}:{}}}async function rerunFailedChecksOp(client,taskId){let res=await client.request("pr.rerunFailedChecks",{taskId});return{rerunRuns:res.rerunRuns??0,external:res.external??0,...res.refused?{refused:res.refused}:{},...res.unavailable?{unavailable:res.unavailable}:{}}}async function listIssuesOp(client,repoRoot){return client.request("issue.list",{repoRoot})}async function listIssueReposOp(client){return(await client.request("issue.repos",{})).repos??[]}async function listFieldNotesOp(client,repo){return(await client.request("note.list",{repo})).notes??[]}async function deleteFieldNoteOp(client,repo,id){return(await client.request("note.delete",{repo,id})).deleted===!0}async function mutateIssueOp(client,repoRoot,op){return client.request("issue.mutate",{repoRoot,op})}async function listAutomationsOp(client){return client.request("automation.list",{})}async function createAutomationOp(client,input){return client.request("automation.create",input)}async function automationRunsOp(client,id){return client.request("automation.runs",{id})}async function setAutomationEnabledOp(client,id,enabled){return client.request("automation.update",{id,enabled})}async function runAutomationNowOp(client,id){return client.request("automation.runNow",{id})}async function deleteAutomationOp(client,id){return client.request("automation.delete",{id})}async function listWorkItemsOp(client,args){return client.request("workitem.list",args)}async function startWorkItemOp(client,args){return client.request("workitem.start",args)}async function setActiveTaskOp(client,id){await client.request("task.setActive",{taskId:id===null?null:String(id)})}function replyTabCloseOp(client,requestId,closed){client.request("terminalTab.closeReply",{requestId,closed}).catch(()=>{})}function replyPromptOp(client,promptId,value){client.request("ui.promptReply",{promptId,...value!==void 0?{value}:{}}).catch(()=>{})}function reportUiEventOp(client,kind,taskId,detail){client.request("ui.reportEvent",{kind,...taskId?{taskId}:{},...detail?{detail}:{}}).catch(()=>{})}function recentTaskEventsOp(client,id){return client.request("task.recentEvents",{taskId:String(id)})}class RemoteOrchestrator{client;tasksAcc=createStateCell([],"orchestrator.tasks");activeTaskAcc=createStateCell(null,"orchestrator.active-task");updateAcc=createStateCell(null);daemonVersionAcc=createStateCell(null);daemonRestartingAcc=createStateCell(!1);daemonStaleAcc=mapReadableState(this.daemonVersionAcc,(version)=>isDaemonVersionStale(version??void 0,CURRENT_VERSION));engineStateAcc=createStateCell(new Map);engineTabStateAcc=createStateCell(new Map);attentionInboxAcc=createStateCell([]);gatesAcc=createStateCell([]);taskJobsAcc=createStateCell(new Map);rowTokensAcc=createStateCell(new Map);modPanesAcc=createStateCell([]);worktreeChangesAcc=createStateCell(null);usageSnapshotAcc=createStateCell(null);contextUsageAcc=createStateCell(null);transcriptActivityAcc=createStateCell(null);noticeAcc=createStateCell(null);tabOpenAcc=createStateCell(null);tabCloseAcc=createStateCell(null);tabRenameAcc=createStateCell(null);tabAddAcc=createStateCell(null);tabs;rowStatus;uiPromptAcc=createStateCell(null);engineLifecycleAcc=createStateCell(new Map);uiPrefsAcc=createStateCell(null);rawAcc={state:createStateCell(null),machines:createStateCell(null)};keybindingsRevAcc=createStateCell(null);connectionStateAcc=createStateCell("online","orchestrator.connection");staleInstallAcc=createStateCell(null);ensureReachable;role;cellPixelSize;channels;subscribesTasks;expectForeignHome;onPeerIdentity;reconnectLoop;signals;constructor(client,options={}){this.client=client;this.ensureReachable=options.ensureReachable??ensureDaemonReachable,this.role=options.role??"pane",this.cellPixelSize=options.cellPixelSize??null,this.channels=options.channels,this.subscribesTasks=!options.channels||options.channels.includes("task.snapshot"),this.expectForeignHome=options.expectForeignHome===!0,this.onPeerIdentity=options.onPeerIdentity,this.reconnectLoop=singleFlightReconnect({isDisposed:()=>client.isDisposed,ensureReachable:this.ensureReachable,init:()=>this.init(),shouldLogAttempt:shouldLogReconnectAttempt,onFatal:(err)=>this.staleInstallAcc.set(err instanceof Error?err.message:String(err))}),this.tabs=new TabsChannel(client),this.rowStatus=new RowStatusChannel(client),this.signals={writeGraphics:options.graphicsOut??(this.role==="gui"?writeGraphicsToStdout:()=>{}),tasksAcc:this.tasksAcc,setTasks:this.tasksAcc.set,setActiveTaskSig:this.activeTaskAcc.set,setUpdateSig:this.updateAcc.set,setDaemonVersionSig:this.daemonVersionAcc.set,setDaemonRestartingSig:this.daemonRestartingAcc.set,engineStateAcc:this.engineStateAcc,setEngineStateSig:this.engineStateAcc.set,engineTabStateAcc:this.engineTabStateAcc,setEngineTabStateSig:this.engineTabStateAcc.set,setAttentionInboxSig:this.attentionInboxAcc.set,setGatesSig:this.gatesAcc.set,taskJobsAcc:this.taskJobsAcc,setTaskJobsSig:this.taskJobsAcc.set,rowTokensAcc:this.rowTokensAcc,setRowTokensSig:this.rowTokensAcc.set,modPanesAcc:this.modPanesAcc,setModPanesSig:this.modPanesAcc.set,worktreeChangesAcc:this.worktreeChangesAcc,setWorktreeChangesSig:this.worktreeChangesAcc.set,usageSnapshotAcc:this.usageSnapshotAcc,setUsageSnapshotSig:this.usageSnapshotAcc.set,contextUsageAcc:this.contextUsageAcc,setContextUsageSig:this.contextUsageAcc.set,transcriptActivityAcc:this.transcriptActivityAcc,setTranscriptActivitySig:this.transcriptActivityAcc.set,setNoticeSig:this.noticeAcc.set,setTabOpenSig:this.tabOpenAcc.set,setTabCloseSig:this.tabCloseAcc.set,setTabRenameSig:this.tabRenameAcc.set,setTabAddSig:this.tabAddAcc.set,emitTabsChanged:this.tabs.emit,emitRowStatus:this.rowStatus.emit,setUiPromptSig:this.uiPromptAcc.set,engineLifecycleAcc:this.engineLifecycleAcc,setEngineLifecycleSig:this.engineLifecycleAcc.set,setUiPrefsSig:this.uiPrefsAcc.set,setRawSig:(name,payload)=>this.rawAcc[name].set(payload),setKeybindingsRevSig:this.keybindingsRevAcc.set,setConnectionState:this.connectionStateAcc.set},this.client.on("*",(frame)=>handleOrchestratorEvent(frame.name,frame.payload,this.signals)),this.client.onLifecycle("close",()=>{this.connectionStateAcc.set("disconnected");let spawnDaemon=this.role==="gui";logClient("orch",spawnDaemon?"daemon socket closed \u2014 starting silent spawning reconnect loop":"daemon socket closed \u2014 starting non-spawning reconnect loop"),this.reconnectLoop(spawnDaemon)})}writeGraphics(data){this.signals.writeGraphics(data)}async init(){await performInit(this.client,{role:this.role,cellPixelSize:this.cellPixelSize,channels:this.channels,subscribesTasks:this.subscribesTasks,expectForeignHome:this.expectForeignHome,onPeerIdentity:this.onPeerIdentity},this.signals)}connectionStateSignal(){return this.connectionStateAcc}staleInstallSignal(){return this.staleInstallAcc}async manualReconnect(){this.client.forceDisconnect(),await this.reconnectLoop(!0)}dispose(){this.client.close()}tasksSignal=()=>this.tasksAcc;activeTaskSignal=()=>this.activeTaskAcc;updateSignal=()=>this.updateAcc;daemonVersionSignal=()=>this.daemonVersionAcc;daemonStaleSignal=()=>this.daemonStaleAcc;daemonRestartingSignal=()=>this.daemonRestartingAcc;async restartDaemon(){await this.client.request("daemon.stop",{reason:"restart"}).catch(()=>{})}engineStateSignal=()=>this.engineStateAcc;engineTabStatesSignal=()=>this.engineTabStateAcc;attentionInboxSignal=()=>this.attentionInboxAcc;gatesSignal=()=>this.gatesAcc;taskJobsSignal=()=>this.taskJobsAcc;rowTokensSignal=()=>this.rowTokensAcc;modPanesSignal=()=>this.modPanesAcc;pressMod=(plugin,pane,key)=>this.client.request("mod.press",{plugin,pane,key});submitMod=(plugin,pane,key,value)=>this.client.request("mod.submit",{plugin,pane,key,value});worktreeChangesSignal=()=>this.worktreeChangesAcc;usageSnapshotSignal=()=>this.usageSnapshotAcc;contextUsageSignal=()=>this.contextUsageAcc;transcriptActivitySignal=()=>this.transcriptActivityAcc;transcriptActivityStore=()=>this.transcriptActivityAcc;noticeStore=()=>this.noticeAcc;tabOpenStore=()=>this.tabOpenAcc;tabCloseStore=()=>this.tabCloseAcc;tabRenameStore=()=>this.tabRenameAcc;tabAddStore=()=>this.tabAddAcc;rpc={request:(name,payload)=>this.client.request(name,payload)};replyTerminalTabClose=(requestId,closed)=>replyTabCloseOp(this.client,requestId,closed);uiPromptStore=()=>this.uiPromptAcc;replyPrompt=(promptId,value)=>replyPromptOp(this.client,promptId,value);engineLifecycleSignal=()=>this.engineLifecycleAcc;recentTaskEvents(id){return recentTaskEventsOp(this.client,id)}reportUiEvent=(kind,taskId,detail)=>reportUiEventOp(this.client,kind,taskId,detail);reportScreenInput=async(taskId,tabId,blocked)=>{await this.client.request("engine.reportEvent",{source:"screen",taskId,tabId,blocked})};reportEngineInterrupt=(taskId,tabId)=>reportEngineInterruptOp(this.client,String(taskId),tabId);uiPrefsSignal=()=>this.uiPrefsAcc;uiPrefsStore=()=>this.uiPrefsAcc;rawChannelSignal=(name)=>this.rawAcc[name];keybindingsRevSignal=()=>this.keybindingsRevAcc;keybindingsRevStore=()=>this.keybindingsRevAcc;listTasks=()=>this.tasksAcc();getTask=(id)=>this.tasksAcc().find((task)=>task.id===id);subscribeTasks(listener){return subscribeTasksOp(this.tasksAcc,listener)}createTask=(input)=>createTaskOp(this.client,input);ensureMainTask=(repo)=>ensureMainTaskOp(this.client,repo);openDirectoryTask=(input)=>openDirectoryTaskOp(this.client,input);adoptScratchRepo=(id,repo)=>adoptScratchRepoOp(this.client,id,repo);moveTaskToProject=(id,repo)=>moveTaskToProjectOp(this.client,id,repo);ensureWorktree=(id)=>ensureWorktreeOp(this.client,id);forgetProject=(repo)=>forgetProjectOp(this.client,repo);setTitle=(id,title)=>setTitleOp(this.client,id,title);setBranch=(id,branch)=>setBranchOp(this.client,id,branch);setVendor=(id,vendor,effort,model)=>setVendorOp(this.client,id,vendor,effort,model);setCommand=(id,command,vendor)=>setCommandOp(this.client,id,command,vendor);setPinned=(id,pinned)=>setPinnedOp(this.client,id,pinned);archiveTask=(id,archived,force)=>archiveTaskOp(this.client,id,archived,force);moveTask=(id,delta)=>moveTaskOp(this.client,id,delta);moveTaskToTop=(id)=>moveTaskToTopOp(this.client,id);setStatus=(id,status)=>setStatusOp(this.client,id,status);setPrompt=(id,prompt)=>setPromptOp(this.client,id,prompt);deleteTask=(id,opts)=>deleteTaskOp(this.client,id,opts);spawnChildTask=(input)=>spawnChildTaskOp(this.client,input);dismissAttention=(taskId,tabId,at,deliveryId)=>dismissAttentionOp(this.client,taskId,tabId,at,deliveryId);dismissRoutineAttention=(automationId)=>dismissRoutineAttentionOp(this.client,automationId);markAttentionRead=(taskId,tabId,at)=>markAttentionReadOp(this.client,taskId,tabId,at);answerGate=(gateId,answer)=>answerGateOp(this.client,gateId,answer);withdrawGate=(gateId)=>withdrawGateOp(this.client,gateId);landPreflight(id){return landPreflightOp(this.client,id)}landTask(id,opts){return landTaskOp(this.client,id,opts)}discoverAdoptableWorktrees(repo){return discoverAdoptableWorktreesOp(this.client,repo)}adoptWorktree(input){return adoptWorktreeOp(this.client,input)}listWorktrees(opts){return listWorktreesOp(this.client,opts)}listIssues(repoRoot){return listIssuesOp(this.client,repoRoot)}listIssueRepos(){return listIssueReposOp(this.client)}mutateIssue(repoRoot,op){return mutateIssueOp(this.client,repoRoot,op)}listAutomations=()=>listAutomationsOp(this.client);createAutomation=(i)=>createAutomationOp(this.client,i);automationRuns=(id)=>automationRunsOp(this.client,id);setAutomationEnabled=(id,on)=>setAutomationEnabledOp(this.client,id,on);runAutomationNow=(id)=>runAutomationNowOp(this.client,id);deleteAutomation=(id)=>deleteAutomationOp(this.client,id);listWorkItems=(a)=>listWorkItemsOp(this.client,a);listFieldNotes=(repo)=>listFieldNotesOp(this.client,repo);deleteFieldNote=(repo,id)=>deleteFieldNoteOp(this.client,repo,id);failingChecks=(taskId)=>failingChecksOp(this.client,taskId);rerunFailedChecks=(taskId)=>rerunFailedChecksOp(this.client,taskId);syncBase=(taskId)=>syncBaseOp(this.client,taskId);startWorkItem=(a)=>startWorkItemOp(this.client,a);removeWorktree(path,force){return removeWorktreeOp(this.client,path,force)}setActiveTask(id){return setActiveTaskOp(this.client,id)}}
|
|
2
|
+
import{parseDaemonStopReason}from"./chunk-6xr1prk6.js";import{isRowTokenTone}from"./chunk-atn06ncf.js";import{ensureDaemonReachable,isStaleInstallError}from"./chunk-e58kj4gm.js";import{sameWorktreeChanges}from"./chunk-0r1jf8m9.js";import{CURRENT_VERSION}from"./chunk-2wrt80ft.js";import{createStateCell,mapReadableState}from"./chunk-cmp64q4j.js";import{DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,isAttentionInboxState,isDaemonVersionStale,isForeignDaemonHome,isProtocolCompatible,isRoutineInboxState}from"./chunk-qzzmd63x.js";import{parseModUiPayload}from"./chunk-96kvwzj8.js";import{toTaskId}from"./chunk-xy8be792.js";import{homeDir}from"./chunk-z1nj22va.js";import{logClient,logClientError}from"./chunk-0g4wc808.js";function parseWorktreeChangesPayload(payload){let changes=payload?.changes;if(!changes||typeof changes!=="object"||Array.isArray(changes))return null;let map=new Map;for(let[path,value]of Object.entries(changes)){let counts=value;if(typeof counts?.added!=="number"||typeof counts.deleted!=="number")return null;map.set(path,{added:counts.added,deleted:counts.deleted,...typeof counts.behind==="number"?{behind:counts.behind}:{},...typeof counts.ahead==="number"?{ahead:counts.ahead}:{}})}let unreadable=payload?.unreadable;if(Array.isArray(unreadable)){for(let path of unreadable)if(typeof path==="string"&&path.length>0)map.set(path,null)}return map}function sameWorktreeChangesMap(a,b){if(a.size!==b.size)return!1;for(let[path,counts]of a){if(!b.has(path))return!1;if(!sameWorktreeChanges(counts,b.get(path)??null))return!1}return!0}function parseToken(raw){if(!raw||typeof raw!=="object")return null;let t=raw;if(typeof t.source!=="string"||typeof t.key!=="string")return null;if(typeof t.text!=="string"||t.text.length===0)return null;if(typeof t.expiresAt!=="number"||!Number.isFinite(t.expiresAt))return null;return{source:t.source,key:t.key,text:t.text,...isRowTokenTone(t.tone)?{tone:t.tone}:{},expiresAt:t.expiresAt}}function parseRowTokensPayload(payload){let tokens=payload?.tokens;if(!tokens||typeof tokens!=="object"||Array.isArray(tokens))return null;let out=new Map;for(let[taskId,list]of Object.entries(tokens)){if(!Array.isArray(list))continue;let parsed=list.map(parseToken).filter((token)=>token!==null);if(parsed.length>0)out.set(taskId,parsed)}return out}function sameRowTokenMap(a,b){if(a.size!==b.size)return!1;for(let[taskId,left]of a){let right=b.get(taskId);if(!right||right.length!==left.length)return!1;for(let[i,token]of left.entries()){let other=right[i];if(!other||other.source!==token.source||other.key!==token.key||other.text!==token.text||other.tone!==token.tone||other.expiresAt!==token.expiresAt)return!1}}return!0}function liveRowTokens(map,taskId,now){let tokens=map?.get(taskId);if(!tokens||tokens.length===0)return[];return tokens.filter((token)=>token.expiresAt>now)}function shouldLogReconnectAttempt(attempt){if(attempt>100)return!1;return attempt===1||attempt%10===0}function describePayload(value){if(value===void 0)return"undefined";if(value===null)return"null";let type=Array.isArray(value)?"array":typeof value,text;try{text=typeof value==="string"?value:JSON.stringify(value)}catch{text=String(value)}if(text.length>120)text=`${text.slice(0,120)}\u2026`;return`${type}:${text}`}function decodeUiPrefsPayload(payload){let p=payload;if(!p||typeof p!=="object"||!("theme"in p))return null;if(p.theme!==null&&typeof p.theme!=="string")return null;return{theme:typeof p.theme==="string"&&p.theme.length>0?p.theme:null,..."themeMode"in p?{themeMode:typeof p.themeMode==="string"?p.themeMode:null}:{},transparentBackground:p.transparentBackground!==!1,focusAccent:typeof p.focusAccent==="string"?p.focusAccent:null,locale:typeof p.locale==="string"?p.locale:"",sortMode:p.sortMode==="recent"||p.sortMode==="attention"||p.sortMode==="name"?p.sortMode:"default",keysCollapsed:p.keysCollapsed===!0,projectFilter:typeof p.projectFilter==="string"&&p.projectFilter.length>0?p.projectFilter:null}}var TOKEN_TOTAL_FIELDS=["inputTokens","outputTokens","cacheReadTokens","cacheCreationTokens"];function parseContextUsagePayload(payload){let context=payload?.context;if(!context||typeof context!=="object"||Array.isArray(context))return null;let map=new Map;for(let[key,value]of Object.entries(context)){let v=value;if(typeof v?.contextTokens!=="number")return null;if(v.contextWindowTokens!==void 0&&typeof v.contextWindowTokens!=="number")return null;let parts=v.parts;if(parts!==void 0&&(!Array.isArray(parts)||!parts.every((p)=>typeof p?.key==="string"&&typeof p?.tokens==="number")))return null;let totals={};for(let field of TOKEN_TOTAL_FIELDS){let raw=v[field];if(raw===void 0)continue;if(typeof raw!=="number")return null;totals[field]=raw}map.set(key,{contextTokens:v.contextTokens,...typeof v.contextWindowTokens==="number"?{contextWindowTokens:v.contextWindowTokens}:{},...v.approximate===!0?{approximate:!0}:{},...totals,...Array.isArray(parts)?{parts:parts.map((p)=>({key:p.key,tokens:p.tokens}))}:{}})}return map}function sameContextUsageMap(a,b){if(a.size!==b.size)return!1;for(let[key,value]of a){let other=b.get(key);if(!other||other.contextTokens!==value.contextTokens||other.contextWindowTokens!==value.contextWindowTokens||other.approximate!==value.approximate||TOKEN_TOTAL_FIELDS.some((field)=>other[field]!==value[field])||JSON.stringify(other.parts)!==JSON.stringify(value.parts))return!1}return!0}function parseUsageSnapshotPayload(payload){let usage=payload?.usage;if(!usage||typeof usage!=="object"||Array.isArray(usage))return null;let map=new Map;for(let[vendor,value]of Object.entries(usage)){let snapshot=value;if(typeof snapshot?.capturedAt!=="number"||!Array.isArray(snapshot.windows))return null;let windows=[];for(let raw of snapshot.windows){let w=raw;if(typeof w?.kind!=="string"||typeof w.label!=="string"||typeof w.percent!=="number")return null;if(w.resetsAt!==null&&typeof w.resetsAt!=="number")return null;windows.push({kind:w.kind,label:w.label,percent:w.percent,resetsAt:w.resetsAt})}map.set(vendor,{windows,capturedAt:snapshot.capturedAt})}return map}function sameUsageSnapshotMap(a,b){if(a.size!==b.size)return!1;for(let[vendor,usage]of a){let other=b.get(vendor);if(!other||other.capturedAt!==usage.capturedAt||other.windows.length!==usage.windows.length)return!1;for(let i=0;i<usage.windows.length;i++){let x=usage.windows[i],y=other.windows[i];if(!x||!y||x.kind!==y.kind||x.label!==y.label||x.percent!==y.percent||x.resetsAt!==y.resetsAt)return!1}}return!0}function parseTranscriptActivityPayload(payload){let activity=payload?.activity;if(!activity||typeof activity!=="object"||Array.isArray(activity))return null;let map=new Map;for(let[path,value]of Object.entries(activity)){let v=value;if(typeof v?.mtimeMs!=="number"||typeof v.completionAt!=="number")return null;if(v.completionId!==null&&typeof v.completionId!=="string")return null;map.set(path,{mtimeMs:v.mtimeMs,completionId:v.completionId,completionAt:v.completionAt})}return map}function sameTranscriptActivityMap(a,b){if(a.size!==b.size)return!1;for(let[path,v]of a){let other=b.get(path);if(!other||other.mtimeMs!==v.mtimeMs||other.completionId!==v.completionId||other.completionAt!==v.completionAt)return!1}return!0}function deserializeTask(s){return{id:toTaskId(s.id),title:s.title,repo:s.repo,branch:s.branch,worktreePath:s.worktreePath,kind:s.kind,...s.scratch?{scratch:!0}:{},...s.noProject?{noProject:!0}:{},...s.routine?{routine:s.routine}:{},status:s.status,pinned:s.pinned,...s.kept?{kept:!0}:{},...s.notes?{notes:s.notes}:{},...s.todos?{todos:s.todos}:{},...s.archived?{archived:!0}:{},vendor:s.vendor,command:s.command,prStatus:s.prStatus,modelEffort:s.modelEffort,model:s.model,tier:s.tier,groupId:s.groupId,observedLanguage:s.observedLanguage,deletion:s.deletion,quotaResume:s.quotaResume,scheduledStart:s.scheduledStart,...s.autoFixCi?{autoFixCi:s.autoFixCi}:{},linkedWorkItem:s.linkedWorkItem,dispatcher:s.dispatcher,...s.parentTaskId?{parentTaskId:toTaskId(s.parentTaskId)}:{},...s.sharesWorkspaceOf?{sharesWorkspaceOf:toTaskId(s.sharesWorkspaceOf)}:{},...s.cwdSubpath?{cwdSubpath:s.cwdSubpath}:{},...s.ptyAlias?{ptyAlias:s.ptyAlias}:{},...s.extraRepos?.length?{extraRepos:s.extraRepos}:{},...s.workspace?{workspace:s.workspace}:{},...s.sessionPrs?.length?{sessionPrs:s.sessionPrs}:{},requireReport:s.requireReport,prompt:s.prompt,baseRef:s.baseRef,worktreeName:s.worktreeName,...s.gitRepo?{gitRepo:s.gitRepo}:{},report:s.report,...s.repoId?{repoId:s.repoId}:{},createdAt:s.createdAt,updatedAt:s.updatedAt}}async function runReconnectLoop(deps){let delayMs=deps.spawnDaemon?Math.floor(Math.random()*400):500,attempt=0;while(!deps.isDisposed()){if(delayMs>0)await new Promise((r)=>setTimeout(r,delayMs));if(deps.isDisposed())break;attempt++;try{if(deps.spawnDaemon)await deps.ensureReachable();await deps.init(),logClient("orch",`reconnected and re-subscribed after ${attempt} attempt(s) \u2014 task list re-synced`);return}catch(err){if(isStaleInstallError(err)){logClientError("orch-reconnect-fatal",err),deps.onFatal?.(err);return}if(deps.shouldLogAttempt(attempt))logClientError("orch-reconnect",err);delayMs=delayMs===0?500:Math.min(delayMs*2,3000)}}}function singleFlightReconnect(deps){let current=null;return(spawnDaemon)=>{if(current)return current;let task=runReconnectLoop({...deps,spawnDaemon});current=task;let clear=()=>{if(current===task)current=null};return task.then(clear,clear),task}}async function performInit(client,opts,signals){let hello=await client.request("hello",{protocolVersion:DAEMON_PROTOCOL_VERSION,minProtocolVersion:MIN_COMPATIBLE_PROTOCOL_VERSION}),daemonVersion=typeof hello.protocolVersion==="number"?hello.protocolVersion:DAEMON_PROTOCOL_VERSION,daemonMin=typeof hello.minProtocolVersion==="number"?hello.minProtocolVersion:daemonVersion;if(!isProtocolCompatible({localVersion:DAEMON_PROTOCOL_VERSION,localMin:MIN_COMPATIBLE_PROTOCOL_VERSION,remoteVersion:daemonVersion,remoteMin:daemonMin}))throw Error(`Rove daemon is protocol v${daemonVersion} (min v${daemonMin}); this client is v${DAEMON_PROTOCOL_VERSION} (min v${MIN_COMPATIBLE_PROTOCOL_VERSION}). Restart the daemon (\`rove daemon restart\`) or upgrade Rove.`);let clientHome=homeDir();if(!opts.expectForeignHome&&isForeignDaemonHome(hello.homeDir,clientHome))throw Error(`Rove daemon on this socket serves ${hello.homeDir}, but this client uses ${clientHome}. A sandbox or dev daemon has taken the production socket \u2014 stop it (\`rove daemon stop\`), or unset ROVE_DAEMON_SOCKET_PATH / ROVE_DAEMON_SOCKET_PATH before starting it.`);if(signals.setDaemonVersionSig(typeof hello.roveVersion==="string"?hello.roveVersion:null),opts.onPeerIdentity?.({hostname:typeof hello.hostname==="string"?hello.hostname:"",homeDir:typeof hello.homeDir==="string"?hello.homeDir:"",daemonPid:typeof hello.daemonPid==="number"?hello.daemonPid:0,roveVersion:typeof hello.roveVersion==="string"?hello.roveVersion:""}),signals.setDaemonRestartingSig(!1),hello.tasks&&opts.subscribesTasks)signals.setTasks(hello.tasks.map(deserializeTask));if(await client.subscribe({role:opts.role,channels:opts.channels,cellPixelSize:opts.cellPixelSize}),hello.capabilities?.includes("worktree.changes")){if(signals.worktreeChangesAcc()===null)signals.setWorktreeChangesSig(new Map)}else signals.setWorktreeChangesSig(null);if(hello.capabilities?.includes("transcript.activity")){if(signals.transcriptActivityAcc()===null)signals.setTranscriptActivitySig(new Map)}else signals.setTranscriptActivitySig(null);signals.setConnectionState("online"),logClient("orch",`subscribed as ${opts.role} (${signals.tasksAcc().length} tasks)`)}function ordinalOf(tabId,fallback){let match=/^tab-(\d+)$/.exec(tabId);return match?Number(match[1]):fallback}function adoptTabs(state,tabIds){let known=new Set(state.tabs.map((tab)=>tab.id)),fresh=[];for(let id of tabIds){if(known.has(id))continue;known.add(id),fresh.push(id)}if(fresh.length===0)return state;let minted=state.nextOrdinal,adopted=fresh.map((id)=>({kind:"engine",id,title:null,ordinal:ordinalOf(id,minted++),spawned:!0}));adopted.sort((a,b)=>a.ordinal-b.ordinal);let tabs=[...state.tabs,...adopted],maxOrdinal=tabs.reduce((max,tab)=>Math.max(max,tab.ordinal),0);return{tabs,activeId:state.activeId,nextOrdinal:Math.max(state.nextOrdinal,maxOrdinal+1)}}function isAddedTab(raw){if(typeof raw!=="object"||raw===null)return!1;if(!("id"in raw)||typeof raw.id!=="string")return!1;if(!("ordinal"in raw)||typeof raw.ordinal!=="number")return!1;if(!("title"in raw)||raw.title!==null&&typeof raw.title!=="string")return!1;if(!("kind"in raw))return!1;if(raw.kind==="engine")return!0;return raw.kind==="command"&&"command"in raw&&Array.isArray(raw.command)}function absorbTab(state,tab){let nextOrdinal=Math.max(state.nextOrdinal,tab.ordinal+1),known=state.tabs.find((t)=>t.id===tab.id);if(known?.kind===tab.kind){if(Object.entries(tab).every(([key,value])=>JSON.stringify(Reflect.get(known,key))===JSON.stringify(value))&&nextOrdinal===state.nextOrdinal)return state}let merged=known?.kind===tab.kind?{...known,...tab,title:known.title}:tab,tabs=known?state.tabs.map((t)=>t===known?merged:t):[...state.tabs,merged];return{...state,tabs,nextOrdinal}}var MAP_CHANNELS={"usage.snapshot":{what:"usage payload",parse:parseUsageSnapshotPayload,same:sameUsageSnapshotMap,read:(signals)=>signals.usageSnapshotAcc(),write:(signals,next)=>signals.setUsageSnapshotSig(next)},"usage.context":{what:"context payload",parse:parseContextUsagePayload,same:sameContextUsageMap,read:(signals)=>signals.contextUsageAcc(),write:(signals,next)=>signals.setContextUsageSig(next)},"worktree.changes":{what:"changes payload",parse:parseWorktreeChangesPayload,same:sameWorktreeChangesMap,read:(signals)=>signals.worktreeChangesAcc(),write:(signals,next)=>signals.setWorktreeChangesSig(next)},"transcript.activity":{what:"activity payload",parse:parseTranscriptActivityPayload,same:sameTranscriptActivityMap,read:(signals)=>signals.transcriptActivityAcc(),write:(signals,next)=>signals.setTranscriptActivitySig(next)},"mod.ui":{what:"mod pane list",parse:parseModUiPayload,same:(a,b)=>JSON.stringify(a)===JSON.stringify(b),read:(signals)=>signals.modPanesAcc(),write:(signals,next)=>signals.setModPanesSig(next)},"task.tokens":{what:"token map",parse:parseRowTokensPayload,same:sameRowTokenMap,read:(signals)=>signals.rowTokensAcc(),write:(signals,next)=>signals.setRowTokensSig(next)}};function handleMapChannel(name,payload,signals){let channel=MAP_CHANNELS[name];if(!channel)return!1;let next=channel.parse(payload);if(!next)return logClientError("orch",`dropped ${name} event: malformed ${channel.what} (${describePayload(payload)})`),!0;let current=channel.read(signals);if(current&&channel.same(current,next))return!0;return channel.write(signals,next),!0}function writeGraphicsToStdout(data){if(!process.stdout.isTTY)return;process.stdout.write(data)}function pruneEngineState(tasks,signals){let live=new Set(tasks.map((t)=>t.id)),current=signals.engineStateAcc();if(current.size>0){let next=null;for(let key of current.keys()){if(live.has(key))continue;if(!next)next=new Map(current);next.delete(key)}if(next)signals.setEngineStateSig(next)}let tabs=signals.engineTabStateAcc();if(tabs.size>0){let nextTabs=null;for(let key of tabs.keys()){if(live.has(key))continue;if(!nextTabs)nextTabs=new Map(tabs);nextTabs.delete(key)}if(nextTabs)signals.setEngineTabStateSig(nextTabs)}let lifecycle=signals.engineLifecycleAcc();if(lifecycle.size>0){let nextLifecycle=null;for(let key of lifecycle.keys()){if(live.has(key))continue;if(!nextLifecycle)nextLifecycle=new Map(lifecycle);nextLifecycle.delete(key)}if(nextLifecycle)signals.setEngineLifecycleSig(nextLifecycle)}}function pruneTaskJobs(tasks,signals){let current=signals.taskJobsAcc();if(current.size===0)return;let live=new Set(tasks.map((t)=>t.id)),next=null;for(let key of current.keys()){if(live.has(key))continue;if(!next)next=new Map(current);next.delete(key)}if(next)signals.setTaskJobsSig(next)}function handleOrchestratorEvent(name,payload,signals){if(name==="task.snapshot"){let value=payload?.tasks;if(Array.isArray(value))signals.setTasks(value.map(deserializeTask)),pruneEngineState(value,signals),pruneTaskJobs(value,signals);else logClientError("orch",`dropped task.snapshot event: tasks is not an array (got ${describePayload(value)})`);return}if(name==="daemon.stopping"){let p=payload;if(typeof p?.roveVersion==="string")signals.setDaemonVersionSig(p.roveVersion);if(parseDaemonStopReason(p?.reason)==="restart")signals.setDaemonRestartingSig(!0);return}if(name==="active-task"){let id=payload?.taskId;signals.setActiveTaskSig(typeof id==="string"?id:null);return}if(name==="update"){let info=payload?.info;signals.setUpdateSig(info??null);return}if(name==="engine-state"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.state!=="string"){logClientError("orch",`dropped engine-state event: taskId/state must be strings (taskId=${describePayload(p?.taskId)}, state=${describePayload(p?.state)})`);return}let tabId=typeof p.tabId==="string"&&p.tabId?p.tabId:void 0,entry={state:p.state,detail:p.detail,...typeof p.sessionId==="string"&&p.sessionId?{sessionId:p.sessionId}:{},...typeof p.transcriptPath==="string"&&p.transcriptPath?{transcriptPath:p.transcriptPath}:{},...tabId?{tabId}:{},at:typeof p.at==="number"?p.at:0},prevTaskState=signals.engineStateAcc().get(p.taskId)?.state;if(!tabId){let next=new Map(signals.engineStateAcc());if(p.state==="idle")next.delete(p.taskId);else next.set(p.taskId,entry);signals.setEngineStateSig(next)}if((p.state==="idle"||p.state==="turn_complete"||p.state==="error"||p.state==="running"&&prevTaskState!=="running")&&signals.engineLifecycleAcc().has(p.taskId)){let lifecycle=new Map(signals.engineLifecycleAcc());lifecycle.delete(p.taskId),signals.setEngineLifecycleSig(lifecycle)}if(tabId){let nextTabs=new Map(signals.engineTabStateAcc()),tabs=new Map(nextTabs.get(p.taskId)??[]);tabs.set(tabId,entry),nextTabs.set(p.taskId,tabs),signals.setEngineTabStateSig(nextTabs)}return}if(name==="attention.inbox"){let items=payload?.items;if(!Array.isArray(items)){logClientError("orch",`dropped attention.inbox event: items is not an array (${describePayload(items)})`);return}let kept=items.filter((item)=>{if(!item||typeof item!=="object"||Array.isArray(item))return!1;let p=item;return(typeof p.taskId==="string"||p.taskId===null&&isRoutineInboxState(p.state))&&(p.tabId===null||typeof p.tabId==="string")&&isAttentionInboxState(p.state)&&(p.unread===void 0||typeof p.unread==="boolean")&&typeof p.at==="number"});if(kept.length!==items.length)logClientError("orch",`dropped ${items.length-kept.length} malformed attention.inbox item(s) of ${items.length} (${describePayload(items)})`);if(kept.length===0&&items.length>0)return;signals.setAttentionInboxSig(kept.map((item)=>({...item,unread:item.unread!==!1})));return}if(name==="gates"){let gates=payload?.gates;if(!Array.isArray(gates)){logClientError("orch",`dropped gates event: gates is not an array (${describePayload(gates)})`);return}let kept=gates.filter((g)=>{if(!g||typeof g!=="object"||Array.isArray(g))return!1;let p=g;return typeof p.id==="string"&&typeof p.taskId==="string"&&typeof p.question==="string"});if(kept.length===0&&gates.length>0)return;signals.setGatesSig(kept.map((g)=>({...g,options:Array.isArray(g.options)?g.options:[]})));return}if(name==="task.jobs"){let p=payload;if(typeof p?.taskId!=="string"||p.kind!=="ensureWorktree"){logClientError("orch",`dropped task.jobs event: expected string taskId + kind "ensureWorktree" (taskId=${describePayload(p?.taskId)}, kind=${describePayload(p?.kind)})`);return}let current=signals.taskJobsAcc();if(p.phase==="running"){let progress=typeof p.progress==="number"&&Number.isFinite(p.progress)?p.progress:current.get(p.taskId)?.progress,next=new Map(current);next.set(p.taskId,progress===void 0?{kind:p.kind}:{kind:p.kind,progress}),signals.setTaskJobsSig(next);return}if((p.phase==="done"||p.phase==="error")&¤t.has(p.taskId)){let next=new Map(current);next.delete(p.taskId),signals.setTaskJobsSig(next)}return}if(handleMapChannel(name,payload,signals))return;if(name==="tab.open"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.at!=="number"||typeof p.title!=="string"||!Array.isArray(p.argv)){logClientError("orch",`dropped tab.open event: malformed payload (${describePayload(payload)})`);return}signals.setTabOpenSig(p);return}if(name==="tab.close"){let p=payload;if(!(p&&"kind"in p&&p.kind==="terminal-tab"?typeof p.taskId==="string"&&typeof p.tabId==="string"&&typeof p.requestId==="string"&&typeof p.at==="number":typeof p?.taskId==="string"&&typeof p.at==="number"&&("title"in p)&&typeof p.title==="string")){logClientError("orch",`dropped tab.close event: malformed payload (${describePayload(payload)})`);return}signals.setTabCloseSig(p);return}if(name==="tab.rename"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.tabId!=="string"||typeof p.title!=="string"||typeof p.at!=="number"){logClientError("orch",`dropped tab.rename event: malformed payload (${describePayload(payload)})`);return}signals.setTabRenameSig(p);return}if(name==="tabs.changed"){let p=payload,state=p?.state;if(typeof p?.taskId!=="string"||typeof p.rev!=="number"||state!==null&&(typeof state!=="object"||!Array.isArray(state?.tabs))){logClientError("orch",`dropped tabs.changed event: malformed payload (${describePayload(payload)})`);return}signals.emitTabsChanged(p);return}if(name==="row.status"){let p=payload;if(typeof p?.rev!=="number"||typeof p.tasks!=="object"||p.tasks===null){logClientError("orch",`dropped row.status event: malformed payload (${describePayload(payload)})`);return}signals.emitRowStatus(p);return}if(name==="tab.add"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.at!=="number"||!isAddedTab(p.tab)){logClientError("orch",`dropped tab.add event: malformed payload (${describePayload(payload)})`);return}signals.setTabAddSig({taskId:p.taskId,tab:p.tab,at:p.at});return}if(name==="ui.prompt"){let p=payload;if(typeof p?.promptId!=="string"||typeof p.title!=="string"||typeof p.at!=="number"){logClientError("orch",`dropped ui.prompt event: malformed payload (${describePayload(payload)})`);return}signals.setUiPromptSig(p);return}if(name==="engine.lifecycle"){let p=payload;if(typeof p?.taskId!=="string"||typeof p.kind!=="string"){logClientError("orch",`dropped engine.lifecycle event: malformed payload (${describePayload(payload)})`);return}let prev=signals.engineLifecycleAcc(),cur=prev.get(p.taskId)??{subagents:0},entry=p.kind==="subagent-start"?{subagents:cur.subagents+1}:p.kind==="subagent-stop"?{subagents:Math.max(0,cur.subagents-1)}:cur;if(entry===cur&&!prev.has(p.taskId))return;let map=new Map(prev);if(entry.subagents===0)map.delete(p.taskId);else map.set(p.taskId,entry);signals.setEngineLifecycleSig(map);return}if(name==="graphics.write"){let p=payload;if(typeof p?.data!=="string"||typeof p.imageId!=="number"||typeof p.at!=="number"){logClientError("orch",`dropped graphics.write event: malformed payload (${describePayload(payload)})`);return}signals.writeGraphics(Buffer.from(p.data,"base64"));return}if(name==="notice.event"){let p=payload;if(typeof p?.title!=="string"||typeof p.at!=="number"||typeof p.kind!=="string"){logClientError("orch",`dropped notice.event: malformed payload (${describePayload(payload)})`);return}signals.setNoticeSig(p);return}if(name==="ui-prefs"){let decoded=decodeUiPrefsPayload(payload);if(!decoded){let theme=payload?.theme;logClientError("orch",`dropped ui-prefs event: theme must be a string (got ${describePayload(theme)})`);return}signals.setUiPrefsSig(decoded);return}if(name==="state"||name==="machines"){signals.setRawSig(name,payload);return}if(name==="keybindings"){let p=payload;if(typeof p?.rev!=="number"){logClientError("orch",`dropped keybindings event: rev must be a number (got ${describePayload(p?.rev)})`);return}signals.setKeybindingsRevSig(p.rev)}}function subscribeTasksOp(tasks,listener){try{listener(tasks())}catch(err){console.error("[rove RemoteOrchestrator] task listener threw on subscribe:",err)}return tasks.subscribe(()=>{try{listener(tasks.get())}catch(err){console.error("[rove RemoteOrchestrator] task listener threw:",err)}})}class RowStatusChannel{client;listeners=new Set;constructor(client){this.client=client}emit=(payload)=>{for(let listener of this.listeners)listener(payload)};onChanged=(listener)=>{return this.listeners.add(listener),()=>this.listeners.delete(listener)};list=()=>this.client.request("status.list");viewing=(taskId,tabId)=>this.client.request("ui.viewing",taskId===null?{taskId:null}:{taskId,...tabId?{tabId}:{}});answered=(taskId,tabId)=>this.client.request("activity.answered",{taskId,tabId})}class TabsChannel{client;listeners=new Set;constructor(client){this.client=client}emit=(event)=>{for(let listener of this.listeners)listener(event)};onChanged=(listener)=>{return this.listeners.add(listener),()=>this.listeners.delete(listener)};apply=(taskId,ops)=>this.client.request("tabs.apply",{taskId,ops});list=()=>this.client.request("tabs.list");reserve=(taskId,count)=>this.client.request("tabs.reserve",{taskId,count});release=(taskId,from,to)=>this.client.request("tabs.release",{taskId,from,to})}async function createTaskOp(client,input){let{modelEffort,...rest}=input,res=await client.request("task.create",{...rest,effort:modelEffort});return deserializeTask(res.task)}async function ensureMainTaskOp(client,repo){let res=await client.request("task.ensureMain",{repo});return deserializeTask(res.task)}async function openDirectoryTaskOp(client,input){let res=await client.request("task.openDir",input);return deserializeTask(res.task)}async function adoptScratchRepoOp(client,id,repo){await client.request("task.adoptScratchRepo",{taskId:String(id),repo})}async function moveTaskToProjectOp(client,id,repo){let res=await client.request("task.moveToProject",{taskId:String(id),repo});return{repo:res.repo,moved:res.moved}}async function ensureWorktreeOp(client,id){return(await client.request("task.ensureWorktree",{taskId:String(id)})).worktreePath}async function forgetProjectOp(client,repo){await client.request("project.forget",{repo})}function reportEngineInterruptOp(client,taskId,tabId){client.request("engine.reportEvent",{kind:"turn-interrupted",taskId,tabId}).catch(()=>{})}async function setTitleOp(client,id,title){await client.request("task.rename",{taskId:String(id),title})}async function setBranchOp(client,id,branch){await client.request("task.setBranch",{taskId:String(id),branch})}async function setVendorOp(client,id,vendor,effort,model){await client.request("task.setVendor",{taskId:String(id),vendor,...effort!==void 0?{effort}:{},...model!==void 0?{model}:{}})}async function setCommandOp(client,id,command,vendor){await client.request("task.setCommand",{taskId:String(id),command,...vendor?{vendor}:{}})}async function setPinnedOp(client,id,pinned){await client.request("task.pin",{taskId:String(id),pinned})}async function archiveTaskOp(client,id,archived,force=!1){await client.request("task.archive",{taskId:String(id),archived,force})}async function moveTaskOp(client,id,delta){await client.request("task.move",{taskId:String(id),direction:delta<0?"up":"down"})}async function moveTaskToTopOp(client,id){await client.request("task.move",{taskId:String(id),direction:"top"})}async function setPromptOp(client,id,prompt){await client.request("task.setPrompt",{taskId:String(id),prompt})}async function setStatusOp(client,id,status){await client.request("task.status",{taskId:String(id),status})}async function deleteTaskOp(client,id,opts){return client.request("task.delete",{taskId:String(id),force:opts?.force,deleteBranch:opts?.deleteBranch,cascade:opts?.cascade})}async function spawnChildTaskOp(client,input){let{dispatcher,...rest}=input,res=await client.request("task.spawn",{...rest,...dispatcher?{dispatcherTaskId:dispatcher.taskId,dispatcherTabId:dispatcher.tabId}:{}});return{task:deserializeTask(res.task),parentDirty:res.parentDirty,sharedLinks:res.sharedLinks}}async function dismissAttentionOp(client,taskId,tabId,at,deliveryId){return(await client.request("attention.dismiss",{taskId:String(taskId),...tabId!==null?{tabId}:{},at,...deliveryId!==void 0?{deliveryId}:{}})).deleted}async function dismissRoutineAttentionOp(client,automationId){return(await client.request("attention.dismissRoutine",{automationId})).deleted}async function answerGateOp(client,gateId,answer){return{delivered:(await client.request("gate.answer",{gateId,...answer,by:"tui"})).delivered}}async function withdrawGateOp(client,gateId){await client.request("gate.withdraw",{gateId})}async function markAttentionReadOp(client,taskId,tabId,at){return(await client.request("attention.read",{taskId:String(taskId),...tabId!==null?{tabId}:{},at})).updated}async function landPreflightOp(client,id){return(await client.request("task.landPreflight",{taskId:String(id)})).result}async function landTaskOp(client,id,opts){return(await client.request("task.land",{taskId:String(id),strategy:opts?.strategy,deleteBranch:opts?.deleteBranch,removeWorktree:opts?.removeWorktree,callerCwd:opts?.callerCwd})).result}async function discoverAdoptableWorktreesOp(client,repo){return(await client.request("worktree.discoverAdoptable",{repo})).worktrees}async function adoptWorktreeOp(client,input){let res=await client.request("worktree.adopt",input);return deserializeTask(res.task)}async function listWorktreesOp(client,opts){return(await client.request("worktree.list",{network:opts?.network!==!1})).projects}async function removeWorktreeOp(client,path,force){return(await client.request("worktree.remove",{path,force})).residue??null}async function syncBaseOp(client,taskId){let res=await client.request("task.syncBase",{taskId}),failed=res.result.repos?.find((r)=>!r.ok);if(failed)throw Error(failed.error??"sync failed");return res.result}async function failingChecksOp(client,taskId){let res=await client.request("pr.failingChecks",{taskId});return{checks:res.checks??[],totalFailing:res.totalFailing??0,...res.unavailable?{unavailable:res.unavailable}:{}}}async function rerunFailedChecksOp(client,taskId){let res=await client.request("pr.rerunFailedChecks",{taskId});return{rerunRuns:res.rerunRuns??0,external:res.external??0,...res.refused?{refused:res.refused}:{},...res.unavailable?{unavailable:res.unavailable}:{}}}async function listIssuesOp(client,repoRoot){return client.request("issue.list",{repoRoot})}async function listIssueReposOp(client){return(await client.request("issue.repos",{})).repos??[]}async function listFieldNotesOp(client,repo){return(await client.request("note.list",{repo})).notes??[]}async function deleteFieldNoteOp(client,repo,id){return(await client.request("note.delete",{repo,id})).deleted===!0}async function mutateIssueOp(client,repoRoot,op){return client.request("issue.mutate",{repoRoot,op})}async function listAutomationsOp(client){return client.request("automation.list",{})}async function createAutomationOp(client,input){return client.request("automation.create",input)}async function automationRunsOp(client,id){return client.request("automation.runs",{id})}async function setAutomationEnabledOp(client,id,enabled){return client.request("automation.update",{id,enabled})}async function runAutomationNowOp(client,id){return client.request("automation.runNow",{id})}async function deleteAutomationOp(client,id){return client.request("automation.delete",{id})}async function listWorkItemsOp(client,args){return client.request("workitem.list",args)}async function startWorkItemOp(client,args){return client.request("workitem.start",args)}async function setActiveTaskOp(client,id){await client.request("task.setActive",{taskId:id===null?null:String(id)})}function replyTabCloseOp(client,requestId,closed){client.request("terminalTab.closeReply",{requestId,closed}).catch(()=>{})}function replyPromptOp(client,promptId,value){client.request("ui.promptReply",{promptId,...value!==void 0?{value}:{}}).catch(()=>{})}function reportUiEventOp(client,kind,taskId,detail){client.request("ui.reportEvent",{kind,...taskId?{taskId}:{},...detail?{detail}:{}}).catch(()=>{})}function recentTaskEventsOp(client,id){return client.request("task.recentEvents",{taskId:String(id)})}class RemoteOrchestrator{client;tasksAcc=createStateCell([],"orchestrator.tasks");activeTaskAcc=createStateCell(null,"orchestrator.active-task");updateAcc=createStateCell(null);daemonVersionAcc=createStateCell(null);daemonRestartingAcc=createStateCell(!1);daemonStaleAcc=mapReadableState(this.daemonVersionAcc,(version)=>isDaemonVersionStale(version??void 0,CURRENT_VERSION));engineStateAcc=createStateCell(new Map);engineTabStateAcc=createStateCell(new Map);attentionInboxAcc=createStateCell([]);gatesAcc=createStateCell([]);taskJobsAcc=createStateCell(new Map);rowTokensAcc=createStateCell(new Map);modPanesAcc=createStateCell([]);worktreeChangesAcc=createStateCell(null);usageSnapshotAcc=createStateCell(null);contextUsageAcc=createStateCell(null);transcriptActivityAcc=createStateCell(null);noticeAcc=createStateCell(null);tabOpenAcc=createStateCell(null);tabCloseAcc=createStateCell(null);tabRenameAcc=createStateCell(null);tabAddAcc=createStateCell(null);tabs;rowStatus;uiPromptAcc=createStateCell(null);engineLifecycleAcc=createStateCell(new Map);uiPrefsAcc=createStateCell(null);rawAcc={state:createStateCell(null),machines:createStateCell(null)};keybindingsRevAcc=createStateCell(null);connectionStateAcc=createStateCell("online","orchestrator.connection");staleInstallAcc=createStateCell(null);ensureReachable;role;cellPixelSize;channels;subscribesTasks;expectForeignHome;onPeerIdentity;reconnectLoop;signals;constructor(client,options={}){this.client=client;this.ensureReachable=options.ensureReachable??ensureDaemonReachable,this.role=options.role??"pane",this.cellPixelSize=options.cellPixelSize??null,this.channels=options.channels,this.subscribesTasks=!options.channels||options.channels.includes("task.snapshot"),this.expectForeignHome=options.expectForeignHome===!0,this.onPeerIdentity=options.onPeerIdentity,this.reconnectLoop=singleFlightReconnect({isDisposed:()=>client.isDisposed,ensureReachable:this.ensureReachable,init:()=>this.init(),shouldLogAttempt:shouldLogReconnectAttempt,onFatal:(err)=>this.staleInstallAcc.set(err instanceof Error?err.message:String(err))}),this.tabs=new TabsChannel(client),this.rowStatus=new RowStatusChannel(client),this.signals={writeGraphics:options.graphicsOut??(this.role==="gui"?writeGraphicsToStdout:()=>{}),tasksAcc:this.tasksAcc,setTasks:this.tasksAcc.set,setActiveTaskSig:this.activeTaskAcc.set,setUpdateSig:this.updateAcc.set,setDaemonVersionSig:this.daemonVersionAcc.set,setDaemonRestartingSig:this.daemonRestartingAcc.set,engineStateAcc:this.engineStateAcc,setEngineStateSig:this.engineStateAcc.set,engineTabStateAcc:this.engineTabStateAcc,setEngineTabStateSig:this.engineTabStateAcc.set,setAttentionInboxSig:this.attentionInboxAcc.set,setGatesSig:this.gatesAcc.set,taskJobsAcc:this.taskJobsAcc,setTaskJobsSig:this.taskJobsAcc.set,rowTokensAcc:this.rowTokensAcc,setRowTokensSig:this.rowTokensAcc.set,modPanesAcc:this.modPanesAcc,setModPanesSig:this.modPanesAcc.set,worktreeChangesAcc:this.worktreeChangesAcc,setWorktreeChangesSig:this.worktreeChangesAcc.set,usageSnapshotAcc:this.usageSnapshotAcc,setUsageSnapshotSig:this.usageSnapshotAcc.set,contextUsageAcc:this.contextUsageAcc,setContextUsageSig:this.contextUsageAcc.set,transcriptActivityAcc:this.transcriptActivityAcc,setTranscriptActivitySig:this.transcriptActivityAcc.set,setNoticeSig:this.noticeAcc.set,setTabOpenSig:this.tabOpenAcc.set,setTabCloseSig:this.tabCloseAcc.set,setTabRenameSig:this.tabRenameAcc.set,setTabAddSig:this.tabAddAcc.set,emitTabsChanged:this.tabs.emit,emitRowStatus:this.rowStatus.emit,setUiPromptSig:this.uiPromptAcc.set,engineLifecycleAcc:this.engineLifecycleAcc,setEngineLifecycleSig:this.engineLifecycleAcc.set,setUiPrefsSig:this.uiPrefsAcc.set,setRawSig:(name,payload)=>this.rawAcc[name].set(payload),setKeybindingsRevSig:this.keybindingsRevAcc.set,setConnectionState:this.connectionStateAcc.set},this.client.on("*",(frame)=>handleOrchestratorEvent(frame.name,frame.payload,this.signals)),this.client.onLifecycle("close",()=>{this.connectionStateAcc.set("disconnected");let spawnDaemon=this.role==="gui";logClient("orch",spawnDaemon?"daemon socket closed \u2014 starting silent spawning reconnect loop":"daemon socket closed \u2014 starting non-spawning reconnect loop"),this.reconnectLoop(spawnDaemon)})}writeGraphics(data){this.signals.writeGraphics(data)}async init(){await performInit(this.client,{role:this.role,cellPixelSize:this.cellPixelSize,channels:this.channels,subscribesTasks:this.subscribesTasks,expectForeignHome:this.expectForeignHome,onPeerIdentity:this.onPeerIdentity},this.signals)}connectionStateSignal(){return this.connectionStateAcc}staleInstallSignal(){return this.staleInstallAcc}async manualReconnect(){this.client.forceDisconnect(),await this.reconnectLoop(!0)}dispose(){this.client.close()}tasksSignal=()=>this.tasksAcc;activeTaskSignal=()=>this.activeTaskAcc;updateSignal=()=>this.updateAcc;daemonVersionSignal=()=>this.daemonVersionAcc;daemonStaleSignal=()=>this.daemonStaleAcc;daemonRestartingSignal=()=>this.daemonRestartingAcc;async restartDaemon(){await this.client.request("daemon.stop",{reason:"restart"}).catch(()=>{})}engineStateSignal=()=>this.engineStateAcc;engineTabStatesSignal=()=>this.engineTabStateAcc;attentionInboxSignal=()=>this.attentionInboxAcc;gatesSignal=()=>this.gatesAcc;taskJobsSignal=()=>this.taskJobsAcc;rowTokensSignal=()=>this.rowTokensAcc;modPanesSignal=()=>this.modPanesAcc;pressMod=(plugin,pane,key)=>this.client.request("mod.press",{plugin,pane,key});submitMod=(plugin,pane,key,value)=>this.client.request("mod.submit",{plugin,pane,key,value});worktreeChangesSignal=()=>this.worktreeChangesAcc;usageSnapshotSignal=()=>this.usageSnapshotAcc;contextUsageSignal=()=>this.contextUsageAcc;transcriptActivitySignal=()=>this.transcriptActivityAcc;transcriptActivityStore=()=>this.transcriptActivityAcc;noticeStore=()=>this.noticeAcc;tabOpenStore=()=>this.tabOpenAcc;tabCloseStore=()=>this.tabCloseAcc;tabRenameStore=()=>this.tabRenameAcc;tabAddStore=()=>this.tabAddAcc;rpc={request:(name,payload)=>this.client.request(name,payload)};replyTerminalTabClose=(requestId,closed)=>replyTabCloseOp(this.client,requestId,closed);uiPromptStore=()=>this.uiPromptAcc;replyPrompt=(promptId,value)=>replyPromptOp(this.client,promptId,value);engineLifecycleSignal=()=>this.engineLifecycleAcc;recentTaskEvents(id){return recentTaskEventsOp(this.client,id)}reportUiEvent=(kind,taskId,detail)=>reportUiEventOp(this.client,kind,taskId,detail);reportScreenInput=async(taskId,tabId,blocked)=>{await this.client.request("engine.reportEvent",{source:"screen",taskId,tabId,blocked})};reportEngineInterrupt=(taskId,tabId)=>reportEngineInterruptOp(this.client,String(taskId),tabId);uiPrefsSignal=()=>this.uiPrefsAcc;uiPrefsStore=()=>this.uiPrefsAcc;rawChannelSignal=(name)=>this.rawAcc[name];keybindingsRevSignal=()=>this.keybindingsRevAcc;keybindingsRevStore=()=>this.keybindingsRevAcc;listTasks=()=>this.tasksAcc();getTask=(id)=>this.tasksAcc().find((task)=>task.id===id);subscribeTasks(listener){return subscribeTasksOp(this.tasksAcc,listener)}createTask=(input)=>createTaskOp(this.client,input);ensureMainTask=(repo)=>ensureMainTaskOp(this.client,repo);openDirectoryTask=(input)=>openDirectoryTaskOp(this.client,input);adoptScratchRepo=(id,repo)=>adoptScratchRepoOp(this.client,id,repo);moveTaskToProject=(id,repo)=>moveTaskToProjectOp(this.client,id,repo);ensureWorktree=(id)=>ensureWorktreeOp(this.client,id);forgetProject=(repo)=>forgetProjectOp(this.client,repo);setTitle=(id,title)=>setTitleOp(this.client,id,title);setBranch=(id,branch)=>setBranchOp(this.client,id,branch);setVendor=(id,vendor,effort,model)=>setVendorOp(this.client,id,vendor,effort,model);setCommand=(id,command,vendor)=>setCommandOp(this.client,id,command,vendor);setPinned=(id,pinned)=>setPinnedOp(this.client,id,pinned);archiveTask=(id,archived,force)=>archiveTaskOp(this.client,id,archived,force);moveTask=(id,delta)=>moveTaskOp(this.client,id,delta);moveTaskToTop=(id)=>moveTaskToTopOp(this.client,id);setStatus=(id,status)=>setStatusOp(this.client,id,status);setPrompt=(id,prompt)=>setPromptOp(this.client,id,prompt);deleteTask=(id,opts)=>deleteTaskOp(this.client,id,opts);spawnChildTask=(input)=>spawnChildTaskOp(this.client,input);dismissAttention=(taskId,tabId,at,deliveryId)=>dismissAttentionOp(this.client,taskId,tabId,at,deliveryId);dismissRoutineAttention=(automationId)=>dismissRoutineAttentionOp(this.client,automationId);markAttentionRead=(taskId,tabId,at)=>markAttentionReadOp(this.client,taskId,tabId,at);answerGate=(gateId,answer)=>answerGateOp(this.client,gateId,answer);withdrawGate=(gateId)=>withdrawGateOp(this.client,gateId);landPreflight(id){return landPreflightOp(this.client,id)}landTask(id,opts){return landTaskOp(this.client,id,opts)}discoverAdoptableWorktrees(repo){return discoverAdoptableWorktreesOp(this.client,repo)}adoptWorktree(input){return adoptWorktreeOp(this.client,input)}listWorktrees(opts){return listWorktreesOp(this.client,opts)}listIssues(repoRoot){return listIssuesOp(this.client,repoRoot)}listIssueRepos(){return listIssueReposOp(this.client)}mutateIssue(repoRoot,op){return mutateIssueOp(this.client,repoRoot,op)}listAutomations=()=>listAutomationsOp(this.client);createAutomation=(i)=>createAutomationOp(this.client,i);automationRuns=(id)=>automationRunsOp(this.client,id);setAutomationEnabled=(id,on)=>setAutomationEnabledOp(this.client,id,on);runAutomationNow=(id)=>runAutomationNowOp(this.client,id);deleteAutomation=(id)=>deleteAutomationOp(this.client,id);listWorkItems=(a)=>listWorkItemsOp(this.client,a);listFieldNotes=(repo)=>listFieldNotesOp(this.client,repo);deleteFieldNote=(repo,id)=>deleteFieldNoteOp(this.client,repo,id);failingChecks=(taskId)=>failingChecksOp(this.client,taskId);rerunFailedChecks=(taskId)=>rerunFailedChecksOp(this.client,taskId);syncBase=(taskId)=>syncBaseOp(this.client,taskId);startWorkItem=(a)=>startWorkItemOp(this.client,a);removeWorktree(path,force){return removeWorktreeOp(this.client,path,force)}setActiveTask(id){return setActiveTaskOp(this.client,id)}}
|
|
3
3
|
export{liveRowTokens,adoptTabs,absorbTab,RemoteOrchestrator};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{formatBytes}from"./chunk-my20q579.js";import{hookConfigIssues}from"./chunk-p2cbtrzg.js";import{applyFixes,daemonRestartFix,defaultFixRuntime,engineTabsManualFix,humanOnlyFix,killOrphansManualFix,noEngineFix,reinstallManualFix,resetManualFix,skillInstallFix,spawnHelperFix}from"./chunk-am5cpb9n.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-gkdfct7t.js";import"./chunk-nrx8pf9p.js";import"./chunk-1g6vhgfe.js";import"./chunk-a4hsqj1b.js";import"./chunk-6hcyvg0m.js";import{skillOverview}from"./chunk-y7mjhjby.js";import"./chunk-tq0h3vy6.js";import"./chunk-cpgnm1xr.js";import"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{describeAccount,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-zpxpwgds.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-vp29jgbt.js";import"./chunk-gq36nzg8.js";import{resolveNodeBinary}from"./chunk-z43e08kw.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import{formatDaemonInfo}from"./chunk-rxqdw6s5.js";import"./chunk-rjq38twt.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-tn9gtf18.js";import{isStaleInstallError,resolveRoveSpawn}from"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-5rgrde6b.js";import"./chunk-4gjvmfa9.js";import"./chunk-2tfnscxk.js";import"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-2w228s7t.js";import"./chunk-etfh8f4z.js";import"./chunk-rfp0ayra.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-kg9kmwt9.js";import{CURRENT_VERSION,package_default}from"./chunk-
|
|
2
|
+
import{formatBytes}from"./chunk-my20q579.js";import{hookConfigIssues}from"./chunk-p2cbtrzg.js";import{applyFixes,daemonRestartFix,defaultFixRuntime,engineTabsManualFix,humanOnlyFix,killOrphansManualFix,noEngineFix,reinstallManualFix,resetManualFix,skillInstallFix,spawnHelperFix}from"./chunk-am5cpb9n.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-gkdfct7t.js";import"./chunk-nrx8pf9p.js";import"./chunk-1g6vhgfe.js";import"./chunk-a4hsqj1b.js";import"./chunk-6hcyvg0m.js";import{skillOverview}from"./chunk-y7mjhjby.js";import"./chunk-tq0h3vy6.js";import"./chunk-cpgnm1xr.js";import"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{describeAccount,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-zpxpwgds.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-vp29jgbt.js";import"./chunk-gq36nzg8.js";import{resolveNodeBinary}from"./chunk-z43e08kw.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import{formatDaemonInfo}from"./chunk-rxqdw6s5.js";import"./chunk-rjq38twt.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-tn9gtf18.js";import{isStaleInstallError,resolveRoveSpawn}from"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-5rgrde6b.js";import"./chunk-4gjvmfa9.js";import"./chunk-2tfnscxk.js";import"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-2w228s7t.js";import"./chunk-etfh8f4z.js";import"./chunk-rfp0ayra.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-kg9kmwt9.js";import{CURRENT_VERSION,package_default}from"./chunk-2wrt80ft.js";import"./chunk-zsfyj36g.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import{t}from"./chunk-nqwza8b0.js";import"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import{RoveDaemonClient,isForeignDaemonHome}from"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import{readableLegacyIndexPath}from"./chunk-hz1x3hak.js";import"./chunk-x1jxxmtc.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import{readPidFile}from"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import{homeDir,kvStatePath,roveStateDir}from"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-eqdbfgq5.js";import{preRenameStateDir}from"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__require}from"./chunk-91sykzqq.js";import{existsSync,readFileSync as readFileSync2,statSync as statSync2}from"fs";import{join as join2}from"path";var MIN_BUN_VERSION=package_default.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0";function parseBunVersion(raw){return raw.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function isBunAtLeast(raw,minimum=MIN_BUN_VERSION){let found=parseBunVersion(raw),floor=parseBunVersion(minimum);if(!found||!floor)return!0;let a=found.split(".").map(Number),b=floor.split(".").map(Number);for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(av!==bv)return av>bv}return!0}function classifyHookChannel(input){let total=0,hooked=0;for(let tabs of Object.values(input.tabs))for(let entry of Object.values(tabs))if(total++,entry.source==="hook")hooked++;if(total===0)return{kind:"no-tabs"};if(hooked===0)return{kind:"down",totalTabs:total};return{kind:"live",hookTabs:hooked,totalTabs:total}}function hookChannelDoctorLines(verdict,input,cliName){let configLines=(input.configIssues??[]).flatMap((issue)=>[` \u26A0 hook install skipped: ${issue.file}`,` ${issue.reason} \u2014 fix the file, then relaunch Rove`]);if(verdict.kind==="no-tabs")return["hooks: \u2014 no engine tabs yet (nothing to check)",...configLines];if(verdict.kind==="live")return[`hooks: \u2713 engine hook channel live (${verdict.hookTabs}/${verdict.totalTabs} tab(s) hook-sourced)`,...configLines];let out=[`hooks: \u2717 NO hook events reaching the daemon (0/${verdict.totalTabs} tab(s) hook-sourced)`," badges fall back to a ~10s poll, so activity looks seconds late",` daemon socket: ${input.socketPath}`,...configLines];return out.push(' \u2192 compare with an engine tab\'s own path: `ps eww -p <engine-pid> | tr " " "\\n" | grep DAEMON_SOCKET_PATH`',` \u2192 restart the engine tabs (they may hold a stale socket path), or run \`${cliName} daemon restart\``,` \u2192 debug one hook directly: \`ROVE_HOOK_DEBUG=1 echo '{}' | ${cliName} hook turn-start --engine claude\``),out}import{readdirSync,statSync}from"fs";import{createRequire}from"module";import{dirname,join}from"path";function installedSpawnHelpers(){let pkg;try{pkg=dirname(createRequire(import.meta.url).resolve("node-pty/package.json"))}catch{return[]}let prebuilds=join(pkg,"prebuilds"),arches;try{arches=readdirSync(prebuilds).filter((name)=>name.startsWith("darwin-"))}catch{return[]}let helpers=[];for(let arch of arches){let path=join(prebuilds,arch,"spawn-helper");try{helpers.push({path,executable:(statSync(path).mode&64)!==0})}catch{}}return helpers}function spawnHelperDoctorLines(helpers){let broken=helpers.filter((helper)=>!helper.executable).map((helper)=>helper.path);if(helpers.length===0)return{lines:["node-pty: ? no darwin spawn-helper found next to node-pty"],broken};if(broken.length===0)return{lines:[`node-pty: \u2713 spawn-helper executable (${helpers.length} arch)`],broken};return{lines:["node-pty: \u2717 spawn-helper is not executable \u2014 every node-pty PTY spawn fails",...broken.map((path)=>` ${path}`),` \u2192 chmod 755 ${broken.join(" ")}`],broken}}import{appendFileSync,readFileSync}from"fs";var PTY_MARKER="ROVE_TERMINAL_PTY=1",run=async(argv)=>{try{let proc=Bun.spawn([...argv],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),[stdout,code]=await Promise.all([new Response(proc.stdout).text().catch(()=>""),proc.exited]);return{code,stdout}}catch{return{code:127,stdout:""}}};function parsePsRows(output){let rows=[];for(let line of output.split(`
|
|
3
3
|
`)){let parts=line.trim().split(/\s+/);if(parts.length<6)continue;let[pid,ppid,pgid]=[parts[0],parts[1],parts[2]].map((value)=>Number.parseInt(value??"",10)),rssKb=Number.parseInt(parts[4]??"",10);if(!Number.isFinite(pid)||!Number.isFinite(ppid)||!Number.isFinite(pgid)||!Number.isFinite(rssKb))continue;rows.push({pid,ppid,pgid,etime:parts[3]??"",rssKb,command:parts.slice(5).join(" ")})}return rows}function pidAlive(pid,rows){return rows.some((row)=>row.pid===pid)}function orphanCandidates(rows,selfPgid,liveSessionPids){return rows.filter((row)=>row.ppid===1&&row.pgid!==selfPgid&&!liveSessionPids.has(row.pgid)&&!pidAlive(row.pgid,rows))}async function markedPids(pids,deps={}){let runProbe=deps.run??run,readEnviron=deps.readEnviron??((pid)=>readFileSync(`/proc/${pid}/environ`,"utf8")),marked=new Set;if(pids.length===0)return{marked,failed:null};if((deps.platform??process.platform)==="linux"){let refused=null;for(let pid of pids)try{if(readEnviron(pid).split("\x00").includes(PTY_MARKER))marked.add(pid)}catch(err){let code=err.code;if(code!=="ENOENT"&&code!=="ESRCH")refused??=`/proc/${pid}/environ: ${code??"unreadable"}`}return{marked,failed:refused}}let result=await runProbe(["ps","eww","-o","pid=,command=","-p",pids.join(",")]);if(result.code!==0)return{marked,failed:`ps eww exited ${result.code}`};let marker=new RegExp(`(^|\\s)${PTY_MARKER}(\\s|$)`);for(let line of result.stdout.split(`
|
|
4
4
|
`)){let pid=Number.parseInt(line.trim().split(/\s+/)[0]??"",10);if(Number.isFinite(pid)&&marker.test(line))marked.add(pid)}return{marked,failed:null}}async function ownPgid(runProbe){let result=await runProbe(["ps","-o","pgid=","-p",String(process.pid)]),pgid=Number.parseInt(result.stdout.trim(),10);return Number.isFinite(pgid)?pgid:-1}async function collectOrphans(liveSessionPids,deps={}){let runProbe=deps.run??run;if((deps.platform??process.platform)==="win32")return{orphans:[],error:null};let ps=await runProbe(["ps","-A","-o","pid=,ppid=,pgid=,etime=,rss=,command="]);if(ps.code!==0)return{orphans:[],error:`could not read the process table \u2014 ps exited ${ps.code}`};let rows=parsePsRows(ps.stdout),candidates=orphanCandidates(rows,await ownPgid(runProbe),liveSessionPids),{marked,failed}=await markedPids(candidates.map((row)=>row.pid),deps);if(failed)return{orphans:[],error:`could not read process environments \u2014 ${failed}`};return{orphans:candidates.filter((row)=>marked.has(row.pid)),error:null}}function formatMb(rssKb){return`${(rssKb/1024).toFixed(0)} MB`}function orphanDoctorLines(orphans,error,cliName,killing=!1){if(error)return[`orphans: \u2717 ${error}`];if(orphans.length===0)return["orphans: \u2713 none \u2014 no processes left behind by a dead PTY session"];let totalMb=orphans.reduce((sum,row)=>sum+row.rssKb,0)/1024,lines=[`orphans: \u26A0 ${orphans.length} process(es) outlived the PTY session that spawned them (${totalMb.toFixed(0)} MB RSS)`," each is reparented to init, carries Rove's PTY marker, and its process"," group leader is gone \u2014 no live task owns them"];for(let row of[...orphans].sort((a,b)=>b.rssKb-a.rssKb))lines.push(` pid ${row.pid} (group ${row.pgid}) up ${row.etime}, ${formatMb(row.rssKb)}: ${row.command.slice(0,90)}`);if(!killing)lines.push(` \u2192 \`${cliName} doctor --kill-orphans\` ends those process groups (SIGTERM, then SIGKILL)`," read the list first: something you backgrounded from a Rove terminal and then"," closed the tab on looks exactly like a leak, and doctor cannot tell them apart");return lines}var GROUP_EXIT_GRACE_MS=2000,GROUP_POLL_MS=100;function logOrphanKill(pgid,signal,logPath=defaultDaemonLogPath()){try{appendFileSync(logPath,formatDaemonInfo("doctor-kill-orphans",`${signal} process group ${pgid}`))}catch{}}function groupAlive(pgid){try{return process.kill(-pgid,0),!0}catch(err){return err.code!=="ESRCH"}}async function killOrphanGroups(orphans){let groups=[...new Set(orphans.map((row)=>row.pgid))];for(let pgid of groups)try{process.kill(-pgid,"SIGTERM"),logOrphanKill(pgid,"SIGTERM")}catch{}let deadline=Date.now()+GROUP_EXIT_GRACE_MS,survivors=groups.filter(groupAlive);while(survivors.length>0&&Date.now()<deadline)await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),survivors=survivors.filter(groupAlive);for(let pgid of survivors)try{process.kill(-pgid,"SIGKILL"),logOrphanKill(pgid,"SIGKILL")}catch{}return await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),{groups,survivors:survivors.filter(groupAlive)}}function multiplexerLabel(env){if(env.TMUX)return"tmux";if(env.ZELLIJ)return"zellij";if(env.STY)return"screen";return"no"}function terminalEnvLines(env){let show=(v)=>v&&v.length>0?v:"(unset)",program=env.TERM_PROGRAM?`${env.TERM_PROGRAM}${env.TERM_PROGRAM_VERSION?` v${env.TERM_PROGRAM_VERSION}`:""}`:"(unset)";return[`terminal: TERM=${show(env.TERM)} TERM_PROGRAM=${program} COLORTERM=${show(env.COLORTERM)}`,` running inside a multiplexer: ${multiplexerLabel(env)}`]}function parseKittyProbeReply(data){let kitty=data.match(/\x1b\[\?(\d+)u/);if(kitty?.[1]!==void 0)return{kind:"supported",flags:Number.parseInt(kitty[1],10)};if(/\x1b\[\?[\d;]*c/.test(data))return{kind:"unsupported"};return null}function kittyProbeLine(result){switch(result.kind){case"supported":return` kitty keyboard protocol: \u2713 answered (flags=${result.flags})`;case"unsupported":return[" kitty keyboard protocol: \u2717 not supported \u2014 legacy key path"," (ctrl+h/ctrl+j arrive as C0 backspace/linefeed bytes; the"," split chords ctrl+\\ and ctrl+= cannot be encoded at all)"].join(`
|
|
5
5
|
`);case"no-response":return" kitty keyboard protocol: ? no reply (terminal ignored both the kitty query and DA1)";case"skipped":return` kitty keyboard protocol: skipped (${result.reason})`}}async function probeKittyKeyboard(timeoutMs=300){let stdin=process.stdin;if(!stdin.isTTY||!process.stdout.isTTY)return{kind:"skipped",reason:"not an interactive terminal"};let wasRaw=stdin.isRaw===!0,buffer="";return await new Promise((resolve)=>{let done=!1,finish=(result)=>{if(done)return;if(done=!0,clearTimeout(timer),stdin.off("data",onData),stdin.pause(),!wasRaw)stdin.setRawMode(!1);resolve(result)},onData=(chunk)=>{buffer+=chunk.toString("latin1");let decided=parseKittyProbeReply(buffer);if(decided)finish(decided)},timer=setTimeout(()=>finish({kind:"no-response"}),timeoutMs);stdin.setRawMode(!0),stdin.resume(),stdin.on("data",onData),process.stdout.write("\x1B[?u\x1B[c")})}async function terminalDoctorLines(){return[...terminalEnvLines(process.env),kittyProbeLine(await probeKittyKeyboard())]}async function probeGit(){try{let proc=Bun.spawn(["git","--version"],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),text=(await new Response(proc.stdout).text()).trim();if(await proc.exited===0&&text)return{line:`git: \u2713 ${text}`,found:!0}}catch{}return{line:"git: \u2717 not found on PATH",found:!1}}function binaryLabel(binary){return binary.found?`\u2713 ${binary.path}`:`\u2717 ${binary.error}`}async function probeEngines(){let statuses=await detectEngineStatuses(await probeableEngineIds()),lines=["engines:"];for(let status of statuses){let account=describeAccount(status.account),name=`${status.vendor.padEnd(7)} `;if(lines.push(` ${name}${binaryLabel(status.binary)}${status.binary.found?` \u2014 ${account}`:""}`),status.accountError)lines.push(` \u26A0 ${status.accountError}`)}let{usable,signedOut}=summarizeEngines(statuses);return{lines,anyUsable:usable.length>0,signedOut}}var CLI_NAME=ROVE_PRODUCT_NAME;function isProcessAlive(pid){try{return process.kill(pid,0),!0}catch(err){return err.code==="EPERM"}}async function requestIfReachable(socketPath,name){let client=new RoveDaemonClient(socketPath);try{return await client.request(name,{})}catch{return null}finally{client.close()}}function fmtDuration(ms){let seconds=Math.floor(ms/1000);if(seconds<60)return`${seconds}s`;let minutes=Math.floor(seconds/60);if(minutes<60)return`${minutes}m ${seconds%60}s`;return`${Math.floor(minutes/60)}h ${minutes%60}m`}function describeFile(path){try{let stat=statSync2(path);return`present (${formatBytes(stat.size)}, modified ${stat.mtime.toISOString()})`}catch{return"absent"}}function taskCount(path){try{let parsed=JSON.parse(readFileSync2(path,"utf8"));return Array.isArray(parsed.tasks)?parsed.tasks.length:null}catch{return null}}function tailFile(path,count){try{return readFileSync2(path,"utf8").split(`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{stampResetGate}from"./chunk-
|
|
2
|
+
import{stampResetGate}from"./chunk-byh32qnx.js";import{stopLegacyTmux}from"./chunk-gkdfct7t.js";import{clearFrozenSessions}from"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import{stopDaemonProcess}from"./chunk-0a65j1zj.js";import"./chunk-2wrt80ft.js";import{errorMessage}from"./chunk-2brn8e1y.js";import"./chunk-32j6y5d1.js";import"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import{kvStatePath,legacyRoveKvStatePath,legacyRoveStateDir,roveStateDir}from"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyFreezeDir,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{readFileSync}from"fs";import{unlink}from"fs/promises";import{join}from"path";import{createInterface}from"readline";var CLI_NAME=ROVE_PRODUCT_NAME;function printUsage(out){out.write([`Usage: ${CLI_NAME} reset [--hard] [--yes]`,"","Recover a wedged install: stop the daemon, Hosted PTY host, and any pre-v0.8 tmux sessions.","This ends background terminal and engine sessions; the next launch starts fresh.","Never touches your git worktrees.","","Options:"," --hard Also DELETE the task index and the whole settings file"," (saved projects, custom engines, theme, language, onboarding)"," -y, --yes Skip the interactive confirmation. REQUIRED without a terminal;"," a non-interactive run without it exits 2 and changes nothing."," -h, --help Print this help",""].join(`
|
|
3
3
|
`))}function taskCount(path){try{let parsed=JSON.parse(readFileSync(path,"utf8"));return Array.isArray(parsed.tasks)?parsed.tasks.length:null}catch{return null}}function stateSummary(path){let parsed;try{parsed=JSON.parse(readFileSync(path,"utf8"))}catch{return[]}let count=(key)=>Array.isArray(parsed[key])?parsed[key].length:0,lines=[` saved projects: ${count("savedRepos")}`,` custom engines: ${count("customEngineIds")} (their launch commands live here and nowhere else)`],present=[["activeTheme","theme"],["defaultVendor","default engine"],["locale","language"],["onboarded","onboarding (the wizard runs again)"]].filter(([key])=>parsed[key]!==void 0).map(([,label])=>label);if(present.length>0)lines.push(` also set: ${present.join(", ")}`);return lines.push(` ${Object.keys(parsed).length} setting(s) in total`),lines}async function confirmTty(prompt){let readline=createInterface({input:process.stdin,output:process.stdout});try{let answer=await new Promise((resolve)=>readline.question(prompt,resolve));return/^y(es)?$/i.test(answer.trim())}finally{readline.close()}}async function removeStateFile(path,label){try{await unlink(path),console.log(` removed ${label} (${path})`)}catch(err){if(err.code==="ENOENT")console.log(` ${label}: already absent`);else throw Error(`failed to remove ${label} (${path}): ${errorMessage(err)}`)}}async function runResetSubcommand(argv){if(argv.some((arg)=>arg==="--help"||arg==="-h"||arg==="help")){printUsage(process.stdout);return}let known=new Set(["--hard","--yes","-y"]),unknown=argv.find((arg)=>!known.has(arg));if(unknown!==void 0)process.stderr.write(`${CLI_NAME} reset: unknown argument "${unknown}"
|
|
4
4
|
|
|
5
5
|
`),printUsage(process.stderr),process.exit(2);let hard=argv.includes("--hard"),yes=argv.includes("--yes")||argv.includes("-y"),daemonSocket=defaultDaemonSocketPath(),tasksPath=join(roveStateDir(),"tasks.json"),legacyTasksPath=join(legacyRoveStateDir(),"tasks.json"),statePath=kvStatePath(),legacyStatePath=legacyRoveKvStatePath();if(console.log(`${CLI_NAME} reset will:`),console.log(" \u2022 stop the Rove daemon (graceful \u2192 SIGTERM \u2192 SIGKILL)"),console.log(` \u2022 remove its socket + pidfile (${daemonSocket})`),console.log(" \u2022 stop the standalone Hosted PTY host and all background terminal/engine sessions"),console.log(" \u2022 stop any pre-v0.8 tmux sessions after SIGTERM-ing their pane process groups"),hard){let count=taskCount(tasksPath)??taskCount(legacyTasksPath);console.log(` \u2022 DELETE the task index${count===null?"":` (${count} task(s))`} \u2014 ${tasksPath}`),console.log(` \u2022 DELETE the whole settings file \u2014 ${statePath}`);for(let line of stateSummary(statePath))console.log(line);console.log(" \u2022 DELETE the pre-Rove task/UI indexes too, so migration cannot restore reset state")}if(console.log(" \u2022 NOT touch your git worktrees under ~/.rove/worktrees/ or existing repo-local roots"),!hard)console.log(" (your task list, settings & worktrees are kept \u2014 add --hard to also delete the task index and settings file)");if(!yes){if(!process.stdin.isTTY){console.log(`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{API_VERBS,VERBS,VERB_ALIASES,VERB_GROUPS,findVerb,unknownVerbError}from"./chunk-
|
|
2
|
+
import{API_VERBS,VERBS,VERB_ALIASES,VERB_GROUPS,findVerb,unknownVerbError}from"./chunk-txvjg1g9.js";import"./chunk-k2j0tg1h.js";import"./chunk-kdnk8m5j.js";import"./chunk-qcjkactr.js";import"./chunk-rjfdzjhj.js";import"./chunk-zpxpwgds.js";import"./chunk-agvtzads.js";import"./chunk-pm91e38v.js";import"./chunk-2xsxcdp6.js";import"./chunk-17e2tgyg.js";import"./chunk-1vxtd8rh.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-2pfh3zm0.js";import"./chunk-p11emdb2.js";import"./chunk-vytrhm50.js";import"./chunk-vp29jgbt.js";import"./chunk-gq36nzg8.js";import"./chunk-sq6zj3fb.js";import"./chunk-qkehg2c1.js";import"./chunk-s1xn6wav.js";import"./chunk-nv8eyjep.js";import"./chunk-z43e08kw.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import"./chunk-f7egph8g.js";import"./chunk-rxqdw6s5.js";import"./chunk-kxp04jnp.js";import"./chunk-3hxm56h6.js";import"./chunk-qecygh3f.js";import"./chunk-rjq38twt.js";import"./chunk-r5j8fycq.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-ggnq2vvk.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import"./chunk-y1xnjx8x.js";import"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-5rgrde6b.js";import"./chunk-4gjvmfa9.js";import"./chunk-2tfnscxk.js";import"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import"./chunk-9rj2fx6v.js";import"./chunk-rfp0ayra.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-kg9kmwt9.js";import"./chunk-6xppe9bj.js";import"./chunk-2wrt80ft.js";import"./chunk-zsfyj36g.js";import"./chunk-2r1fgng9.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import"./chunk-nqwza8b0.js";import"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import"./chunk-hz1x3hak.js";import"./chunk-x1jxxmtc.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import"./chunk-91sykzqq.js";export{unknownVerbError,findVerb,VERB_GROUPS,VERB_ALIASES,VERBS,API_VERBS};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{MachineHub}from"./chunk-
|
|
2
|
+
import{MachineHub}from"./chunk-rvjnafyt.js";import"./chunk-j54c5a0a.js";import"./chunk-6xr1prk6.js";import"./chunk-atn06ncf.js";import"./chunk-vytrhm50.js";import"./chunk-sq6zj3fb.js";import"./chunk-y1xnjx8x.js";import"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-0r1jf8m9.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-6xppe9bj.js";import"./chunk-2wrt80ft.js";import"./chunk-32j6y5d1.js";import"./chunk-cmp64q4j.js";import"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-7kysxgbq.js";import"./chunk-xy8be792.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";var PUBLISH_DEBOUNCE_MS=50;function startDaemonMachineHub(bus){let hub=new MachineHub,timer=null,publish=()=>{timer=null;let live=hub.liveSignal().get(),payload={machines:hub.machinesSignal().get(),tasks:hub.tasksSignal().get().map((task)=>({...task,kind:task.kind??"task",pinned:task.pinned??!1})),live:{activity:Object.fromEntries(live.activity),changes:Object.fromEntries(live.changes),tokens:Object.fromEntries(live.tokens)}};bus.publish("machines",payload)},schedule=()=>{timer??=setTimeout(publish,PUBLISH_DEBOUNCE_MS)},stops=[hub.machinesSignal(),hub.tasksSignal(),hub.liveSignal()].map((signal)=>signal.subscribe(schedule)),lastRegistry=null,offState=bus.onPublish((event)=>{if(event.channel!=="state")return;let state=event.payload.state,text=JSON.stringify(state.machines??null);if(text===lastRegistry)return;lastRegistry=text,hub.sync()});return hub.sync(),publish(),()=>{offState();for(let stop of stops)stop();if(timer)clearTimeout(timer);hub.dispose(),bus.publish("machines",{machines:[],tasks:[],live:{activity:{},changes:{},tokens:{}}})}}export{startDaemonMachineHub};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{ReleaseNotesBody,bootPaneHost,pageCloseBindings,runShellUpdater,useBindings,useT,useTheme}from"./chunk-
|
|
2
|
+
import{ReleaseNotesBody,bootPaneHost,pageCloseBindings,runShellUpdater,useBindings,useT,useTheme}from"./chunk-t7dyf50m.js";import"./chunk-x85rcep5.js";import{$jsx,$jsxs,useRenderer}from"./chunk-29kvfqeh.js";import{require_react_production}from"./chunk-2wd4744g.js";import"./chunk-j54c5a0a.js";import"./chunk-cpgnm1xr.js";import"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import"./chunk-764bsyb0.js";import"./chunk-w003rpr2.js";import"./chunk-atn06ncf.js";import"./chunk-f7egph8g.js";import"./chunk-rxqdw6s5.js";import"./chunk-kxp04jnp.js";import"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-0r1jf8m9.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-6xppe9bj.js";import{BREAKING_VERSIONS,CURRENT_VERSION,breakingVersionsCrossed,fetchReleaseNotes,fetchReleaseSummaries,updateCommandFor}from"./chunk-2wrt80ft.js";import"./chunk-2r1fgng9.js";import"./chunk-2brn8e1y.js";import"./chunk-32j6y5d1.js";import{currentLang}from"./chunk-nqwza8b0.js";import"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-xy8be792.js";import"./chunk-7ghwdjdc.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import{__toESM}from"./chunk-91sykzqq.js";import{TextAttributes}from"@opentui/core";var import_react2=__toESM(require_react_production(),1);var RELEASE_LIMIT=20;function VersionsPage(props){let{theme}=useTheme(),t=useT(),renderer=useRenderer(),[releases,setReleases]=import_react2.useState(null),[cursor,setCursor]=import_react2.useState(0),[notes,setNotes]=import_react2.useState({}),[status,setStatus]=import_react2.useState(null),selected=releases?.[cursor],crossings=selected?breakingVersionsCrossed(CURRENT_VERSION,selected.version):[],loadSummaries=props.fetchSummaries??fetchReleaseSummaries,loadNotes=props.fetchNotes??fetchReleaseNotes;import_react2.useEffect(()=>{loadSummaries(RELEASE_LIMIT).then((fetched)=>setReleases(fetched))},[loadSummaries]);let selectedVersion=selected?.version;import_react2.useEffect(()=>{if(selectedVersion===void 0||notes[selectedVersion]!==void 0)return;setNotes((cache)=>({...cache,[selectedVersion]:"loading"})),loadNotes(selectedVersion,currentLang()).then((fetched)=>{setNotes((cache)=>({...cache,[selectedVersion]:fetched??"missing"}))})},[selectedVersion,notes,loadNotes]);function move(delta){let count=releases?.length??0;if(count===0)return;setCursor((index)=>(index+delta+count)%count)}async function installSelected(){if(!selected)return;setStatus(t("update.statusRunningUpdater")),await new Promise((resolve)=>setTimeout(resolve,30)),await runShellUpdater({renderer,t,targetLabel:selected.version,command:updateCommandFor(selected.version)})}useBindings(()=>({bindings:[{key:"up",cmd:()=>move(-1)},{key:"down",cmd:()=>move(1)},{key:"k",cmd:()=>move(-1)},{key:"j",cmd:()=>move(1)},{key:"return",cmd:()=>void installSelected()},{key:"u",cmd:()=>void installSelected()},...pageCloseBindings(props.onClose)]}));let selectedNotes=selectedVersion===void 0?void 0:notes[selectedVersion];return $jsxs("box",{flexDirection:"column",flexGrow:1,paddingTop:1,paddingLeft:2,paddingRight:2,children:[$jsxs("box",{flexDirection:"row",justifyContent:"space-between",flexShrink:0,children:[$jsx("text",{fg:theme.text,attributes:TextAttributes.BOLD,wrapMode:"none",children:t("update.versions.pageTitle")}),$jsx("text",{fg:theme.textMuted,wrapMode:"none",onMouseUp:props.onClose,children:t("update.versions.closeHint")})]}),$jsxs("box",{flexDirection:"row",flexGrow:1,paddingTop:1,gap:2,children:[$jsxs("box",{flexDirection:"column",width:26,flexShrink:0,children:[releases===null?$jsx("text",{fg:theme.textMuted,children:t("update.versions.loading")}):null,releases!==null&&releases.length===0?$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("update.versions.unavailable")}):null,(releases??[]).map((release,index)=>{let active=index===cursor,tags=[release.version===CURRENT_VERSION?t("update.versions.tagCurrent"):"",index===0?t("update.versions.tagLatest"):"",BREAKING_VERSIONS.includes(release.version)?t("update.versions.tagBreaking"):""].filter(Boolean).join(" ");return $jsxs("box",{flexDirection:"row",gap:1,paddingLeft:1,backgroundColor:active?theme.primary:void 0,onMouseUp:()=>setCursor(index),children:[$jsxs("text",{fg:active?theme.selectedListItemText:theme.text,attributes:release.version===CURRENT_VERSION?TextAttributes.BOLD:void 0,wrapMode:"none",children:["v",release.version]}),tags?$jsx("text",{fg:active?theme.selectedListItemText:theme.textMuted,wrapMode:"none",children:tags}):null]},release.version)})]}),$jsxs("box",{flexDirection:"column",flexGrow:1,flexShrink:1,children:[$jsx("scrollbox",{flexGrow:1,flexShrink:1,stickyScroll:!1,verticalScrollbarOptions:{trackOptions:{foregroundColor:"transparent"}},children:$jsxs("box",{flexDirection:"column",paddingRight:1,paddingBottom:1,gap:0,children:[selectedNotes==="loading"?$jsx("text",{fg:theme.textMuted,children:t("update.loadingNotes")}):null,selectedNotes==="missing"?$jsx("text",{fg:theme.textMuted,wrapMode:"word",children:t("update.notesUnavailable")}):null,selectedNotes!==void 0&&selectedNotes!=="loading"&&selectedNotes!=="missing"?$jsx(ReleaseNotesBody,{body:selectedNotes.body}):null]})}),crossings.length>0?$jsx("text",{fg:theme.warning,wrapMode:"word",children:t("update.versions.breakingWarning",{versions:crossings.join(", ")})}):null]})]}),status?$jsx("text",{fg:theme.info,wrapMode:"word",children:status}):null,$jsx("box",{flexShrink:0,paddingTop:1,children:$jsx("text",{fg:theme.textMuted,attributes:TextAttributes.DIM,wrapMode:"none",children:t("update.versions.footerHint")})})]})}var INLINE_ROWS=24;async function startVersionsHost(){await bootPaneHost({inlineRows:INLINE_ROWS,setup:()=>({root:()=>$jsx(VersionsPage,{onClose:()=>process.exit(0)})})})}export{startVersionsHost,VersionsPage};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import{expandTilde}from"./chunk-2r1fgng9.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{pathSyntax}from"./chunk-pn5ygqn6.js";import{__require}from"./chunk-91sykzqq.js";import{statSync}from"fs";import{resolve}from"path";function isPathLikeArg(arg){return arg==="."||arg===".."||arg.startsWith("./")||arg.startsWith("../")||arg.startsWith(".\\")||arg.startsWith("..\\")||pathSyntax(arg).isAbsolute(arg)||arg.startsWith("/")||arg==="~"||arg.startsWith("~/")||arg.startsWith("~\\")}async function projectRootFor(dir){let{isGitRepo,resolveRepoRoot}=await import("./chunk-hv79ys32.js"),{projectRejection}=await import("./chunk-qnpkhvrn.js"),top=resolveRepoRoot(dir);if(top!==dir)return null;return projectRejection(top,isGitRepo,"explicit")?null:top}async function runOpenDirectory(arg){let dir=resolve(process.cwd(),expandTilde(arg)),isDir=!1;try{isDir=statSync(dir).isDirectory()}catch{isDir=!1}if(!isDir)process.stderr.write(`${ROVE_PRODUCT_NAME}: "${arg}" is not a directory (resolved to ${dir}).
|
|
3
|
-
`),process.exit(1);let projectRoot=await projectRootFor(dir),{withDaemonOrLocal}=await import("./chunk-mqvkd2g1.js");await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-y8b2p44q.js");writeLastActiveTaskId(String(task.id))}});let{publishRoveTerminalTitle}=await import("./chunk-g8wrdp7n.js");publishRoveTerminalTitle();let{launchTui}=await import("./chunk-
|
|
3
|
+
`),process.exit(1);let projectRoot=await projectRootFor(dir),{withDaemonOrLocal}=await import("./chunk-mqvkd2g1.js");await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-y8b2p44q.js");writeLastActiveTaskId(String(task.id))}});let{publishRoveTerminalTitle}=await import("./chunk-g8wrdp7n.js");publishRoveTerminalTitle();let{launchTui}=await import("./chunk-azt0c2b5.js");await launchTui()}
|
|
4
4
|
export{isPathLikeArg,runOpenDirectory};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{findVerb}from"./chunk-
|
|
2
|
+
import{findVerb}from"./chunk-txvjg1g9.js";import{VERB_GROUP_IDS}from"./chunk-r5j8fycq.js";import{loadStateFile,updateStateFile}from"./chunk-32j6y5d1.js";var INBOUND_KEY="machineInbound",INBOUND_CLASSES=[...VERB_GROUP_IDS,"land","credentials"],LAND_VERBS=new Set(["land","publish"]),CREDENTIAL_VERBS={"github-login":!0,"github-logout":!0,"github-sync":!0,"github-apply":!0};function inboundClassOf(verb){if(LAND_VERBS.has(verb))return"land";if(Object.hasOwn(CREDENTIAL_VERBS,verb))return"credentials";return findVerb(verb)?.group??null}function deniedClasses(state=loadStateFile()){let raw=state[INBOUND_KEY],deny=raw&&typeof raw==="object"?raw.deny:void 0;return Array.isArray(deny)?deny.filter((c)=>typeof c==="string"):[]}function inboundRefusal(verb,state){let cls=inboundClassOf(verb);return cls&&deniedClasses(state).includes(cls)?cls:null}function setInbound(cls,allow){let next=[];return updateStateFile((state)=>{let current=new Set(deniedClasses(state));if(allow)current.delete(cls);else current.add(cls);return next=[...current].sort(),state[INBOUND_KEY]={deny:next},!0}),next}
|
|
3
3
|
export{INBOUND_KEY,INBOUND_CLASSES,inboundClassOf,deniedClasses,inboundRefusal,setInbound};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{deliverPromptToLiveEngineAdapter,deliverPromptToLiveEngineDetailedAdapter,deliverPromptToLiveEngineTabDetailedAdapter,deriveTitleFromSession,deriveTitleFromSessionId,ensureTaskSessionAdapter,startTaskSessionWithPromptAdapter,tearDownTaskSessionAdapter}from"./chunk-8hernv9y.js";import{buildCIPromptForWorktree}from"./chunk-vkz6kkmm.js";import{Orchestrator}from"./chunk-bv050ssb.js";import{GH_PR_VIEW_FIELDS,classifyGhFailure,mapGhPrView,nextPrPoll,samePrStatus}from"./chunk-1wwqf6kx.js";import"./chunk-c1dz3qg3.js";import{resolvePluginBinPath}from"./chunk-b0ssvpht.js";import{GitWorktreeManager,parseDirtyPaths}from"./chunk-3x5g06mw.js";import{startChatChannels}from"./chunk-
|
|
2
|
+
import{deliverPromptToLiveEngineAdapter,deliverPromptToLiveEngineDetailedAdapter,deliverPromptToLiveEngineTabDetailedAdapter,deriveTitleFromSession,deriveTitleFromSessionId,ensureTaskSessionAdapter,startTaskSessionWithPromptAdapter,tearDownTaskSessionAdapter}from"./chunk-8hernv9y.js";import{buildCIPromptForWorktree}from"./chunk-vkz6kkmm.js";import{Orchestrator}from"./chunk-bv050ssb.js";import{GH_PR_VIEW_FIELDS,classifyGhFailure,mapGhPrView,nextPrPoll,samePrStatus}from"./chunk-1wwqf6kx.js";import"./chunk-c1dz3qg3.js";import{resolvePluginBinPath}from"./chunk-b0ssvpht.js";import{GitWorktreeManager,parseDirtyPaths}from"./chunk-3x5g06mw.js";import{startChatChannels}from"./chunk-4drm07mp.js";import{auditDeletionBranchKept,auditDeletionResidue,auditDeletionSalvaged,auditWorktreeResidue,auditWorktreeSalvaged,parseAheadBehind,startDaemonServer}from"./chunk-nrx8pf9p.js";import"./chunk-1g6vhgfe.js";import"./chunk-a4hsqj1b.js";import"./chunk-6hcyvg0m.js";import{refreshOutdatedSkills}from"./chunk-y7mjhjby.js";import"./chunk-4dt1gfb3.js";import"./chunk-tq0h3vy6.js";import"./chunk-cpgnm1xr.js";import"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{preferredReleaseChannel,updateDelayHours}from"./chunk-4z1a65bz.js";import"./chunk-xmwp6je4.js";import{cancelAllLogins}from"./chunk-pm91e38v.js";import{PLACEHOLDER_TASK_TITLE}from"./chunk-2xsxcdp6.js";import{affectsActivityState,isEngineActivityKind}from"./chunk-17e2tgyg.js";import"./chunk-1vxtd8rh.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-vp29jgbt.js";import"./chunk-gq36nzg8.js";import{RELAY_PREAMBLE}from"./chunk-sq6zj3fb.js";import{TaskIndexStore}from"./chunk-7kgcy89w.js";import"./chunk-qkehg2c1.js";import"./chunk-nv8eyjep.js";import"./chunk-z43e08kw.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import"./chunk-f7egph8g.js";import{installDaemonCrashHandlers,logDaemonError,logDaemonInfo}from"./chunk-rxqdw6s5.js";import"./chunk-kxp04jnp.js";import{autoStatusEnabled,protocolUpgradeFromLiveSession,protocolWriteBackFromLiveSession}from"./chunk-qecygh3f.js";import{engineDisplayName,engineProtocolKey,protocolEntry,roveApiInvocation,sessionProtocol}from"./chunk-rjq38twt.js";import"./chunk-r5j8fycq.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import{teardownScope}from"./chunk-g9ba25q5.js";import"./chunk-ggnq2vvk.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import{stateFileTabsPersistence}from"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import{execHostForWorktreePath}from"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import"./chunk-y1xnjx8x.js";import{connectOrStartDaemon,daemonSpawnReason}from"./chunk-e58kj4gm.js";import{stopDaemonProcess}from"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import{foregroundEngineIn,parsePsSnapshot,psSnapshot}from"./chunk-5rgrde6b.js";import{createEngineTurnDetector,engineEntry,engineTitleTurnHint,vendorsWithQuotaProbe}from"./chunk-4gjvmfa9.js";import{spawnCapture}from"./chunk-2tfnscxk.js";import{availableEngineIds}from"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-2w228s7t.js";import"./chunk-etfh8f4z.js";import"./chunk-9rj2fx6v.js";import{backfillSavedReposFromProjects,getCustomEngineIds,getPersistedString,getRemoteRepoConfig,getSavedRepos,setPersistedString}from"./chunk-rfp0ayra.js";import{parsePorcelain}from"./chunk-0r1jf8m9.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import{DEFAULT_BASE_REF_CANDIDATES,readHeadSha,readRefSha,resolveGitDirs}from"./chunk-kg9kmwt9.js";import{readOnlyGitProcessEnv}from"./chunk-6xppe9bj.js";import{CURRENT_VERSION,checkLatestVersion}from"./chunk-2wrt80ft.js";import{argvHasFlag,switchFlag}from"./chunk-zsfyj36g.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import{SUBCOMMAND_VERBS}from"./chunk-qqr4tfhk.js";import{loadStateFile}from"./chunk-32j6y5d1.js";import"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import{RoveDaemonClient}from"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import"./chunk-hz1x3hak.js";import"./chunk-x1jxxmtc.js";import{DEFAULT_TASK_VENDOR,isTaskStatus}from"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import{migrateRoveDaemonStateLayout}from"./chunk-8t7qbr1e.js";import{releaseSync}from"./chunk-bejhca6z.js";import{isProcessAlive,readPidFile}from"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{rotateLogIfNeeded}from"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath}from"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import{readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__require}from"./chunk-91sykzqq.js";async function latestTranscriptMtime(vendor,worktree){if(!worktree)return 0;return protocolEntry(vendor).history.latestTranscriptMtimeForWorktree(worktree)}async function maybeAutoStart(orch,taskId,enabled=autoStatusEnabled){if(!enabled())return"skipped";let task=orch.getTask(taskId);if(!task)return"skipped";if((task.kind??"task")==="main")return"skipped";if(task.status!=="backlog")return"skipped";return await orch.setStatus(taskId,"in_progress"),"moved"}var SYNC_TIMEOUT_MS=60000,SYNC_CONFLICT="SYNC_CONFLICT",SYNC_DIRTY="SYNC_WORKTREE_DIRTY";async function git(cwd,args,signal,write=!1){return spawnCapture("git",args,{cwd,env:write?process.env:readOnlyGitProcessEnv(),signal})}function parseConflictedPaths(stdout){return stdout.split(`
|
|
3
3
|
`).map((line)=>line.trim()).filter((line)=>line.length>0)}async function syncWorktreeWithBase(worktreePath,baseRef,signal){let status=await git(worktreePath,["status","--porcelain=v1"],signal);if(status.status!==0)throw Error("git status failed");let dirty=parseDirtyPaths(status.stdout);if(dirty.length>0)throw Error(`${SYNC_DIRTY}: ${dirty.join(", ")}`);let before=await git(worktreePath,["rev-parse","HEAD"],signal),merge=await git(worktreePath,["merge","--no-edit",baseRef],signal,!0);if(merge.status!==0){let conflicted=await git(worktreePath,["diff","--name-only","--diff-filter=U"],signal),paths=parseConflictedPaths(conflicted.stdout);if(paths.length>0)throw Error(`${SYNC_CONFLICT}: ${paths.join(", ")}`);let detail=merge.stderr?.trim();throw Error(detail?`git merge ${baseRef} failed \u2014 ${detail}`:`git merge ${baseRef} failed`)}let after=await git(worktreePath,["rev-parse","HEAD"],signal);return{baseRef,alreadyCurrent:before.status===0&&before.stdout.trim()===after.stdout.trim()}}import{readFileSync}from"fs";import{join}from"path";var BASE_REF_TTL_MS=300000,cache=new Map;async function git2(worktreePath,args,signal){return await spawnCapture("git",[...args],{cwd:worktreePath,env:readOnlyGitProcessEnv(),signal})}async function refExists(worktreePath,ref,signal){return(await git2(worktreePath,["rev-parse","--verify","--quiet",ref],signal)).status===0}async function sharesHistory(worktreePath,ref,signal){return(await git2(worktreePath,["merge-base",ref,"HEAD"],signal)).status===0}async function baseCheckoutBranchFromGit(worktreePath,signal){let out=await git2(worktreePath,["worktree","list","--porcelain"],signal);if(out.status!==0)return null;return(out.stdout.split(`
|
|
4
4
|
|
|
5
5
|
`,1)[0]??"").split(`
|
|
6
|
-
`).find((l)=>l.startsWith("branch "))?.slice(7).trim().replace(/^refs\/heads\//,"")||null}function readRefSymbolic(dirs,ref){for(let dir of[dirs.gitDir,dirs.commonDir])try{let target=readFileSync(join(dir,ref),"utf8").trim().match(/^ref:\s*(.+)$/)?.[1]?.trim();if(target)return target}catch{}return null}function ladderFromFiles(worktreePath){let dirs=resolveGitDirs(worktreePath);if(!dirs)return;let originHead=readRefSymbolic(dirs,"refs/remotes/origin/HEAD")?.replace(/^refs\/remotes\//,""),baseCheckout=readRefSymbolic({gitDir:dirs.commonDir,commonDir:dirs.commonDir},"HEAD")?.replace(/^refs\/heads\//,""),names=[],head=readHeadSha(dirs),parts=[`HEAD=${head}`];for(let guess of[...originHead?[originHead]:[],...DEFAULT_BASE_REF_CANDIDATES,...baseCheckout?[baseCheckout]:[]]){if(names.includes(guess))continue;let sha=readRefSha(dirs,guess);if(sha===null)continue;names.push(guess),parts.push(`${guess}=${sha}`)}return{names,fingerprint:head===null?null:parts.join(",")}}async function ladderFromGit(worktreePath,signal){let head=await git2(worktreePath,["symbolic-ref","--short","refs/remotes/origin/HEAD"],signal),originHead=head.status===0?head.stdout.trim():"",baseCheckout=await baseCheckoutBranchFromGit(worktreePath,signal),names=[],candidates=[...originHead?[originHead]:[],...DEFAULT_BASE_REF_CANDIDATES,...baseCheckout?[baseCheckout]:[]];for(let guess of candidates){if(names.includes(guess))continue;if(await refExists(worktreePath,guess,signal))names.push(guess)}return{names,fingerprint:null}}async function resolveBaseRefCached(worktreePath,recordedBaseRef,signal,now=Date.now()){if(recordedBaseRef){let dirs=resolveGitDirs(worktreePath);if(dirs&&readRefSha(dirs,recordedBaseRef)!==null)return recordedBaseRef;if(await refExists(worktreePath,recordedBaseRef,signal))return recordedBaseRef}let hit=cache.get(worktreePath);if(hit&&now-hit.at<BASE_REF_TTL_MS)return hit.ref;let ladder=ladderFromFiles(worktreePath)??await ladderFromGit(worktreePath,signal);if(hit&&ladder.fingerprint!==null&&hit.fingerprint===ladder.fingerprint)return cache.set(worktreePath,{...hit,at:now}),hit.ref;let ref=null;for(let candidate of ladder.names)if(await sharesHistory(worktreePath,candidate,signal)){ref=candidate;break}return cache.set(worktreePath,{ref,at:now,fingerprint:ladder.fingerprint}),ref}var cache2=new Map;function readShas(worktreePath,baseRef){let dirs=resolveGitDirs(worktreePath);if(!dirs)return null;let head=readHeadSha(dirs),base=readRefSha(dirs,baseRef);return head&&base?{head,base}:null}async function driftCached(worktreePath,baseRef,compute){let shas=readShas(worktreePath,baseRef),hit=shas?cache2.get(worktreePath):void 0;if(shas&&hit&&hit.head===shas.head&&hit.base===shas.base)return hit.value;let value=await compute();if(shas&&value!==null)cache2.set(worktreePath,{...shas,value});return value}import{statSync}from"fs";function judgeWorktree(signals,nowMs){if(signals.dirty)return{verdict:"active",reason:"dirty"};if(signals.prState==="open")return{verdict:"active",reason:"prOpen"};if(signals.prState==="merged")return{verdict:"merged",reason:"prMerged"};if(signals.aheadOfDefault===0)return{verdict:"merged",reason:"inMain"};if(signals.prState==="closed")return{verdict:"stale",reason:"prClosed"};if(signals.lastActivityMs>0&&nowMs-signals.lastActivityMs>1209600000)return{verdict:"stale",reason:"idle"};return{verdict:"fresh",reason:"fresh"}}function parseGhPrList(stdout){let entries;try{entries=JSON.parse(stdout)}catch{return null}if(!Array.isArray(entries))return null;let rank={open:3,merged:2,closed:1},map=new Map;for(let entry of entries){let branch=entry?.headRefName,rawState=entry?.state;if(typeof branch!=="string"||typeof rawState!=="string")continue;let state=rawState.toLowerCase();if(state!=="open"&&state!=="merged"&&state!=="closed")continue;let cur=map.get(branch);if(!cur||rank[state]>rank[cur])map.set(branch,state)}return map}var TIMEOUT_MS=4000,manager=new GitWorktreeManager;function createdAt(path){try{let stat=statSync(path);return stat.birthtimeMs||stat.mtimeMs}catch{return 0}}async function run(path,argv){return execHostForWorktreePath(path).run(argv,{cwd:path,signal:AbortSignal.timeout(TIMEOUT_MS)})}async function branchOnRemote(path,branch){try{let out=await run(path,["git","ls-remote","--exit-code","--heads","origin",branch]);return out.exitCode===0?!0:out.exitCode===2?!1:null}catch{return null}}async function defaultRef(repo){try{let out=await run(repo,["git","symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(out.exitCode===0&&out.stdout.trim())return out.stdout.trim()}catch{}for(let guess of["origin/main","origin/master"])try{if((await run(repo,["git","rev-parse","--verify","--quiet",guess])).exitCode===0)return guess}catch{}return null}async function prStates(repo){try{let origin=await run(repo,["git","remote","get-url","origin"]);if(origin.exitCode!==0||!origin.stdout.includes("github.com"))return null;let out=await run(repo,["gh","pr","list","--state","all","--limit","200","--json","headRefName,state"]);return out.exitCode===0?parseGhPrList(out.stdout):null}catch{return null}}async function ahead(path,ref){if(!ref)return null;try{let out=await run(path,["git","rev-list","--count",`${ref}..HEAD`]),value=Number.parseInt(out.stdout.trim(),10);return out.exitCode===0&&!Number.isNaN(value)?value:null}catch{return null}}async function listWorktreeProjectsAdapter(network){let repos=getSavedRepos().filter((repo)=>!getRemoteRepoConfig(repo)),now=Date.now();return Promise.all(repos.map(async(repo)=>{let[worktrees,states,ref]=await Promise.all([manager.listAll(repo),network?prStates(repo):null,defaultRef(repo)]),rows=await Promise.all(worktrees.map(async(worktree)=>{let[remote,aheadBy]=await Promise.all([network?branchOnRemote(worktree.path,worktree.branch):null,ahead(worktree.path,ref)]),judgement=judgeWorktree({dirty:worktree.dirty===!0,prState:states?.get(worktree.branch)??null,aheadOfDefault:aheadBy,lastActivityMs:worktree.lastActivityMs},now);return{...worktree,repo,createdAtMs:createdAt(worktree.path),branchOnRemote:remote,verdict:judgement.verdict,verdictReason:judgement.reason}}));return{repo,worktrees:rows}}))}async function listUnreadableWorktreesAdapter(repo){return manager.listUnreadableWorktrees(repo)}async function removeWorktreeAdapter(path,force){let residue=null;return await manager.remove(path,{force,onSalvage:(record)=>{if(record)auditWorktreeSalvaged(path,record.ref,record.commit,record.uncaptured)},onResidue:(r)=>{residue={path:r.path,reason:r.reason},auditWorktreeResidue(r.path,r.reason)}}),residue}function resolveProtocolUpgradeAndLearnPreset(task,evidence){let preset=protocolWriteBackFromLiveSession(task,evidence,getCustomEngineIds());if(preset)setPersistedString(engineProtocolKey(preset.id),preset.protocol);return protocolUpgradeFromLiveSession(task,evidence)}var daemonRuntime={currentVersion:CURRENT_VERSION,tabsPersistence:stateFileTabsPersistence,startMachineHub(bus){let stop=null,stopped=!1;return import("./chunk-hzqfb00a.js").then(({startDaemonMachineHub})=>{if(!stopped)stop=startDaemonMachineHub(bus)}),()=>{stopped=!0,stop?.()}},async invokeApi(verb,params,socketPath,route){let[{executeVerb,errorEnvelope},{daemonCaller},{RoveDaemonClient:RoveDaemonClient2}]=await Promise.all([import("./chunk-k04qvy42.js"),import("./chunk-34tbcjdy.js"),import("./chunk-fq2pefc5.js")]);if(route?.forwarded){let{inboundRefusal}=await import("./chunk-ney5fnem.js"),denied=inboundRefusal(verb);if(denied){let{ApiError}=await import("./chunk-34tbcjdy.js");return errorEnvelope(new ApiError(`this machine refuses "${denied}" verbs from other machines (${verb} from ${route.from??"a hub"})`,"INBOUND_DENIED",{hint:`on this machine: rove machine inbound allow ${denied}`}))}}let client=new RoveDaemonClient2(socketPath);try{await client.connect();let{invokeRouted}=await import("./chunk-9f34p80j.js");return await invokeRouted({verb,params,machine:route?.machine,forwarded:route?.forwarded,localTasks:()=>client.request("task.list").then((res)=>res.tasks??[]),isLocalTask:(id)=>client.request("task.get",{taskId:id}).then(()=>!0,()=>!1),runHere:()=>executeVerb(verb,{params},{client,caller:daemonCaller(route?.forwarded===!0)})})}catch(err){return errorEnvelope(err)}finally{client.close()}},defaultTaskVendor:DEFAULT_TASK_VENDOR,placeholderTaskTitle:PLACEHOLDER_TASK_TITLE,isTaskStatus,isEngineActivityKind,affectsActivityState,async foregroundEngines(pids){let rows=parsePsSnapshot(await psSnapshot([...pids])),out=new Map;for(let pid of pids){let found=foregroundEngineIn(rows,pid);out.set(pid,found?{vendor:found.vendor,pid:found.pid}:null)}return out},titleTurnHint:(vendor,title)=>engineTitleTurnHint(sessionProtocol(vendor),title),sessionProtocol,resolveProtocolUpgrade:resolveProtocolUpgradeAndLearnPreset,readEngineTurns:async(vendor,transcriptPath)=>await protocolEntry(vendor).readTurns?.(transcriptPath)??[],checkLatestVersion:()=>{let state=loadStateFile();return checkLatestVersion({channel:preferredReleaseChannel(state),minAgeHours:updateDelayHours(state)})},latestTranscriptMtime,deriveTitleFromSession,deriveTitleFromSessionId,createEngineTurnDetector:(vendor)=>createEngineTurnDetector(sessionProtocol(vendor)),async runWorktreeStatus(worktreePath,signal,baseRef){let result=await spawnCapture("git",["status","--porcelain=v1"],{cwd:worktreePath,env:readOnlyGitProcessEnv(),signal});if(result.status!==0)throw Error("git status failed");let counts=parsePorcelain(result.stdout),base=await resolveBaseRefCached(worktreePath,baseRef,signal);if(!base)return counts;let drift=await driftCached(worktreePath,base,async()=>{let out=await spawnCapture("git",["rev-list","--left-right","--count",`${base}...HEAD`],{cwd:worktreePath,env:readOnlyGitProcessEnv(),signal});return out.status===0?parseAheadBehind(out.stdout):null});return drift===null?counts:{...counts,...drift}},maybeAutoStart:(orch,taskId)=>maybeAutoStart(orch,taskId),listWorktreeProjects:listWorktreeProjectsAdapter,listUnreadableWorktrees:listUnreadableWorktreesAdapter,removeWorktree:removeWorktreeAdapter,async syncWorktreeWithBase(worktreePath,recordedBaseRef){let controller=new AbortController,timer=setTimeout(()=>controller.abort(),SYNC_TIMEOUT_MS);try{let baseRef=await resolveBaseRefCached(worktreePath,recordedBaseRef,controller.signal);if(!baseRef)throw Error("no base ref resolves for this worktree");return await syncWorktreeWithBase(worktreePath,baseRef,controller.signal)}finally{clearTimeout(timer)}},availableEngineIds,engineDisplayName,roveApiInvocation,engineEntry,ensureTaskSession:ensureTaskSessionAdapter,startTaskSessionWithPrompt:startTaskSessionWithPromptAdapter,tearDownTaskSession:tearDownTaskSessionAdapter,async readEngineContextUsage(vendor,sessionId){let read=protocolEntry(vendor).history.readUsageSnapshot;if(!read)return null;let snapshot=await read(sessionId);if(snapshot?.context_tokens===void 0)return null;return{contextTokens:snapshot.context_tokens,...snapshot.context_window_tokens===void 0?{}:{contextWindowTokens:snapshot.context_window_tokens},...snapshot.context_tokens_approximate?{approximate:!0}:{},...snapshot.input_tokens===void 0?{}:{inputTokens:snapshot.input_tokens},...snapshot.output_tokens===void 0?{}:{outputTokens:snapshot.output_tokens},...snapshot.cache_read_input_tokens===void 0?{}:{cacheReadTokens:snapshot.cache_read_input_tokens},...snapshot.cache_creation_input_tokens===void 0?{}:{cacheCreationTokens:snapshot.cache_creation_input_tokens},...snapshot.context_parts?{parts:snapshot.context_parts}:{}}},quotaUsage:(vendor)=>engineEntry(vendor).quotaUsage?.()??Promise.resolve(null),vendorsWithQuotaProbe,deliverPromptToLiveEngine:deliverPromptToLiveEngineAdapter,deliverPromptToLiveEngineDetailed:deliverPromptToLiveEngineDetailedAdapter,deliverPromptToLiveEngineTabDetailed:deliverPromptToLiveEngineTabDetailedAdapter,getPersistedString,buildCIPrompt:(worktree,state)=>buildCIPromptForWorktree(worktree,state),setPersistedString,getSavedRepos:()=>[...getSavedRepos()],prStatus:{viewFields:GH_PR_VIEW_FIELDS,mapView:(view,at)=>mapGhPrView(view,at),sameStatus:samePrStatus,nextPoll:(outcome,failures,now,config,random)=>nextPrPoll(outcome,failures,now,config,random),classify:classifyGhFailure}};import{homedir}from"os";async function createRoveCore(options={}){let homeDir=options.homeDir??readRoveHomeDirEnv()??homedir(),store=new TaskIndexStore({homeDir});await store.load();let worktrees=new GitWorktreeManager,orchestrator=new Orchestrator({store,worktrees,onSalvage:(taskId,salvage,repo)=>auditDeletionSalvaged(String(taskId),salvage.ref,salvage.commit,repo,salvage.uncaptured),onWorktreeResidue:(taskId,residue)=>auditDeletionResidue(String(taskId),residue.path,residue.reason),onBranchKept:(taskId,kept)=>auditDeletionBranchKept(String(taskId),kept.branch,kept.reason),tearDownSession:(taskId)=>tearDownTaskSessionAdapter(String(taskId),teardownScope(store.list(),String(taskId),new Set([String(taskId)])))}),backfilled=backfillSavedReposFromProjects(store.list().filter((task)=>task.kind==="main").map((task)=>task.repo));if(backfilled.length>0)console.error(`[rove] added ${backfilled.length} existing project(s) to the new-task picker`);return{homeDir,orchestrator,store,worktrees,async close(){orchestrator.dispose()}}}import{existsSync,readFileSync as readFileSync2,readdirSync,statSync as statSync2,unlinkSync}from"fs";import{join as join2}from"path";var TMP_MAX_AGE_MS=300000;function sweepIndexLeftovers(stateDir,now=Date.now()){let tmp=[],tmpBytes=0,entries;try{entries=readdirSync(stateDir)}catch{return{tmp,tmpBytes,lock:!1}}for(let name of entries){if(!name.startsWith("tasks.json.")||!name.endsWith(".tmp"))continue;let path=join2(stateDir,name);try{let stat=statSync2(path);if(now-stat.mtimeMs<TMP_MAX_AGE_MS)continue;unlinkSync(path),tmp.push(path),tmpBytes+=stat.size}catch{}}return{tmp,tmpBytes,lock:clearStaleLock(join2(stateDir,"tasks.json.lock"))}}function clearStaleLock(lockPath){let holder;try{holder=readFileSync2(lockPath,"utf8").trim()}catch{return!1}let pid=Number.parseInt(holder,10);if(Number.isFinite(pid)&&pid>0&&isProcessAlive(pid))return!1;return releaseSync(lockPath,holder),!existsSync(lockPath)}var CLI_NAME=ROVE_PRODUCT_NAME;function printDaemonUsage(out){out.write([`Usage: ${CLI_NAME} daemon <command>`,"","Commands:"," status Print the running daemon's status JSON (default)"," start Run the daemon in the foreground (this process becomes it)"," --resident: never idle-stop when the last TUI leaves (headless host)"," stop Ask the running daemon to shut down"," restart Stop the daemon (graceful \u2192 SIGTERM \u2192 SIGKILL) and respawn it",""].join(`
|
|
6
|
+
`).find((l)=>l.startsWith("branch "))?.slice(7).trim().replace(/^refs\/heads\//,"")||null}function readRefSymbolic(dirs,ref){for(let dir of[dirs.gitDir,dirs.commonDir])try{let target=readFileSync(join(dir,ref),"utf8").trim().match(/^ref:\s*(.+)$/)?.[1]?.trim();if(target)return target}catch{}return null}function ladderFromFiles(worktreePath){let dirs=resolveGitDirs(worktreePath);if(!dirs)return;let originHead=readRefSymbolic(dirs,"refs/remotes/origin/HEAD")?.replace(/^refs\/remotes\//,""),baseCheckout=readRefSymbolic({gitDir:dirs.commonDir,commonDir:dirs.commonDir},"HEAD")?.replace(/^refs\/heads\//,""),names=[],head=readHeadSha(dirs),parts=[`HEAD=${head}`];for(let guess of[...originHead?[originHead]:[],...DEFAULT_BASE_REF_CANDIDATES,...baseCheckout?[baseCheckout]:[]]){if(names.includes(guess))continue;let sha=readRefSha(dirs,guess);if(sha===null)continue;names.push(guess),parts.push(`${guess}=${sha}`)}return{names,fingerprint:head===null?null:parts.join(",")}}async function ladderFromGit(worktreePath,signal){let head=await git2(worktreePath,["symbolic-ref","--short","refs/remotes/origin/HEAD"],signal),originHead=head.status===0?head.stdout.trim():"",baseCheckout=await baseCheckoutBranchFromGit(worktreePath,signal),names=[],candidates=[...originHead?[originHead]:[],...DEFAULT_BASE_REF_CANDIDATES,...baseCheckout?[baseCheckout]:[]];for(let guess of candidates){if(names.includes(guess))continue;if(await refExists(worktreePath,guess,signal))names.push(guess)}return{names,fingerprint:null}}async function resolveBaseRefCached(worktreePath,recordedBaseRef,signal,now=Date.now()){if(recordedBaseRef){let dirs=resolveGitDirs(worktreePath);if(dirs&&readRefSha(dirs,recordedBaseRef)!==null)return recordedBaseRef;if(await refExists(worktreePath,recordedBaseRef,signal))return recordedBaseRef}let hit=cache.get(worktreePath);if(hit&&now-hit.at<BASE_REF_TTL_MS)return hit.ref;let ladder=ladderFromFiles(worktreePath)??await ladderFromGit(worktreePath,signal);if(hit&&ladder.fingerprint!==null&&hit.fingerprint===ladder.fingerprint)return cache.set(worktreePath,{...hit,at:now}),hit.ref;let ref=null;for(let candidate of ladder.names)if(await sharesHistory(worktreePath,candidate,signal)){ref=candidate;break}return cache.set(worktreePath,{ref,at:now,fingerprint:ladder.fingerprint}),ref}var cache2=new Map;function readShas(worktreePath,baseRef){let dirs=resolveGitDirs(worktreePath);if(!dirs)return null;let head=readHeadSha(dirs),base=readRefSha(dirs,baseRef);return head&&base?{head,base}:null}async function driftCached(worktreePath,baseRef,compute){let shas=readShas(worktreePath,baseRef),hit=shas?cache2.get(worktreePath):void 0;if(shas&&hit&&hit.head===shas.head&&hit.base===shas.base)return hit.value;let value=await compute();if(shas&&value!==null)cache2.set(worktreePath,{...shas,value});return value}import{statSync}from"fs";function judgeWorktree(signals,nowMs){if(signals.dirty)return{verdict:"active",reason:"dirty"};if(signals.prState==="open")return{verdict:"active",reason:"prOpen"};if(signals.prState==="merged")return{verdict:"merged",reason:"prMerged"};if(signals.aheadOfDefault===0)return{verdict:"merged",reason:"inMain"};if(signals.prState==="closed")return{verdict:"stale",reason:"prClosed"};if(signals.lastActivityMs>0&&nowMs-signals.lastActivityMs>1209600000)return{verdict:"stale",reason:"idle"};return{verdict:"fresh",reason:"fresh"}}function parseGhPrList(stdout){let entries;try{entries=JSON.parse(stdout)}catch{return null}if(!Array.isArray(entries))return null;let rank={open:3,merged:2,closed:1},map=new Map;for(let entry of entries){let branch=entry?.headRefName,rawState=entry?.state;if(typeof branch!=="string"||typeof rawState!=="string")continue;let state=rawState.toLowerCase();if(state!=="open"&&state!=="merged"&&state!=="closed")continue;let cur=map.get(branch);if(!cur||rank[state]>rank[cur])map.set(branch,state)}return map}var TIMEOUT_MS=4000,manager=new GitWorktreeManager;function createdAt(path){try{let stat=statSync(path);return stat.birthtimeMs||stat.mtimeMs}catch{return 0}}async function run(path,argv){return execHostForWorktreePath(path).run(argv,{cwd:path,signal:AbortSignal.timeout(TIMEOUT_MS)})}async function branchOnRemote(path,branch){try{let out=await run(path,["git","ls-remote","--exit-code","--heads","origin",branch]);return out.exitCode===0?!0:out.exitCode===2?!1:null}catch{return null}}async function defaultRef(repo){try{let out=await run(repo,["git","symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(out.exitCode===0&&out.stdout.trim())return out.stdout.trim()}catch{}for(let guess of["origin/main","origin/master"])try{if((await run(repo,["git","rev-parse","--verify","--quiet",guess])).exitCode===0)return guess}catch{}return null}async function prStates(repo){try{let origin=await run(repo,["git","remote","get-url","origin"]);if(origin.exitCode!==0||!origin.stdout.includes("github.com"))return null;let out=await run(repo,["gh","pr","list","--state","all","--limit","200","--json","headRefName,state"]);return out.exitCode===0?parseGhPrList(out.stdout):null}catch{return null}}async function ahead(path,ref){if(!ref)return null;try{let out=await run(path,["git","rev-list","--count",`${ref}..HEAD`]),value=Number.parseInt(out.stdout.trim(),10);return out.exitCode===0&&!Number.isNaN(value)?value:null}catch{return null}}async function listWorktreeProjectsAdapter(network){let repos=getSavedRepos().filter((repo)=>!getRemoteRepoConfig(repo)),now=Date.now();return Promise.all(repos.map(async(repo)=>{let[worktrees,states,ref]=await Promise.all([manager.listAll(repo),network?prStates(repo):null,defaultRef(repo)]),rows=await Promise.all(worktrees.map(async(worktree)=>{let[remote,aheadBy]=await Promise.all([network?branchOnRemote(worktree.path,worktree.branch):null,ahead(worktree.path,ref)]),judgement=judgeWorktree({dirty:worktree.dirty===!0,prState:states?.get(worktree.branch)??null,aheadOfDefault:aheadBy,lastActivityMs:worktree.lastActivityMs},now);return{...worktree,repo,createdAtMs:createdAt(worktree.path),branchOnRemote:remote,verdict:judgement.verdict,verdictReason:judgement.reason}}));return{repo,worktrees:rows}}))}async function listUnreadableWorktreesAdapter(repo){return manager.listUnreadableWorktrees(repo)}async function removeWorktreeAdapter(path,force){let residue=null;return await manager.remove(path,{force,onSalvage:(record)=>{if(record)auditWorktreeSalvaged(path,record.ref,record.commit,record.uncaptured)},onResidue:(r)=>{residue={path:r.path,reason:r.reason},auditWorktreeResidue(r.path,r.reason)}}),residue}function resolveProtocolUpgradeAndLearnPreset(task,evidence){let preset=protocolWriteBackFromLiveSession(task,evidence,getCustomEngineIds());if(preset)setPersistedString(engineProtocolKey(preset.id),preset.protocol);return protocolUpgradeFromLiveSession(task,evidence)}var daemonRuntime={currentVersion:CURRENT_VERSION,tabsPersistence:stateFileTabsPersistence,startMachineHub(bus){let stop=null,stopped=!1;return import("./chunk-mjzjah9d.js").then(({startDaemonMachineHub})=>{if(!stopped)stop=startDaemonMachineHub(bus)}),()=>{stopped=!0,stop?.()}},async invokeApi(verb,params,socketPath,route){let[{executeVerb,errorEnvelope},{daemonCaller},{RoveDaemonClient:RoveDaemonClient2}]=await Promise.all([import("./chunk-0g1h35mr.js"),import("./chunk-34tbcjdy.js"),import("./chunk-fq2pefc5.js")]);if(route?.forwarded){let{inboundRefusal}=await import("./chunk-d2wndk4q.js"),denied=inboundRefusal(verb);if(denied){let{ApiError}=await import("./chunk-34tbcjdy.js");return errorEnvelope(new ApiError(`this machine refuses "${denied}" verbs from other machines (${verb} from ${route.from??"a hub"})`,"INBOUND_DENIED",{hint:`on this machine: rove machine inbound allow ${denied}`}))}}let client=new RoveDaemonClient2(socketPath);try{await client.connect();let{invokeRouted}=await import("./chunk-9f34p80j.js");return await invokeRouted({verb,params,machine:route?.machine,forwarded:route?.forwarded,localTasks:()=>client.request("task.list").then((res)=>res.tasks??[]),isLocalTask:(id)=>client.request("task.get",{taskId:id}).then(()=>!0,()=>!1),runHere:()=>executeVerb(verb,{params},{client,caller:daemonCaller(route?.forwarded===!0)})})}catch(err){return errorEnvelope(err)}finally{client.close()}},defaultTaskVendor:DEFAULT_TASK_VENDOR,placeholderTaskTitle:PLACEHOLDER_TASK_TITLE,isTaskStatus,isEngineActivityKind,affectsActivityState,async foregroundEngines(pids){let rows=parsePsSnapshot(await psSnapshot([...pids])),out=new Map;for(let pid of pids){let found=foregroundEngineIn(rows,pid);out.set(pid,found?{vendor:found.vendor,pid:found.pid}:null)}return out},titleTurnHint:(vendor,title)=>engineTitleTurnHint(sessionProtocol(vendor),title),sessionProtocol,resolveProtocolUpgrade:resolveProtocolUpgradeAndLearnPreset,readEngineTurns:async(vendor,transcriptPath)=>await protocolEntry(vendor).readTurns?.(transcriptPath)??[],checkLatestVersion:()=>{let state=loadStateFile();return checkLatestVersion({channel:preferredReleaseChannel(state),minAgeHours:updateDelayHours(state)})},latestTranscriptMtime,deriveTitleFromSession,deriveTitleFromSessionId,createEngineTurnDetector:(vendor)=>createEngineTurnDetector(sessionProtocol(vendor)),async runWorktreeStatus(worktreePath,signal,baseRef){let result=await spawnCapture("git",["status","--porcelain=v1"],{cwd:worktreePath,env:readOnlyGitProcessEnv(),signal});if(result.status!==0)throw Error("git status failed");let counts=parsePorcelain(result.stdout),base=await resolveBaseRefCached(worktreePath,baseRef,signal);if(!base)return counts;let drift=await driftCached(worktreePath,base,async()=>{let out=await spawnCapture("git",["rev-list","--left-right","--count",`${base}...HEAD`],{cwd:worktreePath,env:readOnlyGitProcessEnv(),signal});return out.status===0?parseAheadBehind(out.stdout):null});return drift===null?counts:{...counts,...drift}},maybeAutoStart:(orch,taskId)=>maybeAutoStart(orch,taskId),listWorktreeProjects:listWorktreeProjectsAdapter,listUnreadableWorktrees:listUnreadableWorktreesAdapter,removeWorktree:removeWorktreeAdapter,async syncWorktreeWithBase(worktreePath,recordedBaseRef){let controller=new AbortController,timer=setTimeout(()=>controller.abort(),SYNC_TIMEOUT_MS);try{let baseRef=await resolveBaseRefCached(worktreePath,recordedBaseRef,controller.signal);if(!baseRef)throw Error("no base ref resolves for this worktree");return await syncWorktreeWithBase(worktreePath,baseRef,controller.signal)}finally{clearTimeout(timer)}},availableEngineIds,engineDisplayName,roveApiInvocation,engineEntry,ensureTaskSession:ensureTaskSessionAdapter,startTaskSessionWithPrompt:startTaskSessionWithPromptAdapter,tearDownTaskSession:tearDownTaskSessionAdapter,async readEngineContextUsage(vendor,sessionId){let read=protocolEntry(vendor).history.readUsageSnapshot;if(!read)return null;let snapshot=await read(sessionId);if(snapshot?.context_tokens===void 0)return null;return{contextTokens:snapshot.context_tokens,...snapshot.context_window_tokens===void 0?{}:{contextWindowTokens:snapshot.context_window_tokens},...snapshot.context_tokens_approximate?{approximate:!0}:{},...snapshot.input_tokens===void 0?{}:{inputTokens:snapshot.input_tokens},...snapshot.output_tokens===void 0?{}:{outputTokens:snapshot.output_tokens},...snapshot.cache_read_input_tokens===void 0?{}:{cacheReadTokens:snapshot.cache_read_input_tokens},...snapshot.cache_creation_input_tokens===void 0?{}:{cacheCreationTokens:snapshot.cache_creation_input_tokens},...snapshot.context_parts?{parts:snapshot.context_parts}:{}}},quotaUsage:(vendor)=>engineEntry(vendor).quotaUsage?.()??Promise.resolve(null),vendorsWithQuotaProbe,deliverPromptToLiveEngine:deliverPromptToLiveEngineAdapter,deliverPromptToLiveEngineDetailed:deliverPromptToLiveEngineDetailedAdapter,deliverPromptToLiveEngineTabDetailed:deliverPromptToLiveEngineTabDetailedAdapter,getPersistedString,buildCIPrompt:(worktree,state)=>buildCIPromptForWorktree(worktree,state),setPersistedString,getSavedRepos:()=>[...getSavedRepos()],prStatus:{viewFields:GH_PR_VIEW_FIELDS,mapView:(view,at)=>mapGhPrView(view,at),sameStatus:samePrStatus,nextPoll:(outcome,failures,now,config,random)=>nextPrPoll(outcome,failures,now,config,random),classify:classifyGhFailure}};import{homedir}from"os";async function createRoveCore(options={}){let homeDir=options.homeDir??readRoveHomeDirEnv()??homedir(),store=new TaskIndexStore({homeDir});await store.load();let worktrees=new GitWorktreeManager,orchestrator=new Orchestrator({store,worktrees,onSalvage:(taskId,salvage,repo)=>auditDeletionSalvaged(String(taskId),salvage.ref,salvage.commit,repo,salvage.uncaptured),onWorktreeResidue:(taskId,residue)=>auditDeletionResidue(String(taskId),residue.path,residue.reason),onBranchKept:(taskId,kept)=>auditDeletionBranchKept(String(taskId),kept.branch,kept.reason),tearDownSession:(taskId)=>tearDownTaskSessionAdapter(String(taskId),teardownScope(store.list(),String(taskId),new Set([String(taskId)])))}),backfilled=backfillSavedReposFromProjects(store.list().filter((task)=>task.kind==="main").map((task)=>task.repo));if(backfilled.length>0)console.error(`[rove] added ${backfilled.length} existing project(s) to the new-task picker`);return{homeDir,orchestrator,store,worktrees,async close(){orchestrator.dispose()}}}import{existsSync,readFileSync as readFileSync2,readdirSync,statSync as statSync2,unlinkSync}from"fs";import{join as join2}from"path";var TMP_MAX_AGE_MS=300000;function sweepIndexLeftovers(stateDir,now=Date.now()){let tmp=[],tmpBytes=0,entries;try{entries=readdirSync(stateDir)}catch{return{tmp,tmpBytes,lock:!1}}for(let name of entries){if(!name.startsWith("tasks.json.")||!name.endsWith(".tmp"))continue;let path=join2(stateDir,name);try{let stat=statSync2(path);if(now-stat.mtimeMs<TMP_MAX_AGE_MS)continue;unlinkSync(path),tmp.push(path),tmpBytes+=stat.size}catch{}}return{tmp,tmpBytes,lock:clearStaleLock(join2(stateDir,"tasks.json.lock"))}}function clearStaleLock(lockPath){let holder;try{holder=readFileSync2(lockPath,"utf8").trim()}catch{return!1}let pid=Number.parseInt(holder,10);if(Number.isFinite(pid)&&pid>0&&isProcessAlive(pid))return!1;return releaseSync(lockPath,holder),!existsSync(lockPath)}var CLI_NAME=ROVE_PRODUCT_NAME;function printDaemonUsage(out){out.write([`Usage: ${CLI_NAME} daemon <command>`,"","Commands:"," status Print the running daemon's status JSON (default)"," start Run the daemon in the foreground (this process becomes it)"," --resident: never idle-stop when the last TUI leaves (headless host)"," stop Ask the running daemon to shut down"," restart Stop the daemon (graceful \u2192 SIGTERM \u2192 SIGKILL) and respawn it",""].join(`
|
|
7
7
|
`))}async function runDaemonSubcommand(argv){let[command="status",...flags]=argv,socketPath=defaultDaemonSocketPath(),pidPath=defaultDaemonPidPath();if(command==="--help"||command==="-h"||command==="help"){printDaemonUsage(process.stdout);return}if(!SUBCOMMAND_VERBS.daemon.includes(command))process.stderr.write(`${CLI_NAME} daemon: unknown command "${command}"
|
|
8
8
|
|
|
9
9
|
`),printDaemonUsage(process.stderr),process.exit(2);if(command==="relay"){let pty=argvHasFlag(flags,"--pty"),{ensureDaemonReachable}=await import("./chunk-n2zgej1a.js"),{ensurePtyHostReachable}=await import("./chunk-bagwgxsg.js"),target=pty?await ensurePtyHostReachable():await ensureDaemonReachable(void 0,"autospawn"),{connect}=await import("net"),socket=connect(target);if(argvHasFlag(flags,"--preamble"))process.stdout.write(RELAY_PREAMBLE);process.stdin.pipe(socket),socket.pipe(process.stdout),await new Promise((resolve)=>{socket.on("close",()=>resolve()),process.stdin.on("end",()=>socket.end())}),process.exit(0)}let badFlag=flags.find((flag)=>!(command==="start"&&argvHasFlag([flag],"--resident"))&&!(command==="status"&&flag==="--json")&&!(command==="relay"&&flag==="--pty")),resident=switchFlag(flags,"--resident");if(badFlag!==void 0||resident===void 0)process.stderr.write(`${CLI_NAME} daemon ${command}: bad option "${badFlag??flags.join(" ")}"
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{RemoteOrchestrator}from"./chunk-
|
|
2
|
+
import{RemoteOrchestrator}from"./chunk-j54c5a0a.js";import{dedupeMachines,discoverMachine,duplicateAliasOf,learnedFrom,listMachines,readMachines,setMachineIdentity,startTunnel,updateMachine}from"./chunk-vytrhm50.js";import{loadStateFile}from"./chunk-32j6y5d1.js";import{createStateCell}from"./chunk-cmp64q4j.js";import{RoveDaemonClient}from"./chunk-qzzmd63x.js";import{logClient,logClientError}from"./chunk-0g4wc808.js";function discoverReason(failure){switch(failure.code){case"SSH_FAILED":return!failure.ssh||failure.ssh==="unknown"?"ssh-failed":failure.ssh;case"NO_ROVE":return"no-rove";case"NO_DAEMON":return"no-daemon";default:return"bad-status"}}var NO_LIVE={activity:new Map,changes:new Map,tokens:new Map},PEER_CHANNELS=["task.snapshot","engine-state","worktree.changes","task.tokens"];class MachineHub{slots=new Map;machinesAcc=createStateCell([],"machines.status");tasksAcc=createStateCell([],"machines.tasks");liveAcc=createStateCell(NO_LIVE,"machines.live");disposed=!1;machinesSignal(){return this.machinesAcc}tasksSignal(){return this.tasksAcc}liveSignal(){return this.liveAcc}remoteTaskIds(){let ids=new Set;for(let slot of this.slots.values())for(let task of slot.tasks)ids.add(String(task.id));return ids}sync(entries=dedupeMachines(listMachines())){if(this.disposed)return;let wanted=new Map(entries.map((entry)=>[entry.alias,entry])),fresh=[];for(let[alias,slot]of this.slots){let next=wanted.get(alias);if(next&&sameAddress(slot.entry,next))slot.entry=next;else this.drop(alias)}for(let entry of entries){if(this.slots.has(entry.alias))continue;this.slots.set(entry.alias,{entry,tasks:[]}),fresh.push(entry)}if(fresh.length===0&&wanted.size===this.slots.size&&this.machinesAcc.get().length===wanted.size)return;let known=new Map(this.machinesAcc.get().map((row)=>[row.alias,row]));this.machinesAcc.set([...this.slots.values()].map((slot)=>known.get(slot.entry.alias)??{alias:slot.entry.alias,hostLabel:slot.entry.alias,state:"connecting"})),this.republishTasks(),this.republishLive();for(let entry of fresh)this.connect(entry)}drop(alias){let slot=this.slots.get(alias);if(!slot)return;this.slots.delete(alias),slot.unsubscribe?.(),slot.orchestrator?.dispose(),slot.tunnel?.stop()}async connect(entry){let slot=this.slots.get(entry.alias);if(!slot||this.disposed)return;let found=await discoverMachine(entry.alias,entry);if(this.disposed||this.slots.get(entry.alias)!==slot)return;let sockets=found.ok?{daemon:found.status.socketPath,pty:found.status.ptySocketPath}:entry.sockets,failed=found.ok?{}:{error:found.message,reason:discoverReason(found)};if(!sockets){this.setStatus(entry.alias,{state:"offline",...failed});return}if(!found.ok)this.setStatus(entry.alias,failed);let learned=found.ok?learnedFrom(found):{};if(found.ok)updateMachine(entry.alias,learned);let tunnel=startTunnel({alias:entry.alias,config:{...entry,...learned,sockets},remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty});if(slot.tunnel=tunnel,tunnel.state()==="unsupported"){this.setStatus(entry.alias,{state:"unsupported",error:"SSH unix-socket forwarding is not available on Windows",reason:"no-forwarding"});return}if(tunnel.onState((state)=>{if(this.slots.get(entry.alias)!==slot)return;if(state==="online")this.openOrchestrator(entry,tunnel);else if(state==="offline"){let known=this.machinesAcc.get().find((row)=>row.alias===entry.alias)?.reason;this.setStatus(entry.alias,{state:"offline",reason:known??"lost"}),this.republishTasks()}}),tunnel.state()==="online")await this.openOrchestrator(entry,tunnel)}async openOrchestrator(entry,tunnel){let slot=this.slots.get(entry.alias);if(!slot||this.disposed||slot.orchestrator)return;let client=new RoveDaemonClient(tunnel.daemonSocketPath),orchestrator=new RemoteOrchestrator(client,{role:"gui",channels:PEER_CHANNELS,expectForeignHome:!0,onPeerIdentity:(peer)=>this.onPeerIdentity(entry.alias,peer)});slot.orchestrator=orchestrator;try{if(await orchestrator.init(),this.slots.get(entry.alias)!==slot)return}catch(err){let message=err instanceof Error?err.message:String(err);this.setStatus(entry.alias,{state:classifyHandshakeFailure(message),error:message,reason:"handshake"}),logClientError("machines",err);return}let stopTasks=orchestrator.tasksSignal().subscribe(()=>{slot.tasks=orchestrator.tasksSignal().get(),this.republishTasks()}),stopConnection=orchestrator.connectionStateSignal().subscribe(()=>{let connected=orchestrator.connectionStateSignal().get()==="online";if(this.slots.get(entry.alias)!==slot)return;this.setStatus(entry.alias,connected?{state:"online",error:void 0,reason:void 0}:{state:"offline",reason:"lost"}),this.republishTasks()}),live=[orchestrator.engineStateSignal(),orchestrator.worktreeChangesSignal(),orchestrator.rowTokensSignal()].map((signal)=>signal.subscribe(()=>this.republishLive()));slot.unsubscribe=()=>{stopTasks(),stopConnection();for(let stop of live)stop()},slot.tasks=orchestrator.tasksSignal().get(),this.setStatus(entry.alias,{state:"online",version:orchestrator.daemonVersionSignal().get()??void 0,error:void 0,reason:void 0}),this.republishTasks(),this.republishLive(),logClient("machines",`${entry.alias} online (${slot.tasks.length} tasks)`)}republishLive(){let activity=new Map,changes=new Map,tokens=new Map;for(let slot of this.slots.values()){let o=slot.orchestrator;if(!o)continue;for(let[id,state]of o.engineStateSignal().get())activity.set(id,state);for(let[path,change]of o.worktreeChangesSignal().get()??[])changes.set(path,change);for(let[id,chips]of o.rowTokensSignal().get())tokens.set(id,chips)}this.liveAcc.set({activity,changes,tokens})}onPeerIdentity(alias,peer){if(!peer.hostname&&!peer.homeDir)return;let identity={hostname:peer.hostname,homeDir:peer.homeDir,daemonPid:peer.daemonPid};setMachineIdentity(alias,identity);let duplicate=duplicateAliasOf(readMachines(loadStateFile()),alias,identity);this.setStatus(alias,{hostname:peer.hostname||void 0,version:peer.roveVersion||void 0,...duplicate?{duplicateOf:duplicate}:{}})}setStatus(alias,patch){let next=this.machinesAcc.get().map((row)=>row.alias===alias?{...row,...patch}:row);this.machinesAcc.set(next)}republishTasks(){let merged=[];for(let slot of this.slots.values()){let status=this.machinesAcc.get().find((row)=>row.alias===slot.entry.alias);if(status?.duplicateOf)continue;let hostLabel=status?.hostLabel||slot.entry.alias,stale=status?.state!=="online";for(let task of slot.tasks)merged.push(stampOrigin(task,slot.entry.alias,hostLabel,stale))}this.tasksAcc.set(merged)}dispose(){this.disposed=!0;for(let alias of[...this.slots.keys()])this.drop(alias)}}function classifyHandshakeFailure(message){return/protocol v\d/i.test(message)?"mismatch":"offline"}function sameAddress(a,b){return a.host===b.host&&a.user===b.user&&a.port===b.port&&JSON.stringify(a.auth)===JSON.stringify(b.auth)}function stampOrigin(task,machineId,hostLabel,stale=!1){return{...task,origin:{machineId,hostLabel,...stale?{stale:!0}:{}}}}
|
|
3
3
|
export{MachineHub,stampOrigin};
|