@sma1lboy/rove 0.9.258 → 0.9.259
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{chunk-9v18qy3s.js → chunk-0z1azqkp.js} +1 -1
- package/dist/cli/{chunk-jf46jsdp.js → chunk-15jt6k82.js} +1 -1
- package/dist/cli/{chunk-csdne12x.js → chunk-1dcb0069.js} +1 -1
- package/dist/cli/{chunk-jd02zgwf.js → chunk-1dnyxp0v.js} +1 -1
- package/dist/cli/{chunk-tpt3fn1q.js → chunk-1j4e2jcx.js} +1 -1
- package/dist/cli/{chunk-jtpjdmb6.js → chunk-1x6yahf1.js} +1 -1
- package/dist/cli/{chunk-tq6pq1ws.js → chunk-2676cb62.js} +1 -1
- package/dist/cli/{chunk-x8rkpfqd.js → chunk-3n2jn56j.js} +1 -1
- package/dist/cli/chunk-3v2hgjb2.js +3 -0
- package/dist/cli/{chunk-yktnbb14.js → chunk-3vtpshwx.js} +37 -37
- package/dist/cli/{chunk-ya0h6hcd.js → chunk-3yx6rrgm.js} +2 -2
- package/dist/cli/chunk-44ba9qvn.js +2 -0
- package/dist/cli/chunk-45yxyx4z.js +70 -0
- package/dist/cli/{chunk-y8xb4ys7.js → chunk-4abka29v.js} +1 -1
- package/dist/cli/{chunk-1egwgg6p.js → chunk-4pmx2q7r.js} +1 -1
- package/dist/cli/chunk-4pt3n7cg.js +4 -0
- package/dist/cli/{chunk-1zqzqbek.js → chunk-59hmb90m.js} +1 -1
- package/dist/cli/chunk-5c0dgs7n.js +2 -0
- package/dist/cli/{chunk-zam29b9x.js → chunk-5g3s1a2n.js} +1 -1
- package/dist/cli/{chunk-ke3t032y.js → chunk-5js4agdd.js} +1 -1
- package/dist/cli/{chunk-r6f8h111.js → chunk-5xeywdwg.js} +2 -2
- package/dist/cli/{chunk-pw87thvf.js → chunk-5yv3jzc5.js} +1 -1
- package/dist/cli/{chunk-kqf371ff.js → chunk-601dsgex.js} +1 -1
- package/dist/cli/chunk-67stdpfn.js +2 -0
- package/dist/cli/{chunk-6p9yxt3q.js → chunk-6h12b2k0.js} +1 -1
- package/dist/cli/chunk-6q52d0nj.js +7 -0
- package/dist/cli/{chunk-xnaehfby.js → chunk-6v8rhkr8.js} +1 -1
- package/dist/cli/{chunk-hfvz23r6.js → chunk-7rfy6zpw.js} +1 -1
- package/dist/cli/chunk-8sq09avz.js +2 -0
- package/dist/cli/{chunk-edpbz0gz.js → chunk-9ed3gqj9.js} +3 -3
- package/dist/cli/{chunk-cb7hc2xm.js → chunk-9f1xbpxn.js} +1 -1
- package/dist/cli/{chunk-3q1rv3rm.js → chunk-9ztqf6hb.js} +1 -1
- package/dist/cli/{chunk-dd0mtzje.js → chunk-apm5yjkq.js} +1 -1
- package/dist/cli/{chunk-pb5g6161.js → chunk-b41sj385.js} +1 -1
- package/dist/cli/chunk-bc4agaf1.js +2 -0
- package/dist/cli/{chunk-hdnqq66w.js → chunk-bdwp2k8f.js} +1 -1
- package/dist/cli/{chunk-rx2604ry.js → chunk-bkspbk0y.js} +1 -1
- package/dist/cli/{chunk-t25xke74.js → chunk-bkt3ktvx.js} +1 -1
- package/dist/cli/{chunk-8gjpnb83.js → chunk-btygchef.js} +1 -1
- package/dist/cli/chunk-c0gvp57p.js +3 -0
- package/dist/cli/{chunk-qn04z4zb.js → chunk-cc1mzr8d.js} +1 -1
- package/dist/cli/{chunk-95jzkqp2.js → chunk-dc3n6nf7.js} +1 -1
- package/dist/cli/{chunk-68113ts1.js → chunk-e6848rj8.js} +1 -1
- package/dist/cli/{chunk-y0gybgba.js → chunk-ecngwr1v.js} +1 -1
- package/dist/cli/{chunk-b47k0cnw.js → chunk-efjahmtj.js} +1 -1
- package/dist/cli/chunk-emtbtym6.js +3 -0
- package/dist/cli/chunk-g1rqy0nz.js +2 -0
- package/dist/cli/{chunk-ehb0hbrg.js → chunk-h2vv63bh.js} +2 -2
- package/dist/cli/{chunk-1xrbb7gf.js → chunk-hqkzc8cv.js} +1 -1
- package/dist/cli/{chunk-mmc662x2.js → chunk-hwbpbp0c.js} +1 -1
- package/dist/cli/{chunk-0604fza5.js → chunk-hynv8c2k.js} +1 -1
- package/dist/cli/{chunk-cq5qv93a.js → chunk-j5w8n1st.js} +1 -1
- package/dist/cli/{chunk-6x0trw81.js → chunk-jbndzrbw.js} +1 -1
- package/dist/cli/chunk-jfbnz454.js +2 -0
- package/dist/cli/{chunk-qpc8bv02.js → chunk-jj3nbb2g.js} +4 -4
- package/dist/cli/{chunk-pwbtezsa.js → chunk-jtf8qstz.js} +1 -1
- package/dist/cli/{chunk-4d4d59vp.js → chunk-jzf2d1pj.js} +1 -1
- package/dist/cli/{chunk-yaqkajw4.js → chunk-k3b5cnd5.js} +12 -12
- package/dist/cli/{chunk-eyzjma6q.js → chunk-kcefxpn1.js} +1 -1
- package/dist/cli/chunk-n3br556t.js +11 -0
- package/dist/cli/{chunk-zqq3djrw.js → chunk-ndbxpd01.js} +3 -3
- package/dist/cli/{chunk-wyt2vgjv.js → chunk-ngc1n7h3.js} +1 -1
- package/dist/cli/{chunk-7cd1epfw.js → chunk-nxdm60xy.js} +1 -1
- package/dist/cli/{chunk-8q1g1xq0.js → chunk-p27ph0g8.js} +1 -1
- package/dist/cli/chunk-pbfehk8q.js +3 -0
- package/dist/cli/{chunk-c8anewjn.js → chunk-pgbsb202.js} +1 -1
- package/dist/cli/{chunk-0d57z680.js → chunk-pw9teydh.js} +1 -1
- package/dist/cli/{chunk-sma961wh.js → chunk-q07r6hf7.js} +1 -1
- package/dist/cli/{chunk-4ab8y1yp.js → chunk-q2kweazg.js} +8 -7
- package/dist/cli/chunk-qpvvc1xz.js +4 -0
- package/dist/cli/{chunk-ebea569y.js → chunk-qtewm0jz.js} +1 -1
- package/dist/cli/chunk-r3zkpbf5.js +9 -0
- package/dist/cli/{chunk-sabpcket.js → chunk-rsvh7n8v.js} +1 -1
- package/dist/cli/chunk-s83qnstd.js +2 -0
- package/dist/cli/{chunk-cqychwvw.js → chunk-sh5a4djc.js} +1 -1
- package/dist/cli/{chunk-kgddz8pw.js → chunk-smqmpz5c.js} +1 -1
- package/dist/cli/chunk-sqks9vyt.js +2 -0
- package/dist/cli/{chunk-yjyjg7sk.js → chunk-stng29vp.js} +2 -2
- package/dist/cli/{chunk-80zzjcvp.js → chunk-syqbc3a3.js} +1 -1
- package/dist/cli/chunk-wg9w0xf4.js +3 -0
- package/dist/cli/{chunk-v7prawj1.js → chunk-wqcs5mz0.js} +1 -1
- package/dist/cli/chunk-wv6d96t6.js +2 -0
- package/dist/cli/{chunk-45thgqdr.js → chunk-wv8vfhty.js} +1 -1
- package/dist/cli/{chunk-jv11f2c2.js → chunk-xpr9sf8t.js} +3 -3
- package/dist/cli/chunk-ymq20jvp.js +62 -0
- package/dist/cli/{chunk-79r3wbhh.js → chunk-ywtsqm67.js} +1 -1
- package/dist/cli/chunk-z3qhpthz.js +3 -0
- package/dist/cli/{chunk-jetsx9zr.js → chunk-zae59k1j.js} +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/cli/rove.js +1 -1
- package/dist/completions/rove.bash +2 -2
- package/dist/completions/rove.fish +2 -2
- package/dist/completions/rove.zsh +2 -2
- package/dist/skills/rove/SKILL.md +1 -1
- package/dist/skills/rove/references/api-flags.md +13 -11
- package/dist/web/assets/index-B4sS_af0.js +109 -0
- package/dist/web/assets/index-znAxiX5H.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/cli/chunk-1378mh2w.js +0 -3
- package/dist/cli/chunk-1qge84t7.js +0 -3
- package/dist/cli/chunk-1vxykwb9.js +0 -3
- package/dist/cli/chunk-2yjpqb47.js +0 -3
- package/dist/cli/chunk-658859k9.js +0 -31
- package/dist/cli/chunk-6t5d02s4.js +0 -2
- package/dist/cli/chunk-7nr405tr.js +0 -9
- package/dist/cli/chunk-82zpp3yx.js +0 -4
- package/dist/cli/chunk-8dggnfaf.js +0 -2
- package/dist/cli/chunk-fehxbwcb.js +0 -6
- package/dist/cli/chunk-g846fbp7.js +0 -52
- package/dist/cli/chunk-hkv6t5v9.js +0 -2
- package/dist/cli/chunk-q301ewyq.js +0 -2
- package/dist/cli/chunk-rmk69hvh.js +0 -2
- package/dist/cli/chunk-s1rg1zae.js +0 -3
- package/dist/cli/chunk-skpkscne.js +0 -11
- package/dist/cli/chunk-x7cv6deh.js +0 -2
- package/dist/cli/chunk-y85e24s9.js +0 -2
- package/dist/cli/chunk-yc9bytrj.js +0 -2
- package/dist/web/assets/index-BiUiNIOp.css +0 -1
- package/dist/web/assets/index-jy27XaL0.js +0 -109
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import{countCronBetween,isValidCron,latestCronAtOrBefore,nextCronAfter}from"./chunk-a4hsqj1b.js";import{tightenInstalledPluginPermissions}from"./chunk-dqprpnd6.js";import{ClientWriter,LineReceiver,objectPayload,optionalActivityDetail,optionalBoolean,optionalNumber,optionalString,optionalVendor,requireNumber,requireString,statusActivity}from"./chunk-k67vbszb.js";import{IssuesStore,defaultIssuesStorePath,resolveRepoRoot}from"./chunk-4hestsjp.js";import{
|
|
2
|
+
import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import{countCronBetween,isValidCron,latestCronAtOrBefore,nextCronAfter}from"./chunk-a4hsqj1b.js";import{tightenInstalledPluginPermissions}from"./chunk-dqprpnd6.js";import{ClientWriter,LineReceiver,objectPayload,optionalActivityDetail,optionalBoolean,optionalNumber,optionalString,optionalVendor,requireNumber,requireString,statusActivity}from"./chunk-k67vbszb.js";import{IssuesStore,defaultIssuesStorePath,resolveRepoRoot}from"./chunk-4hestsjp.js";import{buildPluginEnv}from"./chunk-stcvcsfm.js";import{STICKY_STATES,activityStillWorking,reduceActivity,resolveEngineStateTtlMs}from"./chunk-2bgmby1d.js";import{managedWorktreeRootsFor,readWorktreeBaseOverride}from"./chunk-41x1hrqe.js";import{serialized,writeJsonAtomic,writeTextAtomic}from"./chunk-5mhvjytn.js";import{currentPluginPlatform,loadPluginRegistry,pluginConfigDir,pluginLogPath,pluginManifestPath,pluginRegistryPath,pluginStateDir,readPluginManifest,supportsPlatform}from"./chunk-edsm15ht.js";import{RowTokenStore,isRowTokenTone}from"./chunk-atn06ncf.js";import{ptyHostHasLiveSessions,sweepPtyHostSessions}from"./chunk-qpvvc1xz.js";import{logDaemonError,logDaemonInfo}from"./chunk-rxqdw6s5.js";import{resolveLoginShell}from"./chunk-f5n0tgky.js";import{decodeCapturedChunks,maybeStartScheduledRun}from"./chunk-2tfnscxk.js";import{ENGINE_EXIT_BANNER,engineExitCodeFromTail,plainTail,readPtyExitRecords,readPtyExitStore,recordEngineExit}from"./chunk-sr4c9fve.js";import{parsePorcelainRows}from"./chunk-dmzg9zdc.js";import{worktreeFingerprint}from"./chunk-kg9kmwt9.js";import{probeDaemonSocket}from"./chunk-601dsgex.js";import{detachOptions}from"./chunk-3vtpshwx.js";import{createSocketOwnershipGuard,isProcessAlive,listenOnUnixSocket}from"./chunk-wqckm0k6.js";import{defaultKeybindingsPath,defaultUiPrefsStatePath}from"./chunk-prqeddy7.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE,ensureOwnerOnlyStateDir}from"./chunk-yt15y085.js";import{CHANNEL_NAMES,DAEMON_PROTOCOL_VERSION,DELIVERY_EVIDENCE_MAX_CHARS,DELIVERY_EVIDENCE_MAX_ITEMS,DELIVERY_NEXT_MAX_CHARS,DELIVERY_OUTCOMES,DELIVERY_PROMPT_HEAD_CHARS,DELIVERY_STALL_MS,DELIVERY_SUMMARY_MAX_CHARS,GATE_CONTEXT_MAX,GATE_OPTIONS_MAX,GATE_QUESTION_MAX,MAX_DELIVERIES_PER_TASK,MIN_COMPATIBLE_PROTOCOL_VERSION,ROUTINE_RESPONSE_MAX_CHARS,RoveDaemonClient,attentionInboxItemKey,automationRunNeedsAttention,deliveryFooter,displayTaskTitle,frameToLine,isAttentionInboxState,isProtocolCompatible,isRoutineInboxState,normalizeChannelFilter,parseDaemonStopReason,parseSkipVerdict,serializeTask}from"./chunk-s0jbtyd9.js";import{MOD_INPUT_MAX,MOD_PANE_ID_PATTERN,MOD_TITLE_MAX,ROVE_API_VERSION,validateModTree}from"./chunk-278sc87n.js";import{rotateLogIfNeeded}from"./chunk-gskbzgc3.js";import{pathIdentity,pathSyntax,pathWithin,samePath}from"./chunk-pn5ygqn6.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultDeliveriesPath,defaultPtyExitsPath,defaultPtyHostSocketPath,endpointPathFor,resolveDaemonHomeDir}from"./chunk-n0rtj4z7.js";import{ROVE_STATE_DIR_BASENAME,readRoveEnv,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.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;limitedSince=new Map;tabbed=new Set;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[];let at=this.now(),base={taskId:payload.taskId,task:taskContext(this.tasks?.get(payload.taskId)),...payload.tabId?{tabId:payload.tabId}:{},at},out=[{event,...base}],recovered=this.trackRateLimit(key,payload,at);if(recovered!==void 0)out.push({event:"agent.rate-limit-recovered",...base,detail:{limitedAt:new Date(recovered).toISOString(),limitedForMs:at-recovered}});return out}trackRateLimit(key,payload,at){if(payload.tabId)this.tabbed.add(payload.taskId);else if(this.tabbed.has(payload.taskId))return;if(payload.state==="rate_limited"){if(!this.limitedSince.has(key))this.limitedSince.set(key,at);return}if(payload.state!=="turn_complete")return;let since=this.limitedSince.get(key);if(since===void 0)return;return this.limitedSince.delete(key),since}}import{execFile,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 appendPluginLogRecord(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){appendPluginLogRecord(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"],...detachOptions(opts.platform)}),kill=()=>{try{if(child.pid&&(opts.platform??process.platform)==="win32")execFile("taskkill",["/pid",String(child.pid),"/T","/F"],{windowsHide:!0},(err)=>{if(err)child.kill("SIGKILL")});else 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(()=>{appendPluginLogRecord(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()})}),appendPluginLogRecord(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}`}`)}import{execFile as execFile2,spawn as spawn2}from"child_process";import{mkdirSync as mkdirSync2}from"fs";var MOD_MAX_PANES=8,MAX_LINE_BYTES=524288,RESTART_MIN_MS=1000,RESTART_MAX_MS=30000,HEALTHY_RUN_MS=60000;function treeHasControl(node,type,key){if(node.type===type)return node.key===key;if(node.type==="box")return node.children.some((child)=>treeHasControl(child,type,key));return!1}class ModHost{opts;mods=new Map;stopped=!1;constructor(opts){this.opts=opts}sync(specs){if(this.stopped)return;let next=new Map(specs.map((s)=>[s.pluginId,s]));for(let[id,running]of this.mods){let spec=next.get(id);if(!spec||spec.root!==running.spec.root||!sameCommand(spec.mod,running.spec.mod))this.retire(id)}for(let spec of specs)if(!this.mods.has(spec.pluginId))this.launch(spec);this.publish()}press(pluginId,paneId,key){return this.forward(pluginId,paneId,"button",key,{type:"press",pane:paneId,key})}submit(pluginId,paneId,key,value){if(value.length>MOD_INPUT_MAX)return"too-long";return this.forward(pluginId,paneId,"input",key,{type:"submit",pane:paneId,key,value})}deliver(pluginIds,event){for(let running of this.mods.values()){if(!pluginIds.has(running.spec.pluginId)||!running.events.has(event.event))continue;if(running.child?.stdin?.writable)running.child.stdin.write(`${JSON.stringify({type:"event",event})}
|
|
4
4
|
`)}}forward(pluginId,paneId,type,key,msg){let running=this.mods.get(pluginId);if(!running?.child?.stdin?.writable)return"no-mod";let pane=running.panes.get(paneId);if(!pane)return"no-pane";if(!treeHasControl(pane.tree,type,key))return"no-key";return running.child.stdin.write(`${JSON.stringify(msg)}
|
|
5
5
|
`),"sent"}panes(){return[...this.mods.values()].flatMap((m)=>[...m.panes.values()])}stop(){if(this.stopped)return;this.stopped=!0;for(let id of[...this.mods.keys()])this.retire(id)}publish(){this.opts.publish(this.panes())}retire(pluginId){let running=this.mods.get(pluginId);if(!running)return;if(this.mods.delete(pluginId),running.restartTimer)clearTimeout(running.restartTimer);if(running.child)killGroup(running.child,this.opts.platform);running.child=null}launch(spec){let running={spec,child:null,startedAt:0,backoffMs:RESTART_MIN_MS,restartTimer:void 0,panes:new Map,events:new Set};this.mods.set(spec.pluginId,running),this.spawnChild(running)}record(running,record){appendPluginLogRecord(running.spec.pluginId,this.opts.homeDir,{at:Date.now(),kind:"mod",...record})}spawnChild(running){let{pluginId,root,mod}=running.spec,[cmd,...args]=mod.command,child;try{mkdirSync2(pluginConfigDir(pluginId,this.opts.homeDir),{recursive:!0,mode:OWNER_ONLY_DIR_MODE}),mkdirSync2(pluginStateDir(pluginId,this.opts.homeDir),{recursive:!0,mode:OWNER_ONLY_DIR_MODE}),child=spawn2(cmd,args,{cwd:root,env:buildPluginEnv({homeDir:this.opts.homeDir,socketPath:this.opts.socketPath,binPath:this.opts.binPath,pluginId,pluginRoot:root,extra:{ROVE_PLUGIN_EVENT:"mod"}}),stdio:["pipe","pipe","pipe"],...detachOptions(this.opts.platform)})}catch(err){this.record(running,{spawnError:String(err)}),this.scheduleRestart(running);return}running.child=child,running.events=new Set,running.startedAt=Date.now(),this.record(running,{phase:"started",command:mod.command}),child.stdin?.on("error",()=>{}),readLines(child,"stdout",(line)=>this.onLine(running,child,line)),readLines(child,"stderr",(line)=>this.record(running,{stderr:line.slice(0,2048)})),child.on("error",(err)=>this.record(running,{spawnError:String(err)})),child.on("close",(code,signal)=>{if(running.child!==child)return;if(running.child=null,this.record(running,{phase:"exited",exitCode:code,...signal?{signal}:{}}),this.opts.log?.(`mod ${pluginId} exited (${signal??`exit ${code}`})`),running.panes.size>0)running.panes.clear(),this.publish();if(Date.now()-running.startedAt>=HEALTHY_RUN_MS)running.backoffMs=RESTART_MIN_MS;this.scheduleRestart(running)})}scheduleRestart(running){if(this.stopped||this.mods.get(running.spec.pluginId)!==running)return;let delay=running.backoffMs;running.backoffMs=Math.min(running.backoffMs*2,RESTART_MAX_MS),running.restartTimer=setTimeout(()=>{if(running.restartTimer=void 0,this.stopped||this.mods.get(running.spec.pluginId)!==running)return;this.spawnChild(running)},delay),running.restartTimer.unref?.()}onLine(running,child,line){if(running.child!==child||line.trim()==="")return;let msg;try{msg=JSON.parse(line)}catch{this.record(running,{refused:"stdout line is not JSON",line:line.slice(0,200)});return}let refused=this.apply(running,msg);if(refused)this.record(running,{refused})}apply(running,msg){if(msg.type==="subscribe"){if(!Array.isArray(msg.events)||!msg.events.every((e)=>typeof e==="string"))return"subscribe needs events: string[]";return running.events=new Set(msg.events),null}if(typeof msg.id!=="string"||!MOD_PANE_ID_PATTERN.test(msg.id))return"bad pane id";if(msg.type==="close"){if(running.panes.delete(msg.id))this.publish();return null}if(msg.type!=="pane")return`unknown message type ${JSON.stringify(msg.type)}`;if(typeof msg.title!=="string"||msg.title.length===0||msg.title.length>MOD_TITLE_MAX)return`pane ${msg.id}: title must be 1-${MOD_TITLE_MAX} chars`;if(!running.panes.has(msg.id)&&running.panes.size>=MOD_MAX_PANES)return`pane ${msg.id}: more than ${MOD_MAX_PANES} panes`;let tree=validateModTree(msg.tree);if(!tree.ok)return`pane ${msg.id}: ${tree.error}`;return running.panes.set(msg.id,{plugin:running.spec.pluginId,id:msg.id,title:msg.title,tree:tree.tree}),this.publish(),null}}function sameCommand(a,b){return a.command.length===b.command.length&&a.command.every((part,i)=>part===b.command[i])}function killGroup(child,platform=process.platform){try{if(child.pid&&platform==="win32")execFile2("taskkill",["/pid",String(child.pid),"/T","/F"],{windowsHide:!0},(err)=>{if(err)child.kill("SIGTERM")});else if(child.pid)process.kill(-child.pid,"SIGTERM");else child.kill("SIGTERM")}catch{child.kill("SIGTERM")}}function readLines(child,stream,onLine){let buf="";child[stream]?.on("data",(chunk)=>{buf+=chunk.toString();let nl=buf.indexOf(`
|
|
@@ -13,7 +13,7 @@ import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import{countCronBetween,i
|
|
|
13
13
|
${prompt}`:prompt}function carryOwedGateAnswers(gates,taskId,tabId,prompt){let handoff=gates?takeUndeliveredGateAnswers(gates,taskId,tabId):null;return{prompt:withGateAnswers(prompt,handoff),commit:async()=>{if(handoff&&gates)await gates.markDelivered(handoff.gateIds)}}}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}}var ALARMING_REFUSALS={"engine-dead":!0,"engine-error":!0};function blockedOutcome(verdict,where){if(!verdict||verdict.run)return;let error=`${verdict.reason}${verdict.detail?`: ${verdict.detail}`:""}${verdict.until?` (until ${verdict.until})`:""}`;return{status:ALARMING_REFUSALS[verdict.reason]?"dispatch_failed":"skipped_blocked",...where,blocked:verdict,error}}async function createRunTask(deps,automation){return await deps.orch.createTask({repo:automation.repo,title:automation.name,...automation.vendor?{vendor:automation.vendor}:{},...automation.model?{model:automation.model}:{},...automation.modelEffort?{modelEffort:automation.modelEffort}:{},...automation.baseRef?{baseRef:automation.baseRef}:{},...automation.persistentSession?{routine:{automationId:automation.id}}:{}})}async function spawnWithPrompt(deps,prompt,taskId,status){if(deps.canDeliver?.()===!1)return{status:"skipped_cancelled",taskId};let owed=carryOwedGateAnswers(deps.gates,taskId,null,prompt),outcome=await deps.runtime.startTaskSessionWithPrompt(deps.link(),taskId,owed.prompt);if(!outcome.started)return{status:"dispatch_failed",taskId,error:outcome.error??"engine session did not start"};return await owed.commit(),{status,taskId}}async function resolvePrompt(prompt,target){return typeof prompt==="string"?prompt:await prompt(target)}async function dispatchAutomation(deps,automation,prompt=automation.prompt){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 blocked2=blockedOutcome(deps.runnability?.check(task2.id,target.tabId),{taskId:task2.id,tabId:target.tabId});if(blocked2)return blocked2;let text2=await resolvePrompt(prompt,{taskId:task2.id,tabId:target.tabId}),owed2=carryOwedGateAnswers(deps.gates,task2.id,target.tabId,text2),result2=await deps.runtime.deliverPromptToLiveEngineTabDetailed({id:task2.id,tabId:target.tabId,vendor:task2.vendor,command:task2.command,worktreePath:task2.worktreePath},owed2.prompt);if(result2.outcome==="delivered")await owed2.commit();return await liveDeliveryOutcome(deps,automation,task2.id,result2)}if(target.kind==="fresh"){let quota=blockedOutcome(deps.runnability?.freshQuota(automation.vendor),{});if(quota)return quota;let task2=await createRunTask(deps,automation);return await spawnWithPrompt(deps,await resolvePrompt(prompt,{taskId:task2.id,tabId:"tab-1"}),task2.id,"dispatched")}let standing=resolveStandingTask(deps.orch,automation);if(standing.task===null){let quota=blockedOutcome(deps.runnability?.freshQuota(automation.vendor),{});if(quota)return quota;let task2=await createRunTask(deps,automation);return{...await spawnWithPrompt(deps,await resolvePrompt(prompt,{taskId:task2.id,tabId:"tab-1"}),task2.id,"dispatched"),sessionTaskIdToSet:task2.id,...standing.hadStaleLink?{sessionTaskIdToClear:!0}:{}}}let task=standing.task,blocked=blockedOutcome(deps.runnability?.check(task.id,null,["engine-dead"]),{taskId:task.id});if(blocked)return blocked;let text=await resolvePrompt(prompt,{taskId:task.id,tabId:null}),owed=carryOwedGateAnswers(deps.gates,task.id,null,text),result=await deps.runtime.deliverPromptToLiveEngineDetailed({id:task.id,vendor:task.vendor,command:task.command,worktreePath:task.worktreePath},owed.prompt);if(result.outcome==="delivered")return await owed.commit(),await liveDeliveryOutcome(deps,automation,task.id,result);return await spawnWithPrompt(deps,text,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 spawn3}from"child_process";import{existsSync}from"fs";var MAX_OUTPUT_CHARS=4000,MAX_TIMEOUT_SECONDS=600;function killGroup2(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(`
|
|
14
14
|
`)}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)killGroup2(child);finish(null,!0)},timeoutMs);timer.unref?.();let child;try{child=spawn3(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,"routine_failed"))?.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}function withRoutineRunHeader(automation,run,api,deliveryId){return`[ROVE ROUTINE] "${automation.name}" run #${run.runNumber} \u2014 when done, report with: ${api} report --delivery ${deliveryId} --outcome done|partial|blocked|failed --summary \u2026 [--evidence \u2026]\u2026 [--next \u2026]
|
|
15
15
|
|
|
16
|
-
${automation.prompt}`}async function runAutomationOnce(deps,automation,args){let now=deps.now??Date.now,reserved=deps.store.reserveRun(automation.id),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},reserved),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,deliveryId,settleDelivery=async(delivered)=>{if(!deliveryId)return;let id=deliveryId;if(delivered===null)deliveryId=void 0;await(delivered===null?deps.deliveries.cancel(id):deps.deliveries.setTab(id,delivered.tabId??"tab-1")).catch((err)=>logDaemonError("automation-delivery",err))};try{outcome=await dispatchAutomation({canDeliver:()=>!cancelled(),orch:deps.orch,runtime:deps.runtime,link:()=>resolveLink(deps.link),...deps.gates?{gates:deps.gates}:{},...deps.runnability&&args.trigger==="scheduled"?{runnability:deps.runnability}:{},...deps.now?{now:deps.now}:{}},automation,async(target)=>{let delivery=await deps.deliveries.arm({taskId:target.taskId,tabId:target.tabId,source:"routine",automationRunId:reserved.id,promptHead:automation.prompt});return deliveryId=delivery.id,withRoutineRunHeader(automation,reserved,deps.runtime.roveApiInvocation?.()??"rove api",delivery.id)})}catch(err){let error=err instanceof Error?err.message:String(err);return logDaemonError("automation-dispatch",err),await settleDelivery(null),await record("skipped_unavailable",{error})}if(await settleDelivery(outcome.status==="dispatched"||outcome.status==="revived"?outcome:null),outcome.sessionTaskIdToSet){if(!await deps.store.linkSessionTask(automation.id,outcome.sessionTaskIdToSet,automation).catch((err)=>{return logDaemonError("automation-session-link",err),!0}))logDaemonInfo("automation",`${automation.name}: not adopting ${outcome.sessionTaskIdToSet}`)}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}:{},...outcome.blocked?{blocked:outcome.blocked}:{},...deliveryId?{deliveryId}:{}})}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}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=basename(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 spawn4}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=spawn4("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,runnability){let verdict=runnability?.check(task.id,null,["quota"]);if(verdict&&!verdict.run){await orch.setQuotaResume(task.id,null),logDaemonInfo("quota-resume",`declined task=${task.id} reason=${verdict.reason}`);return}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,runnability){return startTicker({name:"quota-resume",tickMs,run:async()=>{for(let task of dueQuotaResumes(orch.listTasks(),now()))await resumeDueTask(orch,runtime,task,plugins,runnability).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 basename2}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==="name"?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=basename2(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 spawn5}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=spawn5("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,inbox){let receiveStatus=activity?programStatusActivity(activity,(id)=>!!orch.getTask(id),inbox,automations?.deliveryDeps):void 0,stopStatusWatch=receiveStatus?watchProgramStatus(receiveStatus,{homeDir:options.homeDir}):async()=>{},stopActivityObserver=activity?startActivityObserver(activity,{...createActivityObserverIo(options.homeDir,runtime,activity),onEngineEvidence:createProtocolUpgradeReporter(orch,runtime),onProgramStatusEvent:receiveStatus},()=>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,automations?.runnability),stopAutomationRunner=automations?startAutomationRunner({store:automations.store,deliveries:automations.deliveryDeps.deliveries,orch,runtime,link:automations.link,...automations.plugins?{plugins:automations.plugins}:{},...automations.inbox?{inbox:automations.inbox}:{},...automations.gates?{gates:automations.gates}:{},...automations.runnability?{runnability:automations.runnability}:{}},options.automationTickMs??DEFAULT_AUTOMATION_TICK_MS):()=>{},deliverySweepBootedAt=(automations?.deliveryDeps.now??Date.now)(),stopDeliverySweep=automations&&activity?startTicker({name:"delivery-sweep",tickMs:options.automationTickMs??DEFAULT_AUTOMATION_TICK_MS,run:()=>sweepStalledDeliveries(automations.deliveryDeps,activity,deliverySweepBootedAt)}):()=>{},stopQuotaUsagePoller=quotaUsage?startQuotaUsagePoller(quotaUsage,()=>runtime.vendorsWithQuotaProbe(),()=>hasSubscribersFor("usage.snapshot"),options.quotaUsageTickMs):()=>{};return async()=>{if(updateTimer)clearInterval(updateTimer);await Promise.allSettled([stopActivityObserver,stopStatusWatch,stopAutoTitlePoller,stopPrStatusPoller,stopQuotaResumeRunner,stopAutomationRunner,stopDeliverySweep,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}:{}})??[]}}}];function refusal(code,message){return{apiVersion:ROVE_API_VERSION,ok:!1,error:{code,message}}}function isParamValue(value){if(typeof value==="string"||typeof value==="boolean")return!0;if(typeof value==="number")return Number.isFinite(value);return Array.isArray(value)&&value.every((v)=>typeof v==="string")}var API_HANDLERS=[{name:"api.invoke",blocking:!0,async handle(payload,ctx){let verb=requireString(payload,"verb"),raw=payload.params??{};if(typeof raw!=="object"||raw===null||Array.isArray(raw))return refusal("BAD_FLAG","params must be an object keyed by flag name");let params=raw,bad=Object.entries(params).find(([,value])=>!isParamValue(value));if(bad)return refusal("BAD_FLAG",`param ${bad[0]} must be a string, number, boolean or string list`);if(!ctx.runtime.invokeApi)return refusal("RPC_ERROR","this daemon cannot run verbs");return ctx.runtime.invokeApi(verb,params,ctx.daemon.socketPath,{machine:optionalString(payload,"machine"),forwarded:optionalBoolean(payload,"forwarded")})}}];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 deliveryId=optionalString(payload,"deliveryId");if(deliveryId&&payload.taskId===void 0&&!ctx.deliveries.get(deliveryId))return{deleted:!1,found:!1};let taskId=deliveryId?optionalString(payload,"taskId")??ctx.deliveries.get(deliveryId)?.taskId:requireString(payload,"taskId"),tabId=optionalString(payload,"tabId")??null,at=payload.at===void 0?void 0:requireNumber(payload,"at"),deleted=deliveryId?await ctx.inbox.deleteDeliveryEpisode(deliveryId):await ctx.inbox.deleteEpisode(taskId,tabId,at);if(deliveryId)await ctx.deliveries.dismiss(deliveryId);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 as execFile3}from"child_process";import{stat}from"fs/promises";import{promisify}from"util";var execFileAsync=promisify(execFile3);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 deliveryDepsOf(ctx){return{deliveries:ctx.deliveries,inbox:ctx.inbox,orch:ctx.orch,automations:ctx.automations}}function evidenceOf(payload){let raw=payload.evidence;if(raw===void 0)return;if(!Array.isArray(raw)||raw.some((item)=>typeof item!=="string"))throw Error("evidence must be an array of strings");return raw}function reportInputOf(payload){let next=optionalString(payload,"next"),evidence=evidenceOf(payload);return{outcome:requireString(payload,"outcome"),summary:requireString(payload,"summary"),...evidence?{evidence}:{},...next?{next}:{}}}var DELIVERY_HANDLERS=[{name:"delivery.arm",async handle(payload,ctx){let taskId=requireString(payload,"taskId");if(!ctx.orch.getTask(taskId))throw Error(`task not found: ${taskId}`);return{deliveryId:(await ctx.deliveries.arm({taskId,tabId:optionalString(payload,"tabId")??null,source:"send",promptHead:requireString(payload,"promptHead")})).id}}},{name:"delivery.settle",async handle(payload,ctx){let deliveryId=requireString(payload,"deliveryId");if(payload.delivered!==!0)return{cancelled:await ctx.deliveries.cancel(deliveryId)};let tabId=optionalString(payload,"tabId");if(tabId)await ctx.deliveries.setTab(deliveryId,tabId);return{cancelled:!1}}},{name:"delivery.report",async handle(payload,ctx){let deliveryId=requireString(payload,"deliveryId");return{delivery:await reportDelivery(deliveryDepsOf(ctx),deliveryId,reportInputOf(payload))}}},{name:"delivery.list",handle(payload,ctx){let taskId=requireString(payload,"taskId"),limit=optionalNumber(payload,"limit");if(limit!==void 0&&(!Number.isInteger(limit)||limit<1))throw Error("limit must be a positive integer");return{deliveries:ctx.deliveries.listForTask(taskId,Math.min(limit??MAX_DELIVERIES_PER_TASK,MAX_DELIVERIES_PER_TASK))}}}];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 model=optionalString(payload,"model"),modelEffort=optionalString(payload,"effort"),targetOptions={target:target??void 0,vendor:optionalVendor(payload,"vendor"),model,modelEffort,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")}:{},...model?{model}:{},...modelEffort?{modelEffort}:{},...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")}:{},..."model"in payload?{model:optionalString(payload,"model")??null}:{},..."effort"in payload?{modelEffort:optionalString(payload,"effort")??null}:{},..."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).map((run)=>withDeliveryReport(run,ctx.deliveries))}}},{name:"automation.respond",async handle(payload,ctx){let runId=requireString(payload,"runId"),text=requireString(payload,"text");if(text.length>ROUTINE_RESPONSE_MAX_CHARS)throw Error(`response is ${text.length} characters; the cap is ${ROUTINE_RESPONSE_MAX_CHARS}`);let stored=ctx.automations.getRun(runId);if(!stored)return{run:null};if(stored.deliveryId&&ctx.deliveries.get(stored.deliveryId))return await reportDelivery(deliveryDepsOf(ctx),stored.deliveryId,{outcome:"done",summary:text}),{run:withDeliveryReport(stored,ctx.deliveries)};let run=await ctx.automations.setRunResponse(runId,text);if(!run)return{run:null};let automation=ctx.automations.get(run.automationId);if(automation)await ctx.inbox.recordRoutineResponse({automationId:automation.id,name:automation.name,status:run.status,runNumber:run.runNumber},run.taskId??null,Date.now()).catch((err)=>logDaemonError("automation-respond-inbox",err));return{run}}},{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,deliveries:ctx.deliveries,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){if(payload.source==="screen"){let taskId2=requireString(payload,"taskId"),tabId2=requireString(payload,"tabId");if(typeof payload.blocked!=="boolean")throw Error("blocked must be a boolean");if(ctx.activity.reportScreen(taskId2,tabId2,payload.blocked))await ctx.inbox.record(taskId2,payload.blocked?"awaiting-input":"turn-start",void 0,tabId2);return{}}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)),await trackDeliveryTurn(deliveryDepsOf(ctx),taskId,tabId??null,kind,detail)}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{}}};async function countGateRaiseAsReport(ctx,gate){return await reportCurrentDelivery(deliveryDepsOf(ctx),gate.taskId,gate.tabId,{outcome:"blocked",summary:gate.question,next:`awaiting owner decision ${gate.id}`})}async function armGateAnswerDelivery(ctx,task,gate){if(task.requireReport!==!0)return null;let delivery=await ctx.deliveries.arm({taskId:task.id,tabId:gate.tabId,source:"gate-answer",gateId:gate.id,promptHead:gate.question});return{deliveryId:delivery.id,footer:deliveryFooter(delivery.id,ctx.runtime.roveApiInvocation())}}var SURFACES=["tui","bridge","weixin","cli"],STATUS_FILTERS=["open","answered","withdrawn","all"];function parseOptions(raw){if(raw===void 0||raw===null)return[];if(!Array.isArray(raw))throw Error("options must be an array");return raw.map((entry)=>{let o=entry;if(!o||typeof o.key!=="string"||typeof o.label!=="string")throw Error("each option needs a string key and label");return{key:o.key,label:o.label,...typeof o.detail==="string"&&o.detail?{detail:o.detail}:{}}})}var deliveryChains=new Map;function deliverGateAnswer(ctx,gate){let run=(deliveryChains.get(gate.taskId)??Promise.resolve()).then(()=>pasteGateAnswer(ctx,gate)),next=run.catch(()=>{});return deliveryChains.set(gate.taskId,next),next.then(()=>{if(deliveryChains.get(gate.taskId)===next)deliveryChains.delete(gate.taskId)}),run}async function pasteGateAnswer(ctx,gate){let task=ctx.orch.getTask(gate.taskId);if(!task||task.deletion||!task.worktreePath)return!1;let handoff=takeUndeliveredGateAnswers(ctx.gates,gate.taskId,gate.tabId);if(!handoff)return!1;let target={id:task.id,vendor:task.vendor,command:task.command,worktreePath:task.worktreePath},armed=null;try{armed=await armGateAnswerDelivery(ctx,task,gate);let text=armed?`${handoff.text}
|
|
16
|
+
${automation.prompt}`}async function runAutomationOnce(deps,automation,args){let now=deps.now??Date.now,reserved=deps.store.reserveRun(automation.id),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},reserved),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,deliveryId,settleDelivery=async(delivered)=>{if(!deliveryId)return;let id=deliveryId;if(delivered===null)deliveryId=void 0;await(delivered===null?deps.deliveries.cancel(id):deps.deliveries.setTab(id,delivered.tabId??"tab-1")).catch((err)=>logDaemonError("automation-delivery",err))};try{outcome=await dispatchAutomation({canDeliver:()=>!cancelled(),orch:deps.orch,runtime:deps.runtime,link:()=>resolveLink(deps.link),...deps.gates?{gates:deps.gates}:{},...deps.runnability&&args.trigger==="scheduled"?{runnability:deps.runnability}:{},...deps.now?{now:deps.now}:{}},automation,async(target)=>{let delivery=await deps.deliveries.arm({taskId:target.taskId,tabId:target.tabId,source:"routine",automationRunId:reserved.id,promptHead:automation.prompt});return deliveryId=delivery.id,withRoutineRunHeader(automation,reserved,deps.runtime.roveApiInvocation?.()??"rove api",delivery.id)})}catch(err){let error=err instanceof Error?err.message:String(err);return logDaemonError("automation-dispatch",err),await settleDelivery(null),await record("skipped_unavailable",{error})}if(await settleDelivery(outcome.status==="dispatched"||outcome.status==="revived"?outcome:null),outcome.sessionTaskIdToSet){if(!await deps.store.linkSessionTask(automation.id,outcome.sessionTaskIdToSet,automation).catch((err)=>{return logDaemonError("automation-session-link",err),!0}))logDaemonInfo("automation",`${automation.name}: not adopting ${outcome.sessionTaskIdToSet}`)}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}:{},...outcome.blocked?{blocked:outcome.blocked}:{},...deliveryId?{deliveryId}:{}})}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}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=basename(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 spawn4}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=spawn4("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,runnability){let verdict=runnability?.check(task.id,null,["quota"]);if(verdict&&!verdict.run){await orch.setQuotaResume(task.id,null),logDaemonInfo("quota-resume",`declined task=${task.id} reason=${verdict.reason}`);return}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,runnability){return startTicker({name:"quota-resume",tickMs,run:async()=>{for(let task of dueQuotaResumes(orch.listTasks(),now()))await resumeDueTask(orch,runtime,task,plugins,runnability).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 basename2}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==="name"?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=basename2(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 spawn5}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=spawn5("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,inbox){let receiveStatus=activity?programStatusActivity(activity,(id)=>!!orch.getTask(id),inbox,automations?.deliveryDeps):void 0,stopStatusWatch=receiveStatus?watchProgramStatus(receiveStatus,{homeDir:options.homeDir}):async()=>{},stopActivityObserver=activity?startActivityObserver(activity,{...createActivityObserverIo(options.homeDir,runtime,activity),onEngineEvidence:createProtocolUpgradeReporter(orch,runtime),onProgramStatusEvent:receiveStatus},()=>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,automations?.runnability),stopAutomationRunner=automations?startAutomationRunner({store:automations.store,deliveries:automations.deliveryDeps.deliveries,orch,runtime,link:automations.link,...automations.plugins?{plugins:automations.plugins}:{},...automations.inbox?{inbox:automations.inbox}:{},...automations.gates?{gates:automations.gates}:{},...automations.runnability?{runnability:automations.runnability}:{}},options.automationTickMs??DEFAULT_AUTOMATION_TICK_MS):()=>{},deliverySweepBootedAt=(automations?.deliveryDeps.now??Date.now)(),stopDeliverySweep=automations&&activity?startTicker({name:"delivery-sweep",tickMs:options.automationTickMs??DEFAULT_AUTOMATION_TICK_MS,run:()=>sweepStalledDeliveries(automations.deliveryDeps,activity,deliverySweepBootedAt)}):()=>{},stopQuotaUsagePoller=quotaUsage?startQuotaUsagePoller(quotaUsage,()=>runtime.vendorsWithQuotaProbe(),()=>hasSubscribersFor("usage.snapshot"),options.quotaUsageTickMs):()=>{};return async()=>{if(updateTimer)clearInterval(updateTimer);await Promise.allSettled([stopActivityObserver,stopStatusWatch,stopAutoTitlePoller,stopPrStatusPoller,stopQuotaResumeRunner,stopAutomationRunner,stopDeliverySweep,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}:{}})??[]}}}];function refusal(code,message){return{apiVersion:ROVE_API_VERSION,ok:!1,error:{code,message}}}function isParamValue(value){if(typeof value==="string"||typeof value==="boolean")return!0;if(typeof value==="number")return Number.isFinite(value);return Array.isArray(value)&&value.every((v)=>typeof v==="string")}var API_HANDLERS=[{name:"api.invoke",blocking:!0,async handle(payload,ctx){let verb=requireString(payload,"verb"),raw=payload.params??{};if(typeof raw!=="object"||raw===null||Array.isArray(raw))return refusal("BAD_FLAG","params must be an object keyed by flag name");let params=raw,bad=Object.entries(params).find(([,value])=>!isParamValue(value));if(bad)return refusal("BAD_FLAG",`param ${bad[0]} must be a string, number, boolean or string list`);if(!ctx.runtime.invokeApi)return refusal("RPC_ERROR","this daemon cannot run verbs");return ctx.runtime.invokeApi(verb,params,ctx.daemon.socketPath,{machine:optionalString(payload,"machine"),forwarded:optionalBoolean(payload,"forwarded"),from:optionalString(payload,"from")})}}];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 deliveryId=optionalString(payload,"deliveryId");if(deliveryId&&payload.taskId===void 0&&!ctx.deliveries.get(deliveryId))return{deleted:!1,found:!1};let taskId=deliveryId?optionalString(payload,"taskId")??ctx.deliveries.get(deliveryId)?.taskId:requireString(payload,"taskId"),tabId=optionalString(payload,"tabId")??null,at=payload.at===void 0?void 0:requireNumber(payload,"at"),deleted=deliveryId?await ctx.inbox.deleteDeliveryEpisode(deliveryId):await ctx.inbox.deleteEpisode(taskId,tabId,at);if(deliveryId)await ctx.deliveries.dismiss(deliveryId);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 as execFile3}from"child_process";import{stat}from"fs/promises";import{promisify}from"util";var execFileAsync=promisify(execFile3);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 deliveryDepsOf(ctx){return{deliveries:ctx.deliveries,inbox:ctx.inbox,orch:ctx.orch,automations:ctx.automations}}function evidenceOf(payload){let raw=payload.evidence;if(raw===void 0)return;if(!Array.isArray(raw)||raw.some((item)=>typeof item!=="string"))throw Error("evidence must be an array of strings");return raw}function reportInputOf(payload){let next=optionalString(payload,"next"),evidence=evidenceOf(payload);return{outcome:requireString(payload,"outcome"),summary:requireString(payload,"summary"),...evidence?{evidence}:{},...next?{next}:{}}}var DELIVERY_HANDLERS=[{name:"delivery.arm",async handle(payload,ctx){let taskId=requireString(payload,"taskId");if(!ctx.orch.getTask(taskId))throw Error(`task not found: ${taskId}`);return{deliveryId:(await ctx.deliveries.arm({taskId,tabId:optionalString(payload,"tabId")??null,source:"send",promptHead:requireString(payload,"promptHead")})).id}}},{name:"delivery.settle",async handle(payload,ctx){let deliveryId=requireString(payload,"deliveryId");if(payload.delivered!==!0)return{cancelled:await ctx.deliveries.cancel(deliveryId)};let tabId=optionalString(payload,"tabId");if(tabId)await ctx.deliveries.setTab(deliveryId,tabId);return{cancelled:!1}}},{name:"delivery.report",async handle(payload,ctx){let deliveryId=requireString(payload,"deliveryId");return{delivery:await reportDelivery(deliveryDepsOf(ctx),deliveryId,reportInputOf(payload))}}},{name:"delivery.list",handle(payload,ctx){let taskId=requireString(payload,"taskId"),limit=optionalNumber(payload,"limit");if(limit!==void 0&&(!Number.isInteger(limit)||limit<1))throw Error("limit must be a positive integer");return{deliveries:ctx.deliveries.listForTask(taskId,Math.min(limit??MAX_DELIVERIES_PER_TASK,MAX_DELIVERIES_PER_TASK))}}}];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 model=optionalString(payload,"model"),modelEffort=optionalString(payload,"effort"),targetOptions={target:target??void 0,vendor:optionalVendor(payload,"vendor"),model,modelEffort,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")}:{},...model?{model}:{},...modelEffort?{modelEffort}:{},...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")}:{},..."model"in payload?{model:optionalString(payload,"model")??null}:{},..."effort"in payload?{modelEffort:optionalString(payload,"effort")??null}:{},..."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).map((run)=>withDeliveryReport(run,ctx.deliveries))}}},{name:"automation.respond",async handle(payload,ctx){let runId=requireString(payload,"runId"),text=requireString(payload,"text");if(text.length>ROUTINE_RESPONSE_MAX_CHARS)throw Error(`response is ${text.length} characters; the cap is ${ROUTINE_RESPONSE_MAX_CHARS}`);let stored=ctx.automations.getRun(runId);if(!stored)return{run:null};if(stored.deliveryId&&ctx.deliveries.get(stored.deliveryId))return await reportDelivery(deliveryDepsOf(ctx),stored.deliveryId,{outcome:"done",summary:text}),{run:withDeliveryReport(stored,ctx.deliveries)};let run=await ctx.automations.setRunResponse(runId,text);if(!run)return{run:null};let automation=ctx.automations.get(run.automationId);if(automation)await ctx.inbox.recordRoutineResponse({automationId:automation.id,name:automation.name,status:run.status,runNumber:run.runNumber},run.taskId??null,Date.now()).catch((err)=>logDaemonError("automation-respond-inbox",err));return{run}}},{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,deliveries:ctx.deliveries,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){if(payload.source==="screen"){let taskId2=requireString(payload,"taskId"),tabId2=requireString(payload,"tabId");if(typeof payload.blocked!=="boolean")throw Error("blocked must be a boolean");if(ctx.activity.reportScreen(taskId2,tabId2,payload.blocked))await ctx.inbox.record(taskId2,payload.blocked?"awaiting-input":"turn-start",void 0,tabId2);return{}}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)),await trackDeliveryTurn(deliveryDepsOf(ctx),taskId,tabId??null,kind,detail)}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{}}};async function countGateRaiseAsReport(ctx,gate){return await reportCurrentDelivery(deliveryDepsOf(ctx),gate.taskId,gate.tabId,{outcome:"blocked",summary:gate.question,next:`awaiting owner decision ${gate.id}`})}async function armGateAnswerDelivery(ctx,task,gate){if(task.requireReport!==!0)return null;let delivery=await ctx.deliveries.arm({taskId:task.id,tabId:gate.tabId,source:"gate-answer",gateId:gate.id,promptHead:gate.question});return{deliveryId:delivery.id,footer:deliveryFooter(delivery.id,ctx.runtime.roveApiInvocation())}}var SURFACES=["tui","bridge","weixin","cli"],STATUS_FILTERS=["open","answered","withdrawn","all"];function parseOptions(raw){if(raw===void 0||raw===null)return[];if(!Array.isArray(raw))throw Error("options must be an array");return raw.map((entry)=>{let o=entry;if(!o||typeof o.key!=="string"||typeof o.label!=="string")throw Error("each option needs a string key and label");return{key:o.key,label:o.label,...typeof o.detail==="string"&&o.detail?{detail:o.detail}:{}}})}var deliveryChains=new Map;function deliverGateAnswer(ctx,gate){let run=(deliveryChains.get(gate.taskId)??Promise.resolve()).then(()=>pasteGateAnswer(ctx,gate)),next=run.catch(()=>{});return deliveryChains.set(gate.taskId,next),next.then(()=>{if(deliveryChains.get(gate.taskId)===next)deliveryChains.delete(gate.taskId)}),run}async function pasteGateAnswer(ctx,gate){let task=ctx.orch.getTask(gate.taskId);if(!task||task.deletion||!task.worktreePath)return!1;let handoff=takeUndeliveredGateAnswers(ctx.gates,gate.taskId,gate.tabId);if(!handoff)return!1;let target={id:task.id,vendor:task.vendor,command:task.command,worktreePath:task.worktreePath},armed=null;try{armed=await armGateAnswerDelivery(ctx,task,gate);let text=armed?`${handoff.text}
|
|
17
17
|
|
|
18
18
|
${armed.footer}`:handoff.text,result=gate.tabId?await ctx.runtime.deliverPromptToLiveEngineTabDetailed({...target,tabId:gate.tabId},text):await ctx.runtime.deliverPromptToLiveEngineDetailed(target,text);if(result.outcome!=="delivered"){if(armed)await ctx.deliveries.cancel(armed.deliveryId);return!1}if(armed)await ctx.deliveries.setTab(armed.deliveryId,result.tabId);return await ctx.gates.markDelivered(handoff.gateIds),!0}catch(err){if(logDaemonError("gate-answer-delivery",err),armed)await ctx.deliveries.cancel(armed.deliveryId).catch(()=>{});return!1}}var GATE_HANDLERS=[{name:"gate.raise",async handle(payload,ctx){let taskId=requireString(payload,"taskId"),task=ctx.orch.getTask(taskId);if(!task||task.deletion)throw Error(`task not found: ${taskId}`);let recommended=optionalString(payload,"recommended"),context=optionalString(payload,"context"),gate=await ctx.gates.raise({taskId,tabId:optionalString(payload,"tabId")??null,question:requireString(payload,"question"),options:parseOptions(payload.options),...recommended?{recommended}:{},...context?{context}:{}}),reported=await countGateRaiseAsReport(ctx,gate);return{gate:reported?await ctx.gates.attachDelivery(gate.id,reported.id):gate}}},{name:"gate.answer",async handle(payload,ctx){let by=optionalString(payload,"by")??"cli";if(!SURFACES.includes(by))throw Error(`by must be one of ${SURFACES.join(", ")}`);let gateId=requireString(payload,"gateId"),option=optionalString(payload,"option"),text=optionalString(payload,"text"),gate=await ctx.gates.answer(gateId,{...option!==void 0?{option}:{},...text!==void 0?{text}:{},by}),delivered=await deliverGateAnswer(ctx,gate);return{gate:ctx.gates.get(gateId)??gate,delivered}}},{name:"gate.withdraw",async handle(payload,ctx){return{gate:await ctx.gates.withdraw(requireString(payload,"gateId"))}}},{name:"gate.list",handle(payload,ctx){let status=optionalString(payload,"status")??"open";if(!STATUS_FILTERS.includes(status))throw Error(`status must be one of ${STATUS_FILTERS.join(", ")}`);let taskId=optionalString(payload,"taskId"),repo=optionalString(payload,"repo");return{gates:ctx.gates.list({status,...taskId?{taskId}:{}}).filter((g)=>repo===void 0||ctx.orch.getTask(g.taskId)?.repo===repo)}}},{name:"gate.takeUndelivered",handle(payload,ctx){return takeUndeliveredGateAnswers(ctx.gates,requireString(payload,"taskId"),optionalString(payload,"tabId"))??{text:null,gateIds:[]}}},{name:"gate.markDelivered",async handle(payload,ctx){let ids=payload.gateIds;if(!Array.isArray(ids)||ids.some((id)=>typeof id!=="string"))throw Error("gateIds must be strings");return await ctx.gates.markDelivered(ids),{}}}];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(`
|
|
19
19
|
`)){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(`
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{argvToParams,booleanFlagsOf,callVerb,errorBody,errorEnvelope,executeVerb,paramsToFlags,repeatableFlagsOf,runVerb,successEnvelope,toApiError}from"./chunk-0z1azqkp.js";import"./chunk-q2kweazg.js";import"./chunk-1j4e2jcx.js";import"./chunk-rc2nwsdd.js";import"./chunk-t60qcvcj.js";import"./chunk-e6848rj8.js";import"./chunk-j11hzmwy.js";import"./chunk-6h12b2k0.js";import"./chunk-17e2tgyg.js";import"./chunk-cbc1h345.js";import"./chunk-jjv7xem7.js";import"./chunk-4hestsjp.js";import"./chunk-stcvcsfm.js";import"./chunk-2bgmby1d.js";import"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-edsm15ht.js";import"./chunk-atn06ncf.js";import"./chunk-j5w8n1st.js";import"./chunk-qkehg2c1.js";import"./chunk-1dcb0069.js";import"./chunk-9ztqf6hb.js";import"./chunk-rsvh7n8v.js";import"./chunk-ampdybqg.js";import"./chunk-sak1tphp.js";import"./chunk-pbfehk8q.js";import"./chunk-4250pw6r.js";import"./chunk-qpvvc1xz.js";import"./chunk-rxqdw6s5.js";import"./chunk-zae59k1j.js";import"./chunk-f5n0tgky.js";import"./chunk-z3zaa155.js";import"./chunk-yewmtant.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-bdwp2k8f.js";import"./chunk-efjahmtj.js";import"./chunk-2tfnscxk.js";import"./chunk-9ecnsh42.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-kg9kmwt9.js";import"./chunk-6xppe9bj.js";import"./chunk-4pt3n7cg.js";import"./chunk-b7xjhgts.js";import"./chunk-x7r75e3p.js";import"./chunk-zsfyj36g.js";import"./chunk-601dsgex.js";import"./chunk-1vwngrmf.js";import"./chunk-3vtpshwx.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-bkt3ktvx.js";import"./chunk-7zyyvc3d.js";import"./chunk-r6k3ve2g.js";import"./chunk-xy8be792.js";import"./chunk-7kysxgbq.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-tdhk4dz8.js";import"./chunk-hqkzc8cv.js";import"./chunk-22d0yc7m.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-g4281a0g.js";import"./chunk-zh0c8yzw.js";import"./chunk-wqckm0k6.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-2676cb62.js";import"./chunk-q07r6hf7.js";import"./chunk-cmp64q4j.js";import"./chunk-s0jbtyd9.js";import"./chunk-278sc87n.js";import"./chunk-gskbzgc3.js";import"./chunk-pn5ygqn6.js";import"./chunk-n0rtj4z7.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import"./chunk-91sykzqq.js";export{toApiError,successEnvelope,runVerb,repeatableFlagsOf,paramsToFlags,executeVerb,errorEnvelope,errorBody,callVerb,booleanFlagsOf,argvToParams};
|