@sma1lboy/rove 0.9.222 → 0.9.223
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-k0ymxqbc.js → chunk-0cfmq5yw.js} +1 -1
- package/dist/cli/{chunk-0zcr89a6.js → chunk-0r46kk4s.js} +1 -1
- package/dist/cli/chunk-12jedc14.js +8 -0
- package/dist/cli/{chunk-fykzzj26.js → chunk-1f8c92xt.js} +1 -1
- package/dist/cli/{chunk-vyr2ga59.js → chunk-2cwb64fj.js} +1 -1
- package/dist/cli/{chunk-hmsqfmhg.js → chunk-2fntqq4z.js} +1 -1
- package/dist/cli/{chunk-4pf41rdt.js → chunk-2xsem13q.js} +1 -1
- package/dist/cli/{chunk-58avfm7n.js → chunk-3atfaa4h.js} +1 -1
- package/dist/cli/{chunk-ed3r9mb4.js → chunk-3c7bvsb3.js} +2 -2
- package/dist/cli/chunk-3h73z1x9.js +12 -0
- package/dist/cli/{chunk-94jwnk5q.js → chunk-3htqngp4.js} +1 -1
- package/dist/cli/{chunk-59c04v65.js → chunk-3wb64q0p.js} +1 -1
- package/dist/cli/{chunk-h0zssfds.js → chunk-3xz0w8tj.js} +8 -8
- package/dist/cli/{chunk-psbfd19k.js → chunk-3yh71rdr.js} +1 -1
- package/dist/cli/{chunk-89vj273t.js → chunk-44pjeyc5.js} +1 -1
- package/dist/cli/{chunk-5qb8czj2.js → chunk-4g3tq47n.js} +1 -1
- package/dist/cli/{chunk-jbx6t00x.js → chunk-4rnfvn7x.js} +1 -1
- package/dist/cli/chunk-4vsrjqz8.js +2 -0
- package/dist/cli/chunk-57q6gykd.js +2 -0
- package/dist/cli/chunk-5xqa2ys0.js +2 -0
- package/dist/cli/chunk-64bam14p.js +2 -0
- package/dist/cli/{chunk-7taqx3cm.js → chunk-6r478s75.js} +1 -1
- package/dist/cli/{chunk-3skf3g0c.js → chunk-6wfxd468.js} +1 -1
- package/dist/cli/{chunk-7nndmapz.js → chunk-6x5vzzpx.js} +1 -1
- package/dist/cli/{chunk-8rk6ecgf.js → chunk-7mfjczcz.js} +1 -1
- package/dist/cli/{chunk-y1pebzpv.js → chunk-7sd9m43a.js} +1 -1
- package/dist/cli/{chunk-5mweps5x.js → chunk-7txq91d9.js} +1 -1
- package/dist/cli/{chunk-63wmhbqs.js → chunk-85mk6j0s.js} +1 -1
- package/dist/cli/{chunk-smyp21f3.js → chunk-8bknntvc.js} +1 -1
- package/dist/cli/{chunk-q5jhy3t8.js → chunk-8hbtca1g.js} +2 -2
- package/dist/cli/{chunk-nxr2qg1f.js → chunk-9e6rnnsy.js} +1 -1
- package/dist/cli/{chunk-ndtbxgyp.js → chunk-9mtxxsb3.js} +1 -1
- package/dist/cli/{chunk-92k1jste.js → chunk-b1kg21v2.js} +2 -2
- package/dist/cli/chunk-bm1z1zsp.js +2 -0
- package/dist/cli/{chunk-h30gy8x8.js → chunk-bs7v83x0.js} +1 -1
- package/dist/cli/{chunk-80jwjzn8.js → chunk-bw73t1zw.js} +1 -1
- package/dist/cli/chunk-bx2m48tf.js +2 -0
- package/dist/cli/{chunk-d8a464tx.js → chunk-cb4gdbxn.js} +1 -1
- package/dist/cli/{chunk-jyghj39f.js → chunk-cezewj1a.js} +1 -1
- package/dist/cli/{chunk-mmdvkep0.js → chunk-chmhmxmc.js} +1 -1
- package/dist/cli/{chunk-35xdfn8a.js → chunk-d1a1kw0c.js} +1 -1
- package/dist/cli/{chunk-t116w45w.js → chunk-d9hjspk0.js} +1 -1
- package/dist/cli/{chunk-t5r0e11g.js → chunk-dfa8fz7d.js} +1 -1
- package/dist/cli/{chunk-p5yb73tg.js → chunk-eyx792dw.js} +1 -1
- package/dist/cli/chunk-frrjz0dr.js +2 -0
- package/dist/cli/chunk-fwb72vzc.js +2 -0
- package/dist/cli/{chunk-878cxvry.js → chunk-gfwxx6mh.js} +1 -1
- package/dist/cli/{chunk-ad6wj8y8.js → chunk-ggq4vsdv.js} +1 -1
- package/dist/cli/chunk-ghxhqkey.js +2 -0
- package/dist/cli/{chunk-b9xgyff6.js → chunk-gjtyxam6.js} +1 -1
- package/dist/cli/{chunk-mz0khr9c.js → chunk-h9gh63kp.js} +1 -1
- package/dist/cli/{chunk-dhfcgq6t.js → chunk-hf1sjxtt.js} +1 -1
- package/dist/cli/chunk-hg87p5n8.js +3 -0
- package/dist/cli/chunk-hgx20x94.js +2 -0
- package/dist/cli/{chunk-rga7a5kk.js → chunk-jtbk2jqm.js} +1 -1
- package/dist/cli/{chunk-9zf2wn5c.js → chunk-k7g060qr.js} +1 -1
- package/dist/cli/chunk-k95j7j3a.js +3 -0
- package/dist/cli/{chunk-09g89dxy.js → chunk-kbsrbpbf.js} +1 -1
- package/dist/cli/chunk-mbxn4tj2.js +2 -0
- package/dist/cli/{chunk-81p6mm0p.js → chunk-mkksdcsw.js} +1 -1
- package/dist/cli/{chunk-w0tdbrpw.js → chunk-mvz494h2.js} +1 -1
- package/dist/cli/chunk-n8dkpf4v.js +3 -0
- package/dist/cli/{chunk-kf8whkc2.js → chunk-nnz4r6p4.js} +1 -1
- package/dist/cli/{chunk-pvwfah6e.js → chunk-ntr5zmav.js} +1 -1
- package/dist/cli/{chunk-fczqwtmq.js → chunk-nvqdmx7q.js} +1 -1
- package/dist/cli/{chunk-ekdh3m31.js → chunk-nzjx0c9k.js} +1 -1
- package/dist/cli/{chunk-f6fws7v6.js → chunk-p5cq4s0x.js} +1 -1
- package/dist/cli/chunk-ppwpjm39.js +3 -0
- package/dist/cli/chunk-pycgw6f8.js +2 -0
- package/dist/cli/{chunk-a9zyq3m8.js → chunk-qdfcdhy8.js} +2 -2
- package/dist/cli/chunk-qhbg7mcd.js +2 -0
- package/dist/cli/{chunk-j98bfbz1.js → chunk-qm637645.js} +1 -1
- package/dist/cli/chunk-qqkw8v6p.js +2 -0
- package/dist/cli/chunk-qzfksm8e.js +9 -0
- package/dist/cli/{chunk-jtpcbk1y.js → chunk-r84kan7b.js} +1 -1
- package/dist/cli/{chunk-gp72n435.js → chunk-ream62r3.js} +1 -1
- package/dist/cli/{chunk-pq897z3n.js → chunk-rhczy26f.js} +1 -1
- package/dist/cli/{chunk-53akb9x8.js → chunk-s1e0e9hc.js} +2 -2
- package/dist/cli/{chunk-x6c4jega.js → chunk-s278gjet.js} +1 -1
- package/dist/cli/{chunk-eswcq53q.js → chunk-s9tesp5e.js} +2 -2
- package/dist/cli/{chunk-3xs0hv9f.js → chunk-sn2r47e9.js} +1 -1
- package/dist/cli/{chunk-hrrpfxpk.js → chunk-snaz3hq7.js} +1 -1
- package/dist/cli/{chunk-s08dx83v.js → chunk-vbhhrewn.js} +1 -1
- package/dist/cli/{chunk-q6h7128y.js → chunk-vh5bkm9k.js} +2 -2
- package/dist/cli/chunk-vzqrj32e.js +2 -0
- package/dist/cli/{chunk-wm7gc75a.js → chunk-xkt7pf15.js} +2 -2
- package/dist/cli/chunk-xmdbky9n.js +2 -0
- package/dist/cli/{chunk-cs1k9d61.js → chunk-xtw1bcaw.js} +1 -1
- package/dist/cli/{chunk-nzshm6jy.js → chunk-y3k1accw.js} +1 -1
- package/dist/cli/{chunk-3gbfsmqf.js → chunk-y5y0sc9a.js} +1 -1
- package/dist/cli/chunk-ywmw8pvp.js +2 -0
- package/dist/cli/{chunk-ebhc6q1y.js → chunk-yynhrtxx.js} +2 -2
- package/dist/cli/{chunk-bgnjt0pv.js → chunk-zja9chrd.js} +1 -1
- package/dist/cli/{chunk-k74rfmkd.js → chunk-zm2f0d23.js} +1 -1
- package/dist/cli/{chunk-6cm9pb1f.js → chunk-zyd6k6ak.js} +1 -1
- package/dist/cli/index.js +7 -7
- package/dist/cli/kobe-run.js +1 -1
- package/dist/cli/kobe.js +6 -6
- package/dist/cli/rove-run.js +1 -1
- package/dist/cli/rove.js +6 -6
- package/dist/skills/rove/SKILL.md +1 -1
- package/dist/skills/rove/references/api-flags.md +1 -1
- package/dist/web-ui/assets/{harness-BP9XoO1F.js → harness-DiS1yHqA.js} +1 -1
- package/dist/web-ui/assets/{index-CgF_t_5x.css → index-D3usUDr4.css} +1 -1
- package/dist/web-ui/assets/{index-DnDOnFJk.js → index-DxszcdCE.js} +2 -2
- package/dist/web-ui/index.html +2 -2
- package/package.json +2 -1
- package/dist/cli/chunk-00ehck55.js +0 -3
- package/dist/cli/chunk-228be43v.js +0 -2
- package/dist/cli/chunk-2wxhkv4v.js +0 -3
- package/dist/cli/chunk-55xh5e1h.js +0 -2
- package/dist/cli/chunk-7eb6g8h1.js +0 -2
- package/dist/cli/chunk-87zgxa61.js +0 -2
- package/dist/cli/chunk-9213863e.js +0 -9
- package/dist/cli/chunk-ad8dbps8.js +0 -2
- package/dist/cli/chunk-ah9ky2f7.js +0 -2
- package/dist/cli/chunk-c8dbw8rz.js +0 -3
- package/dist/cli/chunk-d0f53cxh.js +0 -2
- package/dist/cli/chunk-eny3f446.js +0 -2
- package/dist/cli/chunk-gkxvcb9n.js +0 -8
- package/dist/cli/chunk-j5ye4gwh.js +0 -3
- package/dist/cli/chunk-md0fz63v.js +0 -2
- package/dist/cli/chunk-mvz2a6a1.js +0 -3
- package/dist/cli/chunk-nxht58t9.js +0 -2
- package/dist/cli/chunk-p92skpts.js +0 -2
- package/dist/cli/chunk-pvr86wd3.js +0 -2
- package/dist/cli/chunk-qsne628q.js +0 -2
- package/dist/cli/chunk-rgw6ddre.js +0 -2
- package/dist/cli/chunk-txevhry4.js +0 -2
- package/dist/cli/chunk-wmv1bjak.js +0 -2
- package/dist/cli/chunk-y4a23q6m.js +0 -2
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{isRowTokenTone}from"./chunk-59xc6m1q.js";import{sameWorktreeChanges}from"./chunk-k6nxyxyh.js";import{ensureDaemonReachable,isStaleInstallError}from"./chunk-5t8cazgm.js";import{toTaskId}from"./chunk-xy8be792.js";import{CURRENT_VERSION}from"./chunk-2wxhkv4v.js";import{homeDir}from"./chunk-q5jhy3t8.js";import{createStateCell,mapReadableState}from"./chunk-sdyzxayr.js";import{DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,isAttentionInboxState,isDaemonVersionStale,isForeignDaemonHome,isProtocolCompatible,parseDaemonStopReason}from"./chunk-p1zab1sy.js";import{logClient,logClientError}from"./chunk-3es6spp4.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:"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 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})}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]))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.routine?{routine:s.routine}:{},status:s.status,pinned:s.pinned,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,linkedWorkItem:s.linkedWorkItem,dispatcher:s.dispatcher,prompt:s.prompt,baseRef:s.baseRef,worktreeName:s.worktreeName,report:s.report,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)}}}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 / KOBE_DAEMON_SOCKET_PATH before starting it.`);if(signals.setDaemonVersionSig(typeof hello.kobeVersion==="string"?hello.kobeVersion: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,kobeVersion:typeof hello.kobeVersion==="string"?hello.kobeVersion:""}),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)`)}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)},"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?.kobeVersion==="string")signals.setDaemonVersionSig(p.kobeVersion);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&&p.state==="routine_failed")&&(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==="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 next=new Map(current);next.set(p.taskId,{kind:p.kind}),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==="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==="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)}})}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 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 moveTaskOp(client,id,delta){await client.request("task.move",{taskId:String(id),direction:delta<0?"up":"down"})}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){await client.request("task.delete",{taskId:String(id),force:opts?.force,deleteBranch:opts?.deleteBranch})}async function dismissAttentionOp(client,taskId,tabId,at){return(await client.request("attention.dismiss",{taskId:String(taskId),...tabId!==null?{tabId}:{},at})).deleted}async function dismissRoutineAttentionOp(client,automationId){return(await client.request("attention.dismissRoutine",{automationId})).deleted}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){return(await client.request("task.syncBase",{taskId})).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 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([]);taskJobsAcc=createStateCell(new Map);rowTokensAcc=createStateCell(new Map);worktreeChangesAcc=createStateCell(null);usageSnapshotAcc=createStateCell(null);contextUsageAcc=createStateCell(null);transcriptActivityAcc=createStateCell(null);noticeAcc=createStateCell(null);tabOpenAcc=createStateCell(null);tabCloseAcc=createStateCell(null);tabRenameAcc=createStateCell(null);uiPromptAcc=createStateCell(null);engineLifecycleAcc=createStateCell(new Map);uiPrefsAcc=createStateCell(null);keybindingsRevAcc=createStateCell(null);connectionStateAcc=createStateCell("online","orchestrator.connection");staleInstallAcc=createStateCell(null);ensureReachable;role;cellPixelSize;channels;subscribesTasks;expectForeignHome;onPeerIdentity;reconnectTask=null;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.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,taskJobsAcc:this.taskJobsAcc,setTaskJobsSig:this.taskJobsAcc.set,rowTokensAcc:this.rowTokensAcc,setRowTokensSig:this.rowTokensAcc.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,setUiPromptSig:this.uiPromptAcc.set,engineLifecycleAcc:this.engineLifecycleAcc,setEngineLifecycleSig:this.engineLifecycleAcc.set,setUiPrefsSig:this.uiPrefsAcc.set,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)})}reconnectLoop(spawnDaemon){if(this.reconnectTask)return this.reconnectTask;let task=runReconnectLoop({isDisposed:()=>this.client.isDisposed,spawnDaemon,ensureReachable:this.ensureReachable,init:()=>this.init(),shouldLogAttempt:shouldLogReconnectAttempt,onFatal:(err)=>this.staleInstallAcc.set(err instanceof Error?err.message:String(err))});this.reconnectTask=task;let clear=()=>{if(this.reconnectTask===task)this.reconnectTask=null};return task.then(clear,clear),task}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;taskJobsSignal=()=>this.taskJobsAcc;rowTokensSignal=()=>this.rowTokensAcc;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;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);reportEngineInterrupt=(taskId,tabId)=>reportEngineInterruptOp(this.client,String(taskId),tabId);uiPrefsSignal=()=>this.uiPrefsAcc;uiPrefsStore=()=>this.uiPrefsAcc;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);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);moveTask=(id,delta)=>moveTaskOp(this.client,id,delta);setStatus=(id,status)=>setStatusOp(this.client,id,status);setPrompt=(id,prompt)=>setPromptOp(this.client,id,prompt);deleteTask=(id,opts)=>deleteTaskOp(this.client,id,opts);dismissAttention=(taskId,tabId,at)=>dismissAttentionOp(this.client,taskId,tabId,at);dismissRoutineAttention=(automationId)=>dismissRoutineAttentionOp(this.client,automationId);markAttentionRead=(taskId,tabId,at)=>markAttentionReadOp(this.client,taskId,tabId,at);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);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{isRowTokenTone}from"./chunk-59xc6m1q.js";import{sameWorktreeChanges}from"./chunk-k6nxyxyh.js";import{ensureDaemonReachable,isStaleInstallError}from"./chunk-5t8cazgm.js";import{toTaskId}from"./chunk-xy8be792.js";import{CURRENT_VERSION}from"./chunk-n8dkpf4v.js";import{homeDir}from"./chunk-8hbtca1g.js";import{createStateCell,mapReadableState}from"./chunk-sdyzxayr.js";import{DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,isAttentionInboxState,isDaemonVersionStale,isForeignDaemonHome,isProtocolCompatible,parseDaemonStopReason}from"./chunk-p1zab1sy.js";import{logClient,logClientError}from"./chunk-3es6spp4.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:"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 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})}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]))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.routine?{routine:s.routine}:{},status:s.status,pinned:s.pinned,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,linkedWorkItem:s.linkedWorkItem,dispatcher:s.dispatcher,prompt:s.prompt,baseRef:s.baseRef,worktreeName:s.worktreeName,report:s.report,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)}}}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 / KOBE_DAEMON_SOCKET_PATH before starting it.`);if(signals.setDaemonVersionSig(typeof hello.kobeVersion==="string"?hello.kobeVersion: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,kobeVersion:typeof hello.kobeVersion==="string"?hello.kobeVersion:""}),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)`)}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)},"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?.kobeVersion==="string")signals.setDaemonVersionSig(p.kobeVersion);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&&p.state==="routine_failed")&&(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==="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 next=new Map(current);next.set(p.taskId,{kind:p.kind}),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==="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==="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)}})}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 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 moveTaskOp(client,id,delta){await client.request("task.move",{taskId:String(id),direction:delta<0?"up":"down"})}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){await client.request("task.delete",{taskId:String(id),force:opts?.force,deleteBranch:opts?.deleteBranch})}async function dismissAttentionOp(client,taskId,tabId,at){return(await client.request("attention.dismiss",{taskId:String(taskId),...tabId!==null?{tabId}:{},at})).deleted}async function dismissRoutineAttentionOp(client,automationId){return(await client.request("attention.dismissRoutine",{automationId})).deleted}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){return(await client.request("task.syncBase",{taskId})).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 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([]);taskJobsAcc=createStateCell(new Map);rowTokensAcc=createStateCell(new Map);worktreeChangesAcc=createStateCell(null);usageSnapshotAcc=createStateCell(null);contextUsageAcc=createStateCell(null);transcriptActivityAcc=createStateCell(null);noticeAcc=createStateCell(null);tabOpenAcc=createStateCell(null);tabCloseAcc=createStateCell(null);tabRenameAcc=createStateCell(null);uiPromptAcc=createStateCell(null);engineLifecycleAcc=createStateCell(new Map);uiPrefsAcc=createStateCell(null);keybindingsRevAcc=createStateCell(null);connectionStateAcc=createStateCell("online","orchestrator.connection");staleInstallAcc=createStateCell(null);ensureReachable;role;cellPixelSize;channels;subscribesTasks;expectForeignHome;onPeerIdentity;reconnectTask=null;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.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,taskJobsAcc:this.taskJobsAcc,setTaskJobsSig:this.taskJobsAcc.set,rowTokensAcc:this.rowTokensAcc,setRowTokensSig:this.rowTokensAcc.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,setUiPromptSig:this.uiPromptAcc.set,engineLifecycleAcc:this.engineLifecycleAcc,setEngineLifecycleSig:this.engineLifecycleAcc.set,setUiPrefsSig:this.uiPrefsAcc.set,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)})}reconnectLoop(spawnDaemon){if(this.reconnectTask)return this.reconnectTask;let task=runReconnectLoop({isDisposed:()=>this.client.isDisposed,spawnDaemon,ensureReachable:this.ensureReachable,init:()=>this.init(),shouldLogAttempt:shouldLogReconnectAttempt,onFatal:(err)=>this.staleInstallAcc.set(err instanceof Error?err.message:String(err))});this.reconnectTask=task;let clear=()=>{if(this.reconnectTask===task)this.reconnectTask=null};return task.then(clear,clear),task}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;taskJobsSignal=()=>this.taskJobsAcc;rowTokensSignal=()=>this.rowTokensAcc;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;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);reportEngineInterrupt=(taskId,tabId)=>reportEngineInterruptOp(this.client,String(taskId),tabId);uiPrefsSignal=()=>this.uiPrefsAcc;uiPrefsStore=()=>this.uiPrefsAcc;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);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);moveTask=(id,delta)=>moveTaskOp(this.client,id,delta);setStatus=(id,status)=>setStatusOp(this.client,id,status);setPrompt=(id,prompt)=>setPromptOp(this.client,id,prompt);deleteTask=(id,opts)=>deleteTaskOp(this.client,id,opts);dismissAttention=(taskId,tabId,at)=>dismissAttentionOp(this.client,taskId,tabId,at);dismissRoutineAttention=(automationId)=>dismissRoutineAttentionOp(this.client,automationId);markAttentionRead=(taskId,tabId,at)=>markAttentionReadOp(this.client,taskId,tabId,at);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);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,RemoteOrchestrator};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{activeCliName}from"./chunk-
|
|
2
|
+
import{activeCliName}from"./chunk-ppwpjm39.js";var SEARCH_TIMEOUT_MS=5000,CLI_NAME=activeCliName(),FIRST_PARTY=[{ref:"Sma1lboy/kobe-plugins/notify",desc:"Desktop/ntfy notifications when an agent finishes or needs input"},{ref:"Sma1lboy/kobe-plugins/github-start",desc:"Start a Rove task from a GitHub issue or PR"},{ref:"Sma1lboy/kobe-plugins/worktree-include",desc:"Copy .worktreeinclude-matched files into new worktrees"},{ref:"Sma1lboy/kobe-plugins/linear-start",desc:"Pick a Linear issue (fzf) and start a task on its branch"},{ref:"Sma1lboy/kobe-plugins/lazygit",desc:"lazygit on the task worktree, as a pane tab"},{ref:"Sma1lboy/kobe-plugins/browser",desc:"Chromium rendered as terminal cells (carbonyl) in a pane tab"}];async function fetchTopic(topic,query){let q=encodeURIComponent(`topic:${topic}${query?` ${query}`:""}`),ctrl=new AbortController,timer=setTimeout(()=>ctrl.abort(),SEARCH_TIMEOUT_MS);try{let res=await fetch(`https://api.github.com/search/repositories?q=${q}&sort=stars&order=desc&per_page=50`,{signal:ctrl.signal,headers:{accept:"application/vnd.github+json"}});if(!res.ok)return null;let body=await res.json();if(!Array.isArray(body.items))return null;return body.items.filter((r)=>typeof r.full_name==="string").map((r)=>({ref:r.full_name,desc:r.description??"",stars:r.stargazers_count}))}catch{return null}finally{clearTimeout(timer)}}async function fetchMarketplace(query){let topicResults=await Promise.all([fetchTopic("rove-plugin",query),fetchTopic("kobe-plugin",query)]),lower=query?.toLowerCase(),seeds=FIRST_PARTY.filter((s)=>!lower||`${s.ref} ${s.desc}`.toLowerCase().includes(lower)).map((s)=>({...s,firstParty:!0}));return{entries:dedupeEntries([...seeds,...topicResults.flatMap((result)=>result??[])]),offline:topicResults.every((result)=>result===null)}}async function searchMarketplace(query){let{entries,offline}=await fetchMarketplace(query);if(offline)console.error("(GitHub search unreachable \u2014 showing first-party plugins only)");if(entries.length===0){console.log(query?`no plugins match \`${query}\``:"no plugins found");return}let width=Math.min(48,Math.max(...entries.map((e)=>e.ref.length))+2);for(let e of entries){let stars=e.stars!==void 0?`\u2605${e.stars}`:e.firstParty?"first-party":"";console.log(`${e.ref.padEnd(width)}${stars.padEnd(12)}${e.desc}`)}console.log(`
|
|
3
3
|
install: ${CLI_NAME} plugin install <owner/repo[/subdir]> \u2014 browse: https://rove.run/plugins`)}function dedupeEntries(entries){let seen=new Set;return entries.filter((entry)=>{let key=entry.ref.toLowerCase();if(seen.has(key))return!1;return seen.add(key),!0})}
|
|
4
4
|
export{fetchMarketplace,searchMarketplace};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{generateCompletions,isShellKind,mergeSubVerbs,shippedCompletionsPath}from"./chunk-yybpg7fh.js";import"./chunk-fhch0x0q.js";import{activeCliName}from"./chunk-ppwpjm39.js";import"./chunk-fxs82dsx.js";import"./chunk-zyd6k6ak.js";import"./chunk-8hbtca1g.js";import"./chunk-hq2n27y1.js";import"./chunk-sb0ns0c7.js";import"./chunk-vnpqemb0.js";import"./chunk-9prawccj.js";import"./chunk-y8fqdnh3.js";import"./chunk-hq4b3fca.js";import{__require}from"./chunk-wqfp8d9w.js";import{existsSync,readFileSync}from"fs";var HELP_WORDS=["--help","-h","help"];function completionUsage(cliName){return[`Usage: ${cliName} completions <bash|zsh|fish> [--path|--install]`,"",`Print a shell completion script for ${cliName}, or locate the copy shipped`,"with this install.","",` ${cliName} completions zsh --path print the shipped script's path`,` ${cliName} completions zsh --install hook it into your shell config`,"","Install:",` zsh source <(${cliName} completions zsh) # one-off, or in ~/.zshrc after compinit`," # with no process start per shell \u2014 what the first-run wizard writes:",` # ${cliName} completions zsh --install`,` bash ${cliName} completions bash --install # appends to ~/.bashrc`,` fish ${cliName} completions fish --install # writes ~/.config/fish/completions/${cliName}.fish`," # the manual way, any shell:",` # ${cliName} completions zsh > ~/.zsh/completions/_${cliName}`," # fpath=(~/.zsh/completions $fpath) # in ~/.zshrc, BEFORE compinit"," # rm -f ~/.zcompdump && exec zsh # rebuild the completion cache",""].join(`
|
|
3
|
+
`)}async function runCompletionsSubcommand(rest,cliName=activeCliName(),deps={}){let usage=completionUsage(cliName),fail=(message)=>{process.stderr.write(`${cliName} completions: ${message}
|
|
4
|
+
|
|
5
|
+
${usage}`),process.exit(2)};if(rest.some((arg)=>HELP_WORDS.includes(arg))){process.stdout.write(usage);return}let flags=rest.filter((arg)=>arg.startsWith("-")),shells=rest.filter((arg)=>!arg.startsWith("-")),unknownFlag=flags.find((flag)=>flag!=="--path"&&flag!=="--install");if(unknownFlag)fail(`unknown option "${unknownFlag}"`);if(new Set(flags).size>1)fail("--path and --install are different things; pass one");let shell=shells.length===1?shells[0]:void 0;if(!isShellKind(shell))fail(`unknown shell "${shells.join(" ")}"`);let scriptPath=shippedCompletionsPath(shell,cliName,deps.shippedDir),shipped=existsSync(scriptPath)?scriptPath:null;if(flags[0]==="--path"){if(!shipped)fail(`no pre-generated ${shell} script at ${scriptPath}
|
|
6
|
+
${cliName} completions ${shell} # print the script to stdout instead`);process.stdout.write(`${shipped}
|
|
7
|
+
`);return}if(flags[0]==="--install"){let[{installCompletions},{t}]=await Promise.all([import("./chunk-qhbg7mcd.js"),import("./chunk-4rnfvn7x.js")]),completion=installCompletions(shell,deps.home,cliName,shipped),line=completion.installed?"onboarding.appliedCompletions":"onboarding.keptCompletions";process.stdout.write(`${t(line,{path:completion.path})}
|
|
8
|
+
`);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-mbxn4tj2.js");process.stdout.write(generateCompletions(shell,cliName,mergeSubVerbs(API_VERBS)))}export{runCompletionsSubcommand};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{countCronBetween,isValidCron,latestCronAtOrBefore,nextCronAfter,tightenInstalledPluginPermissions}from"./chunk-85pk7c74.js";import{buildPluginEnv}from"./chunk-53afdybj.js";import{ClientWriter,LineReceiver,linkLegacyRuntimePath,objectPayload,optionalActivityDetail,optionalBoolean,optionalNumber,optionalString,optionalVendor,requireNumber,requireString}from"./chunk-rz8zs7j8.js";import{IssuesStore,defaultIssuesStorePath,resolveRepoRoot}from"./chunk-mhg40es1.js";import{STICKY_STATES,activityStillWorking,reduceActivity,resolveEngineStateTtlMs}from"./chunk-r2pztgm6.js";import{currentPluginPlatform,loadPluginRegistry,pluginConfigDir,pluginLogPath,pluginManifestPath,pluginRegistryPath,pluginStateDir,readPluginManifest,supportsPlatform}from"./chunk-1da3bqjc.js";import{managedWorktreeRootsFor,readWorktreeBaseOverride}from"./chunk-
|
|
2
|
+
import{countCronBetween,isValidCron,latestCronAtOrBefore,nextCronAfter,tightenInstalledPluginPermissions}from"./chunk-85pk7c74.js";import{buildPluginEnv}from"./chunk-53afdybj.js";import{ClientWriter,LineReceiver,linkLegacyRuntimePath,objectPayload,optionalActivityDetail,optionalBoolean,optionalNumber,optionalString,optionalVendor,requireNumber,requireString}from"./chunk-rz8zs7j8.js";import{IssuesStore,defaultIssuesStorePath,resolveRepoRoot}from"./chunk-mhg40es1.js";import{STICKY_STATES,activityStillWorking,reduceActivity,resolveEngineStateTtlMs}from"./chunk-r2pztgm6.js";import{currentPluginPlatform,loadPluginRegistry,pluginConfigDir,pluginLogPath,pluginManifestPath,pluginRegistryPath,pluginStateDir,readPluginManifest,supportsPlatform}from"./chunk-1da3bqjc.js";import{managedWorktreeRootsFor,readWorktreeBaseOverride}from"./chunk-85mk6j0s.js";import{serialized,writeJsonAtomic,writeTextAtomic}from"./chunk-xsrcwcjc.js";import{RowTokenStore,isRowTokenTone}from"./chunk-59xc6m1q.js";import{ptyHostHasLiveSessions,sweepPtyHostSessions}from"./chunk-gfwxx6mh.js";import{logDaemonError,logDaemonInfo}from"./chunk-rcyasw34.js";import{resolveLoginShell}from"./chunk-b99tf0jr.js";import{decodeCapturedChunks,maybeStartScheduledRun}from"./chunk-khj0apc7.js";import{ENGINE_EXIT_BANNER,engineExitCodeFromTail,plainTail,readPtyExitRecords,readPtyExitStore,recordEngineExit}from"./chunk-g3r1dwy9.js";import{parsePorcelainRows}from"./chunk-h4n8ffqy.js";import{worktreeFingerprint}from"./chunk-vyb5a2rh.js";import{probeDaemonSocket}from"./chunk-5t8cazgm.js";import{defaultKeybindingsPath,defaultUiPrefsStatePath}from"./chunk-8hbtca1g.js";import{createSocketOwnershipGuard,isProcessAlive,listenOnUnixSocket}from"./chunk-vnpqemb0.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE,ensureOwnerOnlyStateDir}from"./chunk-9prawccj.js";import{KobeDaemonClient}from"./chunk-mjdt28x6.js";import{CHANNEL_NAMES,DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,attentionInboxItemKey,automationRunNeedsAttention,displayTaskTitle,frameToLine,isAttentionInboxState,isProtocolCompatible,normalizeChannelFilter,parseDaemonStopReason,serializeTask}from"./chunk-p1zab1sy.js";import{rotateLogIfNeeded}from"./chunk-pw6yfj10.js";import{pathIdentity,pathSyntax,pathWithin,samePath}from"./chunk-f10n6063.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyExitsPath,defaultPtyHostSocketPath,legacyDaemonPidPath,legacyDaemonSocketPath,resolveDaemonHomeDir}from"./chunk-y8fqdnh3.js";import{ROVE_STATE_DIR_BASENAME,readRoveEnv,readRoveHomeDirEnv}from"./chunk-hq4b3fca.js";import{__require}from"./chunk-wqfp8d9w.js";import{mkdir,unlink as unlink2}from"fs/promises";import{createServer}from"net";import{dirname as dirname2}from"path";import{statSync}from"fs";var WATCHED_FIELDS=["title","branch","worktreePath","status","pinned","vendor","command","modelEffort","model","tier","linkedWorkItem","scratch"];function same(a,b){if(a===b)return!0;if(a==null||b==null)return a==null&&b==null;if(typeof a==="object"||typeof b==="object")return JSON.stringify(a)===JSON.stringify(b);return!1}function samePr(a,b){let strip=(v)=>{if(v==null||typeof v!=="object"||Array.isArray(v))return v;let{lastCheckedAt:_a,lastError:_b,...rest}=v;return rest};return same(strip(a),strip(b))}function diffTask(prev,next){let fields=[],from={},to={};for(let field of WATCHED_FIELDS){let a=prev[field],b=next[field];if(same(a,b))continue;if(fields.push(field),a!==void 0)from[field]=a;if(b!==void 0)to[field]=b}let prChanged=!samePr(prev.prStatus,next.prStatus);if(fields.length===0&&!prChanged)return null;return{fields,from,to,prChanged,worktreeCreated:next.kind==="task"&&!prev.worktreePath&&!!next.worktreePath}}function bornWithWorktree(task){return task.kind==="task"&&!!task.worktreePath}function lifecycleEventFor(kind,detail){switch(kind){case"session-start":return"session.start";case"session-end":return"session.end";case"turn-start":return"turn.prompt";case"turn-complete":return"turn.complete";case"turn-failed":return"turn.failed";case"turn-interrupted":return"turn.interrupted";case"awaiting-input":return detail?.waiting==="input"?"attention.question":"attention.permission";case"tool-pre":return"tool.pre";case"tool-post":return"tool.post";case"tool-failed":return"tool.failed";case"pre-compact":return"context.pre-compact";case"post-compact":return"context.post-compact";case"subagent-start":return"subagent.start";case"subagent-stop":return"subagent.stop";default:return}}var AGENT_EVENT_BY_STATE={turn_complete:"agent.turn-complete",permission_needed:"agent.permission-needed",rate_limited:"agent.rate-limited",error:"agent.error",running:"agent.running",idle:"agent.idle"};function taskContext(task){if(!task)return;let{id,title,repo,branch,worktreePath,vendor,status}=task;return{id,title,repo,branch,worktreePath,vendor,status}}class PluginEventReducer{tasks;agentState=new Map;now;constructor(now=Date.now){this.now=now}contextFor(taskId){return taskContext(this.tasks?.get(taskId))}reduce(event){switch(event.channel){case"task.snapshot":return this.reduceTasks(event.payload.tasks);case"engine-state":return this.reduceEngine(event.payload);default:return[]}}reduceTasks(tasks){let next=new Map(tasks.map((t)=>[t.id,t])),prev=this.tasks;if(this.tasks=next,!prev)return[];let at=this.now(),out=[];for(let[id,task]of next){let before=prev.get(id);if(!before){if(out.push({event:"task.created",taskId:id,task:taskContext(task),at}),bornWithWorktree(task))out.push({event:"worktree.created",taskId:id,task:taskContext(task),at});continue}let diff=diffTask(before,task);if(!diff)continue;let ctx=taskContext(task);if(diff.fields.length>0)out.push({event:"task.changed",taskId:id,task:ctx,detail:{fields:diff.fields,from:diff.from,to:diff.to},at});if(diff.prChanged)out.push({event:"task.pr-changed",taskId:id,task:ctx,detail:{...before.prStatus!==void 0?{from:before.prStatus}:{},...task.prStatus!==void 0?{to:task.prStatus}:{}},at});if(diff.worktreeCreated)out.push({event:"worktree.created",taskId:id,task:ctx,at})}for(let[id,task]of prev)if(!next.has(id))out.push({event:"task.deleted",taskId:id,task:taskContext(task),at});return out}reduceEngine(payload){let key=`${payload.taskId}\x00${payload.tabId??""}`,prev=this.agentState.get(key);if(this.agentState.set(key,payload.state),prev===payload.state)return[];let event=AGENT_EVENT_BY_STATE[payload.state];if(!event)return[];return[{event,taskId:payload.taskId,task:taskContext(this.tasks?.get(payload.taskId)),...payload.tabId?{tabId:payload.tabId}:{},at:this.now()}]}}import{spawn}from"child_process";import{appendFileSync,mkdirSync}from"fs";var OUTPUT_CAP=8192,PLUGIN_LOG_CAP_BYTES=4194304,SHUTDOWN_GRACE_MS=3000,HOOK_TIMEOUT_MS=30000,HOOK_SLOW_MS=2000;function hookTimeoutMs(spec,kind){return spec.timeoutMs??(kind==="shutdown"?SHUTDOWN_GRACE_MS:HOOK_TIMEOUT_MS)}function appendRecord(pluginId,homeDir,record){try{let logPath=pluginLogPath(pluginId,homeDir);rotateLogIfNeeded(logPath,PLUGIN_LOG_CAP_BYTES),appendFileSync(logPath,`${JSON.stringify(record)}
|
|
3
3
|
`,{mode:OWNER_ONLY_FILE_MODE})}catch{}}async function runPluginHook(opts){let{pluginId,spec,kind,label,homeDir}=opts,timeoutMs=hookTimeoutMs(spec,kind),startedAt=Date.now();try{mkdirSync(pluginConfigDir(pluginId,homeDir),{recursive:!0,mode:OWNER_ONLY_DIR_MODE}),mkdirSync(pluginStateDir(pluginId,homeDir),{recursive:!0,mode:OWNER_ONLY_DIR_MODE})}catch(err){appendRecord(pluginId,homeDir,{at:startedAt,kind,label,command:spec.command,exitCode:null,durationMs:Date.now()-startedAt,spawnError:String(err)}),opts.log?.(`plugin ${pluginId} ${label}: ${String(err)}`);return}let exitCode=null,stdout="",stderr="",spawnError,timedOut=!1;if(await new Promise((resolve)=>{let[cmd,...args]=spec.command,child=spawn(cmd,args,{cwd:opts.pluginRoot,env:buildPluginEnv({homeDir,socketPath:opts.socketPath,binPath:opts.binPath,pluginId,pluginRoot:opts.pluginRoot,extra:opts.extraEnv}),stdio:["ignore","pipe","pipe"],detached:!0}),kill=()=>{try{if(child.pid)process.kill(-child.pid,"SIGKILL");else child.kill("SIGKILL")}catch{child.kill("SIGKILL")}},deadline=setTimeout(()=>{timedOut=!0,kill()},timeoutMs);deadline.unref?.();let slow=setTimeout(()=>{appendRecord(pluginId,homeDir,{at:startedAt,kind,label,command:spec.command,phase:"running",runningMs:Date.now()-startedAt,timeoutMs})},Math.min(HOOK_SLOW_MS,Math.floor(timeoutMs/2)));slow.unref?.(),opts.inFlight?.add(kill);let finish=()=>{clearTimeout(deadline),clearTimeout(slow),opts.inFlight?.delete(kill),resolve()};child.stdout.on("data",(chunk)=>{if(stdout.length<OUTPUT_CAP)stdout+=chunk.toString().slice(0,OUTPUT_CAP-stdout.length)}),child.stderr.on("data",(chunk)=>{if(stderr.length<OUTPUT_CAP)stderr+=chunk.toString().slice(0,OUTPUT_CAP-stderr.length)}),child.on("error",(err)=>{spawnError=String(err),finish()}),child.on("close",(code)=>{exitCode=code,finish()})}),appendRecord(pluginId,homeDir,{at:startedAt,kind,label,command:spec.command,exitCode,durationMs:Date.now()-startedAt,...timedOut?{timedOut:!0,timeoutMs}:{},...stdout?{stdout}:{},...stderr?{stderr}:{},...spawnError?{spawnError}:{}}),timedOut)opts.log?.(`plugin ${pluginId} ${label}: killed after ${timeoutMs}ms (hook did not exit)`);else if(spawnError||exitCode!==null&&exitCode!==0)opts.log?.(`plugin ${pluginId} ${label}: ${spawnError??`exit ${exitCode}`}`)}var RELOAD_DEBOUNCE_MS=150,REGISTRY_POLL_MS=200;function fileStamp(path){if(!path)return"absent";try{let s=statSync(path,{bigint:!0});return`${s.mtimeNs}:${s.size}:${s.ino}`}catch{return"absent"}}function startPluginHost(bus,opts){let host=new PluginHost(opts);bus.onPublish((event)=>host.handleChannel(event));for(let event of bus.snapshot())host.handleChannel(event);return host.start(),host}function maybeStartPluginHost(bus,options,socketPath,log){if(!options.plugins)return null;return startPluginHost(bus,{homeDir:options.homeDir,socketPath,binPath:options.plugins.binPath,log})}class PluginHost{opts;reducer=new PluginEventReducer;plugins=[];enabledIds=new Set;manifestStamps=new Map;pollTimer;registryStamp="";reloadTimer;inFlight=new Set;stopped=!1;constructor(opts){this.opts=opts}start(){this.watchRegistry(),this.plugins=this.loadPlugins();for(let plugin of this.plugins)for(let[i,hook]of plugin.manifest.startup.entries()){if(!supportsPlatform(hook,plugin.manifest,currentPluginPlatform()))continue;this.run(plugin,hook,"startup",{ROVE_PLUGIN_EVENT:"startup"},`startup[${i}]`)}}async stop(){if(this.stopped)return;if(this.stopped=!0,this.reloadTimer)clearTimeout(this.reloadTimer);if(this.pollTimer)clearInterval(this.pollTimer);for(let kill of[...this.inFlight])kill();let runs=[];for(let plugin of this.plugins)for(let[i,hook]of plugin.manifest.shutdown.entries()){if(!supportsPlatform(hook,plugin.manifest,currentPluginPlatform()))continue;runs.push(this.run(plugin,hook,"shutdown",{ROVE_PLUGIN_EVENT:"shutdown"},`shutdown[${i}]`))}await Promise.allSettled(runs)}handleChannel(event){if(this.stopped)return;try{for(let derived of this.reducer.reduce(event))this.dispatch(derived)}catch(err){this.opts.log?.(`plugin event reduce failed on ${event.channel} \u2014 ${String(err)}`)}}handleUiReport(report){if(this.stopped)return;try{this.dispatch({event:report.kind,...report.taskId?{taskId:report.taskId,task:this.reducer.contextFor(report.taskId)}:{},...report.detail?{detail:report.detail}:{},at:Date.now()})}catch(err){this.opts.log?.(`plugin ui-report dispatch failed for ${report.kind} \u2014 ${String(err)}`)}}handleEngineReport(report){if(this.stopped)return;let event=lifecycleEventFor(report.kind,report.detail);if(!event)return;try{this.dispatch({event,taskId:report.taskId,task:this.reducer.contextFor(report.taskId),...report.vendor?{vendor:report.vendor}:{},...report.tabId?{tabId:report.tabId}:{},...report.sessionId?{sessionId:report.sessionId}:{},...report.detail?{detail:report.detail}:{},at:Date.now()})}catch(err){this.opts.log?.(`plugin engine-report dispatch failed for ${event} \u2014 ${String(err)}`)}}dispatchTo(plugin,event){let platform=currentPluginPlatform();try{for(let hook of plugin.manifest.events){if(hook.on!==event.event)continue;if(!supportsPlatform(hook,plugin.manifest,platform))continue;this.run(plugin,hook,"event",{ROVE_PLUGIN_EVENT:event.event,ROVE_PLUGIN_EVENT_JSON:JSON.stringify(event)},hook.on)}}catch(err){this.opts.log?.(`plugin ${plugin.manifest.id}: ${event.event} dispatch failed \u2014 ${String(err)}`)}}dispatch(event){let platform=currentPluginPlatform();for(let plugin of this.plugins)try{for(let hook of plugin.manifest.events){if(hook.on!==event.event)continue;if(!supportsPlatform(hook,plugin.manifest,platform))continue;this.run(plugin,hook,"event",{ROVE_PLUGIN_EVENT:event.event,ROVE_PLUGIN_EVENT_JSON:JSON.stringify(event),...event.taskId?{ROVE_PLUGIN_TASK_ID:event.taskId}:{},...event.task?.title?{ROVE_PLUGIN_TASK_TITLE:event.task.title}:{}},hook.on)}}catch(err){this.opts.log?.(`plugin ${plugin.manifest.id}: ${event.event} dispatch failed \u2014 ${String(err)}`)}}loadPlugins(){let registry=loadPluginRegistry(this.opts.homeDir),platform=currentPluginPlatform(),out=[],enabled=new Set,stamps=new Map;for(let entry of registry.plugins){if(!entry.enabled)continue;enabled.add(entry.id),stamps.set(entry.root,fileStamp(pluginManifestPath(entry.root)));let manifest;try{manifest=readPluginManifest(entry.root).manifest}catch(err){this.opts.log?.(`plugin ${entry.id}: manifest unreadable, skipping \u2014 ${String(err)}`);continue}if(!supportsPlatform({},manifest,platform))continue;out.push({manifest,root:entry.root})}return this.enabledIds=enabled,this.manifestStamps=stamps,out}sourcesChanged(){let stamp=fileStamp(pluginRegistryPath(this.opts.homeDir));if(stamp!==this.registryStamp)return this.registryStamp=stamp,!0;for(let[root,was]of this.manifestStamps)if(fileStamp(pluginManifestPath(root))!==was)return!0;return!1}watchRegistry(){this.registryStamp=fileStamp(pluginRegistryPath(this.opts.homeDir)),this.pollTimer=setInterval(()=>{if(!this.sourcesChanged())return;if(this.reloadTimer)clearTimeout(this.reloadTimer);this.reloadTimer=setTimeout(()=>{if(this.stopped)return;try{let loadedBefore=new Map(this.plugins.map((p)=>[p.manifest.id,p])),enabledBefore=this.enabledIds;this.plugins=this.loadPlugins(),this.opts.log?.(`plugin registry reloaded (${this.plugins.length} enabled)`);let at=Date.now();for(let plugin of this.plugins)if(!enabledBefore.has(plugin.manifest.id))this.dispatchTo(plugin,{event:"plugin.enabled",detail:{pluginId:plugin.manifest.id},at});for(let[id,plugin]of loadedBefore)if(!this.enabledIds.has(id))this.dispatchTo(plugin,{event:"plugin.disabled",detail:{pluginId:id},at})}catch(err){this.opts.log?.(`plugin registry reload failed \u2014 ${String(err)}`)}},RELOAD_DEBOUNCE_MS)},REGISTRY_POLL_MS),this.pollTimer.unref?.()}run(plugin,spec,kind,extraEnv,label){return runPluginHook({pluginId:plugin.manifest.id,pluginRoot:plugin.root,spec,kind,label,extraEnv,homeDir:this.opts.homeDir,socketPath:this.opts.socketPath,binPath:this.opts.binPath,log:this.opts.log,inFlight:this.inFlight}).catch((err)=>{this.opts.log?.(`plugin ${plugin.manifest.id} ${label}: ${String(err)}`)})}}function replacementKey(frame){if(frame.type!=="event")return null;switch(frame.name){case"task.snapshot":case"active-task":case"update":case"attention.inbox":case"ui-prefs":case"worktree.changes":case"transcript.activity":case"usage.snapshot":case"usage.context":return frame.name;default:return null}}function writeFrame(client,frame){client.writer.write(frameToLine(frame),replacementKey(frame))}function broadcast(clients,frame){let channel=frame.type==="event"&&frame.name!=="daemon.stopping"?frame.name:null,replaceKey=replacementKey(frame),line=null;for(let client of clients){if(!client.subscribed&&frame.type==="event")continue;if(channel&&client.channels&&!client.channels.has(channel))continue;line??=frameToLine(frame),client.writer.write(line,replaceKey)}}function handleClientLine(client,line,onRequest){if(line.trim().length===0)return;try{let frame=JSON.parse(line);if(frame.type!=="request")throw Error("daemon only accepts request frames from clients");onRequest(frame,client)}catch(err){writeFrame(client,{type:"response",id:"parse-error",error:{message:err instanceof Error?err.message:String(err)}})}}import{statSync as statSync2}from"fs";import{basename,dirname,join}from"path";var POLL_MS=200;function startFileWatchTrigger(opts){if(opts.debounceMs<=0)return()=>{};let dir=dirname(opts.filePath),names=[...new Set([basename(opts.filePath),...opts.matchBasenames??[]])],timer=null,trigger=()=>{try{opts.onTrigger()}catch(err){opts.onError(err)}},schedule=()=>{if(timer)clearTimeout(timer);timer=setTimeout(()=>{timer=null,trigger()},opts.debounceMs),timer.unref?.()},stampOf=(name)=>{try{let s=statSync2(join(dir,name),{bigint:!0});return`${s.mtimeNs}:${s.size}:${s.ino}`}catch{return"absent"}},stamps=new Map;for(let name of names)stamps.set(name,stampOf(name));let poll=setInterval(()=>{for(let name of names){let stamp=stampOf(name);if(stamp===stamps.get(name))continue;stamps.set(name,stamp),schedule()}},POLL_MS);return poll.unref?.(),()=>{if(clearInterval(poll),timer)clearTimeout(timer),timer=null}}var DEBOUNCE_MS=250,KEY_RE=/^(.+?)::(.+)$/;function startPtyExitWatch(opts){let path=opts.path??defaultPtyExitsPath(opts.homeDir),seen=new Map,baselined=!1,sweep=()=>{let host=opts.plugins();if(!host)return;let{records,readable}=readPtyExitStore(path);if(!readable)return;for(let[storeKey,record]of Object.entries(records)){if(seen.get(storeKey)===record.at)continue;if(seen.set(storeKey,record.at),!baselined)continue;host.handleUiReport({kind:"session.exited",...exitReport(record)}),publishDeath(record)}baselined=!0;for(let key of seen.keys())if(!(key in records))seen.delete(key)},publishDeath=(record)=>{let registry=opts.activity;if(!registry&&!opts.inbox)return;let death=engineDeathOf(record);if(!death)return;let{taskId,tabId,exit,at}=death;registry?.recordEngineDeath(taskId,tabId,exit,at),opts.inbox?.recordEngineDeath(taskId,tabId,{exit},at).catch((err)=>opts.log?.(`pty-exit inbox: ${String(err)}`))},stop=startFileWatchTrigger({filePath:path,debounceMs:DEBOUNCE_MS,onTrigger:sweep,onError:(err)=>opts.log?.(`pty-exit watch: ${String(err)}`)}),initial=readPtyExitStore(path);if(initial.readable){for(let[storeKey,record]of Object.entries(initial.records))seen.set(storeKey,record.at);baselined=!0}return stop}function engineDeathOf(record){let match=KEY_RE.exec(record.key),taskId=match?.[1],tabId=match?.[2];if(!taskId||!tabId)return null;let at=Date.parse(record.at);if(!Number.isFinite(at))return null;let lastLine=lastErrorLine(record.tail);return{taskId,tabId,exit:{code:record.code,signal:record.signal,...lastLine?{lastLine}:{}},at}}function lastErrorLine(tail){let last;for(let i=tail.length-1;i>=0;i--){let line=(tail[i]??"").trim();if(line.length===0)continue;if(ENGINE_EXIT_BANNER.test(line))return line;last??=line}return last}function exitReport(record){let match=KEY_RE.exec(record.key);return{...match?.[1]?{taskId:match[1]}:{},detail:{key:record.key,...match?.[2]?{tabId:match[2]}:{},pid:record.pid,code:record.code,signal:record.signal,exitedAt:record.at,tail:record.tail}}}function createActivityObserverIo(homeDir,runtime,activity){let peek=async(key)=>{let client=new KobeDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let result=await client.request("pty.peek",{key});return Buffer.from(result.data??"","base64").toString("utf8")}catch{return""}finally{client.close()}};return{onEngineExit({taskId,tabId,vendor,pid}){let key=`${taskId}::${tabId}`,pending=peek(key).then((tail)=>recordEngineExit({key,vendor,pid,at:new Date().toISOString(),tail},defaultPtyExitsPath(homeDir))).catch((err)=>logDaemonInfo("engine-exit",`record failed for ${key}: ${String(err)}`));return logDaemonInfo("engine-exit",`${vendor} (pid ${pid??"?"}) gone from live session ${key}`),pending},onEngineAbsentAtStart({taskId,tabId}){let key=`${taskId}::${tabId}`,path=defaultPtyExitsPath(homeDir),existing=readPtyExitRecords(path)[`${key}#engine`];if(existing){let death=engineDeathOf(existing);if(death)activity?.recordEngineDeath(death.taskId,death.tabId,death.exit,death.at);return}return peek(key).then((raw)=>{if(engineExitCodeFromTail(plainTail(raw))===null)return;recordEngineExit({key,pid:null,at:new Date().toISOString(),tail:raw,atApproximate:!0},path),logDaemonInfo("engine-exit",`recorded an unwatched death in ${key} (exit time unknown)`)}).catch((err)=>logDaemonInfo("engine-exit",`boot record failed for ${key}: ${String(err)}`))},async listSessions(){let client=new KobeDaemonClient(defaultPtyHostSocketPath(homeDir));try{return await client.connect(),((await client.request("pty.list")).sessions??[]).map((s)=>({key:s.key??"",alive:s.alive===!0,pid:typeof s.pid==="number"?s.pid:null,title:typeof s.title==="string"?s.title:"",totalBytes:typeof s.totalBytes==="number"?s.totalBytes:0}))}catch{return null}finally{client.close()}},foregroundEngines:(pids)=>runtime.foregroundEngines(pids),titleTurnHint:(vendor,title)=>runtime.titleTurnHint(vendor,title)}}var DEFAULT_OBSERVER_POLL_MS=1e4,DEFAULT_SILENCE_MS=30000,DEFAULT_WALK_EVERY_TICKS=6,DEFAULT_UNSUBSCRIBED_EVERY_TICKS=6,DEFAULT_CORRECT_AFTER_MS=20000;function startActivityObserver(activity,io,hasSubscribers,options={}){let pollMs=options.pollMs??DEFAULT_OBSERVER_POLL_MS,silenceMs=options.silenceMs??DEFAULT_SILENCE_MS,walkEvery=Math.max(1,options.walkEveryTicks??DEFAULT_WALK_EVERY_TICKS),unsubscribedEvery=Math.max(1,options.unsubscribedEveryTicks??DEFAULT_UNSUBSCRIBED_EVERY_TICKS),correctAfterMs=options.correctAfterMs??DEFAULT_CORRECT_AFTER_MS,log=options.log??logDaemonInfo,tracks=new Map,tickCount=0,unsubscribedTicks=0,inFlight,stopped=!1,bootWalkDone=!1,applyRest=(track,why)=>{if(activity.observeTab(track.taskId,track.tabId,"rest",{...track.vendor?{vendor:track.vendor}:{},correctHookRunningAfterMs:correctAfterMs})==="corrected-hook-running")log("activity-observe",`idled hook-claimed running for ${track.taskId}/${track.tabId} (${why})`)},tick=async()=>{let effects=[];try{let subscribed=hasSubscribers();if(!subscribed&&unsubscribedTicks++%unsubscribedEvery!==0)return;let walkTick=!subscribed||tickCount%walkEvery===0;tickCount++;let listed=await io.listSessions();if(stopped)return;if(listed===null){for(let track of tracks.values())activity.observeTab(track.taskId,track.tabId,"rest",{});return}let sessions=listed,seen=new Set,now=Date.now(),live=[],newborn=new Set;for(let s of sessions){let parts=s.key.split("::");if(parts.length!==2||!parts[0]||!parts[1])continue;if(seen.add(s.key),!s.alive){let track2=tracks.get(s.key);applyRest(track2??{taskId:parts[0],tabId:parts[1],vendor:void 0},"session exited"),tracks.delete(s.key);continue}let track=tracks.get(s.key);if(!track)track={taskId:parts[0],tabId:parts[1],firstSeenAt:now,lastTotalBytes:s.totalBytes,lastTitle:s.title,lastActivityAt:null,vendor:void 0,enginePid:null},tracks.set(s.key,track),newborn.add(s.key);else if(s.totalBytes!==track.lastTotalBytes||s.title!==track.lastTitle)track.lastTotalBytes=s.totalBytes,track.lastTitle=s.title,track.lastActivityAt=now;live.push(track)}for(let[key,track]of tracks){if(seen.has(key)&&sessions.some((s)=>s.key===key&&s.alive))continue;applyRest(track,"session gone"),tracks.delete(key)}let toWalk=live.filter((t)=>walkTick||newborn.has(`${t.taskId}::${t.tabId}`)||t.vendor===void 0);if(toWalk.length>0){let pidByKey=new Map;for(let s of sessions)if(s.alive&&s.pid!==null)pidByKey.set(s.key,s.pid);try{let pids=toWalk.map((t)=>pidByKey.get(`${t.taskId}::${t.tabId}`)).filter((pid)=>pid!==void 0),verdicts=await io.foregroundEngines(pids);if(stopped)return;let bootWalk=!bootWalkDone;bootWalkDone=!0;for(let track of toWalk){let pid=pidByKey.get(`${track.taskId}::${track.tabId}`);if(pid===void 0||!verdicts.has(pid))continue;let found=verdicts.get(pid)??null;if(found===null&&typeof track.vendor==="string")effects.push(io.onEngineExit?.({taskId:track.taskId,tabId:track.tabId,vendor:track.vendor,pid:track.enginePid}));else if(found===null&&track.vendor===void 0&&bootWalk)effects.push(io.onEngineAbsentAtStart?.({taskId:track.taskId,tabId:track.tabId}));track.vendor=found?.vendor??null,track.enginePid=found?.pid??null}}catch{}}if(stopped)return;for(let track of live){let key=`${track.taskId}::${track.tabId}`,session=sessions.find((s)=>s.key===key);if(!session||track.vendor===void 0)continue;if(effects.push(io.onEngineEvidence?.(track.taskId,track.tabId,{walkVendor:track.vendor,title:session.title})),track.vendor===null){applyRest(track,"no engine in foreground");continue}let silentForMs=now-(track.lastActivityAt??track.firstSeenAt),hint=io.titleTurnHint(track.vendor,session.title),claimWorking=(why)=>{if(activity.observeTab(track.taskId,track.tabId,"working",{vendor:track.vendor??void 0})==="observed-running")log("activity-observe",`seeded running for ${track.taskId}/${track.tabId} (${why})`)};if(hint==="rest")applyRest(track,"engine title at rest");else if(track.lastActivityAt!==null&&now-track.lastActivityAt<silenceMs)claimWorking("live output");else if(hint==="working"&&silentForMs<silenceMs)claimWorking("working title frame");else if(silentForMs>=silenceMs)applyRest(track,`no output for ${Math.round(silentForMs/1000)}s`)}}catch{}finally{await Promise.allSettled(effects)}},schedule=()=>{if(stopped||inFlight)return;inFlight=tick().finally(()=>{inFlight=void 0})};schedule();let timer=setInterval(schedule,pollMs);return timer.unref?.(),async()=>{stopped=!0,clearInterval(timer),await inFlight}}function isThenable(value){return typeof value?.then==="function"}function startTicker(opts){if(opts.tickMs<=0)return async()=>{};let running=null,stopped=!1,tick=()=>{if(stopped||opts.gate&&!opts.gate())return;if(running)return;let result;try{result=opts.run()}catch(err){logDaemonError(opts.name,err);return}if(!isThenable(result))return;running=Promise.resolve(result).then(()=>{return}).catch((err)=>logDaemonError(opts.name,err)).finally(()=>{running=null})};if(opts.immediate)tick();let timer=setInterval(tick,opts.tickMs);return timer.unref?.(),async()=>{try{if(!stopped)stopped=!0,clearInterval(timer),opts.onStop?.()}finally{await running}}}var DEFAULT_AUTO_TITLE_POLL_MS=4000;async function runAutoTitlePass(orch,derive,placeholderTitle,defaultVendor){let renamed=[],snapshot=orch.listTasks();for(let task of snapshot){if(task.title!==placeholderTitle||!task.worktreePath)continue;try{let derived=await derive(task.worktreePath,task.vendor??defaultVendor);if(!derived)continue;let title=withGroupOrdinal(derived,task.id,task.groupId,snapshot),current=orch.getTask(task.id);if(!current||current.title!==placeholderTitle)continue;await orch.setTitle(task.id,title),renamed.push({id:task.id,title})}catch(err){logDaemonError("auto-title-poller",err)}}return renamed}function withGroupOrdinal(title,taskId,groupId,snapshot){if(!groupId)return title;let siblings=snapshot.filter((t)=>t.groupId===groupId);if(siblings.length<2)return title;let ordinal=siblings.findIndex((t)=>t.id===taskId);if(ordinal<0)return title;return`${title} #${ordinal+1}/${siblings.length}`}function startAutoTitlePoller(orch,runtime,intervalMs=DEFAULT_AUTO_TITLE_POLL_MS,hasSubscribers){return startTicker({name:"auto-title-poller",tickMs:intervalMs,...hasSubscribers?{gate:hasSubscribers}:{},run:()=>runAutoTitlePass(orch,runtime.deriveTitleFromSession,runtime.placeholderTaskTitle,runtime.defaultTaskVendor)})}import{realpath}from"fs/promises";function automationTarget(automation){if(automation.target)return automation.target;return automation.persistentSession?{kind:"standing",taskId:automation.sessionTaskId}:{kind:"fresh"}}function readAutomationTarget(value){if(value===null)return null;if(typeof value!=="object"||!value||!("kind"in value)||value.kind!=="existing-tab"||!("taskId"in value)||typeof value.taskId!=="string"||!value.taskId.trim()||!("tabId"in value)||typeof value.tabId!=="string"||!/^tab-[\w-]+$/.test(value.tabId))throw Error("target must be { kind: 'existing-tab', taskId, tabId } or null");return{kind:"existing-tab",taskId:value.taskId.trim(),tabId:value.tabId}}function assertAutomationTargetOptions(value){if(!value.target)return;if(value.vendor||value.baseRef||value.persistentSession)throw Error("an existing-tab target cannot set vendor, baseRef or persistentSession; clear them when binding")}function mergeAutomationTargetOptions(automation,patch){return{target:patch.target===null?void 0:patch.target??automation.target,vendor:patch.vendor===null?void 0:patch.vendor??automation.vendor,baseRef:patch.baseRef===null?void 0:patch.baseRef??automation.baseRef,persistentSession:patch.persistentSession??automation.persistentSession,sessionTaskId:patch.target||patch.sessionTaskId===null?void 0:patch.sessionTaskId??automation.sessionTaskId}}async function assertAutomationTargetTask(value,orch){if(!value.target)return;let task=orch.getTask(value.target.taskId);if(!task||task.deletion||!task.worktreePath)throw Error(`target task unavailable: ${value.target.taskId}`);let[repo,taskRepo]=await Promise.all([realpath(value.repo),realpath(task.repo)]);if(repo!==taskRepo)throw Error(`routine repo must match target task repo: ${task.repo}`)}function resolveStandingTask(orch,automation){let id=automation.sessionTaskId;if(!id)return{task:null,hadStaleLink:!1};let task=orch.getTask(id);if(!task||task.deletion||!task.worktreePath)return{task:null,hadStaleLink:!0};return{task}}async function createRunTask(deps,automation){return await deps.orch.createTask({repo:automation.repo,title:automation.name,...automation.vendor?{vendor:automation.vendor}:{},...automation.baseRef?{baseRef:automation.baseRef}:{},...automation.persistentSession?{routine:{automationId:automation.id}}:{}})}async function spawnWithPrompt(deps,automation,taskId,status){if(deps.canDeliver?.()===!1)return{status:"skipped_cancelled",taskId};let outcome=await deps.runtime.startTaskSessionWithPrompt(deps.link(),taskId,automation.prompt);if(!outcome.started)return{status:"dispatch_failed",taskId,error:outcome.error??"engine session did not start"};return{status,taskId}}async function dispatchAutomation(deps,automation){if(deps.canDeliver?.()===!1)return{status:"skipped_cancelled"};let target=automationTarget(automation);if(target.kind==="existing-tab"){try{await assertAutomationTargetTask(automation,deps.orch)}catch(error){return{status:"skipped_unavailable",taskId:target.taskId,tabId:target.tabId,error:String(error)}}let task2=deps.orch.getTask(target.taskId);if(!task2||task2.deletion||!task2.worktreePath)return{status:"skipped_unavailable",taskId:target.taskId,tabId:target.tabId,error:"target task unavailable"};if(deps.canDeliver?.()===!1)return{status:"skipped_cancelled",taskId:task2.id,tabId:target.tabId};let currentTask=deps.orch.getTask(task2.id);if(!currentTask||currentTask.deletion||!currentTask.worktreePath)return{status:"skipped_unavailable",taskId:task2.id,tabId:target.tabId,error:"target task unavailable"};let result2=await deps.runtime.deliverPromptToLiveEngineTabDetailed({id:task2.id,tabId:target.tabId,vendor:task2.vendor,command:task2.command,worktreePath:task2.worktreePath},automation.prompt);return await liveDeliveryOutcome(deps,automation,task2.id,result2)}if(target.kind==="fresh"){let task2=await createRunTask(deps,automation);return await spawnWithPrompt(deps,automation,task2.id,"dispatched")}let standing=resolveStandingTask(deps.orch,automation);if(standing.task===null){let task2=await createRunTask(deps,automation);return{...await spawnWithPrompt(deps,automation,task2.id,"dispatched"),sessionTaskIdToSet:task2.id,...standing.hadStaleLink?{sessionTaskIdToClear:!0}:{}}}let task=standing.task,result=await deps.runtime.deliverPromptToLiveEngineDetailed({id:task.id,vendor:task.vendor,command:task.command,worktreePath:task.worktreePath},automation.prompt);if(result.outcome==="delivered")return await liveDeliveryOutcome(deps,automation,task.id,result);return await spawnWithPrompt(deps,automation,task.id,"revived")}async function liveDeliveryOutcome(deps,automation,taskId,result){switch(result.outcome){case"delivered":return logDaemonInfo("automation",`delivered ${automation.name} task=${taskId} tab=${result.tabId}`),{status:"dispatched",taskId,tabId:result.tabId};case"no-engine":case"no-session":return{status:"dispatch_failed",taskId,tabId:automation.target?.tabId,error:result.outcome==="no-engine"?"target engine exited; restart it explicitly":"target tab has no live session"}}}import{spawn as spawn2}from"child_process";import{existsSync}from"fs";var MAX_OUTPUT_CHARS=4000,MAX_TIMEOUT_SECONDS=600;function killGroup(child){let pid=child.pid;if(pid===void 0)return;try{process.kill(-pid,"SIGKILL")}catch{try{child.kill("SIGKILL")}catch{}}}function withWatchdog(command,timeoutSeconds){return["set +m 2>/dev/null",`{ sleep ${timeoutSeconds} && { kill -9 -$$ 2>/dev/null || kill -9 $$ ; } ; } >/dev/null 2>&1 </dev/null &`,"__rove_watchdog=$!",`trap 'kill "$__rove_watchdog" 2>/dev/null' EXIT`,command].join(`
|
|
4
4
|
`)}function tail(chunks){let text=Buffer.concat(chunks.map((c)=>typeof c==="string"?Buffer.from(c):c)).toString("utf8");if(text.length<=MAX_OUTPUT_CHARS)return text;let points=Array.from(text);return points.length<=MAX_OUTPUT_CHARS?text:points.slice(-MAX_OUTPUT_CHARS).join("")}function runAutomationPrecheck(precheck,cwd,shell=resolveLoginShell({fallback:"/bin/sh"})){let startedAt=Date.now(),timeoutMs=Math.min(Math.max(precheck.timeoutSeconds,1),MAX_TIMEOUT_SECONDS)*1000;if(!existsSync(cwd))return Promise.resolve({exitCode:null,timedOut:!1,stdout:"",stderr:`working directory does not exist: ${cwd}`,durationMs:0});return new Promise((resolve)=>{let out=[],err=[],settled=!1,timedOut=!1,finish=(exitCode,timedOut2)=>{if(settled)return;settled=!0,clearTimeout(timer),resolve({exitCode,timedOut:timedOut2,stdout:tail(out),stderr:tail(err),durationMs:Date.now()-startedAt})},timer=setTimeout(()=>{if(timedOut=!0,child)killGroup(child);finish(null,!0)},timeoutMs);timer.unref?.();let child;try{child=spawn2(shell,["-ilc",withWatchdog(precheck.command,timeoutMs/1000+1)],{cwd,stdio:["ignore","pipe","pipe"],detached:process.platform!=="win32"})}catch(spawnError){err.push(spawnError instanceof Error?spawnError.message:String(spawnError)),finish(null,!1);return}child.stdout?.on("data",(chunk)=>out.push(chunk)),child.stderr?.on("data",(chunk)=>err.push(chunk)),child.on("error",(spawnError)=>{if(timedOut){finish(null,!0);return}err.push(spawnError.message),finish(null,!1)}),child.on("close",(code)=>finish(code,timedOut))})}function precheckPassed(result){return result.exitCode===0&&!result.timedOut}function formatPrecheckSkip(result){if(result.timedOut)return`precheck timed out after ${result.durationMs}ms`;if(result.exitCode===null)return`precheck could not run: ${result.stderr.trim()||"unknown error"}`;return`precheck exited ${result.exitCode}`}var DEFAULT_AUTOMATION_TICK_MS=60000;function dueAutomations(automations,nowMs){return automations.filter((a)=>{if(!a.enabled)return!1;let at=Date.parse(a.nextRunAt);return Number.isFinite(at)&&at<=nowMs})}function resolveDueOccurrence(automation,nowMs,tickMs=DEFAULT_AUTOMATION_TICK_MS){let notBefore=Date.parse(automation.createdAt),scheduledFor=latestCronAtOrBefore(automation.schedule,nowMs,Number.isFinite(notBefore)?notBefore:0);if(scheduledFor===null)return null;let graceMs=automation.missedRunGraceMinutes*60000+Math.max(tickMs,0);return{scheduledFor,missed:nowMs-scheduledFor>graceMs}}function runEventFor(status){if(status==="dispatched"||status==="revived")return"automation.dispatched";if(status==="dispatch_failed")return"automation.failed";return"automation.skipped"}function resolveLink(link){return typeof link==="function"?link():link}function emitRunEvent(deps,automation,status,args,extra){deps.plugins?.()?.handleUiReport({kind:runEventFor(status),...extra.taskId?{taskId:extra.taskId}:{},detail:{automationId:automation.id,name:automation.name,repo:automation.repo,status,trigger:args.trigger,scheduledFor:new Date(args.scheduledFor).toISOString(),...extra.tabId?{tabId:extra.tabId}:{},...extra.error?{error:extra.error}:{}}})}async function raiseOrClearInboxEpisode(deps,automation,status,extra){let inbox=deps.inbox;if(!inbox)return;let now=deps.now??Date.now;await(automationRunNeedsAttention(status)?inbox.recordRoutineFailure({automationId:automation.id,name:automation.name,status,...extra.error?{error:extra.error}:{}},extra.taskId??null,now()):inbox.deleteRoutineEpisode?.(automation.id))?.catch((err)=>logDaemonError("automation-inbox",err))}async function recordSkip(deps,automation,status,scheduledFor,error){let now=deps.now??Date.now;await deps.store.recordRun({automationId:automation.id,scheduledFor:new Date(scheduledFor).toISOString(),status,trigger:"scheduled",at:new Date(now()).toISOString(),error}),emitRunEvent(deps,automation,status,{scheduledFor,trigger:"scheduled"},{error})}function droppedOccurrences(automation,scheduledFor){let armedAt=Date.parse(automation.nextRunAt);if(!Number.isFinite(armedAt)||armedAt>=scheduledFor)return null;let count=countCronBetween(automation.schedule,armedAt,scheduledFor);return count>0?{count,firstMs:armedAt}:null}async function runAutomationOnce(deps,automation,args){let now=deps.now??Date.now,record=async(status,extra={})=>{return await deps.store.recordRun({automationId:automation.id,scheduledFor:new Date(args.scheduledFor).toISOString(),status,trigger:args.trigger,at:new Date(now()).toISOString(),...extra}),emitRunEvent(deps,automation,status,args,extra),await raiseOrClearInboxEpisode(deps,automation,status,extra),status},cancelled=()=>deps.stopped?.()===!0||deps.store.get(automation.id)!==automation||args.trigger==="scheduled"&&!automation.enabled;if(cancelled())return await record("skipped_cancelled",{error:"routine disabled, changed, deleted or runner stopped before delivery"});if(args.trigger==="scheduled"&&automation.precheck){let result=await runAutomationPrecheck(automation.precheck,automation.repo);if(!precheckPassed(result))return logDaemonInfo("automation",`skip ${automation.name}: ${formatPrecheckSkip(result)}`),await record("skipped_precheck",{precheckResult:result,error:formatPrecheckSkip(result)})}if(cancelled())return await record("skipped_cancelled",{error:"routine disabled, changed, deleted or runner stopped before delivery"});let outcome;try{outcome=await dispatchAutomation({canDeliver:()=>!cancelled(),orch:deps.orch,runtime:deps.runtime,link:()=>resolveLink(deps.link),...deps.now?{now:deps.now}:{}},automation)}catch(err){let error=err instanceof Error?err.message:String(err);return logDaemonError("automation-dispatch",err),await record("skipped_unavailable",{error})}if(outcome.sessionTaskIdToSet)await deps.store.update(automation.id,{sessionTaskId:outcome.sessionTaskIdToSet}).catch((err)=>logDaemonError("automation-session-link",err));else if(outcome.sessionTaskIdToClear)await deps.store.update(automation.id,{sessionTaskId:null}).catch((err)=>logDaemonError("automation-session-unlink",err));if(outcome.status==="dispatched"||outcome.status==="revived")logDaemonInfo("automation",`${outcome.status} ${automation.name} task=${outcome.taskId}`);return await record(outcome.status,{...outcome.taskId?{taskId:outcome.taskId}:{},...outcome.tabId?{tabId:outcome.tabId}:{},...outcome.error?{error:outcome.error}:{}})}async function sweepAutomations(deps,tickMs=DEFAULT_AUTOMATION_TICK_MS){let now=deps.now??Date.now;for(let automation of dueAutomations(deps.store.list(),now())){if(deps.stopped?.())return;let nowMs=now(),occurrence=resolveDueOccurrence(automation,nowMs,tickMs);if(!occurrence){await deps.store.advanceNextRun(automation.id,nowMs);continue}let dropped=droppedOccurrences(automation,occurrence.scheduledFor),claimed=await deps.store.advanceNextRun(automation.id,occurrence.scheduledFor,automation.nextRunAt);if(!claimed)continue;if(dropped){let first=new Date(dropped.firstMs).toISOString();await recordSkip(deps,automation,"skipped_missed",dropped.firstMs,`${dropped.count} earlier occurrence${dropped.count===1?"":"s"} never ran (from ${first})`).catch((err)=>logDaemonError("automation-dropped",err))}if(occurrence.missed){await recordSkip(deps,automation,"skipped_missed",occurrence.scheduledFor,`missed by more than the ${automation.missedRunGraceMinutes}m grace window`);continue}await runAutomationOnce(deps,claimed,{scheduledFor:occurrence.scheduledFor,trigger:"scheduled"}).catch((err)=>logDaemonError("automation-run",err))}}function startAutomationRunner(deps,tickMs=DEFAULT_AUTOMATION_TICK_MS){let stopped=!1;return startTicker({name:"automation-sweep",tickMs,run:()=>sweepAutomations({...deps,stopped:()=>stopped},tickMs),onStop:()=>{stopped=!0}})}var DEFAULT_CONTEXT_USAGE_TICK_MS=1e4,CONTEXT_USAGE_TIMEOUT_MS=4000,CONTEXT_USAGE_SLOW_RETRY_MS=60000,CONTEXT_USAGE_MIN_INTERVAL_MS=5000;function sameContextUsage(a,b){return a.contextTokens===b.contextTokens&&a.contextWindowTokens===b.contextWindowTokens&&a.approximate===b.approximate&&a.inputTokens===b.inputTokens&&a.outputTokens===b.outputTokens&&a.cacheReadTokens===b.cacheReadTokens&&a.cacheCreationTokens===b.cacheCreationTokens}function contextUsageTargets(states,getVendor){let seen=new Set,targets=[];for(let state of states){if(!state.tabId||!state.sessionId)continue;let vendor=getVendor(state.taskId);if(!vendor)continue;let key=`${state.taskId}::${state.tabId}`;if(seen.has(key))continue;seen.add(key),targets.push({key,vendor,sessionId:state.sessionId})}return targets}class ContextUsageCollector{registry;orch;bus;runtime;options;entries=new Map;stopped=!1;constructor(registry,orch,bus,runtime,options={}){this.registry=registry;this.orch=orch;this.bus=bus;this.runtime=runtime;this.options=options}tick(){if(this.stopped)return;if(this.options.hasSubscribers&&!this.options.hasSubscribers())return;try{let targets=contextUsageTargets(this.registry.liveSessions(),(id)=>this.orch.getTask(id)?.vendor),live=new Set(targets.map((t)=>t.key)),pruned=!1;for(let key of[...this.entries.keys()]){if(live.has(key))continue;if(this.entries.get(key)?.value)pruned=!0;this.entries.delete(key)}if(pruned)this.publish();for(let target of targets)this.collect(target)}catch(err){logDaemonError("context-usage",err)}}stop(){this.stopped=!0}collect(target){let entry=this.entries.get(target.key);if(!entry)entry={inFlight:!1,nextAllowedAt:0},this.entries.set(target.key,entry);if(entry.sessionId!==void 0&&entry.sessionId!==target.sessionId){let had=entry.value!==void 0;if(entry.value=void 0,entry.nextAllowedAt=0,entry.sessionId=target.sessionId,had)this.publish()}entry.sessionId=target.sessionId;let cadence=this.options.cadence??{timeoutMs:CONTEXT_USAGE_TIMEOUT_MS,slowRetryMs:CONTEXT_USAGE_SLOW_RETRY_MS,minIntervalMs:CONTEXT_USAGE_MIN_INTERVAL_MS},read=this.options.read??((t)=>this.runtime.readEngineContextUsage(t.vendor,t.sessionId)),startedAt=Date.now();if(entry.inFlight||startedAt<entry.nextAllowedAt)return;entry.inFlight=!0;let controller=new AbortController,timer=setTimeout(()=>controller.abort(),cadence.timeoutMs),held=entry;read(target,controller.signal).then((value)=>{if(controller.signal.aborted||this.stopped)return;if(this.entries.get(target.key)!==held)return;if(!value)return;if(held.value&&sameContextUsage(held.value,value))return;held.value=value,this.publish()}).catch(()=>{}).finally(()=>{clearTimeout(timer);let finishedAt=Date.now();held.nextAllowedAt=controller.signal.aborted?startedAt+cadence.slowRetryMs:finishedAt+Math.max(cadence.minIntervalMs,(finishedAt-startedAt)*5),held.inFlight=!1})}publish(){let context={};for(let[key,entry]of this.entries)if(entry.value)context[key]=entry.value;this.bus.publish("usage.context",{context})}}function startContextUsageCollector(registry,orch,bus,runtime,tickMs=DEFAULT_CONTEXT_USAGE_TICK_MS,hasSubscribers){if(tickMs<=0)return()=>{};let collector=new ContextUsageCollector(registry,orch,bus,runtime,{hasSubscribers});collector.tick();let timer=setInterval(()=>collector.tick(),tickMs);return timer.unref?.(),()=>{clearInterval(timer),collector.stop()}}import{basename as basename2}from"path";var DEFAULT_KEYBINDINGS_DEBOUNCE_MS=200;function startKeybindingsWatcher(bus,options={}){let debounceMs=options.debounceMs??DEFAULT_KEYBINDINGS_DEBOUNCE_MS;if(debounceMs<=0)return()=>{};let filePath=options.path??defaultKeybindingsPath(),baseYaml=basename2(filePath),baseYml=baseYaml.replace(/\.yaml$/,".yml"),rev=0;return bus.publish("keybindings",{rev}),startFileWatchTrigger({filePath,matchBasenames:[baseYaml,baseYml],debounceMs,onTrigger:()=>{try{rev+=1,bus.publish("keybindings",{rev})}catch(err){logDaemonError("keybindings-watcher",err)}},onError:(err)=>logDaemonError("keybindings-watcher",err)})}import{spawn as spawn3}from"child_process";var PR_STATE_RANK={OPEN:2,MERGED:1,CLOSED:1};function pickPr(views){let best,bestRank=-1;for(let view of views){let rank=PR_STATE_RANK[(view.state??"").toUpperCase()]??0;if(rank>bestRank)best=view,bestRank=rank}return best}var DEFAULT_PR_STATUS_POLL_MS=30000,NO_PR_BACKOFF_MS=300000,SETTLED_BACKOFF_MS=600000,PR_FAILURE_BASE_MS=DEFAULT_PR_STATUS_POLL_MS,PR_FAILURE_CAP_MS=900000,NO_REMOTE_BACKOFF_MS=1800000,PR_POLL_JITTER_RATIO=0.2,PR_VIEW_TIMEOUT_MS=1e4,PR_POLL_CONCURRENCY=8;function spawnGh(args,cwd,signal){return new Promise((resolve)=>{let outChunks=[],errChunks=[],settled=!1,finish=(status,spawnError)=>{if(settled)return;settled=!0,resolve({status,stdout:decodeCapturedChunks(outChunks),stderr:decodeCapturedChunks(errChunks),spawnError})},child=spawn3("gh",args.slice(),{cwd,stdio:["ignore","pipe","pipe"],signal,killSignal:"SIGKILL"});child.stdout?.on("data",(chunk)=>{outChunks.push(chunk)}),child.stderr?.on("data",(chunk)=>{errChunks.push(chunk)}),child.on("error",()=>finish(null,!signal.aborted)),child.on("close",(code)=>finish(code,!1))})}function makeGhPrViewRunner(classify,viewFields){return async(worktreePath,branch)=>{let controller=new AbortController,timedOut=!1,timer=setTimeout(()=>{timedOut=!0,controller.abort()},PR_VIEW_TIMEOUT_MS);try{let res=await spawnGh(["pr","list","--head",branch,"--state","all","--json",viewFields],worktreePath,controller.signal);if(res.status===0&&!timedOut)try{let views=JSON.parse(res.stdout),picked=Array.isArray(views)?pickPr(views):void 0;return picked?{kind:"pr",view:picked}:{kind:"empty"}}catch{return classify({parseError:!0})}return classify({spawnError:res.spawnError,timedOut,exitCode:res.status,stderr:res.stderr})}finally{clearTimeout(timer)}}}function isPrPollable(task){if(task.kind==="main")return!1;if(!task.branch||!task.worktreePath)return!1;if(task.repo.startsWith("ssh://")||task.worktreePath.startsWith("ssh://"))return!1;return!0}async function setPrStaleMarker(orch,taskId,error){let prev=orch.getTask(taskId)?.prStatus;if(!prev||prev.lastError===error)return!1;let{lastError:_cleared,...rest}=prev;return await orch.setPRStatus(taskId,error===void 0?rest:{...rest,lastError:error}),!0}async function runPrStatusPass(orch,opts){let tickMs=opts.tickMs??DEFAULT_PR_STATUS_POLL_MS,rand=opts.rand,cfg={tickMs,settledMs:SETTLED_BACKOFF_MS,noPrMs:NO_PR_BACKOFF_MS,noRemoteMs:NO_REMOTE_BACKOFF_MS,failureBaseMs:PR_FAILURE_BASE_MS,failureCapMs:PR_FAILURE_CAP_MS,jitterRatio:PR_POLL_JITTER_RATIO},tasks=orch.listTasks(),live=new Set(tasks.map((task)=>task.id));for(let id of opts.schedule.keys())if(!live.has(id))opts.schedule.delete(id);let due=[];for(let task of tasks){if(!isPrPollable(task)){opts.schedule.delete(task.id);continue}let entry=opts.schedule.get(task.id);if(entry&&opts.now<entry.nextAllowedAt)continue;due.push({task,prevFailures:entry?.failures??0})}let pollOne=async(task,prevFailures)=>{try{let result=await opts.run(task.worktreePath,task.branch);if(result.kind==="error"){logDaemonInfo("pr-status-poller",`gh pr list failed (${result.error}) for task ${task.id} [${task.branch}] \u2014 keeping last PR status, backing off`);let marked=await setPrStaleMarker(orch,task.id,result.error);return opts.schedule.set(task.id,opts.runtime.prStatus.nextPoll({kind:"error",error:result.error},prevFailures,opts.now,cfg,rand)),marked?task.id:void 0}if(result.kind==="empty"){let marked=await setPrStaleMarker(orch,task.id,void 0);return opts.schedule.set(task.id,opts.runtime.prStatus.nextPoll({kind:"empty"},prevFailures,opts.now,cfg,rand)),marked?task.id:void 0}let next=opts.runtime.prStatus.mapView(result.view,opts.at),current=orch.getTask(task.id);if(!current){opts.schedule.delete(task.id);return}let wasStale=current.prStatus?.lastError!==void 0,changedId;if(wasStale||!opts.runtime.prStatus.sameStatus(current.prStatus,next??void 0))await orch.setPRStatus(task.id,next),changedId=task.id;let settled=next?.lifecycle==="merged"||next?.lifecycle==="closed";return opts.schedule.set(task.id,opts.runtime.prStatus.nextPoll({kind:"pr",settled},prevFailures,opts.now,cfg,rand)),changedId}catch(err){logDaemonError("pr-status-poller",err);let marked=await setPrStaleMarker(orch,task.id,"network").catch(()=>!1);return opts.schedule.set(task.id,opts.runtime.prStatus.nextPoll({kind:"error",error:"network"},prevFailures,opts.now,cfg,rand)),marked?task.id:void 0}},slots=Array(due.length),cursor=0,worker=async()=>{for(let i=cursor++;i<due.length;i=cursor++){let item=due[i];if(item)slots[i]=await pollOne(item.task,item.prevFailures)}};return await Promise.all(Array.from({length:Math.min(PR_POLL_CONCURRENCY,due.length)},worker)),slots.filter((id)=>id!==void 0)}function startPrStatusPoller(orch,runtime,intervalMs=DEFAULT_PR_STATUS_POLL_MS,hasSubscribers,run=makeGhPrViewRunner(runtime.prStatus.classify,runtime.prStatus.viewFields),hasWorkingAgent){let schedule=new Map;return startTicker({name:"pr-status-poller",tickMs:intervalMs,...hasSubscribers?{gate:()=>hasSubscribers()||(hasWorkingAgent?.()??!1)}:{},run:()=>runPrStatusPass(orch,{runtime,run,now:Date.now(),at:new Date().toISOString(),schedule,tickMs:intervalMs})})}function quotaResumeContinuePrompt(language){return language==="zh"?"\u4ECE\u4E2D\u65AD\u7684\u5730\u65B9\u7EE7\u7EED\u8FD9\u4E2A\u4EFB\u52A1\u3002\u4E0A\u9762\u7684\u5BF9\u8BDD\u8BB0\u5F55\u91CC\u5DF2\u7ECF\u5B8C\u6210\u7684\u5DE5\u4F5C\u4E0D\u8981\u91CD\u505A\u3002":"Continue the task from where it stopped. The transcript above shows the work already completed \u2014 do not redo it."}var DEFAULT_QUOTA_RESUME_TICK_MS=60000;function dueQuotaResumes(tasks,nowMs){return tasks.filter((task)=>{if(!task.quotaResume||!task.worktreePath)return!1;if(task.deletion)return!1;let at=Date.parse(task.quotaResume.resumeAt);return Number.isFinite(at)&&at<=nowMs})}function exhaustedResetAtMs(usage,nowMs){let candidates=usage.windows.filter((w)=>w.percent>=100&&w.resetsAt!=null&&w.resetsAt>nowMs).map((w)=>w.resetsAt);return candidates.length>0?Math.min(...candidates):null}async function scheduleQuotaResume(orch,runtime,cache,taskId,now=Date.now,plugins){let task=orch.getTask(taskId);if(!task||!task.worktreePath||task.deletion)return;let usage=await cache.get(task.vendor??runtime.defaultTaskVendor,0),resetAtMs=usage?exhaustedResetAtMs(usage,now()):null;if(resetAtMs==null)return;let resumeAt=new Date(resetAtMs).toISOString();await orch.setQuotaResume(taskId,{resumeAt,requestedAt:new Date(now()).toISOString()}),logDaemonInfo("quota-resume",`armed task=${taskId} resumeAt=${resumeAt}`),plugins?.()?.handleUiReport({kind:"quota.exhausted",taskId,detail:{vendor:task.vendor??runtime.defaultTaskVendor,resumeAt}})}async function resumeDueTask(orch,runtime,task,plugins){await orch.setQuotaResume(task.id,null);let delivered=await runtime.deliverPromptToLiveEngine({id:task.id,vendor:task.vendor,command:task.command,worktreePath:task.worktreePath},quotaResumeContinuePrompt(task.observedLanguage));logDaemonInfo("quota-resume",`resume task=${task.id} delivered=${delivered}`),plugins?.()?.handleUiReport({kind:"quota.resumed",taskId:task.id,detail:{delivered}})}function startQuotaResumeRunner(orch,runtime,tickMs=DEFAULT_QUOTA_RESUME_TICK_MS,now=Date.now,plugins){return startTicker({name:"quota-resume",tickMs,run:async()=>{for(let task of dueQuotaResumes(orch.listTasks(),now()))await resumeDueTask(orch,runtime,task,plugins).catch((err)=>logDaemonError("quota-resume",err))}})}var FRESH_POLL_MS=900000,RETRY_BASE_MS=60000,MIN_FETCH_INTERVAL_MS=60000;class QuotaUsageCache{runtime;bus;now;entries=new Map;constructor(runtime,bus,now=Date.now){this.runtime=runtime;this.bus=bus;this.now=now}peek(vendor){return this.entries.get(vendor)?.usage??null}async get(vendor,maxAgeMs){let entry=this.entry(vendor),age=this.now()-(entry.usage?.capturedAt??0);if(entry.usage&&age<=maxAgeMs)return entry.usage;if(entry.inFlight)return entry.inFlight;if(this.now()-entry.attemptedAt<MIN_FETCH_INTERVAL_MS)return entry.usage;return this.fetch(vendor,entry)}async refreshIfDue(vendor){let entry=this.entry(vendor),retryAfter=entry.failures===0?0:Math.min(RETRY_BASE_MS*2**(entry.failures-1),FRESH_POLL_MS),dueAfter=entry.usage?FRESH_POLL_MS:retryAfter;if(this.now()-entry.attemptedAt<dueAfter)return;await this.fetch(vendor,entry)}entry(vendor){let existing=this.entries.get(vendor);if(existing)return existing;let fresh={usage:null,attemptedAt:0,failures:0,inFlight:null};return this.entries.set(vendor,fresh),fresh}fetch(vendor,entry){if(entry.inFlight)return entry.inFlight;return entry.attemptedAt=this.now(),entry.inFlight=this.runtime.quotaUsage(vendor).catch(()=>null).then((usage)=>{if(entry.inFlight=null,usage){entry.failures=0;let changed=JSON.stringify(usage.windows)!==JSON.stringify(entry.usage?.windows);if(entry.usage=usage,changed)this.publish()}else entry.failures+=1;return entry.usage}),entry.inFlight}publish(){let usage={};for(let[vendor,entry]of this.entries)if(entry.usage)usage[vendor]=entry.usage;this.bus.publish("usage.snapshot",{usage})}}function startQuotaUsagePoller(cache,listVendors,hasSubscribers,tickMs=MIN_FETCH_INTERVAL_MS){return startTicker({name:"quota-usage-poller",tickMs,gate:hasSubscribers,immediate:!0,run:()=>{for(let vendor of new Set(listVendors()))cache.refreshIfDue(vendor)}})}function isRemoteRepoKey(value){return value.startsWith("ssh://")}var DEFAULT_TRANSCRIPT_ACTIVITY_TICK_MS=1500,TRANSCRIPT_ACTIVITY_TIMEOUT_MS=4000,TRANSCRIPT_ACTIVITY_SLOW_RETRY_MS=60000,TRANSCRIPT_ACTIVITY_MIN_INTERVAL_MS=1500;function sameTranscriptActivityEntry(a,b){return a.mtimeMs===b.mtimeMs&&a.completionId===b.completionId&&a.completionAt===b.completionAt}async function runTranscriptActivity(worktreePath,vendor,detector,_signal){let{marker,mtimeMs}=await detector.latestActivity(worktreePath);return{mtimeMs:detector.supportsCompletionMarkers()?mtimeMs:0,completionId:marker?.id??null,completionAt:marker?.timestampMs??0}}function trackedWorktrees(tasks,defaultVendor){let map=new Map;for(let task of tasks){if(!task.worktreePath)continue;if(isRemoteRepoKey(task.repo)||isRemoteRepoKey(task.worktreePath))continue;if(map.has(task.worktreePath))continue;map.set(task.worktreePath,task.vendor??defaultVendor)}return map}class TranscriptActivityCollector{orch;bus;options;entries=new Map;stopped=!1;constructor(orch,bus,options){this.orch=orch;this.bus=bus;this.options=options}tick(){if(this.stopped)return;if(this.options.hasSubscribers&&!this.options.hasSubscribers())return;try{let tracked=trackedWorktrees(this.orch.listTasks(),this.options.defaultVendor),pruned=!1;for(let path of this.entries.keys()){if(tracked.has(path))continue;if(this.entries.get(path)?.value)pruned=!0;this.entries.delete(path)}if(pruned)this.publish();for(let[path,vendor]of tracked)this.maybeCollect(path,vendor)}catch(err){logDaemonError("transcript-activity",err)}}stop(){this.stopped=!0}maybeCollect(worktreePath,vendor){let entry=this.entries.get(worktreePath);if(!entry)entry={inFlight:!1,nextAllowedAt:0,vendor,detector:this.createDetector(vendor)},this.entries.set(worktreePath,entry);else if(entry.vendor!==vendor)entry.vendor=vendor,entry.detector=this.createDetector(vendor);let cadence=this.options.cadence??{timeoutMs:TRANSCRIPT_ACTIVITY_TIMEOUT_MS,slowRetryMs:TRANSCRIPT_ACTIVITY_SLOW_RETRY_MS,minIntervalMs:TRANSCRIPT_ACTIVITY_MIN_INTERVAL_MS},run=this.options.run??runTranscriptActivity,current=entry;maybeStartScheduledRun(current,cadence,(signal)=>run(worktreePath,current.vendor,current.detector,signal),(value)=>{if(this.stopped)return;if(this.entries.get(worktreePath)!==current)return;if(current.value&&sameTranscriptActivityEntry(current.value,value))return;current.value=value,this.publish()})}publish(){let activity={};for(let[path,entry]of this.entries)if(entry.value)activity[path]=entry.value;this.bus.publish("transcript.activity",{activity})}createDetector(vendor){return this.options.createDetector?.(vendor)??{latestActivity:async()=>({marker:null,mtimeMs:0}),latestActivityInFile:async()=>null,supportsCompletionMarkers:()=>!1}}}function startTranscriptActivityCollector(orch,runtime,bus,tickMs=DEFAULT_TRANSCRIPT_ACTIVITY_TICK_MS,hasSubscribers){let collector=new TranscriptActivityCollector(orch,bus,{hasSubscribers,createDetector:runtime.createEngineTurnDetector,defaultVendor:runtime.defaultTaskVendor,run:async(path,vendor,detector,signal)=>{let{marker,mtimeMs}=await detector.latestActivity(path);return{mtimeMs:detector.supportsCompletionMarkers()?mtimeMs:await runtime.latestTranscriptMtime(vendor,path),completionId:marker?.id??null,completionAt:marker?.timestampMs??0}}});return startTicker({name:"transcript-activity-collector",tickMs,immediate:!0,run:()=>collector.tick(),onStop:()=>collector.stop()})}import{readFileSync}from"fs";import{basename as basename3}from"path";var DEFAULT_UI_PREFS_DEBOUNCE_MS=200,FOCUS_ACCENT_SLOT_NAMES=["primary","success","info"],THEME_MODE_NAMES=["dark","light","auto"];function readUiPrefsFromStateFile(statePath){let parsed={};try{let raw=JSON.parse(readFileSync(statePath,"utf8"));if(raw&&typeof raw==="object"&&!Array.isArray(raw))parsed=raw}catch{}let theme=typeof parsed.activeTheme==="string"&&parsed.activeTheme.length>0?parsed.activeTheme:null,themeMode=typeof parsed.themeMode==="string"&&THEME_MODE_NAMES.includes(parsed.themeMode)?parsed.themeMode:null,transparentBackground=parsed.transparentBackground!==!1,focusAccent=typeof parsed.focusAccent==="string"&&FOCUS_ACCENT_SLOT_NAMES.includes(parsed.focusAccent)?parsed.focusAccent:null,sortMode=parsed.activeSortMode==="recent"||parsed.activeSortMode==="attention"?parsed.activeSortMode:"default",keysCollapsed=parsed["tasksPane.keysCollapsed"]===!0,projectFilter=typeof parsed["tasksPane.projectFilter"]==="string"&&parsed["tasksPane.projectFilter"].length>0?parsed["tasksPane.projectFilter"]:null,locale=typeof parsed.locale==="string"&&parsed.locale.length>0?parsed.locale:"en";return{theme,themeMode,transparentBackground,focusAccent,locale,sortMode,keysCollapsed,projectFilter}}function samePrefs(a,b){return a.theme===b.theme&&a.themeMode===b.themeMode&&a.transparentBackground===b.transparentBackground&&a.focusAccent===b.focusAccent&&a.locale===b.locale&&a.sortMode===b.sortMode&&a.keysCollapsed===b.keysCollapsed&&a.projectFilter===b.projectFilter}function startUiPrefsWatcher(bus,options={}){let debounceMs=options.debounceMs??DEFAULT_UI_PREFS_DEBOUNCE_MS;if(debounceMs<=0)return()=>{};let statePath=options.statePath??defaultUiPrefsStatePath(),stateFile=basename3(statePath),last=null,publishIfChanged=()=>{try{let next=readUiPrefsFromStateFile(statePath);if(last&&samePrefs(last,next))return;last=next,bus.publish("ui-prefs",next)}catch(err){logDaemonError("ui-prefs-watcher",err)}},stop=startFileWatchTrigger({filePath:statePath,matchBasenames:[stateFile],debounceMs,onTrigger:publishIfChanged,onError:(err)=>logDaemonError("ui-prefs-watcher",err)});return publishIfChanged(),stop}import{spawn as spawn4}from"child_process";function runGit(worktreePath,args,signal){return new Promise((resolve)=>{let stdout="",settled=!1,finish=(status)=>{if(settled)return;settled=!0,resolve(status===0?stdout:null)},child=spawn4("git",args.slice(),{cwd:worktreePath,stdio:["ignore","pipe","ignore"],env:{...process.env,GIT_OPTIONAL_LOCKS:"0"},signal,killSignal:"SIGKILL"});child.stdout?.on("data",(chunk)=>{stdout+=String(chunk)}),child.on("error",()=>finish(null)),child.on("close",finish)})}async function countDrift(worktreePath,baseRef,signal){return parseAheadBehind(await runGit(worktreePath,["rev-list","--left-right","--count",`${baseRef}...HEAD`],signal))}function parseAheadBehind(stdout){if(stdout===null)return null;let parts=stdout.trim().split(/\s+/);if(parts.length!==2)return null;let behind=Number.parseInt(parts[0]??"",10),ahead=Number.parseInt(parts[1]??"",10);if(!Number.isInteger(behind)||behind<0||!Number.isInteger(ahead)||ahead<0)return null;return{behind,ahead}}function countPorcelain(stdout){let added=0,deleted=0;for(let row of parsePorcelainRows(stdout))if(row.x==="D"||row.y==="D")deleted++;else added++;return{added,deleted}}async function runGitStatus(worktreePath,signal,baseRef){let stdout=await runGit(worktreePath,["status","--porcelain=v1"],signal);if(stdout===null)throw Error("git status failed");let counts=countPorcelain(stdout);if(!baseRef)return counts;let drift=await countDrift(worktreePath,baseRef,signal);return drift===null?counts:{...counts,...drift}}var EMPTY_PATHS=new Set;function isRemoteRepoKey2(value){return value.startsWith("ssh://")}function sameWorktreeChanges(a,b){return a.added===b.added&&a.deleted===b.deleted&&a.behind===b.behind&&a.ahead===b.ahead}var DEFAULT_WORKTREE_CHANGES_TICK_MS=2000,WORKTREE_CHANGES_CONCURRENCY=4,WORKTREE_CHANGES_TIMEOUT_MS=4000,WORKTREE_CHANGES_SLOW_RETRY_MS=60000,WORKTREE_CHANGES_MIN_INTERVAL_MS=1500,WORKTREE_CHANGES_QUIET_INTERVAL_MS=60000;function trackedWorktreePaths(tasks){let paths=new Map;for(let task of tasks){if(!task.worktreePath)continue;if(isRemoteRepoKey2(task.repo)||isRemoteRepoKey2(task.worktreePath))continue;if(paths.get(task.worktreePath)===void 0)paths.set(task.worktreePath,task.baseRef)}return paths}var UNREADABLE=Symbol("worktree-changes-unreadable");class WorktreeChangesCollector{orch;bus;options;entries=new Map;stopped=!1;queued=new Map;active=0;activePaths=new Set;drainHandle;publishTimer;controllers=new Set;constructor(orch,bus,options={}){this.orch=orch;this.bus=bus;this.options=options}tick(){if(this.stopped)return;if(this.options.hasSubscribers&&!this.options.hasSubscribers())return;try{let tasks=this.orch.listTasks(),tracked=trackedWorktreePaths(tasks),pruned=!1;for(let path of this.entries.keys()){if(tracked.has(path))continue;if(this.entries.get(path)?.value)pruned=!0;this.entries.delete(path),this.queued.delete(path)}for(let path of this.queued.keys())if(!tracked.has(path))this.queued.delete(path);if(pruned)this.publish();let busy=this.busyPaths(tasks);for(let[path,baseRef]of tracked)if(!this.entries.get(path)?.inFlight)this.queued.set(path,{baseRef,busy:busy.has(path)});this.drain()}catch(err){logDaemonError("worktree-changes",err)}}stop(){if(this.stopped=!0,this.queued.clear(),this.drainHandle)clearImmediate(this.drainHandle);if(this.publishTimer)clearTimeout(this.publishTimer);for(let controller of this.controllers)controller.abort()}drain(){if(this.stopped||this.options.hasSubscribers?.()===!1)return;let limit=WORKTREE_CHANGES_CONCURRENCY;for(let[path,demand]of this.queued){if(this.active>=limit)break;if(this.activePaths.has(path))continue;this.queued.delete(path);try{this.maybeCollect(path,demand.baseRef,demand.busy)}catch(err){logDaemonError("worktree-changes",err)}}}runFinished(path){if(this.active--,this.activePaths.delete(path),this.stopped||this.drainHandle)return;this.drainHandle=setImmediate(()=>{this.drainHandle=void 0,this.drain()})}busyPaths(tasks){let ids=this.options.activeTaskIds?.();if(!ids)return EMPTY_PATHS;let active=new Set(ids);if(active.size===0)return EMPTY_PATHS;let paths=new Set;for(let task of tasks)if(task.worktreePath&&active.has(task.id))paths.add(task.worktreePath);return paths}maybeCollect(worktreePath,baseRef,busy=!1){let entry=this.entries.get(worktreePath);if(!entry)entry={inFlight:!1,nextAllowedAt:0},this.entries.set(worktreePath,entry);let now=Date.now(),probe=(this.options.probe??worktreeFingerprint)(worktreePath,baseRef),quietUntil=entry.quietUntil??0;if(!busy&&probe!==null&&probe===entry.probe&&now<quietUntil)return;let quietIntervalMs=this.options.quietIntervalMs??WORKTREE_CHANGES_QUIET_INTERVAL_MS,cadence=this.options.cadence??{timeoutMs:WORKTREE_CHANGES_TIMEOUT_MS,slowRetryMs:WORKTREE_CHANGES_SLOW_RETRY_MS,minIntervalMs:WORKTREE_CHANGES_MIN_INTERVAL_MS},run=this.options.run??runGitStatus;maybeStartScheduledRun(entry,cadence,(signal)=>{entry.probe=probe,entry.quietUntil=Date.now()+quietIntervalMs,this.active++,this.activePaths.add(worktreePath);let controller=new AbortController;this.controllers.add(controller);let abort=()=>controller.abort();return signal.addEventListener("abort",abort,{once:!0}),(async()=>{try{return await run(worktreePath,controller.signal,baseRef)}catch{return UNREADABLE}finally{signal.removeEventListener("abort",abort),this.controllers.delete(controller),this.runFinished(worktreePath)}})()},(value)=>{if(this.stopped)return;if(this.entries.get(worktreePath)!==entry)return;if(value===UNREADABLE&&entry.value!==void 0&&entry.value!==UNREADABLE)return;if(entry.value===value)return;if(entry.value&&entry.value!==UNREADABLE&&value!==UNREADABLE&&sameWorktreeChanges(entry.value,value))return;entry.value=value,this.publish()})}publish(){if(this.publishTimer||this.stopped)return;this.publishTimer=setTimeout(()=>{if(this.publishTimer=void 0,!this.stopped)this.publishNow()},this.options.publishDelayMs??10)}publishNow(){let changes={},unreadable=[];for(let[path,entry]of this.entries)if(entry.value===UNREADABLE)unreadable.push(path);else if(entry.value)changes[path]=entry.value;this.bus.publish("worktree.changes",unreadable.length>0?{changes,unreadable}:{changes})}}function startWorktreeChangesCollector(orch,runtime,bus,tickMs=DEFAULT_WORKTREE_CHANGES_TICK_MS,hasSubscribers,activeTaskIds){let collector=new WorktreeChangesCollector(orch,bus,{hasSubscribers,run:runtime.runWorktreeStatus,...activeTaskIds?{activeTaskIds}:{}});return startTicker({name:"worktree-changes-collector",tickMs,immediate:!0,run:()=>collector.tick(),onStop:()=>collector.stop()})}var DEFAULT_UPDATE_POLL_MS=21600000;function createProtocolUpgradeReporter(orch,runtime){return(taskId,tabId,evidence)=>{if(tabId!=="tab-1")return;let task=orch.getTask(taskId);if(!task)return;let upgrade=runtime.resolveProtocolUpgrade?.(task,evidence);if(!upgrade)return;return orch.setCommand(taskId,upgrade.command,upgrade.vendor).then(()=>logDaemonInfo("protocol-sniff",`upgraded task ${taskId} to the ${upgrade.vendor} protocol from its live session`)).catch((err)=>logDaemonError("protocol-sniff",err))}}function startDaemonCollectors(orch,runtime,bus,hasSubscribersFor,options,quotaUsage,automations,activity){let stopActivityObserver=activity?startActivityObserver(activity,{...createActivityObserverIo(options.homeDir,runtime,activity),onEngineEvidence:createProtocolUpgradeReporter(orch,runtime)},()=>hasSubscribersFor("engine-state")):()=>{},checkUpdate=options.checkUpdate??runtime.checkLatestVersion,updatePollMs=options.updatePollMs??DEFAULT_UPDATE_POLL_MS,pollUpdate=()=>{checkUpdate().then((info)=>bus.publish("update",{info})).catch((err)=>logDaemonError("update-poller",err))},updateTimer=null;if(updatePollMs>0)pollUpdate(),updateTimer=setInterval(pollUpdate,updatePollMs),updateTimer.unref?.();let stopAutoTitlePoller=startAutoTitlePoller(orch,runtime,options.autoTitlePollMs??DEFAULT_AUTO_TITLE_POLL_MS,()=>hasSubscribersFor("task.snapshot")),stopUiPrefsWatcher=startUiPrefsWatcher(bus,{statePath:defaultUiPrefsStatePath(options.homeDir),debounceMs:options.uiPrefsDebounceMs??DEFAULT_UI_PREFS_DEBOUNCE_MS}),stopKeybindingsWatcher=startKeybindingsWatcher(bus,{path:defaultKeybindingsPath(options.homeDir),debounceMs:options.keybindingsDebounceMs??DEFAULT_KEYBINDINGS_DEBOUNCE_MS}),stopWorktreeChangesCollector=startWorktreeChangesCollector(orch,runtime,bus,options.worktreeChangesTickMs??DEFAULT_WORKTREE_CHANGES_TICK_MS,()=>hasSubscribersFor("worktree.changes"),activity?()=>activity.workingTaskIds():void 0),stopTranscriptActivityCollector=startTranscriptActivityCollector(orch,runtime,bus,options.transcriptActivityTickMs??DEFAULT_TRANSCRIPT_ACTIVITY_TICK_MS,()=>hasSubscribersFor("transcript.activity")),stopContextUsageCollector=activity?startContextUsageCollector(activity,orch,bus,runtime,options.contextUsageTickMs??DEFAULT_CONTEXT_USAGE_TICK_MS,()=>hasSubscribersFor("usage.context")):()=>{},stopPrStatusPoller=startPrStatusPoller(orch,runtime,options.prStatusPollMs??DEFAULT_PR_STATUS_POLL_MS,()=>hasSubscribersFor("task.snapshot"),void 0,activity?()=>activity.workingTaskIds().length>0:void 0),stopQuotaResumeRunner=startQuotaResumeRunner(orch,runtime,options.quotaResumeTickMs??DEFAULT_QUOTA_RESUME_TICK_MS,void 0,automations?.plugins),stopAutomationRunner=automations?startAutomationRunner({store:automations.store,orch,runtime,link:automations.link,...automations.plugins?{plugins:automations.plugins}:{},...automations.inbox?{inbox:automations.inbox}:{}},options.automationTickMs??DEFAULT_AUTOMATION_TICK_MS):()=>{},stopQuotaUsagePoller=quotaUsage?startQuotaUsagePoller(quotaUsage,()=>runtime.vendorsWithQuotaProbe(),()=>hasSubscribersFor("usage.snapshot"),options.quotaUsageTickMs):()=>{};return async()=>{if(updateTimer)clearInterval(updateTimer);await Promise.allSettled([stopActivityObserver,stopAutoTitlePoller,stopPrStatusPoller,stopQuotaResumeRunner,stopAutomationRunner,stopQuotaUsagePoller,stopUiPrefsWatcher,stopKeybindingsWatcher,stopWorktreeChangesCollector,stopTranscriptActivityCollector,stopContextUsageCollector].map(async(stop)=>stop()))}}import{hostname}from"os";var AGENT_TURN_HANDLERS=[{name:"agentTurn.list",handle(payload,ctx){let taskId=optionalString(payload,"taskId"),repo=optionalString(payload,"repoRoot"),since=optionalNumber(payload,"since"),limit=optionalNumber(payload,"limit");return{turns:ctx.agentTurns?.list({...taskId?{taskId}:{},...repo?{repo}:{},...since!==void 0?{since}:{},...limit!==void 0?{limit}:{}})??[]}}}];var ATTENTION_HANDLERS=[{name:"attention.dismissRoutine",async handle(payload,ctx){return await ctx.inbox.deleteRoutineEpisode(requireString(payload,"automationId")),{deleted:!0}}},{name:"attention.dismiss",async handle(payload,ctx){let taskId=requireString(payload,"taskId"),tabId=optionalString(payload,"tabId")??null,at=payload.at===void 0?void 0:requireNumber(payload,"at"),deleted=await ctx.inbox.deleteEpisode(taskId,tabId,at);if(deleted)ctx.plugins?.handleUiReport({kind:"attention.handled",taskId,detail:{how:"dismissed",...tabId?{tabId}:{}}});return{deleted}}},{name:"attention.list",handle(_payload,ctx){return{items:ctx.inbox.snapshot()}}},{name:"attention.read",async handle(payload,ctx){let taskId=requireString(payload,"taskId"),tabId=optionalString(payload,"tabId")??null,at=requireNumber(payload,"at"),updated=await ctx.inbox.markRead(taskId,tabId,at);if(updated)ctx.plugins?.handleUiReport({kind:"attention.handled",taskId,detail:{how:"read",...tabId?{tabId}:{}}});return{updated}}},{name:"task.rowToken",handle(payload,ctx){if(!ctx.rowTokens)return{ok:!1,reason:"UNSUPPORTED"};let taskId=requireString(payload,"taskId"),source=optionalString(payload,"source")??"cli",key=optionalString(payload,"key")??"default";if(optionalBoolean(payload,"clear")===!0)return{ok:!0,cleared:ctx.rowTokens.clear(taskId,source,optionalString(payload,"key"))};let tone=payload.tone;return{ok:!0,token:ctx.rowTokens.set({taskId,source,key,text:requireString(payload,"text"),...isRowTokenTone(tone)?{tone}:{},...optionalNumber(payload,"ttlMs")!==void 0?{ttlMs:optionalNumber(payload,"ttlMs")}:{}})}}}];import{execFile}from"child_process";import{stat}from"fs/promises";import{promisify}from"util";var execFileAsync=promisify(execFile);function isProbeable(repo){return!repo.startsWith("ssh://")}async function isGitWorkTree(repo){try{let{stdout}=await execFileAsync("git",["-C",repo,"rev-parse","--is-inside-work-tree"]);return stdout.trim()==="true"}catch{return!1}}async function assertRoutineRepo(repo){if(!isProbeable(repo))return;if(!(await stat(repo).catch(()=>null))?.isDirectory())throw Error(`repo does not exist: ${repo}`);if(!await isGitWorkTree(repo))throw Error(`not a git repository: ${repo}`)}async function assertRoutineBaseRef(repo,ref){if(!ref||!isProbeable(repo))return;if(!await isGitWorkTree(repo))return;try{await execFileAsync("git",["-C",repo,"rev-parse","--verify","--quiet",`${ref}^{commit}`])}catch{throw Error(`base branch does not resolve in ${repo}: ${ref}`)}}function requireSchedule(payload,key){let schedule=requireString(payload,key);if(!isValidCron(schedule))throw Error(`invalid cron expression: ${schedule}`);return schedule}function readPrecheck(payload){if(!("precheck"in payload))return;let raw=payload.precheck;if(raw===null)return null;if(!raw||typeof raw!=="object")throw Error("precheck must be an object or null");let command=requireString(raw,"command"),timeoutSeconds=optionalNumber(raw,"timeoutSeconds")??120;if(timeoutSeconds<=0)throw Error("precheck.timeoutSeconds must be greater than zero");return{command,timeoutSeconds}}function readGraceMinutes(payload){let value=optionalNumber(payload,"missedRunGraceMinutes");if(value!==void 0&&value<0)throw Error("missedRunGraceMinutes must be zero or more minutes");return value}var AUTOMATION_HANDLERS=[{name:"automation.list",async handle(_payload,ctx){let automations=ctx.automations.list(),lastRunStatus={};for(let automation of automations){let latest=ctx.automations.runsFor(automation.id,1)[0];if(latest)lastRunStatus[automation.id]=latest.status}return{automations,lastRunStatus,keepsDaemonAlive:ctx.automations.hasEnabled()}}},{name:"automation.create",async handle(payload,ctx){let precheck=readPrecheck(payload),repo=requireString(payload,"repo"),baseRef=optionalString(payload,"baseRef"),target="target"in payload?readAutomationTarget(payload.target):void 0;if(!target)await assertRoutineRepo(repo);if(baseRef)await assertRoutineBaseRef(repo,baseRef);let targetOptions={target:target??void 0,vendor:optionalVendor(payload,"vendor"),baseRef,persistentSession:optionalBoolean(payload,"persistentSession")};assertAutomationTargetOptions(targetOptions),await assertAutomationTargetTask({repo,target:target??void 0},ctx.orch);let automation=await ctx.automations.create({name:requireString(payload,"name"),repo,...target?{target}:{},prompt:requireString(payload,"prompt"),schedule:requireSchedule(payload,"schedule"),missedRunGraceMinutes:readGraceMinutes(payload)??60,...optionalVendor(payload,"vendor")?{vendor:optionalVendor(payload,"vendor")}:{},...precheck?{precheck}:{},...baseRef?{baseRef}:{},...optionalBoolean(payload,"persistentSession")===!0?{persistentSession:!0}:{},...optionalBoolean(payload,"enabled")!==void 0?{enabled:optionalBoolean(payload,"enabled")}:{}});return ctx.daemon.reevaluateIdle(),{automation}}},{name:"automation.update",async handle(payload,ctx){let id=requireString(payload,"id"),nextBaseRef="baseRef"in payload?optionalString(payload,"baseRef"):void 0,currentRepo=ctx.automations.get(id)?.repo;if(nextBaseRef&¤tRepo)await assertRoutineBaseRef(currentRepo,nextBaseRef);let patch={...optionalString(payload,"name")!==void 0?{name:optionalString(payload,"name")}:{},...optionalString(payload,"prompt")!==void 0?{prompt:optionalString(payload,"prompt")}:{},...payload.vendor===null?{vendor:null}:optionalVendor(payload,"vendor")!==void 0?{vendor:optionalVendor(payload,"vendor")}:{},..."target"in payload?{target:readAutomationTarget(payload.target)}:{},..."schedule"in payload?{schedule:requireSchedule(payload,"schedule")}:{},...readPrecheck(payload)!==void 0?{precheck:readPrecheck(payload)}:{},..."baseRef"in payload?{baseRef:optionalString(payload,"baseRef")??null}:{},...optionalBoolean(payload,"enabled")!==void 0?{enabled:optionalBoolean(payload,"enabled")}:{},...readGraceMinutes(payload)!==void 0?{missedRunGraceMinutes:readGraceMinutes(payload)}:{},...optionalBoolean(payload,"persistentSession")!==void 0?{persistentSession:optionalBoolean(payload,"persistentSession")}:{}},current=ctx.automations.get(id);if(!current)throw Error(`automation not found: ${id}`);let targetOptions=mergeAutomationTargetOptions(current,patch);if(assertAutomationTargetOptions(targetOptions),patch.target)await assertAutomationTargetTask({repo:current.repo,target:patch.target},ctx.orch);let automation=await ctx.automations.update(id,patch);if(!automation)throw Error(`automation not found: ${id}`);return ctx.daemon.reevaluateIdle(),{automation}}},{name:"automation.delete",async handle(payload,ctx){let id=requireString(payload,"id"),deleted=await ctx.automations.delete(id);if(deleted)await ctx.inbox.deleteRoutineEpisode(id).catch(()=>{}),ctx.daemon.reevaluateIdle();return{deleted}}},{name:"automation.runs",async handle(payload,ctx){let automationId=requireString(payload,"id");if(!ctx.automations.get(automationId))throw Error(`automation not found: ${automationId}`);return{runs:ctx.automations.runsFor(automationId)}}},{name:"automation.runNow",blocking:!0,async handle(payload,ctx){let id=requireString(payload,"id"),automation=ctx.automations.get(id);if(!automation)throw Error(`automation not found: ${id}`);return{status:await runAutomationOnce({store:ctx.automations,orch:ctx.orch,runtime:ctx.runtime,link:ctx.selfLink,...ctx.plugins?{plugins:()=>ctx.plugins??null}:{},inbox:ctx.inbox},automation,{scheduledFor:Date.now(),trigger:"manual"})}}}];async function ingestAgentTurns(store,runtime,orch,input){if(!input.transcriptPath)return{recorded:0,latest:void 0};let task=orch.getTask(input.taskId),vendor=input.vendor??task?.vendor;if(!vendor)return{recorded:0,latest:void 0};let turns=await runtime.readEngineTurns(vendor,input.transcriptPath);if(turns.length===0)return{recorded:0,latest:void 0};let records=turns.map((turn)=>({...turn,taskId:input.taskId,...input.tabId?{tabId:input.tabId}:{},vendor,...task?.repo?{repo:task.repo}:{}})),recorded=await store.record(records),last=records[records.length-1],latest=last?{id:last.id,model:last.model,usage:last.usage,startedAt:last.startedAt,endedAt:last.endedAt}:void 0;return{recorded,latest}}function ingestAgentTurnsBestEffort(store,runtime,orch,input,onDone){if(!store){onDone?.(void 0);return}ingestAgentTurns(store,runtime,orch,input).then(({latest})=>onDone?.(latest)).catch((err)=>{logDaemonError("agent-turns-ingest",err),onDone?.(void 0)})}import{existsSync as existsSync2}from"fs";import path from"path";function crossesRepoBoundary(wt,cwd){let syntax=pathSyntax(cwd);for(let dir=cwd;!samePath(dir,wt);dir=syntax.dirname(dir)){if(existsSync2(syntax.join(dir,".git")))return!0;if(samePath(dir,syntax.dirname(dir)))break}return!1}function matchTaskByCwd(tasks,cwd){let target=pathIdentity(cwd),bestId,bestWt="",bestLen=-1;for(let t of tasks){if(!t.worktreePath)continue;let wt=pathIdentity(t.worktreePath);if(pathWithin(wt,target)!==null&&wt.length>bestLen)bestLen=wt.length,bestWt=wt,bestId=t.id}if(bestId&&crossesRepoBoundary(bestWt,target))return;return bestId}function matchTaskByWorktreePath(tasks,worktreePath){let target=pathIdentity(worktreePath);for(let t of tasks)if(t.worktreePath&&pathIdentity(t.worktreePath)===target)return t.id;return}function findAdoptableWorktree(tasks,cwd){let target=pathIdentity(cwd),repos=new Set,known=new Set;for(let t of tasks){if(t.repo&&path.isAbsolute(t.repo))repos.add(pathIdentity(t.repo));if(t.worktreePath)known.add(pathIdentity(t.worktreePath))}for(let repo of repos)for(let root of managedWorktreeRootsFor(repo,readWorktreeBaseOverride(repo)).map(pathIdentity)){let prefix=root.endsWith("/")?root:`${root}/`,rest=pathWithin(root,target);if(!rest)continue;let name=rest.split("/")[0];if(!name)continue;let worktreePath=`${prefix}${name}`;if(known.has(worktreePath))return;return{repo,worktreePath}}return}var ENGINE_REPORT_HANDLER={name:"engine.reportEvent",async handle(payload,ctx){let kind=requireString(payload,"kind");if(!ctx.runtime.isEngineActivityKind(kind))throw Error(`BAD_EVENT_KIND: unknown engine event kind: ${kind}`);let explicitId=optionalString(payload,"taskId"),cwd=optionalString(payload,"cwd");if(!explicitId&&cwd&&kind==="session-start"){let cand=findAdoptableWorktree(ctx.orch.listTasks(),cwd);if(cand)try{await ctx.orch.adoptWorktree({repo:cand.repo,worktreePath:cand.worktreePath,ifExists:"return"})}catch(err){logDaemonError("worktree-autosync",err)}}let taskId=explicitId??(cwd?matchTaskByCwd(ctx.orch.listTasks(),cwd):void 0);if(!taskId)return{};let detail=optionalActivityDetail(payload),tabId=optionalString(payload,"tabId"),sessionId=optionalString(payload,"sessionId"),transcriptPath=optionalString(payload,"transcriptPath"),session=sessionId?{id:sessionId,transcriptPath}:void 0,isStateKind=ctx.runtime.affectsActivityState(kind),vendor=optionalString(payload,"engine");if(isStateKind){if(ctx.activity.report(taskId,kind,detail,tabId,session,vendor),explicitId)await ctx.inbox.record(taskId,kind,detail,tabId??null).catch((err)=>logDaemonError("attention-inbox-record",err))}if(ctx.engineEvents?.append(taskId,{kind,...tabId?{tabId}:{},...vendor?{vendor}:{},...detail?{detail}:{},at:Date.now()}),kind==="pre-compact"||kind==="post-compact"||kind==="subagent-start"||kind==="subagent-stop")ctx.bus.publish("engine.lifecycle",{taskId,kind,...tabId?{tabId}:{},at:Date.now()});let pluginReport={kind,taskId,...detail?{detail}:{},...vendor?{vendor}:{},...tabId?{tabId}:{},...sessionId?{sessionId}:{}};if(kind!=="turn-complete")ctx.plugins?.handleEngineReport(pluginReport);if(kind==="turn-complete")ingestAgentTurnsBestEffort(ctx.agentTurns,ctx.runtime,ctx.orch,{taskId,...tabId?{tabId}:{},...vendor?{vendor}:{},...transcriptPath?{transcriptPath}:{}},(latest)=>ctx.plugins?.handleEngineReport(latest?{...pluginReport,detail:{...pluginReport.detail??{},turn:latest}}:pluginReport));if(kind==="turn-start"){if(ctx.runtime.maybeAutoStart(ctx.orch,taskId).then((result)=>{if(result==="moved")console.log(`[status-rules] task ${taskId} auto-moved backlog \u2192 in_progress`)}).catch((err)=>logDaemonError("status-rules",err)),ctx.orch.getTask(taskId)?.quotaResume)ctx.orch.setQuotaResume(taskId,null).catch((err)=>logDaemonError("quota-resume",err))}if(kind==="turn-failed"&&detail?.failure==="rate_limit")scheduleQuotaResume(ctx.orch,ctx.runtime,ctx.quotaUsage,taskId,void 0,()=>ctx.plugins??null).catch((err)=>logDaemonError("quota-resume",err));return{}}};var MAX_GRAPHICS_BYTES=4194304,BASE64=/^[A-Za-z0-9+/]+={0,2}$/;function agreedCellSize(sizes){let first=sizes[0];if(!first)return{unsupported:"no-cell-size"};for(let size of sizes)if(size.width!==first.width||size.height!==first.height)return{unsupported:"mixed-cell-size"};return{cell:first}}var GRAPHICS_HANDLERS=[{name:"graphics.write",async handle(payload,ctx){let taskId=requireString(payload,"taskId"),tabId=requireString(payload,"tabId"),data=optionalString(payload,"data");if(!ctx.orch.getTask(taskId))throw Error(`task not found: ${taskId}`);let ids=ctx.graphics;if(!ids)throw Error("graphics unavailable");if(data!==void 0){if(!BASE64.test(data))throw Error("data must be base64");let bytes=Math.floor(data.length*3/4);if(bytes>MAX_GRAPHICS_BYTES)throw Error(`payload too large: ${bytes} bytes (max ${MAX_GRAPHICS_BYTES})`)}let agreed=agreedCellSize(ctx.daemon.guiCellSizes?.()??[]);if("unsupported"in agreed)return{ok:!1,unsupported:agreed.unsupported,clients:ctx.daemon.clientCount()};let reuse=payload.imageId,imageId;if(reuse===void 0)imageId=ids.allocate(taskId,tabId);else if(imageId=requireNumber(payload,"imageId"),!ids.owns(taskId,tabId,imageId))throw Error(`imageId not allocated to this tab: ${imageId}`);if(data!==void 0)ctx.bus.publish("graphics.write",{taskId,tabId,imageId,data,at:Date.now()});return{ok:!0,wrote:data!==void 0,imageId,cellWidth:agreed.cell.width,cellHeight:agreed.cell.height,clients:ctx.daemon.clientCount()}}}];function publishIssueSnapshot(ctx,state){if(ctx.daemon.hasSubscribersFor?.("issue.snapshot")===!1)return;ctx.bus.publish("issue.snapshot",state)}var ISSUE_HANDLERS=[{name:"issue.list",async handle(payload,ctx){return ctx.issues.list(requireString(payload,"repoRoot"))}},{name:"issue.repos",async handle(_payload,ctx){return{repos:await ctx.issues.repos()}}},{name:"issue.mutate",async handle(payload,ctx){let repoRoot=requireString(payload,"repoRoot"),op=payload.op,opType=op&&typeof op==="object"?op.type:void 0;if(opType==="link"||opType==="update"){let taskId=op.taskId;if(typeof taskId==="string"&&taskId.length>0&&!ctx.orch.getTask(taskId))throw Error(`task not found: ${taskId}`)}let state=await ctx.issues.mutate(repoRoot,payload.op);return publishIssueSnapshot(ctx,state),ctx.plugins?.handleUiReport({kind:"issue.changed",detail:{repo:repoRoot,...payload.op&&typeof payload.op==="object"?{op:payload.op}:{}}}),state}}];var MAX_FAILING_JOBS=3,MAX_TAIL_LINES=200,RUN_LOG_TIMEOUT_MS=30000;function stringField(value,key){if(typeof value!=="object"||value===null)return"";let field=value[key];return typeof field==="string"?field:""}function runIdFromDetailsUrl(url){return/\/actions\/runs\/(\d+)\b/.exec(url)?.[1]??null}function failingCheckTargets(rollup){let targets=[];for(let entry of rollup){let status=stringField(entry,"status").toUpperCase(),conclusion=stringField(entry,"conclusion").toUpperCase(),contextState=stringField(entry,"state").toUpperCase(),failedAs=null;if(status&&status!=="COMPLETED")failedAs=null;else if(conclusion)failedAs=conclusion==="SUCCESS"||conclusion==="NEUTRAL"||conclusion==="SKIPPED"?null:conclusion;else if(contextState==="FAILURE"||contextState==="ERROR")failedAs=contextState;if(failedAs===null)continue;let url=stringField(entry,"detailsUrl")||stringField(entry,"targetUrl");targets.push({jobName:stringField(entry,"name")||stringField(entry,"context")||"check",conclusion:failedAs,url,runId:runIdFromDetailsUrl(url)})}return targets}function parseFailedRunLog(text,maxLines=MAX_TAIL_LINES){let byJob=new Map;for(let raw of text.split(`
|
|
5
5
|
`)){let line=raw.replace(/\r$/,"");if(line.length===0)continue;let firstTab=line.indexOf("\t");if(firstTab<=0)continue;let job=line.slice(0,firstTab),secondTab=line.indexOf("\t",firstTab+1),body=(secondTab===-1?line.slice(firstTab+1):line.slice(secondTab+1)).replace(/^\uFEFF/,""),lines=byJob.get(job);if(!lines)lines=[],byJob.set(job,lines);if(lines.push(body),lines.length>maxLines)lines.shift()}return byJob}function joinFailingChecks(targets,logsByJob){return{checks:targets.slice(0,MAX_FAILING_JOBS).map((target)=>({jobName:target.jobName,conclusion:target.conclusion,url:target.url,tail:(logsByJob.get(target.jobName)??[]).join(`
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{loadStateFile,patchStateFile}from"./chunk-
|
|
2
|
+
import{loadStateFile,patchStateFile}from"./chunk-zyd6k6ak.js";var LAST_ACTIVE_TASK_KEY="lastActive.taskId";function readLastActiveTaskId(){let value=loadStateFile()[LAST_ACTIVE_TASK_KEY];return typeof value==="string"&&value?value:null}function writeLastActiveTaskId(id){patchStateFile({[LAST_ACTIVE_TASK_KEY]:id})}
|
|
3
3
|
export{readLastActiveTaskId,writeLastActiveTaskId};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{formatBytes,hookConfigIssues}from"./chunk-
|
|
2
|
+
import{formatBytes,hookConfigIssues}from"./chunk-gjtyxam6.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-dqndd97s.js";import"./chunk-1f8c92xt.js";import"./chunk-85pk7c74.js";import"./chunk-53afdybj.js";import"./chunk-rz8zs7j8.js";import{describeAccount,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-sn2r47e9.js";import"./chunk-mhg40es1.js";import"./chunk-r2pztgm6.js";import"./chunk-1da3bqjc.js";import"./chunk-85mk6j0s.js";import"./chunk-xsrcwcjc.js";import"./chunk-59xc6m1q.js";import{resolveNodeBinary}from"./chunk-gfwxx6mh.js";import{formatDaemonInfo}from"./chunk-rcyasw34.js";import"./chunk-b99tf0jr.js";import"./chunk-chmhmxmc.js";import"./chunk-rhczy26f.js";import"./chunk-7mfjczcz.js";import"./chunk-w7zv47mp.js";import"./chunk-khj0apc7.js";import"./chunk-g3r1dwy9.js";import"./chunk-w25b7xxz.js";import"./chunk-h4n8ffqy.js";import"./chunk-vyb5a2rh.js";import"./chunk-jvxh93nz.js";import{isStaleInstallError,resolveKobeSpawn}from"./chunk-5t8cazgm.js";import"./chunk-wenasn1h.js";import"./chunk-2brn8e1y.js";import"./chunk-y3k1accw.js";import"./chunk-bw73t1zw.js";import"./chunk-7kysxgbq.js";import{readableLegacyIndexPath}from"./chunk-2xsem13q.js";import"./chunk-xy8be792.js";import"./chunk-05jej26n.js";import{CURRENT_VERSION,package_default}from"./chunk-n8dkpf4v.js";import{kobeSkillState,skillInstallCommand}from"./chunk-qdfcdhy8.js";import"./chunk-hg87p5n8.js";import"./chunk-40dgv828.js";import"./chunk-mkksdcsw.js";import{activeCliName}from"./chunk-ppwpjm39.js";import"./chunk-fxs82dsx.js";import"./chunk-zyd6k6ak.js";import{homeDir,kvStatePath,roveStateDir}from"./chunk-8hbtca1g.js";import"./chunk-hq2n27y1.js";import{LEGACY_KOBE_STATE_DIR_BASENAME}from"./chunk-sb0ns0c7.js";import{readPidFile}from"./chunk-vnpqemb0.js";import"./chunk-9prawccj.js";import{t}from"./chunk-mvz494h2.js";import"./chunk-k95j7j3a.js";import"./chunk-sdyzxayr.js";import"./chunk-pxk2c2vj.js";import{KobeDaemonClient}from"./chunk-mjdt28x6.js";import{isForeignDaemonHome}from"./chunk-p1zab1sy.js";import"./chunk-hqbmzz4t.js";import"./chunk-3es6spp4.js";import"./chunk-pw6yfj10.js";import"./chunk-f10n6063.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-y8fqdnh3.js";import"./chunk-hq4b3fca.js";import{__require}from"./chunk-wqfp8d9w.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}import{createInterface}from"readline";function daemonRestartFix(cliName,reason){return{kind:"run",id:"daemon-restart",label:t(`doctor.fix.${reason}`),command:[cliName,"daemon","restart"],why:t("doctor.fix.daemonRestartWhy")}}function skillInstallFix(installCommand,stale){return{kind:"run",id:"skill-install",label:t(stale?"doctor.fix.skillStale":"doctor.fix.skillMissing"),command:installCommand.split(" "),why:t("doctor.fix.skillInstallWhy")}}function resetManualFix(cliName,reason){return{kind:"manual",id:`reset:${reason}`,label:t(`doctor.fix.${reason}`),action:`${cliName} reset`,why:t("doctor.fix.resetWhy")}}function killOrphansManualFix(cliName,count){return{kind:"manual",id:"kill-orphans",label:t("doctor.fix.orphans",{count}),action:`${cliName} doctor --kill-orphans`,why:t("doctor.fix.orphansWhy")}}function engineTabsManualFix(){return{kind:"manual",id:"engine-tabs",label:t("doctor.fix.engineTabs"),action:t("doctor.fix.engineTabsAction"),why:t("doctor.fix.engineTabsWhy")}}function reinstallManualFix(){return{kind:"manual",id:"reinstall",label:t("doctor.fix.staleInstall"),action:t("doctor.fix.staleInstallAction"),why:t("doctor.fix.staleInstallWhy")}}function spawnHelperFix(paths){return{kind:"run",id:"spawn-helper-chmod",label:t("doctor.fix.spawnHelper"),command:["chmod","755",...paths],why:t("doctor.fix.spawnHelperWhy")}}function humanOnlyFix(reason,vars){return{kind:"manual",id:reason,label:t(`doctor.fix.${reason}`),action:t(`doctor.fix.${reason}Action`,vars),why:t("doctor.fix.humanOnlyWhy")}}function noEngineFix(signedOut){return signedOut.length>0?humanOnlyFix("noEngineLogin",{list:signedOut.join(", ")}):humanOnlyFix("noEngine")}function dedupeFixes(fixes){let seen=new Set;return fixes.filter((fix)=>{if(seen.has(fix.id))return!1;return seen.add(fix.id),!0})}async function applyFixes(collected,rt){let fixes=dedupeFixes(collected);if(fixes.length===0){rt.out(""),rt.out(t("doctor.fix.none"));return}let runnable=fixes.filter((fix)=>fix.kind==="run");if(runnable.length>0){rt.out(""),rt.out(t("doctor.fix.header"));for(let fix of runnable){if(rt.out(` ${fix.label}`),rt.out(` ${t("doctor.fix.willRun",{command:fix.command.join(" ")})}`),rt.out(` ${fix.why}`),!rt.interactive)continue;if(!await rt.confirm(` ${t("doctor.fix.confirmPrompt")}`)){rt.out(` ${t("doctor.fix.skipped")}`);continue}let code=await rt.exec(fix.command);rt.out(code===0?` ${t("doctor.fix.done")}`:` ${t("doctor.fix.failed",{code})}`)}if(!rt.interactive)rt.out(` ${t("doctor.fix.nonInteractive")}`)}let manual=fixes.filter((fix)=>fix.kind==="manual");if(manual.length>0){rt.out(""),rt.out(t("doctor.fix.manualHeader"));for(let fix of manual)rt.out(` ${fix.label}`),rt.out(` \u2192 ${fix.action}`),rt.out(` ${fix.why}`)}}async function confirmTty(question){let readline=createInterface({input:process.stdin,output:process.stdout});try{let answer=await new Promise((resolve)=>readline.question(question,resolve));return answer.trim().toLowerCase()==="y"||answer.trim().toLowerCase()==="yes"}finally{readline.close()}}async function execInherited(command){try{return await Bun.spawn([...command],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited}catch{return 127}}function defaultFixRuntime(){return{confirm:confirmTty,exec:execInherited,out:(line)=>console.log(line),interactive:process.stdin.isTTY===!0}}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: \`KOBE_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="KOBE_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=activeCliName();function isProcessAlive(pid){try{return process.kill(pid,0),!0}catch(err){return err.code==="EPERM"}}async function requestIfReachable(socketPath,name){let client=new KobeDaemonClient(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(`
|