@sma1lboy/rove 0.9.279-next.27 → 0.9.280
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{chunk-6908yyyk.js → chunk-02x0ahxk.js} +1 -1
- package/dist/cli/{chunk-k04qvy42.js → chunk-0g1h35mr.js} +1 -1
- package/dist/cli/{chunk-v3yf3gmy.js → chunk-2pfh3zm0.js} +1 -1
- package/dist/cli/{chunk-4a82zjaq.js → chunk-2wrt80ft.js} +1 -1
- package/dist/cli/{chunk-a60qwvyq.js → chunk-3a7x7jg7.js} +3 -3
- package/dist/cli/{chunk-90qathy6.js → chunk-4drm07mp.js} +1 -1
- package/dist/cli/{chunk-cydytp2v.js → chunk-4z1a65bz.js} +1 -1
- package/dist/cli/{chunk-zbdwz30h.js → chunk-5dq0n3h7.js} +1 -1
- package/dist/cli/{chunk-37wbxna9.js → chunk-5g6v6tq5.js} +1 -1
- package/dist/cli/{chunk-cntrqw1e.js → chunk-5kgq379z.js} +1 -1
- package/dist/cli/{chunk-7tbemfgm.js → chunk-6mk6ceb6.js} +2 -2
- package/dist/cli/{chunk-e2zv4b2x.js → chunk-7aaw17vr.js} +1 -1
- package/dist/cli/{chunk-jtf8ag8v.js → chunk-7fya3y0n.js} +1 -1
- package/dist/cli/{chunk-mfp8ax3c.js → chunk-7nnpp89t.js} +1 -1
- package/dist/cli/{chunk-z8eg7tnp.js → chunk-amq030gb.js} +2 -2
- package/dist/cli/{chunk-t9x54xs5.js → chunk-azt0c2b5.js} +1 -1
- package/dist/cli/{chunk-2m22fy6d.js → chunk-bw2y7670.js} +1 -1
- package/dist/cli/{chunk-692jsg07.js → chunk-byh32qnx.js} +1 -1
- package/dist/cli/{chunk-ney5fnem.js → chunk-d2wndk4q.js} +1 -1
- package/dist/cli/{chunk-9192at57.js → chunk-f262ywvg.js} +1 -1
- package/dist/cli/{chunk-hqpfg53t.js → chunk-fkgemeww.js} +1 -1
- package/dist/cli/{chunk-bv7z8jsy.js → chunk-gk8efsx0.js} +1 -1
- package/dist/cli/{chunk-1pcqw0x7.js → chunk-hd1szhba.js} +1 -1
- package/dist/cli/{chunk-apgfbg20.js → chunk-j54c5a0a.js} +1 -1
- package/dist/cli/{chunk-5wt8ect1.js → chunk-jk4f0xsh.js} +1 -1
- package/dist/cli/{chunk-tw3hfkbv.js → chunk-jkgp816v.js} +1 -1
- package/dist/cli/{chunk-g2wwgt6t.js → chunk-mey3vksj.js} +1 -1
- package/dist/cli/{chunk-hzqfb00a.js → chunk-mjzjah9d.js} +1 -1
- package/dist/cli/{chunk-np765y1f.js → chunk-q6tsx6zc.js} +1 -1
- package/dist/cli/{chunk-y7ypda6a.js → chunk-qc9sj5wh.js} +1 -1
- package/dist/cli/{chunk-3btnwykt.js → chunk-qzhfs668.js} +1 -1
- package/dist/cli/{chunk-ngq02svt.js → chunk-r98h6b42.js} +2 -2
- package/dist/cli/{chunk-hg8c3ze3.js → chunk-rvjnafyt.js} +1 -1
- package/dist/cli/{chunk-a5dqhn9k.js → chunk-t7dyf50m.js} +1 -1
- package/dist/cli/{chunk-02bcfavz.js → chunk-tqxbbg3k.js} +1 -1
- package/dist/cli/{chunk-q3wzpn85.js → chunk-txvjg1g9.js} +1 -1
- package/dist/cli/{chunk-1pk5genq.js → chunk-w003rpr2.js} +1 -1
- package/dist/cli/{chunk-qg5wexks.js → chunk-wz307hf6.js} +1 -1
- package/dist/cli/{chunk-qd97s6pt.js → chunk-xmjknfy2.js} +1 -1
- package/dist/cli/{chunk-tt47sn82.js → chunk-xy5mrrqk.js} +1 -1
- package/dist/cli/{chunk-phmt9a1k.js → chunk-zkby63ej.js} +1 -1
- package/dist/cli/{chunk-dsm31j1n.js → chunk-zp0q931y.js} +1 -1
- package/dist/cli/{chunk-56rjpxzc.js → chunk-zv0rrhck.js} +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/rove.js +1 -1
- package/dist/web/assets/{index-CcqHr-Sc.js → index-DIN0Lz5C.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{PER_SESSION,classifyTier,describeTierBlock,isAutoRoutingTier,listFiles,liveSourceProtocol,loadPreviewData,planWorktreeHandoff,readAutoRoutingTable,readClassifierConfig,resolveBase,runWorktreeGit,screenErrorLine,searchTasks,statusFiles,statusFilesBranch,taskGroupOf,tierBlock}from"./chunk-k2j0tg1h.js";import{ensurePluginEnginesLoaded,registeredEngineIds}from"./chunk-kdnk8m5j.js";import{resolveActiveTaskId}from"./chunk-qcjkactr.js";import{listPaneLaunches}from"./chunk-rjfdzjhj.js";import{detectEngineStatus}from"./chunk-zpxpwgds.js";import{resolveEditorLaunch}from"./chunk-agvtzads.js";import{DeviceLogin,GH_ENV,GITHUB_HOST,runTool,spawnGhLogin}from"./chunk-pm91e38v.js";import{PLACEHOLDER_TASK_TITLE,SHELL_TASK_TITLE,deriveTitleFromPrompt}from"./chunk-2xsxcdp6.js";import{ENGINE_ACTIVITY_KINDS,TASK_ACTIVITY_STATES}from"./chunk-17e2tgyg.js";import{DIRTY_WORKTREE_CODE,EMPTY_BRANCH_DIRTY_WORKTREE_CODE,canonicalize}from"./chunk-1vxtd8rh.js";import{canonicalEngineTab}from"./chunk-q8ffd1pc.js";import{ISSUE_STATUSES}from"./chunk-4hestsjp.js";import{ROW_TOKEN_MAX_TEXT,ROW_TOKEN_TONES}from"./chunk-atn06ncf.js";import{DEFAULT_FEEDBACK_CATEGORY_SLUG,submitFeedback}from"./chunk-v3yf3gmy.js";import{cloneDirFor,cloneRepo,dispatcherEnvPayload,findCheckouts,forwardVerb,isCleanCheckout,ownSession,parseRepoRef,pickCheckout,primaryCheckouts,ptyScopeOf,readOwnDispatcher,recordSend,replyTabOf,repoIdOf,repoIdentity,requireMachine,resolveDispatcherTab,verifiedSelfSession,withPeerProvenance}from"./chunk-p11emdb2.js";import{dedupeMachines,listMachines}from"./chunk-vytrhm50.js";import{normalizeRemoteUrl,resolvePtyOwner}from"./chunk-vp29jgbt.js";import{ulid}from"./chunk-qkehg2c1.js";import{ENGINE_NOT_OBSERVED_REASON,ENGINE_START_POLL_MS,ENGINE_START_PROBE_MS,deliverHostedPrompt,deliverToKey,ensurePtyHost,findEngineKey,killTaskSessions,listSessions,listSessionsOrNull,openAdmittedEngine,openPtyHost,outcomeFields,restoredTabLaunch,tabEngineBase,taskKeys}from"./chunk-s1xn6wav.js";import{awaitEngineProcess,enginePresence,findHostedEngineKey,hostedSessionFailureLine,isHostedTaskKey,listHostedSessions,openHostedSessionHost,readPersistedTerminalDefaultColors,sessionArgvNamesEngine,withDeliveryLock}from"./chunk-nv8eyjep.js";import{allocateTab,applyTabOps,closeTabsSnapshot,collapseSplit,findEditorTab,initialSplit,joinTaskTabs,leaves,markCliTabSession,patchTabSplit,publishCliTabSnapshot,readDaemonTabs,readTabsSnapshot,removeLeaf,renameLeaf,renameTabsSnapshot,seedCanonicalTab,seedShellHome,shellIdentityInput,splitActive,splitLeafPtyKey,tabPtyKeyFor,taskEngineArgv,unregisteredTabIds,wireSplit}from"./chunk-3hxm56h6.js";import{RemoteEngineLaunchError,buildEngineSessionLaunch,launchReposOf,repoEnv,trustEngineWorktree,trustExtraRepos}from"./chunk-qecygh3f.js";import{GENERIC_PROTOCOL,describePreset,engineLaunchArgv,engineResumeArgv,listEnginePresets,protocolEntry,resolveCommandProtocol,roveApiInvocation,sessionProtocol,withPinnedSessionId}from"./chunk-rjq38twt.js";import{ApiError,GROUP_MOD,VERB_GROUP_IDS,cliCaller,helpStep,promptMayHaveLanded,requireVerbInstalled,splitDaemonCode,verbInstalled}from"./chunk-r5j8fycq.js";import{isBuiltinModInstalled}from"./chunk-xfgqae9t.js";import{aliasKey,hostedKeyFor,isUnderKey,ptyScopeFor,unclaimedSessions}from"./chunk-g9ba25q5.js";import{resolveSessionShell}from"./chunk-tn9gtf18.js";import{foregroundEngineIn,parsePsSnapshot,psSnapshot}from"./chunk-5rgrde6b.js";import{engineEntry,getCapabilities,supportsStructuredHistory,vendorsWithEffortLevels,vendorsWithTurnReader}from"./chunk-4gjvmfa9.js";import{CONTRIB_ENGINE_IDS,installedEngineIds}from"./chunk-hzz020xx.js";import{terminalRows}from"./chunk-etfh8f4z.js";import{resolvePreferredVendor}from"./chunk-9rj2fx6v.js";import{addSavedRepo,getSavedRepos,isRemoteRepoKey}from"./chunk-rfp0ayra.js";import{readOnlyGitProcessEnv}from"./chunk-6xppe9bj.js";import{CURRENT_VERSION}from"./chunk-4a82zjaq.js";import{parseBoolLiteral}from"./chunk-zsfyj36g.js";import{expandTilde}from"./chunk-2r1fgng9.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{loadStateFile}from"./chunk-32j6y5d1.js";import{DELIVERY_OUTCOMES,DELIVERY_SUMMARY_MAX_CHARS,MAX_DELIVERIES_PER_TASK,ROUTINE_RESPONSE_MAX_CHARS,SHOULD_RUN_SKIP_EXIT_CODE,SKIP_REASONS,deliveryFooter}from"./chunk-qzzmd63x.js";import{ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import{MULTI_REPO_CAP,canonicalPrUrl,gitRepoOf,lineageRootId,repoNameOf,rollupPr,taskCwd,taskRepos,todoCount,uniqueRepoName,workspaceCapabilities}from"./chunk-x1jxxmtc.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";import{ALL_VENDORS,DEFAULT_VENDOR,coerceVendorId}from"./chunk-h2m7em1e.js";import{homeDir}from"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{pathWithin,samePath}from"./chunk-pn5ygqn6.js";import{defaultDaemonSocketPath}from"./chunk-eqdbfgq5.js";import{__require}from"./chunk-91sykzqq.js";import{readFileSync as readFileSync2}from"fs";import{resolve as resolve2}from"path";import{readFileSync}from"fs";import{isAbsolute,resolve}from"path";var FANOUT_CAP=10;function parsePositiveInt(raw){if(!/^\d+$/.test(raw.trim()))return;let n=Number.parseInt(raw,10);return Number.isSafeInteger(n)&&n>0?n:void 0}function parseNonNegativeInt(raw){if(!/^\d+$/.test(raw.trim()))return;let n=Number.parseInt(raw,10);return Number.isSafeInteger(n)&&n>=0?n:void 0}var FANOUT_STEP=helpStep("add"),F={repo:(required=!0)=>({name:"repo",type:"string",required,placeholder:"PATH",description:"Repo root (git toplevel). Relative paths resolve against $PWD."}),taskId:(required=!0)=>({name:"task-id",type:"string",required,placeholder:"ID",description:"Target task id (from `list` / `add`)."}),vendor:()=>({name:"vendor",type:"enum",values:ALL_VENDORS,placeholder:"V",description:"Engine vendor for the task."}),command:()=>({name:"command",type:"string",placeholder:"CMD",description:"Engine launch command, verbatim \u2014 an engine id from `engine-list` (e.g. claude) or a full command line (e.g. 'codex --search'). Unvalidated: probe an unfamiliar engine's flags with `<cmd> --help` first. Omitted = the repo's default engine."}),title:()=>({name:"title",type:"string",placeholder:"T",description:"Human task title."}),prompt:(required,desc)=>({name:"prompt",type:"string",required,placeholder:"TEXT",description:required?`${desc} Required unless --prompt-file is given.`:desc}),promptFile:()=>({name:"prompt-file",type:"string",placeholder:"PATH",description:"Read the prompt from this file instead of --prompt (`-` = stdin). Use it whenever the text has backticks, $vars, or quotes you don't want the shell to touch. Exactly one of --prompt / --prompt-file."})},REPEAT_SEP="\x00";function setFlag(flags,key,value,repeatable){let prev=flags.get(key);flags.set(key,repeatable.has(key)&&prev!==void 0?`${prev}${REPEAT_SEP}${value}`:value)}function parseFlags(argv,booleanFlags=new Set,repeatableFlags=new Set){let flags=new Map,pretty=!1,help=!1;for(let i=0;i<argv.length;i++){let arg=argv[i];if(!arg.startsWith("--")&&arg!=="-h")throw new ApiError(`unexpected positional arg: ${arg}`,"BAD_FLAG");if(arg==="-h"){help=!0;continue}let eq=arg.indexOf("=");if(eq!==-1){let key2=arg.slice(2,eq),value=arg.slice(eq+1);if(key2==="envelope")continue;if(key2==="pretty")pretty=value!=="false"&&value!=="0";else if(key2==="help")help=value!=="false"&&value!=="0";else setFlag(flags,key2,value,repeatableFlags);continue}let key=arg.slice(2);if(key==="envelope")continue;if(key==="pretty"){pretty=!0;continue}if(key==="help"){help=!0;continue}if(booleanFlags.has(key)){let next2=argv[i+1];if(next2!==void 0&&parseBoolLiteral(next2)!==void 0)flags.set(key,next2),i+=1;else flags.set(key,"true");continue}let next=argv[i+1];if(next===void 0||next.startsWith("--"))throw new ApiError(`flag --${key} requires a value`,"BAD_FLAG");setFlag(flags,key,next,repeatableFlags),i+=1}return{flags,pretty,help}}function validateAgainstSpec(verb,flags){let known=new Set(verb.flags.map((f)=>f.name));for(let key of flags.keys())if(!known.has(key))throw new ApiError(`unknown flag --${key} for "${verb.name}"`,"BAD_FLAG",helpStep(verb.name));for(let f of verb.flags){let satisfied=flags.get(f.name)||f.name==="prompt"&&flags.get("prompt-file")||verb.name==="add"&&f.name==="repo"&&(flags.get("fork")||flags.get("no-worktree")||flags.get("isolate-in"));if(f.required&&!satisfied)throw new ApiError(`--${f.name} is required for "${verb.name}"`,"MISSING_FLAG",helpStep(verb.name));if(f.type==="enum"&&f.values){let raw=flags.get(f.name);if(raw!==void 0&&!f.values.includes(raw)){if(f.name==="vendor"&®isteredEngineIds().includes(raw))continue;throw new ApiError(`--${f.name} must be one of ${f.values.join(", ")}`,"BAD_FLAG",helpStep(verb.name))}}if(f.type==="int"){let raw=flags.get(f.name);if(raw!==void 0&&parsePositiveInt(raw)===void 0)throw new ApiError(`--${f.name} must be a positive integer`,"BAD_FLAG")}if(f.type==="uint"){let raw=flags.get(f.name);if(raw!==void 0&&parseNonNegativeInt(raw)===void 0)throw new ApiError(`--${f.name} must be a non-negative integer`,"BAD_FLAG")}}}class VerbArgs{verb;flags;caller;constructor(verb,flags,caller=cliCaller()){this.verb=verb;this.flags=flags;this.caller=caller}resolvePath(name,raw){let expanded=expandTilde(raw);if(isAbsolute(expanded))return expanded;if(this.caller.cwd===void 0)throw new ApiError(`--${name} must be an absolute path: this caller has no working directory`,"BAD_FLAG");return resolve(this.caller.cwd,expanded)}spec(name){let f=this.verb.flags.find((s)=>s.name===name);if(!f)throw Error(`internal: --${name} is not declared on verb "${this.verb.name}"`);return f}str(name){this.spec(name);let v=this.flags.get(name);return v&&v.length>0?v:void 0}present(name){return this.spec(name),this.flags.get(name)!==void 0}list(name){if(!this.spec(name).repeatable)throw Error(`internal: --${name} is not repeatable on verb "${this.verb.name}"`);let raw=this.flags.get(name);return raw===void 0?[]:raw.split(REPEAT_SEP).filter((v)=>v.length>0)}promptText(){if(this.promptMemo!==void 0)return this.promptMemo.value;let value=this.readPromptText();return this.promptMemo={value},value}promptMemo;readPromptText(){let inline=this.verb.flags.some((f)=>f.name==="prompt")?this.str("prompt"):void 0,file=this.str("prompt-file");if(inline!==void 0&&file!==void 0)throw new ApiError("pass --prompt or --prompt-file, not both","BAD_FLAG",helpStep(this.verb.name));if(file===void 0)return inline;if(file==="-"&&!this.caller.cli)throw new ApiError("--prompt-file - reads stdin, which this caller cannot send; pass --prompt","BAD_FLAG");let text=readFileSync(file==="-"?0:this.resolvePath("prompt-file",file),"utf8");if(text.trim().length===0)throw new ApiError(`--prompt-file ${file} is empty`,"BAD_FLAG");return text}require(name){let v=this.str(name);if(v===void 0)throw new ApiError(`--${name} is required`,"MISSING_FLAG");return v}enumOf(name){let f=this.spec(name),v=this.str(name);if(v===void 0)return;if(f.values&&!f.values.includes(v))throw new ApiError(`--${name} must be one of ${f.values.join(", ")}`,"BAD_FLAG",helpStep(this.verb.name));return v}requireEnum(name){return this.require(name),this.enumOf(name)}vendor(){let value=this.str("vendor");if(value===void 0)return;let builtins=this.spec("vendor").values??ALL_VENDORS;if(builtins.includes(value))return value;if(registeredEngineIds().includes(value))return value;throw new ApiError(`--vendor must be a built-in (${builtins.join(", ")}) or a registered engine id \u2014 see \`engine-list\``,"BAD_FLAG",helpStep(this.verb.name))}bool(name){this.spec(name);let raw=this.str(name);if(raw===void 0)return;let value=parseBoolLiteral(raw);if(value===void 0)throw new ApiError(`--${name} must be a boolean (true/false)`,"BAD_FLAG");return value}int(name){this.spec(name);let raw=this.str(name);if(raw===void 0)return;let n=parsePositiveInt(raw);if(n===void 0)throw new ApiError(`--${name} must be a positive integer`,"BAD_FLAG");return n}nonNegativeInt(name){this.spec(name);let raw=this.str(name);if(raw===void 0)return;let n=parseNonNegativeInt(raw);if(n===void 0)throw new ApiError(`--${name} must be a non-negative integer`,"BAD_FLAG");return n}path(name){let v=this.str(name);return v===void 0?void 0:this.resolvePath(name,v)}requirePath(name){return this.resolvePath(name,this.require(name))}requireRepo(name){return this.repoPath(name,this.require(name))}repoPath(name,raw){return isRemoteRepoKey(raw)?raw:this.resolvePath(name,raw)}}function parseAgentsSpec(spec){let out=[];for(let part of spec.split(",")){let trimmed=part.trim();if(!trimmed)continue;let colon=trimmed.indexOf(":");if(colon===-1)throw new ApiError(`--agents entry "${trimmed}" must be engine:count`,"BAD_FLAG",FANOUT_STEP);let vendor=trimmed.slice(0,colon);if(!ALL_VENDORS.includes(vendor)&&!registeredEngineIds().includes(vendor))throw new ApiError(`--agents engine "${vendor}" must be a built-in (${ALL_VENDORS.join(", ")}) or a registered engine id \u2014 see \`engine-list\``,"BAD_FLAG",FANOUT_STEP);let count=parsePositiveInt(trimmed.slice(colon+1));if(count===void 0)throw new ApiError(`--agents count for "${vendor}" must be a positive integer`,"BAD_FLAG",FANOUT_STEP);if(out.length+count>FANOUT_CAP)throw new ApiError(`--agents requests ${out.length+count} agents, exceeds the cap of ${FANOUT_CAP}`,"BAD_FLAG",FANOUT_STEP);for(let i=0;i<count;i++)out.push(vendor)}if(out.length===0)throw new ApiError('--agents specified no agents (e.g. "claude:2,codex:1")',"BAD_FLAG",FANOUT_STEP);return out}function buildCountPlan(count,vendor){if(count>FANOUT_CAP)throw new ApiError(`--count ${count} exceeds the parallel cap of ${FANOUT_CAP} \u2014 spawn in batches`,"BAD_FLAG",FANOUT_STEP);return Array(count).fill(vendor)}function daemonOf(ctx){if(!ctx.client)throw new ApiError("daemon required","BAD_DAEMON");return ctx.client}async function repoFilter(runtime,repoFlag,repos){let target=await runtime.resolveRepoRoot(repoFlag);if(!await runtime.isUsableRepo(target))throw new ApiError(`--repo ${repoFlag} is not a readable git repository (resolved to ${target}) \u2014 the project may have moved or been deleted; \`rove api list\` still shows its tasks`,"REPO_UNRESOLVABLE");let resolved=new Map,unresolvable=new Set;for(let repo of new Set(repos)){let root=await runtime.resolveRepoRoot(repo);if(resolved.set(repo,root),!samePath(root,target)&&!await runtime.isUsableRepo(root))unresolvable.add(repo)}return{target,matches:(repo)=>samePath(resolved.get(repo),target),unresolvableRepos:[...unresolvable].sort()}}async function simpleRpc(ctx,name,payload){let request=name;return daemonOf(ctx).request(request,payload)}async function handlePtyList(){let[{RoveDaemonClient},{defaultPtyHostSocketPath}]=await Promise.all([import("./chunk-fq2pefc5.js"),import("./chunk-1qvrn21x.js")]),client=new RoveDaemonClient(defaultPtyHostSocketPath());try{return await client.connect(),await client.request("pty.list",{})}catch{return{sessions:null}}finally{client.close()}}function readJsonBody(source){let raw=readFileSync2(source==="-"?0:resolve2(process.cwd(),expandTilde(source)),"utf8"),parsed;try{parsed=JSON.parse(raw)}catch{throw new ApiError(`--json ${source} is not valid JSON`,"BAD_FLAG")}if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))throw new ApiError("--json must be an object: {delivery, outcome, summary, evidence?, next?}","BAD_FLAG");let body=parsed,evidence=body.evidence;if(evidence!==void 0&&(!Array.isArray(evidence)||evidence.some((e)=>typeof e!=="string")))throw new ApiError("evidence must be an array of strings","BAD_FLAG");for(let key of["delivery","outcome","summary","next"])if(body[key]!==void 0&&typeof body[key]!=="string")throw new ApiError(`${key} must be a string`,"BAD_FLAG");return body}var FIELD_FLAGS=["delivery","outcome","summary","next"];function readBody(ctx){let json=ctx.args.str("json"),evidence=ctx.args.list("evidence");if(json===void 0)return{delivery:ctx.args.str("delivery"),outcome:ctx.args.str("outcome"),summary:ctx.args.str("summary"),evidence,next:ctx.args.str("next")};if(FIELD_FLAGS.some((f)=>ctx.args.str(f)!==void 0)||evidence.length>0)throw new ApiError("pass --json OR the individual flags, not both","BAD_FLAG");return readJsonBody(json)}async function report(ctx){let body=readBody(ctx);if(!body.delivery)throw new ApiError("--delivery is required","MISSING_FLAG");if(!body.outcome||!DELIVERY_OUTCOMES.includes(body.outcome))throw new ApiError(`--outcome must be one of ${DELIVERY_OUTCOMES.join("|")}`,"MISSING_FLAG");if(!body.summary?.trim())throw new ApiError("--summary is required","MISSING_FLAG");if(body.summary.length>DELIVERY_SUMMARY_MAX_CHARS)throw new ApiError(`summary is ${body.summary.length} characters; the cap is ${DELIVERY_SUMMARY_MAX_CHARS}`,"RESPONSE_TOO_LARGE",{hint:"Summarize: lead with the conclusion, put the detail in --evidence (commits, PR urls, paths)."});let res=await simpleRpc(ctx,"delivery.report",{deliveryId:body.delivery,outcome:body.outcome,summary:body.summary,...body.evidence?.length?{evidence:body.evidence}:{},...body.next?{next:body.next}:{}});if(res.delivery===null)throw new ApiError(`no delivery ${body.delivery}`,"DELIVERY_NOT_FOUND",{hint:"Copy the id from the [ROVE] report line of the prompt you were given; `deliveries --task-id <id>` lists them."});return res}var REPORT_VERB={name:"report",group:"drive",summary:`Close the report a delivered prompt asked for. Run it as the LAST step of the turn, before you stop: a turn that ends without it is flagged \`report_missing\` in the owner's Inbox. --delivery is the id in the prompt's [ROVE] / [ROVE ROUTINE] line. Re-reporting replaces the earlier report; a late report on a flagged delivery clears the flag. --summary \u2264 ${DELIVERY_SUMMARY_MAX_CHARS} chars; put commits, PR urls, test results and paths in repeatable --evidence, and what the next tick should do in --next. Use --json - (stdin) for text with quotes or backticks.`,flags:[{name:"delivery",type:"string",placeholder:"ID",description:"Delivery id, e.g. d-41."},{name:"outcome",type:"enum",values:DELIVERY_OUTCOMES,placeholder:"O",description:"done = finished what was asked; partial = some of it; blocked = needs the owner or an external fix; failed = tried and could not."},{name:"summary",type:"string",placeholder:"TEXT",description:"What was done (or why not)."},{name:"evidence",type:"string",placeholder:"X",repeatable:!0,description:"A commit, PR url, test command + result, or file path. Repeat the flag for several."},{name:"next",type:"string",placeholder:"TEXT",description:"What the next tick should do."},{name:"json",type:"string",placeholder:"PATH",description:"Read {delivery, outcome, summary, evidence?, next?} as JSON from this file (`-` = stdin) instead of the flags."}],handler:report},DELIVERIES_VERB={name:"deliveries",group:"read",summary:`A task's armed deliveries, newest first (newest ${MAX_DELIVERIES_PER_TASK} are kept): status awaiting|reported|missing|skipped, the report (outcome, summary, evidence, next) and, for missing, why (cause turn-complete|turn-failed|engine-dead|stalled|interrupted|session-end|rate-limited + note; rate-limited raises no Inbox row and does not block) plus dismissedAt once the owner dismissed it (a missing row blocks \`send --if-runnable\` and routine ticks until a late report or that dismissal). A skipped row is a \`send --if-runnable\` tick should-run refused: \`skipped\` is the verdict {reason, detail?, until?, gateIds?}, \`repeats\` how many identical refusals (same tab, same reason) the one row stands for. The per-tick log a loop prompt should read instead of a growing MEMO file.`,flags:[F.taskId(!0),{name:"limit",type:"int",placeholder:"N",description:"At most N entries (default: all retained)."}],handler:async(ctx)=>simpleRpc(ctx,"delivery.list",{taskId:ctx.args.require("task-id"),...ctx.args.int("limit")!==void 0?{limit:ctx.args.int("limit")}:{}})};async function listAllEnginePresets(){let presets=await enginePresetsInList(),byProtocol=new Map,modelsOf=(protocol)=>{let pending=byProtocol.get(protocol);if(!pending){let list=engineEntry(protocol).listModels;pending=list?list().catch(()=>null):Promise.resolve(null),byProtocol.set(protocol,pending)}return pending};return Promise.all(presets.map(async(preset)=>({...preset,models:await modelsOf(preset.protocol)})))}async function enginePresetsInList(){ensurePluginEnginesLoaded();let presets=[...listEnginePresets()],seen=new Set(presets.map((p)=>p.id));for(let id of await installedEngineIds())if(!seen.has(id))presets.push(describePreset(id));return presets}async function engineListIds(){return(await enginePresetsInList()).map((p)=>p.id)}var ENGINE_LIST_VERB={name:"engine-list",group:"discover",summary:`List every engine Rove can launch \u2014 built-ins, registered presets, the shipped contrib engines whose CLI is on PATH (${CONTRIB_ENGINE_IDS.join(", ")}), and engines contributed by enabled plugins \u2014 each with its RAW launch command, exactly as it runs. Copy one into \`add --command\` / \`send --tab new --command\` verbatim, or edit its flags first. \`protocol\` is the adapter Rove speaks to it (history, trust, delivery); \`generic\` = none, which still runs fine but loses transcript reads. \`models\` is what the engine can name for \`--model\` (suggestions, not a closed set); null = Rove cannot list them for this engine. Returns { engines }.`,flags:[],offline:!0,handler:async()=>({engines:await listAllEnginePresets()})};function taskEngine(task){let command=task.command?.trim();if(command){let resolved=resolveCommandProtocol(command);if(resolved!==GENERIC_PROTOCOL)return resolved}return sessionProtocol(coerceVendorId(task.vendor))}function assertEngineAcceptsEffort(engine,level,recover){let levels=engineEntry(engine).effortLevels??[];if(levels.length===0)throw new ApiError(`engine ${engine} declares no reasoning effort levels`,"BAD_EFFORT",{engine,hint:`Only engines with declared reasoning levels accept one (${vendorsWithEffortLevels().join(", ")} today). Check the task's engine with \`get-task\`.`,nextCommandArgs:[...recover]});if(!levels.includes(level))throw new ApiError(`engine ${engine} does not accept effort level ${JSON.stringify(level)} \u2014 it declares ${levels.join(", ")}`,"BAD_EFFORT",{engine,levels,hint:`Pass one of: ${levels.join(", ")}.`,nextCommandArgs:[...recover]})}function assertEngineAcceptsModel(engine,model,recover){if(engineEntry(engine).modelArgv)return;throw new ApiError(`engine ${engine} declares no model flag \u2014 it does not accept a model`,"BAD_MODEL",{engine,hint:"Only engines that declare a model flag accept one (claude, codex, kimi, pi, omp today); `engine-list` shows `models` per engine.",nextCommandArgs:[...recover]})}function vendorToRecord(task,engine){let recorded=coerceVendorId(task.vendor);return sessionProtocol(recorded)===engine?recorded:engine}async function readRunnability(daemon,taskId){try{return await daemon.request("task.runnability",{taskId})}catch{return}}async function shouldRun(ctx){let tab=ctx.args.str("tab");if(tab&&tab!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(tab))throw new ApiError(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(tab)})`,"BAD_TAB");let verdict=await daemonOf(ctx).request("task.runnability",{taskId:ctx.args.require("task-id"),...tab?{tabId:tab}:{}});if(!verdict.run)throw new ApiError(`skip: ${verdict.reason}`,"SKIPPED",{...verdict});return verdict}var SHOULD_RUN_VERB={name:"should-run",group:"read",summary:`Would a tick sent to this task be used? Prints the verdict {run:true} or {run:false, reason, detail?, until?, gateIds?} and exits 0 on run, ${SHOULD_RUN_SKIP_EXIT_CODE} on skip (the verdict is still on stdout). reason, first match wins: ${SKIP_REASONS.join(" | ")}. \`awaiting-owner\` = an open gate (answer or withdraw it), \`report-missing\` = the last delivery ended unreported (late \`report\`, or dismiss its Inbox row), \`quota\` clears itself at \`until\`, \`engine-error\` / \`engine-dead\` clear on the engine's next turn or a restart, \`awaiting-permission\` = the engine waits on an approval, \`busy\` = a turn is running or the last delivery still awaits its report. A task whose only gate is answered-but-undelivered is runnable: the next tick carries the answer. Without --tab the whole task is judged and a dead engine is not a skip (\`send\` revives it); --tab tab-N judges that tab and a dead engine is \`engine-dead\`; --tab new judges only task-level state. To check and send in one step use \`send --if-runnable\`.`,flags:[F.taskId(!0),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Judge exactly this tab (e.g. tab-2), or "new" for a tab about to be created. Omitted = the whole task.'}],handler:shouldRun};async function attentionDismiss(ctx){let delivery=ctx.args.require("delivery");if((await daemonOf(ctx).request("attention.dismiss",{deliveryId:delivery})).found===!1)throw new ApiError(`no delivery ${delivery}`,"DELIVERY_NOT_FOUND",{hint:"`deliveries --task-id <id>` lists a task's delivery ids; the Inbox row names it as d-N."});return{ok:!0,delivery,cleared:!0}}var ATTENTION_DISMISS_VERB={name:"attention-dismiss",group:"drive",summary:'Dismiss a `report_missing` Inbox row by its delivery id (d-N): the owner\'s deliberate "seen, carry on" for a tick that ended without a report. It unblocks `should-run` for the task. Opening or visiting the row never does this, and a late `report` clears it on its own. Idempotent; an unknown id is DELIVERY_NOT_FOUND.',flags:[{name:"delivery",type:"string",required:!0,placeholder:"ID",description:"Delivery id, e.g. d-41."}],handler:attentionDismiss};import path from"path";var TASK_STATUSES=["backlog","in_progress","in_review","done","canceled","error"];var TASK_FIELDS=["title","branch","parent","project","command","model","effort","pinned","kept","require-report","auto-fix-ci","status"],REPORT_FLAGS=["report-branch","report-pr","report-summary"];async function renameTab(ctx,taskId,tabId){let title=ctx.args.str("title"),others=[...TASK_FIELDS,...REPORT_FLAGS].filter((f)=>f!=="title"&&ctx.args.str(f)!==void 0);if(title===void 0||others.length>0)throw new ApiError("--tab only renames a tab: pass --title and no other field","BAD_FLAG",{hint:"Update the task's own fields in a separate call without --tab."});let daemon=daemonOf(ctx);if(!await renameTabsSnapshot(daemon,taskId,tabId,title))throw new ApiError(`task ${taskId} has no tab ${tabId}`,"TAB_NOT_FOUND",{hint:"`get-task` lists the addressable tab ids in .tabs[].id",nextCommandArgs:["api","get-task","--task-id",taskId]});let reply=await daemon.request("terminalTab.rename",{taskId,tabId,title});return{ok:!0,taskId,tabId,title,renamed:!0,clients:reply.clients??0}}async function resolveTarget(ctx,verb="update"){let explicit=ctx.args.str("task-id");if(explicit)return explicit;let self=await ownSession(daemonOf(ctx));if(!self)throw new ApiError("no --task-id given and the caller is not a verified rove session \u2014 pass --task-id ID","MISSING_TARGET",helpStep(verb));return self.taskId}async function projectRoot(ctx){let raw=ctx.args.str("project")?.trim();if(raw===void 0)return;if(raw==="")throw new ApiError("--project cannot be empty \u2014 pass the repo's path","BAD_FLAG");let root=await ctx.runtime.resolveRepoRoot(path.resolve(ctx.caller.cwd??process.cwd(),raw));if(!await ctx.runtime.isUsableRepo(root))throw new ApiError(`--project ${raw} is not inside a git repository`,"NOT_A_GIT_REPO",{hint:"clone or `git init` the project first, then pass its path"});return root}var NO_PARENT="none";async function reparentGroup(ctx,groupId){let parent=ctx.args.str("parent"),stray=["task-id","tab",...TASK_FIELDS.filter((f)=>f!=="parent"),...REPORT_FLAGS].filter((f)=>ctx.args.str(f)!==void 0);if(parent===void 0||parent===""||stray.length>0)throw new ApiError(`--group moves a whole fan-out round and takes only --parent ID (or \`none\`)${stray.length>0?` \u2014 drop ${stray.map((f)=>`--${f}`).join(", ")}`:""}`,"BAD_FLAG",helpStep("update"));let daemon=daemonOf(ctx),{tasks}=await daemon.request("task.list"),members=tasks.filter((t)=>t.groupId===groupId);if(members.length===0)throw new ApiError(`no tasks in group ${groupId}`,"TASK_NOT_FOUND",{hint:"the groupId is the one `add --count` returned; any surviving sibling's `.groupId` in `list` recovers it",nextCommandArgs:["api","list"]});if(members.some((t)=>t.id===parent))throw new ApiError(`${parent} is itself a member of group ${groupId} \u2014 a round cannot move under one of its own`,"PARENT_IN_GROUP",{hint:"pick a parent outside the round, or move the members one by one with --task-id"});let parentTaskId=parent===NO_PARENT?null:parent,replyTab=parentTaskId===null?void 0:await replyTabOf(ctx.runtime,daemon,parentTaskId),results=[],failures=0;for(let task of members)try{let moved=await simpleRpc(ctx,"task.setParent",{taskId:task.id,parentTaskId,...replyTab?{replyTab}:{}});results.push({taskId:task.id,status:"moved",...moved})}catch(err){failures++;let message=errorMessage(err),coded=err instanceof ApiError?{code:err.code,rest:message}:splitDaemonCode(message);results.push({taskId:task.id,status:"failed",error:coded?.rest??message,...coded?{code:coded.code}:{}})}return{ok:failures===0,groupId,count:members.length,failures,results}}async function updateTask(ctx){let group=ctx.args.str("group");if(group!==void 0)return reparentGroup(ctx,group);let tabId=ctx.args.str("tab"),taskId=tabId!==void 0?ctx.args.require("task-id"):await resolveTarget(ctx);if(tabId!==void 0)return renameTab(ctx,taskId,tabId);let title=ctx.args.str("title"),branch=ctx.args.str("branch"),parent=ctx.args.str("parent"),command=ctx.args.str("command")?.trim(),model=ctx.args.str("model")?.trim(),effort=ctx.args.str("effort")?.trim(),pinned=ctx.args.bool("pinned"),kept=ctx.args.bool("kept"),requireReport=ctx.args.enumOf("require-report"),autoFixCi=ctx.args.enumOf("auto-fix-ci"),status=ctx.args.enumOf("status"),report2={reportBranch:ctx.args.str("report-branch"),reportPr:ctx.args.int("report-pr"),reportSummary:ctx.args.str("report-summary")},reporting=Object.values(report2).some((v)=>v!==void 0);if(TASK_FIELDS.every((f)=>ctx.args.str(f)===void 0)&&!reporting)throw new ApiError(`nothing to update \u2014 pass at least one of ${TASK_FIELDS.map((f)=>`--${f}`).join(", ")}`,"BAD_FLAG",{nextCommandArgs:["api","update","--help"]});if(reporting&&status===void 0)throw new ApiError("--report-* is recorded with a status: pass --status too","BAD_FLAG",{hint:"A worker reporting delivery usually passes --status in_review (or done)."});if(command==="")throw new ApiError("--command cannot be empty","BAD_FLAG");if(parent==="")throw new ApiError("--parent cannot be empty \u2014 pass a task id, or `none` for top level","BAD_FLAG");let daemon=daemonOf(ctx),protocol=command?resolveCommandProtocol(command):void 0,project=await projectRoot(ctx),task,engine;if(model!==void 0||effort!==void 0){task=(await daemon.request("task.get",{taskId})).task,engine=taskEngine(command?{...task,command}:task);let recover=["api","get-task","--task-id",taskId];if(model!==void 0)assertEngineAcceptsModel(engine,model,recover);if(effort!==void 0)assertEngineAcceptsEffort(engine,effort,recover)}let applied=[],step=async(fields,method,payload)=>{let reply;try{reply=await simpleRpc(ctx,method,{taskId,...payload})}catch(err){if(applied.length===0)throw err;let message=err instanceof Error?err.message:String(err),code=err instanceof ApiError?err.code:"PARTIAL_UPDATE";throw new ApiError(`--${fields.join("/--")} failed after ${applied.join(", ")} applied: ${message}`,code,{applied:[...applied],failed:fields})}return applied.push(...fields),reply},reparented;if(parent!==void 0){let parentTaskId=parent===NO_PARENT?null:parent,replyTab=parentTaskId===null?void 0:await replyTabOf(ctx.runtime,daemon,parentTaskId);reparented=await step(["parent"],"task.setParent",{parentTaskId,...replyTab?{replyTab}:{}})}let regrouped;if(project!==void 0)regrouped=await step(["project"],"task.moveToProject",{repo:project});if(branch!==void 0)await step(["branch"],"task.setBranch",{branch});if(command)await step(["command"],"task.setCommand",{command,vendor:protocol});if(task&&engine){let recorded=vendorToRecord(protocol?{...task,vendor:protocol}:task,engine),fields=[...model!==void 0?["model"]:[],...effort!==void 0?["effort"]:[]];await step(fields,"task.setVendor",{vendor:recorded,model,effort})}if(title!==void 0)await step(["title"],"task.rename",{title});if(pinned!==void 0)await step(["pinned"],"task.pin",{pinned});if(kept!==void 0)await step(["kept"],"task.keep",{kept});if(requireReport!==void 0)await step(["require-report"],"task.requireReport",{required:requireReport==="on"});if(autoFixCi!==void 0)await step(["auto-fix-ci"],"task.autoFixCi",{enabled:autoFixCi==="on"});if(status!==void 0)await step(["status"],"task.status",{status,...report2});return{ok:!0,taskId,updated:applied,...reparented?{parent:reparented}:{},...regrouped?{project:{repo:regrouped.repo,moved:regrouped.moved,note:"regrouped only \u2014 the PTYs, cwd, worktree and branch stay where they were"}}:{},...command?{command,protocol,...protocol===GENERIC_PROTOCOL?{generic:!0}:{}}:{},...engine?{engine}:{}}}var EDIT_VERBS=[{name:"update",group:"edit",summary:"Change a task's metadata \u2014 any combination of title, branch (git branch -m if materialized, else recorded), parent, engine --command / --model / --effort (take effect on the next session rebuild), pin, and status + worker report \u2014 in one call. The flags are checked before anything is written; then they apply in order parent \u2192 branch \u2192 engine \u2192 title/pin/status, and a refusal mid-way names what already applied (`applied`). --parent ID re-parents the task without touching its engine, tabs, worktree or branch: the stored parent is ID's top-level ancestor (children never nest, as with `add` from a child; the task's own children come along, listed in `.parent.moved`) and the task's reply address becomes ID itself, so its bare `send` reaches ID (the caller's own tab when run from inside ID, else ID's live engine tab, else tab-1). `--parent none` makes the task top level and drops a reply address that pointed into its old tree. A parent must live on the same machine as the task. Archiving the stored parent, or `delete --cascade` on it, takes the task along. --group G --parent ID moves a whole fan-out round instead and takes nothing else. With --tab, renames that Terminal Tab instead (the API twin of the TUI's f2) and takes only --title. The status is a cosmetic LABEL: `--status canceled` closes, stops and cleans up nothing \u2014 `delete` ends a task. The --report-* fields record what the WORKER CLAIMS it delivered (`.report` on `get-task` / `collect`), deliberately apart from `.prStatus`, which the daemon polled from the forge; they merge onto any previous report and need --status. Returns { updated } \u2014 the fields written, in order.",flags:[{...F.taskId(!1),description:"Target task id (from `list` / `add`). Default: the calling session's own task, from the verified $ROVE_TASK_ID (an unverifiable env is MISSING_TARGET, never a guess)."},{name:"title",type:"string",placeholder:"T",description:"New task title (or, with --tab, the tab's name)."},{name:"tab",type:"string",placeholder:"TAB",description:"Rename this Terminal Tab (id from `get-task` .tabs[].id, e.g. tab-2) instead of the task; needs --task-id, and only --title may accompany it. TAB_NOT_FOUND when the task's snapshot names no such tab."},{name:"branch",type:"string",placeholder:"B",description:"New branch name."},{name:"parent",type:"string",placeholder:"ID|none",description:"Move the task under this task (its engine, tabs, worktree and branch stay as they are), or `none` to make it top level. Refusals: PARENT_NOT_FOUND, PARENT_IS_SELF, PARENT_CYCLE, TASK_NOT_MOVABLE, REMOTE_PARENT_UNSUPPORTED."},{name:"project",type:"string",placeholder:"PATH",description:"Move a top-level task (and its children) under the project at PATH (relative paths resolve against $PWD; any directory inside the repo names its main checkout), which becomes a project if it was not one. Only the grouping changes: the live session, tabs, cwd, worktree and branch stay exactly where they are, so a running engine keeps its conversation. Moving a worktree task back to the repo that cut it clears the link. Refusals: NOT_A_GIT_REPO, SAME_PROJECT, TASK_NOT_MOVABLE (a project's main task, a routine session or a multi-repo task), CHILD_NOT_MOVABLE (move its parent; children follow), REMOTE_MOVE_UNSUPPORTED."},{name:"group",type:"string",placeholder:"GROUPID",description:"With --parent: move every task of one fan-out round (the `groupId` that `add --count` returns). Takes nothing but --parent; a member's refusal is recorded in `results`, and a parent inside the round is PARENT_IN_GROUP."},{...F.command(),description:"New engine launch command \u2014 an engine id from `engine-list` or a full command line. The protocol Rove speaks to it is derived from it; the result reports which (`generic: true` when the command names no engine Rove knows)."},{name:"model",type:"string",placeholder:"MODEL",description:"Pin a model, passed to the engine VERBATIM in its own spelling (claude alias or id, codex slug, pi/omp pattern); `engine-list` .models are suggestions, not a closed list. BAD_MODEL when the engine declares no model flag."},{name:"effort",type:"string",placeholder:"LEVEL",description:"Reasoning effort level the task's engine declares (codex: none/low/medium/high/xhigh/max; pi, omp: off/minimal/low/medium/high/xhigh/max; claude: low/medium/high/xhigh/max). BAD_EFFORT names the accepted levels."},{name:"pinned",type:"bool",placeholder:"BOOL",description:"true pins the task to the top of the sidebar, false unpins."},{name:"kept",type:"bool",placeholder:"BOOL",description:"true marks the task as the attempt kept from a parallel round (`add --count` / `--agents`); false clears the mark. A flag only: it archives nothing, and other attempts of the round are untouched."},{name:"require-report",type:"enum",values:["on","off"],description:"on: every later `send` to this task arms a delivery the agent must close with `report --delivery <id>` (a turn that ends without one raises a `report_missing` Inbox row); off: back to plain sends."},{name:"auto-fix-ci",type:"enum",values:["on","off"],description:"on: when this task's PR checks go red on a new head sha and its engine is at rest, the daemon types the fix-CI prompt (with the failing logs) into the engine, at most once per sha and 3 times in all, then stops and raises an Inbox row; the count starts over when the checks pass. Never interrupts a running turn. off: stop and forget the count."},{name:"status",type:"enum",values:TASK_STATUSES,description:"New lifecycle label (cosmetic \u2014 see summary)."},{name:"report-branch",type:"string",placeholder:"B",description:"The branch the worker says holds the work (a CLAIM \u2014 `.branch` is the task's actual branch)."},{name:"report-pr",type:"int",placeholder:"N",description:"The PR number the worker says it opened (a CLAIM \u2014 `.prStatus.number` is what the daemon read from the forge)."},{name:"report-summary",type:"string",placeholder:"TEXT",description:"One line of what was delivered."}],handler:updateTask}];async function todo(ctx){let{args}=ctx,taskId=await resolveTarget(ctx,"todo"),add=args.str("add"),check=args.str("check"),uncheck=args.str("uncheck"),edit=args.str("edit"),text=args.str("text"),remove=args.str("remove"),notes=args.bool("clear-notes")===!0?"":args.str("notes");if(edit===void 0!==(text===void 0))throw new ApiError("--edit ID and --text T go together","BAD_FLAG");let ops=[...add!==void 0?[{op:"add",text:add}]:[],...check!==void 0?[{op:"check",id:check,done:!0}]:[],...uncheck!==void 0?[{op:"check",id:uncheck,done:!1}]:[],...edit!==void 0&&text!==void 0?[{op:"edit",id:edit,text}]:[],...remove!==void 0?[{op:"remove",id:remove}]:[]],after=await simpleRpc(ctx,"task.notes",{taskId,...notes!==void 0?{notes}:{},...ops.length>0?{ops}:{}}),count=todoCount(after.todos);return{ok:!0,taskId,notes:after.notes??"",todos:after.todos,done:count?.done??0,total:count?.total??0}}var TODO_VERB={name:"todo",group:"edit",summary:"Read or change a task's notes and checklist \u2014 the owner's own review list (shown in the web Files panel's Notes tab and as `done/total` on the task row). With no flag it lists them. Flags combine in one call and apply together, in this order: --add, --check, --uncheck, --edit/--text, --remove; one refused op (TODO_NOT_FOUND, TODO_EMPTY, TODO_TOO_LONG, TODO_LIMIT) changes nothing. A todo id is `t<N>` as listed. Default target: the calling session's own task. Returns { ok, taskId, notes, todos: [{ id, text, done }], done, total }.",flags:[{...F.taskId(!1),description:"Target task id (from `list` / `add`). Default: the calling session's own task."},{name:"add",type:"string",placeholder:"TEXT",description:"Add an unchecked todo (one line, up to 500 characters; 100 per task)."},{name:"check",type:"string",placeholder:"ID",description:"Mark todo ID done."},{name:"uncheck",type:"string",placeholder:"ID",description:"Mark todo ID not done."},{name:"edit",type:"string",placeholder:"ID",description:"Change todo ID's text to --text."},{name:"text",type:"string",placeholder:"TEXT",description:"The new text for --edit."},{name:"remove",type:"string",placeholder:"ID",description:"Delete todo ID."},{name:"notes",type:"string",placeholder:"TEXT",description:"Replace the task's free-text notes (up to 20000 characters); Use --clear-notes to empty them."},{name:"clear-notes",type:"bool",description:"Empty the free-text notes."}],handler:todo};var API_SCHEMA_VERSION=ROVE_API_VERSION,GLOBAL_FLAGS=[{name:"pretty",type:"bool",description:"Pretty-print stdout JSON."},{name:"help",type:"bool",description:"Show usage for the verb and exit."},{name:"envelope",type:"bool",description:"Print every outcome as one { apiVersion, ok, result | error } on stdout \u2014 what the daemon's and the bridge's api.invoke return."},{name:"machine",type:"string",placeholder:"ALIAS",description:"Run the verb in that registered machine's daemon (`rove machine list`); paths are paths there. A --task-id on another machine goes there without it."}];function displayValues(f){if(!f.values)return;if(f.name!=="vendor")return f.values;let registered=registeredEngineIds().filter((id)=>!f.values.includes(id));return registered.length>0?[...f.values,...registered]:f.values}function flagJson(f){let values=displayValues(f);return{name:f.name,type:f.type,required:f.required??!1,...values?{values}:{},...f.default!==void 0?{default:f.default}:{},...f.placeholder?{placeholder:f.placeholder}:{},...f.repeatable?{repeatable:!0}:{},description:f.description}}function installedVerbs(){return VERBS.filter(verbInstalled)}function installedGroups(){return Object.fromEntries(Object.entries(VERB_GROUPS).filter(([group])=>{let mod=GROUP_MOD[group];return mod===void 0||isBuiltinModInstalled(mod)}))}function verbSchema(v){return{name:v.name,group:v.group,summary:v.summary,offline:v.offline??!1,cliOnly:v.cliOnly??!1,flags:v.flags.map(flagJson)}}function schemaIndex(){let cliName=ROVE_PRODUCT_NAME;return{apiVersion:API_SCHEMA_VERSION,roveVersion:CURRENT_VERSION,hint:`Compact index. Drill into ONE verb: \`${cliName} api schema --verb <name>\` (or \`${cliName} api <verb> --help\`). One group: \`--group <g>\`. Whole spec: \`--all\`.`,groups:installedGroups(),verbs:installedVerbs().map((v)=>({name:v.name,group:v.group,summary:v.summary})),globalFlags:GLOBAL_FLAGS,aliases:VERB_ALIASES}}function groupSchema(group){let verbs=VERBS.filter((v)=>v.group===group);if(verbs[0])requireVerbInstalled(verbs[0]);if(verbs.length===0)throw new ApiError(`unknown group: ${group}. Groups: ${Object.keys(installedGroups()).join(", ")}`,"BAD_VERB",{hint:"that group does not exist \u2014 the compact index lists every group and the verbs in it",nextCommandArgs:["api","schema"]});return{group,verbs:verbs.map((v)=>({name:v.name,summary:v.summary}))}}function fullSchema(){return{apiVersion:API_SCHEMA_VERSION,roveVersion:CURRENT_VERSION,output:{success:"one JSON object on stdout, newline-terminated, exit 0",error:'{"error":{"message","code"}} on stderr, exit != 0',pretty:"--pretty indents stdout JSON",envelope:'--envelope prints {"apiVersion","ok","result"} or {"apiVersion","ok","error"} on stdout instead, exit codes unchanged'},transports:{cli:"rove api <verb> --flag value",daemon:'socket request "api.invoke" {verb, params, machine?} \u2192 the envelope; params are keyed by flag name',bridge:'WebSocket op "api.invoke" {verb, params, machine?} \u2192 result, or the full error object'},globalFlags:GLOBAL_FLAGS,aliases:VERB_ALIASES,groups:installedGroups(),verbs:installedVerbs().map(verbSchema)}}function flagSignature(verb){return verb.flags.map((f)=>{let meta=f.type==="enum"&&f.values?displayValues(f).join("|"):f.placeholder??(f.type==="bool"?"":"X"),core=meta?`--${f.name} ${meta}`:`--${f.name}`;return f.required?core:`[${core}]`}).join(" ")}function verbHelp(verb){let lines=[`${ROVE_PRODUCT_NAME} api ${verb.name} ${flagSignature(verb)}`.trimEnd(),"",verb.summary,""],alias=Object.entries(VERB_ALIASES).find(([,canon])=>canon===verb.name)?.[0];if(alias)lines.push(`Alias: ${alias}`,"");if(verb.flags.length>0){lines.push("Flags:");for(let f of verb.flags){let req=f.required?" (required)":f.repeatable?" (repeatable)":"",def=f.default!==void 0?` [default: ${f.default}]`:"",vals=f.type==="enum"&&f.values?` {${displayValues(f).join("|")}}`:"";lines.push(` --${f.name}${vals}${req}${def} ${f.description}`)}lines.push("")}return lines.push("Global: [--pretty] [--help] [--envelope] [--machine ALIAS]"),lines.join(`
|
|
2
|
+
import{PER_SESSION,classifyTier,describeTierBlock,isAutoRoutingTier,listFiles,liveSourceProtocol,loadPreviewData,planWorktreeHandoff,readAutoRoutingTable,readClassifierConfig,resolveBase,runWorktreeGit,screenErrorLine,searchTasks,statusFiles,statusFilesBranch,taskGroupOf,tierBlock}from"./chunk-k2j0tg1h.js";import{ensurePluginEnginesLoaded,registeredEngineIds}from"./chunk-kdnk8m5j.js";import{resolveActiveTaskId}from"./chunk-qcjkactr.js";import{listPaneLaunches}from"./chunk-rjfdzjhj.js";import{detectEngineStatus}from"./chunk-zpxpwgds.js";import{resolveEditorLaunch}from"./chunk-agvtzads.js";import{DeviceLogin,GH_ENV,GITHUB_HOST,runTool,spawnGhLogin}from"./chunk-pm91e38v.js";import{PLACEHOLDER_TASK_TITLE,SHELL_TASK_TITLE,deriveTitleFromPrompt}from"./chunk-2xsxcdp6.js";import{ENGINE_ACTIVITY_KINDS,TASK_ACTIVITY_STATES}from"./chunk-17e2tgyg.js";import{DIRTY_WORKTREE_CODE,EMPTY_BRANCH_DIRTY_WORKTREE_CODE,canonicalize}from"./chunk-1vxtd8rh.js";import{canonicalEngineTab}from"./chunk-q8ffd1pc.js";import{ISSUE_STATUSES}from"./chunk-4hestsjp.js";import{ROW_TOKEN_MAX_TEXT,ROW_TOKEN_TONES}from"./chunk-atn06ncf.js";import{DEFAULT_FEEDBACK_CATEGORY_SLUG,submitFeedback}from"./chunk-2pfh3zm0.js";import{cloneDirFor,cloneRepo,dispatcherEnvPayload,findCheckouts,forwardVerb,isCleanCheckout,ownSession,parseRepoRef,pickCheckout,primaryCheckouts,ptyScopeOf,readOwnDispatcher,recordSend,replyTabOf,repoIdOf,repoIdentity,requireMachine,resolveDispatcherTab,verifiedSelfSession,withPeerProvenance}from"./chunk-p11emdb2.js";import{dedupeMachines,listMachines}from"./chunk-vytrhm50.js";import{normalizeRemoteUrl,resolvePtyOwner}from"./chunk-vp29jgbt.js";import{ulid}from"./chunk-qkehg2c1.js";import{ENGINE_NOT_OBSERVED_REASON,ENGINE_START_POLL_MS,ENGINE_START_PROBE_MS,deliverHostedPrompt,deliverToKey,ensurePtyHost,findEngineKey,killTaskSessions,listSessions,listSessionsOrNull,openAdmittedEngine,openPtyHost,outcomeFields,restoredTabLaunch,tabEngineBase,taskKeys}from"./chunk-s1xn6wav.js";import{awaitEngineProcess,enginePresence,findHostedEngineKey,hostedSessionFailureLine,isHostedTaskKey,listHostedSessions,openHostedSessionHost,readPersistedTerminalDefaultColors,sessionArgvNamesEngine,withDeliveryLock}from"./chunk-nv8eyjep.js";import{allocateTab,applyTabOps,closeTabsSnapshot,collapseSplit,findEditorTab,initialSplit,joinTaskTabs,leaves,markCliTabSession,patchTabSplit,publishCliTabSnapshot,readDaemonTabs,readTabsSnapshot,removeLeaf,renameLeaf,renameTabsSnapshot,seedCanonicalTab,seedShellHome,shellIdentityInput,splitActive,splitLeafPtyKey,tabPtyKeyFor,taskEngineArgv,unregisteredTabIds,wireSplit}from"./chunk-3hxm56h6.js";import{RemoteEngineLaunchError,buildEngineSessionLaunch,launchReposOf,repoEnv,trustEngineWorktree,trustExtraRepos}from"./chunk-qecygh3f.js";import{GENERIC_PROTOCOL,describePreset,engineLaunchArgv,engineResumeArgv,listEnginePresets,protocolEntry,resolveCommandProtocol,roveApiInvocation,sessionProtocol,withPinnedSessionId}from"./chunk-rjq38twt.js";import{ApiError,GROUP_MOD,VERB_GROUP_IDS,cliCaller,helpStep,promptMayHaveLanded,requireVerbInstalled,splitDaemonCode,verbInstalled}from"./chunk-r5j8fycq.js";import{isBuiltinModInstalled}from"./chunk-xfgqae9t.js";import{aliasKey,hostedKeyFor,isUnderKey,ptyScopeFor,unclaimedSessions}from"./chunk-g9ba25q5.js";import{resolveSessionShell}from"./chunk-tn9gtf18.js";import{foregroundEngineIn,parsePsSnapshot,psSnapshot}from"./chunk-5rgrde6b.js";import{engineEntry,getCapabilities,supportsStructuredHistory,vendorsWithEffortLevels,vendorsWithTurnReader}from"./chunk-4gjvmfa9.js";import{CONTRIB_ENGINE_IDS,installedEngineIds}from"./chunk-hzz020xx.js";import{terminalRows}from"./chunk-etfh8f4z.js";import{resolvePreferredVendor}from"./chunk-9rj2fx6v.js";import{addSavedRepo,getSavedRepos,isRemoteRepoKey}from"./chunk-rfp0ayra.js";import{readOnlyGitProcessEnv}from"./chunk-6xppe9bj.js";import{CURRENT_VERSION}from"./chunk-2wrt80ft.js";import{parseBoolLiteral}from"./chunk-zsfyj36g.js";import{expandTilde}from"./chunk-2r1fgng9.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{loadStateFile}from"./chunk-32j6y5d1.js";import{DELIVERY_OUTCOMES,DELIVERY_SUMMARY_MAX_CHARS,MAX_DELIVERIES_PER_TASK,ROUTINE_RESPONSE_MAX_CHARS,SHOULD_RUN_SKIP_EXIT_CODE,SKIP_REASONS,deliveryFooter}from"./chunk-qzzmd63x.js";import{ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import{MULTI_REPO_CAP,canonicalPrUrl,gitRepoOf,lineageRootId,repoNameOf,rollupPr,taskCwd,taskRepos,todoCount,uniqueRepoName,workspaceCapabilities}from"./chunk-x1jxxmtc.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";import{ALL_VENDORS,DEFAULT_VENDOR,coerceVendorId}from"./chunk-h2m7em1e.js";import{homeDir}from"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{pathWithin,samePath}from"./chunk-pn5ygqn6.js";import{defaultDaemonSocketPath}from"./chunk-eqdbfgq5.js";import{__require}from"./chunk-91sykzqq.js";import{readFileSync as readFileSync2}from"fs";import{resolve as resolve2}from"path";import{readFileSync}from"fs";import{isAbsolute,resolve}from"path";var FANOUT_CAP=10;function parsePositiveInt(raw){if(!/^\d+$/.test(raw.trim()))return;let n=Number.parseInt(raw,10);return Number.isSafeInteger(n)&&n>0?n:void 0}function parseNonNegativeInt(raw){if(!/^\d+$/.test(raw.trim()))return;let n=Number.parseInt(raw,10);return Number.isSafeInteger(n)&&n>=0?n:void 0}var FANOUT_STEP=helpStep("add"),F={repo:(required=!0)=>({name:"repo",type:"string",required,placeholder:"PATH",description:"Repo root (git toplevel). Relative paths resolve against $PWD."}),taskId:(required=!0)=>({name:"task-id",type:"string",required,placeholder:"ID",description:"Target task id (from `list` / `add`)."}),vendor:()=>({name:"vendor",type:"enum",values:ALL_VENDORS,placeholder:"V",description:"Engine vendor for the task."}),command:()=>({name:"command",type:"string",placeholder:"CMD",description:"Engine launch command, verbatim \u2014 an engine id from `engine-list` (e.g. claude) or a full command line (e.g. 'codex --search'). Unvalidated: probe an unfamiliar engine's flags with `<cmd> --help` first. Omitted = the repo's default engine."}),title:()=>({name:"title",type:"string",placeholder:"T",description:"Human task title."}),prompt:(required,desc)=>({name:"prompt",type:"string",required,placeholder:"TEXT",description:required?`${desc} Required unless --prompt-file is given.`:desc}),promptFile:()=>({name:"prompt-file",type:"string",placeholder:"PATH",description:"Read the prompt from this file instead of --prompt (`-` = stdin). Use it whenever the text has backticks, $vars, or quotes you don't want the shell to touch. Exactly one of --prompt / --prompt-file."})},REPEAT_SEP="\x00";function setFlag(flags,key,value,repeatable){let prev=flags.get(key);flags.set(key,repeatable.has(key)&&prev!==void 0?`${prev}${REPEAT_SEP}${value}`:value)}function parseFlags(argv,booleanFlags=new Set,repeatableFlags=new Set){let flags=new Map,pretty=!1,help=!1;for(let i=0;i<argv.length;i++){let arg=argv[i];if(!arg.startsWith("--")&&arg!=="-h")throw new ApiError(`unexpected positional arg: ${arg}`,"BAD_FLAG");if(arg==="-h"){help=!0;continue}let eq=arg.indexOf("=");if(eq!==-1){let key2=arg.slice(2,eq),value=arg.slice(eq+1);if(key2==="envelope")continue;if(key2==="pretty")pretty=value!=="false"&&value!=="0";else if(key2==="help")help=value!=="false"&&value!=="0";else setFlag(flags,key2,value,repeatableFlags);continue}let key=arg.slice(2);if(key==="envelope")continue;if(key==="pretty"){pretty=!0;continue}if(key==="help"){help=!0;continue}if(booleanFlags.has(key)){let next2=argv[i+1];if(next2!==void 0&&parseBoolLiteral(next2)!==void 0)flags.set(key,next2),i+=1;else flags.set(key,"true");continue}let next=argv[i+1];if(next===void 0||next.startsWith("--"))throw new ApiError(`flag --${key} requires a value`,"BAD_FLAG");setFlag(flags,key,next,repeatableFlags),i+=1}return{flags,pretty,help}}function validateAgainstSpec(verb,flags){let known=new Set(verb.flags.map((f)=>f.name));for(let key of flags.keys())if(!known.has(key))throw new ApiError(`unknown flag --${key} for "${verb.name}"`,"BAD_FLAG",helpStep(verb.name));for(let f of verb.flags){let satisfied=flags.get(f.name)||f.name==="prompt"&&flags.get("prompt-file")||verb.name==="add"&&f.name==="repo"&&(flags.get("fork")||flags.get("no-worktree")||flags.get("isolate-in"));if(f.required&&!satisfied)throw new ApiError(`--${f.name} is required for "${verb.name}"`,"MISSING_FLAG",helpStep(verb.name));if(f.type==="enum"&&f.values){let raw=flags.get(f.name);if(raw!==void 0&&!f.values.includes(raw)){if(f.name==="vendor"&®isteredEngineIds().includes(raw))continue;throw new ApiError(`--${f.name} must be one of ${f.values.join(", ")}`,"BAD_FLAG",helpStep(verb.name))}}if(f.type==="int"){let raw=flags.get(f.name);if(raw!==void 0&&parsePositiveInt(raw)===void 0)throw new ApiError(`--${f.name} must be a positive integer`,"BAD_FLAG")}if(f.type==="uint"){let raw=flags.get(f.name);if(raw!==void 0&&parseNonNegativeInt(raw)===void 0)throw new ApiError(`--${f.name} must be a non-negative integer`,"BAD_FLAG")}}}class VerbArgs{verb;flags;caller;constructor(verb,flags,caller=cliCaller()){this.verb=verb;this.flags=flags;this.caller=caller}resolvePath(name,raw){let expanded=expandTilde(raw);if(isAbsolute(expanded))return expanded;if(this.caller.cwd===void 0)throw new ApiError(`--${name} must be an absolute path: this caller has no working directory`,"BAD_FLAG");return resolve(this.caller.cwd,expanded)}spec(name){let f=this.verb.flags.find((s)=>s.name===name);if(!f)throw Error(`internal: --${name} is not declared on verb "${this.verb.name}"`);return f}str(name){this.spec(name);let v=this.flags.get(name);return v&&v.length>0?v:void 0}present(name){return this.spec(name),this.flags.get(name)!==void 0}list(name){if(!this.spec(name).repeatable)throw Error(`internal: --${name} is not repeatable on verb "${this.verb.name}"`);let raw=this.flags.get(name);return raw===void 0?[]:raw.split(REPEAT_SEP).filter((v)=>v.length>0)}promptText(){if(this.promptMemo!==void 0)return this.promptMemo.value;let value=this.readPromptText();return this.promptMemo={value},value}promptMemo;readPromptText(){let inline=this.verb.flags.some((f)=>f.name==="prompt")?this.str("prompt"):void 0,file=this.str("prompt-file");if(inline!==void 0&&file!==void 0)throw new ApiError("pass --prompt or --prompt-file, not both","BAD_FLAG",helpStep(this.verb.name));if(file===void 0)return inline;if(file==="-"&&!this.caller.cli)throw new ApiError("--prompt-file - reads stdin, which this caller cannot send; pass --prompt","BAD_FLAG");let text=readFileSync(file==="-"?0:this.resolvePath("prompt-file",file),"utf8");if(text.trim().length===0)throw new ApiError(`--prompt-file ${file} is empty`,"BAD_FLAG");return text}require(name){let v=this.str(name);if(v===void 0)throw new ApiError(`--${name} is required`,"MISSING_FLAG");return v}enumOf(name){let f=this.spec(name),v=this.str(name);if(v===void 0)return;if(f.values&&!f.values.includes(v))throw new ApiError(`--${name} must be one of ${f.values.join(", ")}`,"BAD_FLAG",helpStep(this.verb.name));return v}requireEnum(name){return this.require(name),this.enumOf(name)}vendor(){let value=this.str("vendor");if(value===void 0)return;let builtins=this.spec("vendor").values??ALL_VENDORS;if(builtins.includes(value))return value;if(registeredEngineIds().includes(value))return value;throw new ApiError(`--vendor must be a built-in (${builtins.join(", ")}) or a registered engine id \u2014 see \`engine-list\``,"BAD_FLAG",helpStep(this.verb.name))}bool(name){this.spec(name);let raw=this.str(name);if(raw===void 0)return;let value=parseBoolLiteral(raw);if(value===void 0)throw new ApiError(`--${name} must be a boolean (true/false)`,"BAD_FLAG");return value}int(name){this.spec(name);let raw=this.str(name);if(raw===void 0)return;let n=parsePositiveInt(raw);if(n===void 0)throw new ApiError(`--${name} must be a positive integer`,"BAD_FLAG");return n}nonNegativeInt(name){this.spec(name);let raw=this.str(name);if(raw===void 0)return;let n=parseNonNegativeInt(raw);if(n===void 0)throw new ApiError(`--${name} must be a non-negative integer`,"BAD_FLAG");return n}path(name){let v=this.str(name);return v===void 0?void 0:this.resolvePath(name,v)}requirePath(name){return this.resolvePath(name,this.require(name))}requireRepo(name){return this.repoPath(name,this.require(name))}repoPath(name,raw){return isRemoteRepoKey(raw)?raw:this.resolvePath(name,raw)}}function parseAgentsSpec(spec){let out=[];for(let part of spec.split(",")){let trimmed=part.trim();if(!trimmed)continue;let colon=trimmed.indexOf(":");if(colon===-1)throw new ApiError(`--agents entry "${trimmed}" must be engine:count`,"BAD_FLAG",FANOUT_STEP);let vendor=trimmed.slice(0,colon);if(!ALL_VENDORS.includes(vendor)&&!registeredEngineIds().includes(vendor))throw new ApiError(`--agents engine "${vendor}" must be a built-in (${ALL_VENDORS.join(", ")}) or a registered engine id \u2014 see \`engine-list\``,"BAD_FLAG",FANOUT_STEP);let count=parsePositiveInt(trimmed.slice(colon+1));if(count===void 0)throw new ApiError(`--agents count for "${vendor}" must be a positive integer`,"BAD_FLAG",FANOUT_STEP);if(out.length+count>FANOUT_CAP)throw new ApiError(`--agents requests ${out.length+count} agents, exceeds the cap of ${FANOUT_CAP}`,"BAD_FLAG",FANOUT_STEP);for(let i=0;i<count;i++)out.push(vendor)}if(out.length===0)throw new ApiError('--agents specified no agents (e.g. "claude:2,codex:1")',"BAD_FLAG",FANOUT_STEP);return out}function buildCountPlan(count,vendor){if(count>FANOUT_CAP)throw new ApiError(`--count ${count} exceeds the parallel cap of ${FANOUT_CAP} \u2014 spawn in batches`,"BAD_FLAG",FANOUT_STEP);return Array(count).fill(vendor)}function daemonOf(ctx){if(!ctx.client)throw new ApiError("daemon required","BAD_DAEMON");return ctx.client}async function repoFilter(runtime,repoFlag,repos){let target=await runtime.resolveRepoRoot(repoFlag);if(!await runtime.isUsableRepo(target))throw new ApiError(`--repo ${repoFlag} is not a readable git repository (resolved to ${target}) \u2014 the project may have moved or been deleted; \`rove api list\` still shows its tasks`,"REPO_UNRESOLVABLE");let resolved=new Map,unresolvable=new Set;for(let repo of new Set(repos)){let root=await runtime.resolveRepoRoot(repo);if(resolved.set(repo,root),!samePath(root,target)&&!await runtime.isUsableRepo(root))unresolvable.add(repo)}return{target,matches:(repo)=>samePath(resolved.get(repo),target),unresolvableRepos:[...unresolvable].sort()}}async function simpleRpc(ctx,name,payload){let request=name;return daemonOf(ctx).request(request,payload)}async function handlePtyList(){let[{RoveDaemonClient},{defaultPtyHostSocketPath}]=await Promise.all([import("./chunk-fq2pefc5.js"),import("./chunk-1qvrn21x.js")]),client=new RoveDaemonClient(defaultPtyHostSocketPath());try{return await client.connect(),await client.request("pty.list",{})}catch{return{sessions:null}}finally{client.close()}}function readJsonBody(source){let raw=readFileSync2(source==="-"?0:resolve2(process.cwd(),expandTilde(source)),"utf8"),parsed;try{parsed=JSON.parse(raw)}catch{throw new ApiError(`--json ${source} is not valid JSON`,"BAD_FLAG")}if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))throw new ApiError("--json must be an object: {delivery, outcome, summary, evidence?, next?}","BAD_FLAG");let body=parsed,evidence=body.evidence;if(evidence!==void 0&&(!Array.isArray(evidence)||evidence.some((e)=>typeof e!=="string")))throw new ApiError("evidence must be an array of strings","BAD_FLAG");for(let key of["delivery","outcome","summary","next"])if(body[key]!==void 0&&typeof body[key]!=="string")throw new ApiError(`${key} must be a string`,"BAD_FLAG");return body}var FIELD_FLAGS=["delivery","outcome","summary","next"];function readBody(ctx){let json=ctx.args.str("json"),evidence=ctx.args.list("evidence");if(json===void 0)return{delivery:ctx.args.str("delivery"),outcome:ctx.args.str("outcome"),summary:ctx.args.str("summary"),evidence,next:ctx.args.str("next")};if(FIELD_FLAGS.some((f)=>ctx.args.str(f)!==void 0)||evidence.length>0)throw new ApiError("pass --json OR the individual flags, not both","BAD_FLAG");return readJsonBody(json)}async function report(ctx){let body=readBody(ctx);if(!body.delivery)throw new ApiError("--delivery is required","MISSING_FLAG");if(!body.outcome||!DELIVERY_OUTCOMES.includes(body.outcome))throw new ApiError(`--outcome must be one of ${DELIVERY_OUTCOMES.join("|")}`,"MISSING_FLAG");if(!body.summary?.trim())throw new ApiError("--summary is required","MISSING_FLAG");if(body.summary.length>DELIVERY_SUMMARY_MAX_CHARS)throw new ApiError(`summary is ${body.summary.length} characters; the cap is ${DELIVERY_SUMMARY_MAX_CHARS}`,"RESPONSE_TOO_LARGE",{hint:"Summarize: lead with the conclusion, put the detail in --evidence (commits, PR urls, paths)."});let res=await simpleRpc(ctx,"delivery.report",{deliveryId:body.delivery,outcome:body.outcome,summary:body.summary,...body.evidence?.length?{evidence:body.evidence}:{},...body.next?{next:body.next}:{}});if(res.delivery===null)throw new ApiError(`no delivery ${body.delivery}`,"DELIVERY_NOT_FOUND",{hint:"Copy the id from the [ROVE] report line of the prompt you were given; `deliveries --task-id <id>` lists them."});return res}var REPORT_VERB={name:"report",group:"drive",summary:`Close the report a delivered prompt asked for. Run it as the LAST step of the turn, before you stop: a turn that ends without it is flagged \`report_missing\` in the owner's Inbox. --delivery is the id in the prompt's [ROVE] / [ROVE ROUTINE] line. Re-reporting replaces the earlier report; a late report on a flagged delivery clears the flag. --summary \u2264 ${DELIVERY_SUMMARY_MAX_CHARS} chars; put commits, PR urls, test results and paths in repeatable --evidence, and what the next tick should do in --next. Use --json - (stdin) for text with quotes or backticks.`,flags:[{name:"delivery",type:"string",placeholder:"ID",description:"Delivery id, e.g. d-41."},{name:"outcome",type:"enum",values:DELIVERY_OUTCOMES,placeholder:"O",description:"done = finished what was asked; partial = some of it; blocked = needs the owner or an external fix; failed = tried and could not."},{name:"summary",type:"string",placeholder:"TEXT",description:"What was done (or why not)."},{name:"evidence",type:"string",placeholder:"X",repeatable:!0,description:"A commit, PR url, test command + result, or file path. Repeat the flag for several."},{name:"next",type:"string",placeholder:"TEXT",description:"What the next tick should do."},{name:"json",type:"string",placeholder:"PATH",description:"Read {delivery, outcome, summary, evidence?, next?} as JSON from this file (`-` = stdin) instead of the flags."}],handler:report},DELIVERIES_VERB={name:"deliveries",group:"read",summary:`A task's armed deliveries, newest first (newest ${MAX_DELIVERIES_PER_TASK} are kept): status awaiting|reported|missing|skipped, the report (outcome, summary, evidence, next) and, for missing, why (cause turn-complete|turn-failed|engine-dead|stalled|interrupted|session-end|rate-limited + note; rate-limited raises no Inbox row and does not block) plus dismissedAt once the owner dismissed it (a missing row blocks \`send --if-runnable\` and routine ticks until a late report or that dismissal). A skipped row is a \`send --if-runnable\` tick should-run refused: \`skipped\` is the verdict {reason, detail?, until?, gateIds?}, \`repeats\` how many identical refusals (same tab, same reason) the one row stands for. The per-tick log a loop prompt should read instead of a growing MEMO file.`,flags:[F.taskId(!0),{name:"limit",type:"int",placeholder:"N",description:"At most N entries (default: all retained)."}],handler:async(ctx)=>simpleRpc(ctx,"delivery.list",{taskId:ctx.args.require("task-id"),...ctx.args.int("limit")!==void 0?{limit:ctx.args.int("limit")}:{}})};async function listAllEnginePresets(){let presets=await enginePresetsInList(),byProtocol=new Map,modelsOf=(protocol)=>{let pending=byProtocol.get(protocol);if(!pending){let list=engineEntry(protocol).listModels;pending=list?list().catch(()=>null):Promise.resolve(null),byProtocol.set(protocol,pending)}return pending};return Promise.all(presets.map(async(preset)=>({...preset,models:await modelsOf(preset.protocol)})))}async function enginePresetsInList(){ensurePluginEnginesLoaded();let presets=[...listEnginePresets()],seen=new Set(presets.map((p)=>p.id));for(let id of await installedEngineIds())if(!seen.has(id))presets.push(describePreset(id));return presets}async function engineListIds(){return(await enginePresetsInList()).map((p)=>p.id)}var ENGINE_LIST_VERB={name:"engine-list",group:"discover",summary:`List every engine Rove can launch \u2014 built-ins, registered presets, the shipped contrib engines whose CLI is on PATH (${CONTRIB_ENGINE_IDS.join(", ")}), and engines contributed by enabled plugins \u2014 each with its RAW launch command, exactly as it runs. Copy one into \`add --command\` / \`send --tab new --command\` verbatim, or edit its flags first. \`protocol\` is the adapter Rove speaks to it (history, trust, delivery); \`generic\` = none, which still runs fine but loses transcript reads. \`models\` is what the engine can name for \`--model\` (suggestions, not a closed set); null = Rove cannot list them for this engine. Returns { engines }.`,flags:[],offline:!0,handler:async()=>({engines:await listAllEnginePresets()})};function taskEngine(task){let command=task.command?.trim();if(command){let resolved=resolveCommandProtocol(command);if(resolved!==GENERIC_PROTOCOL)return resolved}return sessionProtocol(coerceVendorId(task.vendor))}function assertEngineAcceptsEffort(engine,level,recover){let levels=engineEntry(engine).effortLevels??[];if(levels.length===0)throw new ApiError(`engine ${engine} declares no reasoning effort levels`,"BAD_EFFORT",{engine,hint:`Only engines with declared reasoning levels accept one (${vendorsWithEffortLevels().join(", ")} today). Check the task's engine with \`get-task\`.`,nextCommandArgs:[...recover]});if(!levels.includes(level))throw new ApiError(`engine ${engine} does not accept effort level ${JSON.stringify(level)} \u2014 it declares ${levels.join(", ")}`,"BAD_EFFORT",{engine,levels,hint:`Pass one of: ${levels.join(", ")}.`,nextCommandArgs:[...recover]})}function assertEngineAcceptsModel(engine,model,recover){if(engineEntry(engine).modelArgv)return;throw new ApiError(`engine ${engine} declares no model flag \u2014 it does not accept a model`,"BAD_MODEL",{engine,hint:"Only engines that declare a model flag accept one (claude, codex, kimi, pi, omp today); `engine-list` shows `models` per engine.",nextCommandArgs:[...recover]})}function vendorToRecord(task,engine){let recorded=coerceVendorId(task.vendor);return sessionProtocol(recorded)===engine?recorded:engine}async function readRunnability(daemon,taskId){try{return await daemon.request("task.runnability",{taskId})}catch{return}}async function shouldRun(ctx){let tab=ctx.args.str("tab");if(tab&&tab!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(tab))throw new ApiError(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(tab)})`,"BAD_TAB");let verdict=await daemonOf(ctx).request("task.runnability",{taskId:ctx.args.require("task-id"),...tab?{tabId:tab}:{}});if(!verdict.run)throw new ApiError(`skip: ${verdict.reason}`,"SKIPPED",{...verdict});return verdict}var SHOULD_RUN_VERB={name:"should-run",group:"read",summary:`Would a tick sent to this task be used? Prints the verdict {run:true} or {run:false, reason, detail?, until?, gateIds?} and exits 0 on run, ${SHOULD_RUN_SKIP_EXIT_CODE} on skip (the verdict is still on stdout). reason, first match wins: ${SKIP_REASONS.join(" | ")}. \`awaiting-owner\` = an open gate (answer or withdraw it), \`report-missing\` = the last delivery ended unreported (late \`report\`, or dismiss its Inbox row), \`quota\` clears itself at \`until\`, \`engine-error\` / \`engine-dead\` clear on the engine's next turn or a restart, \`awaiting-permission\` = the engine waits on an approval, \`busy\` = a turn is running or the last delivery still awaits its report. A task whose only gate is answered-but-undelivered is runnable: the next tick carries the answer. Without --tab the whole task is judged and a dead engine is not a skip (\`send\` revives it); --tab tab-N judges that tab and a dead engine is \`engine-dead\`; --tab new judges only task-level state. To check and send in one step use \`send --if-runnable\`.`,flags:[F.taskId(!0),{name:"tab",type:"string",required:!1,placeholder:"TAB",description:'Judge exactly this tab (e.g. tab-2), or "new" for a tab about to be created. Omitted = the whole task.'}],handler:shouldRun};async function attentionDismiss(ctx){let delivery=ctx.args.require("delivery");if((await daemonOf(ctx).request("attention.dismiss",{deliveryId:delivery})).found===!1)throw new ApiError(`no delivery ${delivery}`,"DELIVERY_NOT_FOUND",{hint:"`deliveries --task-id <id>` lists a task's delivery ids; the Inbox row names it as d-N."});return{ok:!0,delivery,cleared:!0}}var ATTENTION_DISMISS_VERB={name:"attention-dismiss",group:"drive",summary:'Dismiss a `report_missing` Inbox row by its delivery id (d-N): the owner\'s deliberate "seen, carry on" for a tick that ended without a report. It unblocks `should-run` for the task. Opening or visiting the row never does this, and a late `report` clears it on its own. Idempotent; an unknown id is DELIVERY_NOT_FOUND.',flags:[{name:"delivery",type:"string",required:!0,placeholder:"ID",description:"Delivery id, e.g. d-41."}],handler:attentionDismiss};import path from"path";var TASK_STATUSES=["backlog","in_progress","in_review","done","canceled","error"];var TASK_FIELDS=["title","branch","parent","project","command","model","effort","pinned","kept","require-report","auto-fix-ci","status"],REPORT_FLAGS=["report-branch","report-pr","report-summary"];async function renameTab(ctx,taskId,tabId){let title=ctx.args.str("title"),others=[...TASK_FIELDS,...REPORT_FLAGS].filter((f)=>f!=="title"&&ctx.args.str(f)!==void 0);if(title===void 0||others.length>0)throw new ApiError("--tab only renames a tab: pass --title and no other field","BAD_FLAG",{hint:"Update the task's own fields in a separate call without --tab."});let daemon=daemonOf(ctx);if(!await renameTabsSnapshot(daemon,taskId,tabId,title))throw new ApiError(`task ${taskId} has no tab ${tabId}`,"TAB_NOT_FOUND",{hint:"`get-task` lists the addressable tab ids in .tabs[].id",nextCommandArgs:["api","get-task","--task-id",taskId]});let reply=await daemon.request("terminalTab.rename",{taskId,tabId,title});return{ok:!0,taskId,tabId,title,renamed:!0,clients:reply.clients??0}}async function resolveTarget(ctx,verb="update"){let explicit=ctx.args.str("task-id");if(explicit)return explicit;let self=await ownSession(daemonOf(ctx));if(!self)throw new ApiError("no --task-id given and the caller is not a verified rove session \u2014 pass --task-id ID","MISSING_TARGET",helpStep(verb));return self.taskId}async function projectRoot(ctx){let raw=ctx.args.str("project")?.trim();if(raw===void 0)return;if(raw==="")throw new ApiError("--project cannot be empty \u2014 pass the repo's path","BAD_FLAG");let root=await ctx.runtime.resolveRepoRoot(path.resolve(ctx.caller.cwd??process.cwd(),raw));if(!await ctx.runtime.isUsableRepo(root))throw new ApiError(`--project ${raw} is not inside a git repository`,"NOT_A_GIT_REPO",{hint:"clone or `git init` the project first, then pass its path"});return root}var NO_PARENT="none";async function reparentGroup(ctx,groupId){let parent=ctx.args.str("parent"),stray=["task-id","tab",...TASK_FIELDS.filter((f)=>f!=="parent"),...REPORT_FLAGS].filter((f)=>ctx.args.str(f)!==void 0);if(parent===void 0||parent===""||stray.length>0)throw new ApiError(`--group moves a whole fan-out round and takes only --parent ID (or \`none\`)${stray.length>0?` \u2014 drop ${stray.map((f)=>`--${f}`).join(", ")}`:""}`,"BAD_FLAG",helpStep("update"));let daemon=daemonOf(ctx),{tasks}=await daemon.request("task.list"),members=tasks.filter((t)=>t.groupId===groupId);if(members.length===0)throw new ApiError(`no tasks in group ${groupId}`,"TASK_NOT_FOUND",{hint:"the groupId is the one `add --count` returned; any surviving sibling's `.groupId` in `list` recovers it",nextCommandArgs:["api","list"]});if(members.some((t)=>t.id===parent))throw new ApiError(`${parent} is itself a member of group ${groupId} \u2014 a round cannot move under one of its own`,"PARENT_IN_GROUP",{hint:"pick a parent outside the round, or move the members one by one with --task-id"});let parentTaskId=parent===NO_PARENT?null:parent,replyTab=parentTaskId===null?void 0:await replyTabOf(ctx.runtime,daemon,parentTaskId),results=[],failures=0;for(let task of members)try{let moved=await simpleRpc(ctx,"task.setParent",{taskId:task.id,parentTaskId,...replyTab?{replyTab}:{}});results.push({taskId:task.id,status:"moved",...moved})}catch(err){failures++;let message=errorMessage(err),coded=err instanceof ApiError?{code:err.code,rest:message}:splitDaemonCode(message);results.push({taskId:task.id,status:"failed",error:coded?.rest??message,...coded?{code:coded.code}:{}})}return{ok:failures===0,groupId,count:members.length,failures,results}}async function updateTask(ctx){let group=ctx.args.str("group");if(group!==void 0)return reparentGroup(ctx,group);let tabId=ctx.args.str("tab"),taskId=tabId!==void 0?ctx.args.require("task-id"):await resolveTarget(ctx);if(tabId!==void 0)return renameTab(ctx,taskId,tabId);let title=ctx.args.str("title"),branch=ctx.args.str("branch"),parent=ctx.args.str("parent"),command=ctx.args.str("command")?.trim(),model=ctx.args.str("model")?.trim(),effort=ctx.args.str("effort")?.trim(),pinned=ctx.args.bool("pinned"),kept=ctx.args.bool("kept"),requireReport=ctx.args.enumOf("require-report"),autoFixCi=ctx.args.enumOf("auto-fix-ci"),status=ctx.args.enumOf("status"),report2={reportBranch:ctx.args.str("report-branch"),reportPr:ctx.args.int("report-pr"),reportSummary:ctx.args.str("report-summary")},reporting=Object.values(report2).some((v)=>v!==void 0);if(TASK_FIELDS.every((f)=>ctx.args.str(f)===void 0)&&!reporting)throw new ApiError(`nothing to update \u2014 pass at least one of ${TASK_FIELDS.map((f)=>`--${f}`).join(", ")}`,"BAD_FLAG",{nextCommandArgs:["api","update","--help"]});if(reporting&&status===void 0)throw new ApiError("--report-* is recorded with a status: pass --status too","BAD_FLAG",{hint:"A worker reporting delivery usually passes --status in_review (or done)."});if(command==="")throw new ApiError("--command cannot be empty","BAD_FLAG");if(parent==="")throw new ApiError("--parent cannot be empty \u2014 pass a task id, or `none` for top level","BAD_FLAG");let daemon=daemonOf(ctx),protocol=command?resolveCommandProtocol(command):void 0,project=await projectRoot(ctx),task,engine;if(model!==void 0||effort!==void 0){task=(await daemon.request("task.get",{taskId})).task,engine=taskEngine(command?{...task,command}:task);let recover=["api","get-task","--task-id",taskId];if(model!==void 0)assertEngineAcceptsModel(engine,model,recover);if(effort!==void 0)assertEngineAcceptsEffort(engine,effort,recover)}let applied=[],step=async(fields,method,payload)=>{let reply;try{reply=await simpleRpc(ctx,method,{taskId,...payload})}catch(err){if(applied.length===0)throw err;let message=err instanceof Error?err.message:String(err),code=err instanceof ApiError?err.code:"PARTIAL_UPDATE";throw new ApiError(`--${fields.join("/--")} failed after ${applied.join(", ")} applied: ${message}`,code,{applied:[...applied],failed:fields})}return applied.push(...fields),reply},reparented;if(parent!==void 0){let parentTaskId=parent===NO_PARENT?null:parent,replyTab=parentTaskId===null?void 0:await replyTabOf(ctx.runtime,daemon,parentTaskId);reparented=await step(["parent"],"task.setParent",{parentTaskId,...replyTab?{replyTab}:{}})}let regrouped;if(project!==void 0)regrouped=await step(["project"],"task.moveToProject",{repo:project});if(branch!==void 0)await step(["branch"],"task.setBranch",{branch});if(command)await step(["command"],"task.setCommand",{command,vendor:protocol});if(task&&engine){let recorded=vendorToRecord(protocol?{...task,vendor:protocol}:task,engine),fields=[...model!==void 0?["model"]:[],...effort!==void 0?["effort"]:[]];await step(fields,"task.setVendor",{vendor:recorded,model,effort})}if(title!==void 0)await step(["title"],"task.rename",{title});if(pinned!==void 0)await step(["pinned"],"task.pin",{pinned});if(kept!==void 0)await step(["kept"],"task.keep",{kept});if(requireReport!==void 0)await step(["require-report"],"task.requireReport",{required:requireReport==="on"});if(autoFixCi!==void 0)await step(["auto-fix-ci"],"task.autoFixCi",{enabled:autoFixCi==="on"});if(status!==void 0)await step(["status"],"task.status",{status,...report2});return{ok:!0,taskId,updated:applied,...reparented?{parent:reparented}:{},...regrouped?{project:{repo:regrouped.repo,moved:regrouped.moved,note:"regrouped only \u2014 the PTYs, cwd, worktree and branch stay where they were"}}:{},...command?{command,protocol,...protocol===GENERIC_PROTOCOL?{generic:!0}:{}}:{},...engine?{engine}:{}}}var EDIT_VERBS=[{name:"update",group:"edit",summary:"Change a task's metadata \u2014 any combination of title, branch (git branch -m if materialized, else recorded), parent, engine --command / --model / --effort (take effect on the next session rebuild), pin, and status + worker report \u2014 in one call. The flags are checked before anything is written; then they apply in order parent \u2192 branch \u2192 engine \u2192 title/pin/status, and a refusal mid-way names what already applied (`applied`). --parent ID re-parents the task without touching its engine, tabs, worktree or branch: the stored parent is ID's top-level ancestor (children never nest, as with `add` from a child; the task's own children come along, listed in `.parent.moved`) and the task's reply address becomes ID itself, so its bare `send` reaches ID (the caller's own tab when run from inside ID, else ID's live engine tab, else tab-1). `--parent none` makes the task top level and drops a reply address that pointed into its old tree. A parent must live on the same machine as the task. Archiving the stored parent, or `delete --cascade` on it, takes the task along. --group G --parent ID moves a whole fan-out round instead and takes nothing else. With --tab, renames that Terminal Tab instead (the API twin of the TUI's f2) and takes only --title. The status is a cosmetic LABEL: `--status canceled` closes, stops and cleans up nothing \u2014 `delete` ends a task. The --report-* fields record what the WORKER CLAIMS it delivered (`.report` on `get-task` / `collect`), deliberately apart from `.prStatus`, which the daemon polled from the forge; they merge onto any previous report and need --status. Returns { updated } \u2014 the fields written, in order.",flags:[{...F.taskId(!1),description:"Target task id (from `list` / `add`). Default: the calling session's own task, from the verified $ROVE_TASK_ID (an unverifiable env is MISSING_TARGET, never a guess)."},{name:"title",type:"string",placeholder:"T",description:"New task title (or, with --tab, the tab's name)."},{name:"tab",type:"string",placeholder:"TAB",description:"Rename this Terminal Tab (id from `get-task` .tabs[].id, e.g. tab-2) instead of the task; needs --task-id, and only --title may accompany it. TAB_NOT_FOUND when the task's snapshot names no such tab."},{name:"branch",type:"string",placeholder:"B",description:"New branch name."},{name:"parent",type:"string",placeholder:"ID|none",description:"Move the task under this task (its engine, tabs, worktree and branch stay as they are), or `none` to make it top level. Refusals: PARENT_NOT_FOUND, PARENT_IS_SELF, PARENT_CYCLE, TASK_NOT_MOVABLE, REMOTE_PARENT_UNSUPPORTED."},{name:"project",type:"string",placeholder:"PATH",description:"Move a top-level task (and its children) under the project at PATH (relative paths resolve against $PWD; any directory inside the repo names its main checkout), which becomes a project if it was not one. Only the grouping changes: the live session, tabs, cwd, worktree and branch stay exactly where they are, so a running engine keeps its conversation. Moving a worktree task back to the repo that cut it clears the link. Refusals: NOT_A_GIT_REPO, SAME_PROJECT, TASK_NOT_MOVABLE (a project's main task, a routine session or a multi-repo task), CHILD_NOT_MOVABLE (move its parent; children follow), REMOTE_MOVE_UNSUPPORTED."},{name:"group",type:"string",placeholder:"GROUPID",description:"With --parent: move every task of one fan-out round (the `groupId` that `add --count` returns). Takes nothing but --parent; a member's refusal is recorded in `results`, and a parent inside the round is PARENT_IN_GROUP."},{...F.command(),description:"New engine launch command \u2014 an engine id from `engine-list` or a full command line. The protocol Rove speaks to it is derived from it; the result reports which (`generic: true` when the command names no engine Rove knows)."},{name:"model",type:"string",placeholder:"MODEL",description:"Pin a model, passed to the engine VERBATIM in its own spelling (claude alias or id, codex slug, pi/omp pattern); `engine-list` .models are suggestions, not a closed list. BAD_MODEL when the engine declares no model flag."},{name:"effort",type:"string",placeholder:"LEVEL",description:"Reasoning effort level the task's engine declares (codex: none/low/medium/high/xhigh/max; pi, omp: off/minimal/low/medium/high/xhigh/max; claude: low/medium/high/xhigh/max). BAD_EFFORT names the accepted levels."},{name:"pinned",type:"bool",placeholder:"BOOL",description:"true pins the task to the top of the sidebar, false unpins."},{name:"kept",type:"bool",placeholder:"BOOL",description:"true marks the task as the attempt kept from a parallel round (`add --count` / `--agents`); false clears the mark. A flag only: it archives nothing, and other attempts of the round are untouched."},{name:"require-report",type:"enum",values:["on","off"],description:"on: every later `send` to this task arms a delivery the agent must close with `report --delivery <id>` (a turn that ends without one raises a `report_missing` Inbox row); off: back to plain sends."},{name:"auto-fix-ci",type:"enum",values:["on","off"],description:"on: when this task's PR checks go red on a new head sha and its engine is at rest, the daemon types the fix-CI prompt (with the failing logs) into the engine, at most once per sha and 3 times in all, then stops and raises an Inbox row; the count starts over when the checks pass. Never interrupts a running turn. off: stop and forget the count."},{name:"status",type:"enum",values:TASK_STATUSES,description:"New lifecycle label (cosmetic \u2014 see summary)."},{name:"report-branch",type:"string",placeholder:"B",description:"The branch the worker says holds the work (a CLAIM \u2014 `.branch` is the task's actual branch)."},{name:"report-pr",type:"int",placeholder:"N",description:"The PR number the worker says it opened (a CLAIM \u2014 `.prStatus.number` is what the daemon read from the forge)."},{name:"report-summary",type:"string",placeholder:"TEXT",description:"One line of what was delivered."}],handler:updateTask}];async function todo(ctx){let{args}=ctx,taskId=await resolveTarget(ctx,"todo"),add=args.str("add"),check=args.str("check"),uncheck=args.str("uncheck"),edit=args.str("edit"),text=args.str("text"),remove=args.str("remove"),notes=args.bool("clear-notes")===!0?"":args.str("notes");if(edit===void 0!==(text===void 0))throw new ApiError("--edit ID and --text T go together","BAD_FLAG");let ops=[...add!==void 0?[{op:"add",text:add}]:[],...check!==void 0?[{op:"check",id:check,done:!0}]:[],...uncheck!==void 0?[{op:"check",id:uncheck,done:!1}]:[],...edit!==void 0&&text!==void 0?[{op:"edit",id:edit,text}]:[],...remove!==void 0?[{op:"remove",id:remove}]:[]],after=await simpleRpc(ctx,"task.notes",{taskId,...notes!==void 0?{notes}:{},...ops.length>0?{ops}:{}}),count=todoCount(after.todos);return{ok:!0,taskId,notes:after.notes??"",todos:after.todos,done:count?.done??0,total:count?.total??0}}var TODO_VERB={name:"todo",group:"edit",summary:"Read or change a task's notes and checklist \u2014 the owner's own review list (shown in the web Files panel's Notes tab and as `done/total` on the task row). With no flag it lists them. Flags combine in one call and apply together, in this order: --add, --check, --uncheck, --edit/--text, --remove; one refused op (TODO_NOT_FOUND, TODO_EMPTY, TODO_TOO_LONG, TODO_LIMIT) changes nothing. A todo id is `t<N>` as listed. Default target: the calling session's own task. Returns { ok, taskId, notes, todos: [{ id, text, done }], done, total }.",flags:[{...F.taskId(!1),description:"Target task id (from `list` / `add`). Default: the calling session's own task."},{name:"add",type:"string",placeholder:"TEXT",description:"Add an unchecked todo (one line, up to 500 characters; 100 per task)."},{name:"check",type:"string",placeholder:"ID",description:"Mark todo ID done."},{name:"uncheck",type:"string",placeholder:"ID",description:"Mark todo ID not done."},{name:"edit",type:"string",placeholder:"ID",description:"Change todo ID's text to --text."},{name:"text",type:"string",placeholder:"TEXT",description:"The new text for --edit."},{name:"remove",type:"string",placeholder:"ID",description:"Delete todo ID."},{name:"notes",type:"string",placeholder:"TEXT",description:"Replace the task's free-text notes (up to 20000 characters); Use --clear-notes to empty them."},{name:"clear-notes",type:"bool",description:"Empty the free-text notes."}],handler:todo};var API_SCHEMA_VERSION=ROVE_API_VERSION,GLOBAL_FLAGS=[{name:"pretty",type:"bool",description:"Pretty-print stdout JSON."},{name:"help",type:"bool",description:"Show usage for the verb and exit."},{name:"envelope",type:"bool",description:"Print every outcome as one { apiVersion, ok, result | error } on stdout \u2014 what the daemon's and the bridge's api.invoke return."},{name:"machine",type:"string",placeholder:"ALIAS",description:"Run the verb in that registered machine's daemon (`rove machine list`); paths are paths there. A --task-id on another machine goes there without it."}];function displayValues(f){if(!f.values)return;if(f.name!=="vendor")return f.values;let registered=registeredEngineIds().filter((id)=>!f.values.includes(id));return registered.length>0?[...f.values,...registered]:f.values}function flagJson(f){let values=displayValues(f);return{name:f.name,type:f.type,required:f.required??!1,...values?{values}:{},...f.default!==void 0?{default:f.default}:{},...f.placeholder?{placeholder:f.placeholder}:{},...f.repeatable?{repeatable:!0}:{},description:f.description}}function installedVerbs(){return VERBS.filter(verbInstalled)}function installedGroups(){return Object.fromEntries(Object.entries(VERB_GROUPS).filter(([group])=>{let mod=GROUP_MOD[group];return mod===void 0||isBuiltinModInstalled(mod)}))}function verbSchema(v){return{name:v.name,group:v.group,summary:v.summary,offline:v.offline??!1,cliOnly:v.cliOnly??!1,flags:v.flags.map(flagJson)}}function schemaIndex(){let cliName=ROVE_PRODUCT_NAME;return{apiVersion:API_SCHEMA_VERSION,roveVersion:CURRENT_VERSION,hint:`Compact index. Drill into ONE verb: \`${cliName} api schema --verb <name>\` (or \`${cliName} api <verb> --help\`). One group: \`--group <g>\`. Whole spec: \`--all\`.`,groups:installedGroups(),verbs:installedVerbs().map((v)=>({name:v.name,group:v.group,summary:v.summary})),globalFlags:GLOBAL_FLAGS,aliases:VERB_ALIASES}}function groupSchema(group){let verbs=VERBS.filter((v)=>v.group===group);if(verbs[0])requireVerbInstalled(verbs[0]);if(verbs.length===0)throw new ApiError(`unknown group: ${group}. Groups: ${Object.keys(installedGroups()).join(", ")}`,"BAD_VERB",{hint:"that group does not exist \u2014 the compact index lists every group and the verbs in it",nextCommandArgs:["api","schema"]});return{group,verbs:verbs.map((v)=>({name:v.name,summary:v.summary}))}}function fullSchema(){return{apiVersion:API_SCHEMA_VERSION,roveVersion:CURRENT_VERSION,output:{success:"one JSON object on stdout, newline-terminated, exit 0",error:'{"error":{"message","code"}} on stderr, exit != 0',pretty:"--pretty indents stdout JSON",envelope:'--envelope prints {"apiVersion","ok","result"} or {"apiVersion","ok","error"} on stdout instead, exit codes unchanged'},transports:{cli:"rove api <verb> --flag value",daemon:'socket request "api.invoke" {verb, params, machine?} \u2192 the envelope; params are keyed by flag name',bridge:'WebSocket op "api.invoke" {verb, params, machine?} \u2192 result, or the full error object'},globalFlags:GLOBAL_FLAGS,aliases:VERB_ALIASES,groups:installedGroups(),verbs:installedVerbs().map(verbSchema)}}function flagSignature(verb){return verb.flags.map((f)=>{let meta=f.type==="enum"&&f.values?displayValues(f).join("|"):f.placeholder??(f.type==="bool"?"":"X"),core=meta?`--${f.name} ${meta}`:`--${f.name}`;return f.required?core:`[${core}]`}).join(" ")}function verbHelp(verb){let lines=[`${ROVE_PRODUCT_NAME} api ${verb.name} ${flagSignature(verb)}`.trimEnd(),"",verb.summary,""],alias=Object.entries(VERB_ALIASES).find(([,canon])=>canon===verb.name)?.[0];if(alias)lines.push(`Alias: ${alias}`,"");if(verb.flags.length>0){lines.push("Flags:");for(let f of verb.flags){let req=f.required?" (required)":f.repeatable?" (repeatable)":"",def=f.default!==void 0?` [default: ${f.default}]`:"",vals=f.type==="enum"&&f.values?` {${displayValues(f).join("|")}}`:"";lines.push(` --${f.name}${vals}${req}${def} ${f.description}`)}lines.push("")}return lines.push("Global: [--pretty] [--help] [--envelope] [--machine ALIAS]"),lines.join(`
|
|
3
3
|
`)}function apiUsage(){let cliName=ROVE_PRODUCT_NAME,rows=installedVerbs().map((v)=>` ${v.name.padEnd(18)} ${v.summary}`);return[`usage: ${cliName} api <verb> [flags] [--pretty] [--help]`,"",`Explore the full surface (names, flags, types) with: ${cliName} api schema`,"","verbs:",...rows,"","Output is one JSON object on stdout (exit 0); errors are JSON on stderr (exit != 0)."].join(`
|
|
4
4
|
`)}var DEFAULT_PAGE_MESSAGES=40,MAX_PAGE_MESSAGES=50,PAGE_BYTE_BUDGET=131072,STRING_CLIP_CHARS=16384,DEFAULT_TAIL_LINES=40,TERMINAL_TAIL_LINES=200,TERMINAL_TAIL_BYTES=65536;function encodeCursor(cursor){return Buffer.from(JSON.stringify(cursor),"utf8").toString("base64url")}function decodeCursor(raw,taskId){let parsed;try{parsed=JSON.parse(Buffer.from(raw,"base64url").toString("utf8"))}catch{throw new ApiError("invalid cursor (not a read-output cursor)","CURSOR_INVALID")}let c=parsed;if(!(c!==null&&typeof c==="object"&&c.v===1&&typeof c.task==="string"&&(c.tab===void 0||typeof c.tab==="string")&&(c.src==="history"&&typeof c.sid==="string"&&typeof c.idx==="number"||c.src==="terminal"&&typeof c.off==="number")))throw new ApiError("invalid cursor (unknown version or shape)","CURSOR_INVALID");if(c.task!==taskId)throw new ApiError(`cursor belongs to task ${c.task}, not ${taskId}`,"CURSOR_TASK_MISMATCH");return c}function clipStrings(value){if(typeof value==="string"){if(value.length<=STRING_CLIP_CHARS)return value;let points=[...value];if(points.length<=STRING_CLIP_CHARS)return value;return`${points.slice(0,STRING_CLIP_CHARS).join("")}\u2026[+${points.length-STRING_CLIP_CHARS} chars clipped]`}if(Array.isArray(value))return value.map(clipStrings);if(value!==null&&typeof value==="object"){let out={};for(let[k,v]of Object.entries(value))out[k]=clipStrings(v);return out}return value}function buildHistoryPage(messages,at,limit){let forward="from"in at,page=[],bytes=0,limited=!1,i=forward?at.from:at.before-1;for(;forward?i<messages.length:i>=0;forward?i++:i--){if(page.length>=limit)break;let clipped=clipStrings(messages[i]),size=JSON.stringify(clipped).length;if(page.length>0&&bytes+size>PAGE_BYTE_BUDGET){limited=!0;break}page.push(clipped),bytes+=size}if(forward)return{page,start:at.from,end:i,limited};return page.reverse(),{page,start:i+1,end:at.before,limited}}function terminalLines(text){return terminalRows(text)}function boundedTail(text,maxLines=TERMINAL_TAIL_LINES){let lines=terminalLines(text),start=Math.max(0,lines.length-Math.min(maxLines,TERMINAL_TAIL_LINES)),bytes=0;for(let i=lines.length-1;i>=start;i--)if(bytes+=(lines[i]?.length??0)+1,bytes>TERMINAL_TAIL_BYTES&&i<lines.length-1){start=i+1;break}return{tail:lines.slice(start),truncated:start>0}}async function peekTaskTerminal(taskId,engineBin,tab,sinceOffset,scope){let host=await openPtyHost();if(!host)return"host-unreachable";try{let key;if(tab)key=`${taskId}::${tab}`;else{let sessions=await listSessionsOrNull(host.rpc);if(sessions===null)return"host-unreachable";key=findEngineKey(sessions,taskId,engineBin,scope)??unclaimedSessions(sessions,scope).find((s)=>s.key===`${taskId}::tab-1`)?.key}if(!key)return null;let res;try{res=await host.rpc.request("pty.peek",{key,sinceOffset})}catch{return"host-unreachable"}if(!res.exists){if(tab)throw new ApiError(`tab ${tab} has no hosted session on task ${taskId} \u2014 see \`rove api pty-list\` for live tabs`,"TAB_NOT_FOUND");return null}return{pid:res.pid,offset:res.offset,text:Buffer.from(res.data,"base64").toString("utf8"),sinceValid:res.sinceValid,live:res.alive,exit:res.exit??null}}catch(err){if(err instanceof ApiError)throw err;return null}finally{host.close()}}async function engineScreenError(task,opts={}){let pattern=protocolEntry(task.vendor).errorLine;if(!pattern)return;try{let alias=task.ptyAlias,page=await peekTaskTerminal(alias?.taskId??task.id,taskEngineArgv(task)[0],alias?.tabId);if(!page||page==="host-unreachable")return;return screenErrorLine(pattern,boundedTail(page.text).tail,opts)}catch{return}}var ACTIVITY_STATES_DOC="`.activity.state` is one of: `idle` (at rest), `running` (a turn is in progress), `turn_complete` (a turn finished \u2014 also at rest; treat it like idle when deciding whether the engine is free), `permission_needed` (blocked on an approval prompt), `rate_limited` (clears on its own), `error` (the last turn failed; `.activity.detail.note` carries the engine's text, and `.activity.source: \"screen\"` means it was read off the engine's own screen because the engine reported nothing), `dead` (the engine process exited; the tab's exit record says how).",AT_REST=new Set(["idle","turn_complete"]);async function readActivityRegistry(daemon){try{let dbg=await daemon.request("debug.inspect");return{tasks:dbg?.activity?.tasks??{},tabs:dbg?.activity?.tabs??{}}}catch{return null}}async function activityView(registry,task,tab){let entry=tab?registry?.tabs[task.id]?.[tab]:registry?.tasks[task.id];if(!entry)return null;let base={state:entry.state,at:new Date(entry.at).toISOString(),forMs:Math.max(0,Date.now()-entry.at),...entry.detail?{detail:entry.detail}:{}},atRest=AT_REST.has(entry.state);if(tab||!(atRest||entry.state==="running"))return base;let note=await engineScreenError(task,{last:!atRest});return note?{...base,state:"error",detail:{failure:"other",note},source:"screen"}:base}async function assertNotEmptySuccess(daemon,ctx,prompt){if(ctx.args.bool("allow-empty"))return;if(!/^\s*succeeded\s*[:\uff1a]/i.test(prompt))return;let self=await ownSession(daemon);if(!self)return;let sender;try{sender=(await daemon.request("task.get",{taskId:self.taskId})).task}catch{return}if(!workspaceCapabilities(sender).ownsBranch)return;if(!sender.worktreePath)return;let ahead;try{ahead=(await ctx.runtime.readBranchSignals(sender.worktreePath,sender.baseRef)).ahead}catch{return}if(ahead!==0)return;let branch=sender.branch||"your branch";throw new ApiError(`refusing to report success: ${branch} has 0 commits \u2014 "succeeded" means COMMITTED, and this report would reach the coordinator as a clean success with nothing to land`,"EMPTY_SUCCESS_REPORT",{taskId:self.taskId,branch,hint:"commit your work with a real message and send again \u2014 or, if this task genuinely produced no commits (an investigation or a review), re-send with --allow-empty to say so explicitly",nextCommandArgs:["api","send",...ctx.args.str("task-id")?["--task-id",ctx.args.str("task-id")]:[],...ctx.args.str("tab")?["--tab",ctx.args.str("tab")]:[],"--allow-empty","--prompt",prompt]})}function parseOption(raw){let eq=raw.indexOf("=");if(eq<=0||eq===raw.length-1)throw new ApiError(`--option must be key=label (got ${JSON.stringify(raw)})`,"BAD_FLAG",helpStep("gate-raise"));return{key:raw.slice(0,eq).trim(),label:raw.slice(eq+1).trim()}}async function gateRaise(ctx){let{args}=ctx,daemon=daemonOf(ctx),taskId=args.require("task-id"),tabId=args.str("tab");if(!tabId){let self=await ownSession(daemon);if(self?.taskId===taskId)tabId=self.tabId}return{ok:!0,gate:(await daemon.request("gate.raise",{taskId,...tabId?{tabId}:{},question:args.require("question"),options:args.list("option").map(parseOption),...args.str("recommend")?{recommended:args.str("recommend")}:{},...args.str("context")?{context:args.str("context")}:{}})).gate}}async function gateAnswer(ctx){let{args}=ctx,option=args.str("option"),text=args.str("text");if(option===void 0&&text===void 0)throw new ApiError("pass --option KEY and/or --text TEXT","MISSING_FLAG",helpStep("gate-answer"));let res=await daemonOf(ctx).request("gate.answer",{gateId:args.require("gate"),...option!==void 0?{option}:{},...text!==void 0?{text}:{},by:"cli"});return{ok:!0,gate:res.gate,delivered:res.delivered}}async function gateWithdraw(ctx){return{ok:!0,gate:(await daemonOf(ctx).request("gate.withdraw",{gateId:ctx.args.require("gate")})).gate}}async function gates(ctx){let{args}=ctx,repo=args.str("repo")?args.requireRepo("repo"):void 0;return{gates:(await daemonOf(ctx).request("gate.list",{...repo?{repo}:{},...args.str("task-id")?{taskId:args.str("task-id")}:{},status:args.enumOf("status")??"open"})).gates}}async function takeOwedGateAnswers(daemon,taskId,tab){try{let owed=await daemon.request("gate.takeUndelivered",{taskId,...tab?{tabId:tab}:{}});return owed.text?{text:owed.text,gateIds:owed.gateIds}:null}catch{return null}}async function markGateAnswersDelivered(daemon,gateIds){await daemon.request("gate.markDelivered",{gateIds}).catch(()=>{})}function assertQueueFlags(ctx,tab){if(!ctx.args.bool("queue"))return;let clash=tab==="new"?"--tab new":ctx.args.bool("if-runnable")?"--if-runnable":ctx.args.bool("respawn")?"--respawn":null;if(clash)throw new ApiError(`--queue waits for a running turn; it does not combine with ${clash}`,"BAD_FLAG",helpStep("send"))}async function queueIfBusy(ctx,daemon,task,tab,text){if(!ctx.args.bool("queue"))return null;let tabId=tab??canonicalEngineTab(readTabsSnapshot(task.id)?.tabs??[])?.id;if(!tabId)return null;let reply=await daemon.request("queue.add",{taskId:task.id,tabId,text,expectReport:ctx.args.bool("expect-report")===!0});if(!reply.queued||!reply.item)return null;return{ok:!0,taskId:task.id,tabId,queued:!0,queueId:reply.item.id,position:reply.position}}var QUEUE_LIST_VERB={name:"queue-list",group:"read",summary:"Prompts `send --queue` is holding for a busy tab, oldest first: {items:[{id, taskId, tabId, text, expectReport, at, lastError?}]}. Each is pasted when its tab's turn ends, one per turn; `lastError` says why the last hand-over did not land (it stays at the head). Held in the daemon's memory: a daemon restart drops them.",flags:[F.taskId(!1)],handler:async(ctx)=>simpleRpc(ctx,"queue.list",ctx.args.str("task-id")?{taskId:ctx.args.str("task-id")}:{})},QUEUE_EDIT_VERB={name:"queue-edit",group:"drive",summary:'Rewrite a prompt `send --queue` is holding (`queue-list` gives the id), keeping its id and its place in line: {edited:true, item} or {edited:false, reason:"not-found"|"pasting"}. `pasting` means its turn already came and the old text is going in.',flags:[{name:"id",type:"string",required:!0,placeholder:"q-N",description:"The held prompt's id."},F.prompt(!0,"The new text, replacing the held prompt's."),F.promptFile()],handler:async(ctx)=>{let text=ctx.args.promptText();if(text===void 0)throw new ApiError("pass --prompt or --prompt-file","MISSING_FLAG",helpStep("queue-edit"));return simpleRpc(ctx,"queue.edit",{id:ctx.args.require("id"),text})}},QUEUE_CANCEL_VERB={name:"queue-cancel",group:"drive",summary:"Take back a prompt `send --queue` is holding (`queue-list` gives the id): {cancelled: true|false}.",flags:[{name:"id",type:"string",required:!0,placeholder:"q-N",description:"The held prompt's id."}],handler:async(ctx)=>simpleRpc(ctx,"queue.cancel",{id:ctx.args.require("id")})};async function handoffBrief(ctx,task,tabId){if(!/^tab-[A-Za-z0-9-]+$/.test(tabId))throw new ApiError(`--handoff-from must be a tab id like tab-2 (got ${JSON.stringify(tabId)})`,"BAD_TAB");let source=((await readDaemonTabs(daemonOf(ctx),task.id))?.tabs??readTabsSnapshot(task.id)?.tabs??[]).find((t)=>t.id===tabId);if(!source)throw new ApiError(`task ${task.id} has no tab ${tabId}`,"TAB_NOT_FOUND",{taskId:task.id,tabId});if(source.kind!=="engine")throw new ApiError(`${tabId} is not an engine conversation; nothing to hand over`,"BAD_FLAG",helpStep("send"));let tabVendor=source.vendor??task.vendor,plan=await planWorktreeHandoff(source,liveSourceProtocol(source,tabVendor),taskCwd(task),task.title);if(plan.kind==="handoff")return plan.prompt;throw new ApiError(plan.kind==="no-transcript"?`${plan.engine} keeps no transcript Rove can name, so ${tabId} cannot be handed to another engine`:`${tabId} has no conversation yet; send the prompt directly`,plan.kind==="no-transcript"?"NO_TRANSCRIPT":"NO_CONVERSATION",{taskId:task.id,tabId})}function sessionFailed(taskId,message,hint,extra){return new ApiError(message,"SESSION_FAILED",{taskId,...extra,hint,nextCommandArgs:["api","read-output","--task-id",taskId,"--source","terminal"]})}async function ensureHostFor(taskId,hint){try{return await ensurePtyHost()}catch(error){throw sessionFailed(taskId,`failed to start PTY host for ${taskId}: ${error instanceof Error?error.message:String(error)}`,hint)}}var OLD_CONVERSATION=["sessionId","spawned","forkFrom","initialPrompt","liveVendor","lastTitle","autoTitle"];async function assertDeadEngineTab(runtime,daemon,task,tabId){let scope=await ptyScopeOf(daemon,task);if(hostedKeyFor(task.id,tabId,scope)===null||scope.alias?.tabId===tabId)throw new ApiError(`tab ${tabId} runs under another task's conversation; --replace cannot swap it`,"BAD_FLAG",{taskId:task.id,tabId});let row=(await runtime.taskTabs(task.id,taskEngineArgv(task),scope)).tabs.find((t)=>t.id===tabId);if(!row||row.kind!=="engine")throw new ApiError(`${tabId} is not an engine conversation; nothing to replace`,"BAD_FLAG",helpStep("send"));if(row.viewOf)throw new ApiError(`${tabId} is a view of task ${row.viewOf}'s session; --replace cannot swap it`,"BAD_FLAG",{taskId:task.id,tabId});if(row.alive===!1||row.engineAlive===!1)return;throw new ApiError(`${tabId}'s engine is still running; --replace only takes over a dead or exited tab. Drop --replace to continue in a shared child task`,"TAB_ALIVE",{taskId:task.id,tabId})}var REWRITTEN=[...OLD_CONVERSATION,"vendor","engineCommand"];async function undoReplace(daemon,taskId,tabId,before){let set={},unset=[];for(let field of REWRITTEN)if(before[field]===void 0)unset.push(field);else set[field]=before[field];await applyTabOps(daemon,taskId,[{op:"patch",id:tabId,set,unset}]);let host=await ensureHostFor(taskId,"no PTY host to stop the replacement in");try{await host.rpc.request("pty.kill",{key:`${taskId}::${tabId}`,wait:!0})}finally{host.close()}}function replaceDeadTab(ctx,task,tabId,command){let{runtime,daemon}=ctx;return withDeliveryLock(`${task.id}::${tabId}::replace`,async()=>{await assertDeadEngineTab(runtime,daemon,task,tabId);let worktree=taskCwd(task);if(!worktree)throw new ApiError(`task ${task.id} has no worktree yet`,"NO_WORKTREE");let before=(await readDaemonTabs(daemon,task.id))?.tabs.find((t)=>t.id===tabId)??{},protocol=command?resolveCommandProtocol(command):void 0,set=protocol?{vendor:protocol,...command!==protocol?{engineCommand:command}:{}}:void 0,unset=protocol&&command===protocol?[...OLD_CONVERSATION,"engineCommand"]:OLD_CONVERSATION,undo=()=>undoReplace(daemon,task.id,tabId,before);await applyTabOps(daemon,task.id,[{op:"patch",id:tabId,...set?{set}:{},unset}]);let target={id:task.id,worktreePath:worktree,kind:task.kind,vendor:task.vendor,command:task.command,modelEffort:task.modelEffort,model:task.model,repo:task.repo};try{await runtime.reviveTab(daemon,target,tabId,worktree,{replaceExited:!0,awaitEngine:!0})}catch(error){throw await undo().catch(()=>{}),error}return undo})}function csvOf(ctx,name,allowed,verb="list"){let raw=ctx.args.str(name);if(raw===void 0)return;let values=raw.split(",").map((s)=>s.trim()).filter(Boolean);if(values.find((v)=>!allowed.includes(v))!==void 0||values.length===0)throw new ApiError(`--${name} takes a comma list of ${allowed.join(", ")}`,"BAD_FLAG",helpStep(verb));return new Set(values)}function listFilters(ctx){let repo=ctx.args.path("repo"),statuses=csvOf(ctx,"status",TASK_STATUSES),activities=csvOf(ctx,"activity",TASK_ACTIVITY_STATES);if(!repo&&!statuses&&!activities)return null;return{repo,statuses,activities}}async function filterTaskList(ctx,daemon,tasks,filters){let isLocal=(t)=>!t.origin||t.origin.machineId==="local",repo=filters.repo?await repoFilter(ctx.runtime,filters.repo,tasks.filter(isLocal).map((t)=>t.repo)):null,kept=tasks.filter((t)=>(!repo||isLocal(t)&&repo.matches(t.repo))&&(!filters.statuses||filters.statuses.has(t.status))),out=kept;if(filters.activities){let wanted=filters.activities,registry=await readActivityRegistry(daemon),local=kept.filter(isLocal),views=await Promise.all(local.map((t)=>activityView(registry,t)));out=local.flatMap((task,i)=>{let activity=views[i];return activity&&wanted.has(activity.state)?[{...task,activity}]:[]})}return{tasks:out,...repo&&repo.unresolvableRepos.length>0?{unresolvableRepos:repo.unresolvableRepos}:{}}}var TASK_FIELDS2={id:!0,title:!0,repo:!0,branch:!0,worktreePath:!0,kind:!0,scratch:!0,noProject:!0,routine:!0,status:!0,pinned:!0,kept:!0,notes:!0,todos:!0,archived:!0,vendor:!0,command:!0,prStatus:!0,modelEffort:!0,model:!0,tier:!0,groupId:!0,observedLanguage:!0,deletion:!0,quotaResume:!0,scheduledStart:!0,autoFixCi:!0,linkedWorkItem:!0,dispatcher:!0,parentTaskId:!0,sharesWorkspaceOf:!0,workspace:!0,cwdSubpath:!0,ptyAlias:!0,requireReport:!0,prompt:!0,baseRef:!0,worktreeName:!0,gitRepo:!0,extraRepos:!0,sessionPrs:!0,report:!0,origin:!0,repoId:!0,createdAt:!0,updatedAt:!0},LIST_FIELDS=[...Object.keys(TASK_FIELDS2),"repoCount","activity"];function listFields(ctx){let fields=csvOf(ctx,"fields",LIST_FIELDS);return fields?[...fields]:void 0}function projectTasks(tasks,fields){return tasks.map((task)=>{let row={};for(let field of fields)if(field in task)row[field]=task[field];return row})}var MAX_LIVE_ENGINES_KEY="engine.maxLiveSessions";function normalizeMaxLiveEngines(value){let n=typeof value==="number"?value:typeof value==="string"&&value.trim()!==""?Number(value.trim()):Number.NaN;return Number.isInteger(n)&&n>0?n:void 0}function persistedMaxLiveEngines(){return normalizeMaxLiveEngines(loadStateFile()[MAX_LIVE_ENGINES_KEY])}async function deliverToExactTab(rpc,taskId,tabId,cwd,prompt,opts){let key=`${taskId}::${tabId}`,{sessions=[]}=await rpc.request("pty.list",{}),session=sessions.find((s)=>s.key===key);if(!session?.alive){if(session?.restored===!0){if(!opts?.respawn)throw restoredTabError(taskId,tabId,prompt);let launch=opts.respawn(),open=await openAdmittedEngine(rpc,{key,cwd,...launch?{command:launch.command}:{},defaultColors:readPersistedTerminalDefaultColors()},{maxLiveEngines:opts.maxLiveEngines,snapshot:opts.snapshot,taskId,retryArgs:["api","send","--task-id",taskId,"--tab",tabId,"--respawn","--plain","--prompt",prompt]});if(open.respawned!==!0&&open.alive!==!0)throw new ApiError(`tab ${tabId} on task ${taskId} could not be respawned`,"SESSION_FAILED",{taskId,tabId,hint:"the frozen record is still on disk; open the task in the TUI to see the session's own output",nextCommandArgs:["api","read-output","--task-id",taskId,"--tab",tabId,"--source","terminal"]});let enginePid=await awaitEngineProcess(rpc,key,opts.engineBin,{timeoutMs:ENGINE_START_PROBE_MS,intervalMs:ENGINE_START_POLL_MS,snapshot:opts.snapshot});if(enginePid===null)return{session:key,pane:key,started:!1,respawned:!0,engineReady:!1,delivered:!1,reason:await hostedSessionFailureLine(rpc,key)??ENGINE_NOT_OBSERVED_REASON};return await deliverRespawned(rpc,key,prompt,enginePid.vendor)}throw new ApiError(`tab ${tabId} has no live session on task ${taskId} \u2014 see \`rove api pty-list\` for alive tabs`,"TAB_NOT_FOUND")}let presence=await enginePresence(session.pid,opts?.engineBin,opts?.snapshot);if(presence.kind==="unknown")throw new ApiError(`could not read the process table, so tab ${tabId} on task ${taskId} could not be checked for a live engine`,"ENGINE_PROBE_FAILED",{hint:"the `ps` probe failed or timed out; retry, or check the machine's process table",nextCommandArgs:["api","pty-list"]});if(presence.kind!=="engine")throw new ApiError(`tab ${tabId} on task ${taskId} has no live engine process \u2014 it is a plain shell right now`,"ENGINE_NOT_RUNNING",{hint:"spawn a fresh engine tab for this prompt with --tab new, or pick an engine tab from pty-list",nextCommandArgs:["api","pty-list"]});let outcome=await deliverToKey(rpc,key,prompt,{vendor:presence.vendor});return{session:key,pane:key,started:!1,...outcomeFields(outcome)}}async function deliverRespawned(rpc,key,prompt,vendor){let outcome=await deliverToKey(rpc,key,prompt,{vendor});return{session:key,pane:key,started:!1,respawned:!0,...outcomeFields(outcome)}}function restoredTabError(taskId,tabId,prompt){return new ApiError(`tab ${tabId} on task ${taskId} is a freeze-restored session \u2014 its pty host restarted, so the tab exists with its scrollback but nothing is running in it`,"TAB_RESTORED",{taskId,tabId,hint:"revive it with --respawn (resumes the tab's pinned conversation when it has one \u2014 `get-task` shows `sessionId`; a tab without one replays its recorded launch command)",nextCommandArgs:["api","send","--task-id",taskId,"--tab",tabId,"--respawn","--plain","--prompt",prompt]})}import{realpathSync,statSync}from"fs";import{join}from"path";function collision(taskId,key,retryArgs){return new ApiError(`session ${key} already existed; no new tab was created`,"TAB_COLLISION",{taskId,hint:"a session already held the tab id the daemon minted; retry to get a fresh id",nextCommandArgs:retryArgs})}var createdFresh=(open)=>open.created??open.replay.length===0;async function openShell(client,rpc,taskId,cwd,multiRepo,home,type){let shell=resolveSessionShell(),tab=home?await seedShellHome(client,taskId,shell):await allocateTab(client,taskId,{kind:"command",title:null,command:[shell]}),key=`${taskId}::${tab.id}`;try{let open;try{open=await rpc.request("pty.open",{key,cwd,command:[shell],defaultColors:readPersistedTerminalDefaultColors()})}catch(error){if(!home)await closeTabsSnapshot(client,taskId,tab.id).catch(()=>{return});throw error}if(!createdFresh(open))throw collision(taskId,key,["api","tab-new","--task-id",taskId,"--kind","shell"]);let repos=multiRepo?await launchReposOf(client,taskId):void 0;if(await rpc.request("pty.write",{key,data:shellIdentityInput(taskId,tab.id,repos&&repoEnv(repos))}),type!==void 0)await rpc.request("pty.write",{key,data:`${type}\r`})}finally{await rpc.request("pty.detach",{key}).catch(()=>{})}return{tab,key}}async function openEngine(client,rpc,target,cwd){let taskId=target.id,tab=await seedCanonicalTab(client,taskId),key=`${taskId}::${tab.id}`,retryArgs=["api","tab-new","--task-id",taskId,"--kind","engine"];try{let pinned=withPinnedSessionId(engineLaunchArgv({command:target.command,vendor:target.vendor,effort:target.modelEffort,model:target.model}),target.vendor);trustEngineWorktree(target.vendor,cwd);let repos=target.multiRepo?await launchReposOf(client,taskId):void 0;trustExtraRepos(target.vendor,repos);let launch=buildEngineSessionLaunch({task:{id:taskId,kind:target.kind,vendor:target.vendor,repo:target.repo,repos},worktreePath:cwd,shell:resolveSessionShell(),argv:pinned.argv,promptIntent:{kind:"none"},tabId:tab.id}),open=await openAdmittedEngine(rpc,{key:launch.key,cwd,command:launch.command,defaultColors:readPersistedTerminalDefaultColors()},{maxLiveEngines:persistedMaxLiveEngines(),taskId,retryArgs});if(!createdFresh(open)&&open.respawned!==!0)throw collision(taskId,key,retryArgs);if(!open.alive)throw sessionFailed(taskId,`the new engine tab ${tab.id} exited as it started`,"the session was created but nothing stayed running in it \u2014 fix the task's launch command (`api update --command`), then open another tab",{session:key});tab=(await markCliTabSession(client,taskId,tab.id,pinned.sessionId))?.tabs.find((t)=>t.id===tab.id)??tab}finally{await rpc.request("pty.detach",{key}).catch(()=>{})}return{tab,key}}async function openNewTab(client,target,worktree,kind,opts={}){let host=await ensureHostFor(target.id,"no PTY host to run the tab in \u2014 nothing was started; check `rove daemon status`, then retry");try{let opened=kind==="shell"?await openShell(client,host.rpc,target.id,worktree,target.multiRepo===!0,opts.home===!0,opts.type):await openEngine(client,host.rpc,target,worktree);return{tab:opened.tab,session:opened.key}}catch(error){if(error instanceof ApiError)throw error;throw sessionFailed(target.id,`opening a ${kind} tab failed for ${target.id}: ${error instanceof Error?error.message:String(error)}`,"the PTY host or the daemon refused the new tab \u2014 check `rove daemon status`, then retry")}finally{host.close()}}function fileInside(worktree,rel){if(!rel||rel.startsWith("/")||rel.includes("\x00")||rel.split(/[\\/]/).includes(".."))throw new ApiError("--file must be a path relative to the worktree","BAD_FLAG");let abs,root;try{root=realpathSync(worktree),abs=realpathSync(join(worktree,rel))}catch{throw new ApiError(`${rel} does not exist in the worktree`,"FILE_NOT_FOUND")}if(!pathWithin(root,abs))throw new ApiError(`${rel} resolves outside the worktree`,"BAD_FLAG");if(!statSync(abs).isFile())throw new ApiError(`${rel} is not a file`,"BAD_FLAG");return abs}async function spawnCommandTab(client,taskId,cwd,command,title,purpose,retryArgs){let host=await ensureHostFor(taskId,"no PTY host to run the tab in \u2014 nothing was started; check `rove daemon status`, then retry");try{let tab=await allocateTab(client,taskId,{kind:"command",title,command,...purpose?{purpose}:{}}),key=`${taskId}::${tab.id}`;try{let open;try{open=await host.rpc.request("pty.open",{key,cwd,command,defaultColors:readPersistedTerminalDefaultColors()})}catch(error){throw await closeTabsSnapshot(client,taskId,tab.id).catch(()=>{return}),error}if(!createdFresh(open))throw collision(taskId,key,retryArgs)}finally{await host.rpc.request("pty.detach",{key}).catch(()=>{})}return{tab,session:key}}catch(error){if(error instanceof ApiError)throw error;throw sessionFailed(taskId,`opening the tab failed for ${taskId}: ${error instanceof Error?error.message:String(error)}`,"the PTY host or the daemon refused the new tab \u2014 check `rove daemon status`, then retry")}finally{host.close()}}async function launchEditor(client,spec){let abs=fileInside(spec.worktree,spec.file),launch=await resolveEditorLaunch(spec.worktree,abs,spec.line);if(!launch)throw new ApiError("no editor found \u2014 set $VISUAL/$EDITOR, or Settings \u2192 General \u2192 Editor","NO_EDITOR",{hint:"an editor chosen in Settings wins over $EDITOR; `rove config` shows what resolves"});let snapshot=await readDaemonTabs(client,spec.taskId),previous=snapshot?findEditorTab(snapshot)?.id:void 0;return{...await spawnCommandTab(client,spec.taskId,spec.worktree,["sh","-c",launch.command],launch.label,"editor",["api","tab-new","--task-id",spec.taskId,"--kind","editor",`--file=${spec.file}`,...spec.line===void 0?[]:[`--line=${spec.line}`]]),...previous?{replaces:previous}:{},...launch.atLine===void 0?{}:{atLine:launch.atLine}}}function findPane(taskId,pane){let found=listPaneLaunches({socketPath:defaultDaemonSocketPath(),binPath:ROVE_PRODUCT_NAME,taskId}).find((p)=>`${p.pluginId}.${p.paneId}`===pane);if(!found)throw new ApiError(`no enabled plugin pane named ${pane}`,"PANE_NOT_FOUND",{hint:"panes of enabled plugins only; `rove plugin list` shows what is installed"});return found}async function launchPane(client,spec,split){let pane=findPane(spec.taskId,spec.pane),snapshot=await readDaemonTabs(client,spec.taskId),host=snapshot?.tabs.find((t)=>t.id===(spec.hostTab??snapshot.activeId));if(pane.placement==="split"&&host&&host.kind!=="content"){let out=await split(spec.taskId,host.id,spec.worktree,pane);if(out.changed)return{tab:out.tab,session:`${spec.taskId}::${host.id}::${out.leaf}`,leaf:out.leaf}}return spawnCommandTab(client,spec.taskId,spec.worktree,pane.argv,pane.title,void 0,["api","tab-new","--task-id",spec.taskId,"--kind","pane",`--pane=${spec.pane}`])}async function launchViewport(client,spec){let shown=(await readDaemonTabs(client,spec.view.id))?.tabs.find((t)=>t.id==="tab-1"),engine=shown?.kind==="engine"?shown:void 0;return{tab:await allocateTab(client,spec.taskId,{kind:"engine",title:null,...engine?.vendor?{vendor:engine.vendor}:{},sessionId:engine?.sessionId??null,spawned:!0,ptyTask:{id:spec.view.id,worktree:spec.view.worktree}}),session:`${spec.view.id}::tab-1`}}function launchTab(client,spec,split){switch(spec.kind){case"editor":return launchEditor(client,spec);case"pane":return launchPane(client,spec,split);case"viewport":return launchViewport(client,spec)}}var NO_OP={revived:!1,alive:!0,resumed:!1};function engineRelaunch(target,row,worktree){let base=tabEngineBase(target,row),vendor=row.vendor??target.vendor,resumeArgv=row.sessionId&&row.spawned?engineResumeArgv(base,vendor,row.sessionId):null,pinned=resumeArgv?null:withPinnedSessionId(base,vendor,row.sessionId?()=>row.sessionId:void 0);return trustEngineWorktree(vendor,worktree),{launch:buildEngineSessionLaunch({task:{id:target.id,kind:target.kind,vendor,repo:target.repo},worktreePath:worktree,shell:resolveSessionShell(),argv:resumeArgv??pinned?.argv??base,promptIntent:{kind:"none"},tabId:row.id}),resumed:resumeArgv!==null,sessionId:resumeArgv?row.sessionId:pinned?.sessionId}}async function openEngineTab(client,rpc,target,row,worktree){let{launch,resumed,sessionId}=engineRelaunch(target,row,worktree),open=await openAdmittedEngine(rpc,{key:launch.key,cwd:worktree,command:launch.command,defaultColors:readPersistedTerminalDefaultColors()},{maxLiveEngines:persistedMaxLiveEngines(),taskId:target.id,retryArgs:["api","tab-revive","--task-id",target.id,"--tab",row.id]});if(!createdFresh(open)&&open.respawned!==!0)return NO_OP;if(!open.alive)throw sessionFailed(target.id,`the engine in tab ${row.id} exited as it started`,"the session was reopened but nothing stayed running in it \u2014 fix the task's launch command (`api update --command`), then retry",{session:launch.key});return await markCliTabSession(client,target.id,row.id,sessionId??null),{revived:!0,resumed,...sessionId?{sessionId}:{}}}async function openCommandTab(rpc,target,row,worktree){let key=`${target.id}::${row.id}`,open=await rpc.request("pty.open",{key,cwd:worktree,command:row.command,defaultColors:readPersistedTerminalDefaultColors()});if(!createdFresh(open)&&open.respawned!==!0)return NO_OP;if(!open.alive)throw sessionFailed(target.id,`the command in tab ${row.id} exited as it started`,"run `get-task` for the tab",{session:key});if(row.command.length===1&&!row.purpose)await rpc.request("pty.write",{key,data:shellIdentityInput(target.id,row.id)});return{revived:!0,resumed:!1}}async function reviveTab(client,target,tabId,worktree,opts={}){let host=await ensureHostFor(target.id,"no PTY host to run the tab in \u2014 nothing was started; check `rove daemon status`, then retry"),key=`${target.id}::${tabId}`;try{let{sessions=[]}=await host.rpc.request("pty.list",{}),listed=sessions.find((s)=>s.key===key);if(listed?.alive&&!opts.replaceExited)return NO_OP;let row=(await readDaemonTabs(client,target.id))?.tabs.find((t)=>t.id===tabId);if(!row&&listed&&tabId==="tab-1")row=await seedCanonicalTab(client,target.id);if(!row)throw new ApiError(`tab ${tabId} is not a tab of task ${target.id}`,"TAB_NOT_FOUND",{taskId:target.id,hint:"pick a tab id from `get-task` .tabs[]",nextCommandArgs:["api","get-task","--task-id",target.id]});if(row.kind==="content"||row.kind==="engine"&&row.ptyTask){let why=row.kind==="content"?"is a preview with no session":`is a view of task ${row.ptyTask?.id}'s session`;throw new ApiError(`tab ${tabId} on task ${target.id} ${why}`,"TAB_NOT_REVIVABLE",{taskId:target.id,tabId,hint:"pick a shell or engine tab from `get-task` .tabs[], or revive a view's session under its own task",nextCommandArgs:["api","get-task","--task-id",target.id]})}if(listed&&listed.restored!==!0)await host.rpc.request("pty.kill",{key,wait:!0});if(row.kind!=="engine")return await openCommandTab(host.rpc,target,row,worktree);let revived=await openEngineTab(client,host.rpc,target,row,worktree);if(opts.awaitEngine){if(await awaitEngineProcess(host.rpc,key,tabEngineBase(target,row)[0],{timeoutMs:ENGINE_START_PROBE_MS,intervalMs:ENGINE_START_POLL_MS})===null)throw sessionFailed(target.id,`the engine did not start in tab ${tabId}`,"check the engine's launch command")}return revived}catch(error){if(error instanceof ApiError)throw error;if(error instanceof RemoteEngineLaunchError)throw new ApiError(error.message,error.code,{taskId:target.id,hint:"an SSH-backed project's engine cannot be launched from this machine; open the task on the machine that holds it"});throw sessionFailed(target.id,`reviving tab ${tabId} failed for ${target.id}: ${error instanceof Error?error.message:String(error)}`,"the PTY host or the daemon refused the open \u2014 check `rove daemon status`, then retry")}finally{await host.rpc.request("pty.detach",{key}).catch(()=>{}),host.close()}}function tabNotFound(taskId,tabId){return new ApiError(`tab ${tabId} does not exist on task ${taskId}`,"TAB_NOT_FOUND",{hint:"refresh the task's tab ids with get-task, then retry with one of its .tabs[].id values",nextCommandArgs:["api","get-task","--task-id",taskId]})}function locate(taskId,tabId,state){let tab=state&&Array.isArray(state.tabs)?state.tabs.find((t)=>t.id===tabId):void 0;if(!state||!tab)throw tabNotFound(taskId,tabId);if(tab.kind==="content")throw new ApiError(`tab ${tabId} is a content tab; only terminal tabs split`,"TAB_NOT_SPLITTABLE");return{state,tab}}async function editTree(client,taskId,tabId,edit){let{tab}=locate(taskId,tabId,await readDaemonTabs(client,taskId)),before=tab.splitTree??initialSplit(null),after=edit(before);if(after===before)return{tab,before,after};let saved=await patchTabSplit(client,taskId,tabId,collapseSplit(after));if(!saved)throw tabNotFound(taskId,tabId);return{tab:saved,before,after}}async function openLeafShell(rpc,key,cwd,opts={}){if(await rpc.request("pty.open",{key,cwd,command:opts.command??[resolveSessionShell()],defaultColors:readPersistedTerminalDefaultColors(),...opts.size?{cols:opts.size.cols,rows:opts.size.rows}:{}}),opts.identity)await rpc.request("pty.write",{key,data:opts.identity});await rpc.request("pty.detach",{key}).catch(()=>{})}async function splitTab(client,taskId,tabId,worktree,edit){let host=await ensureHostFor(taskId,"no PTY host to run the split in \u2014 nothing was changed; check `rove daemon status`");try{switch(edit.kind){case"open":{let{tab,before,after}=await editTree(client,taskId,tabId,(tree)=>{let from=leaves(tree.root).some((l)=>l.id===edit.from)?edit.from:tree.activeLeafId,base=from===tree.activeLeafId?tree:{...tree,activeLeafId:from},argv=edit.command?.argv??[resolveSessionShell()],next=splitActive(base,edit.orientation,argv,edit.size??null);if(next===base)return tree;return edit.command?renameLeaf(next,next.activeLeafId,edit.command.title):next});if(after===before)return{tab,leaf:before.activeLeafId,changed:!1};let leaf=after.activeLeafId;try{await openLeafShell(host.rpc,splitLeafPtyKey(tabPtyKeyFor(taskId,tab),leaf),worktree,{size:edit.size,command:edit.command?.argv})}catch(error){throw await editTree(client,taskId,tabId,(tree)=>removeLeaf(tree,leaf)??tree).catch(()=>{return}),sessionFailed(taskId,`opening a split shell failed: ${error instanceof Error?error.message:String(error)}`,"the PTY host refused the shell \u2014 the split was taken back; check `rove daemon status`, then retry")}return{tab,leaf,changed:!0}}case"close":{let{tab,before,after}=await editTree(client,taskId,tabId,(tree)=>{let next=removeLeaf(tree,edit.leaf);if(next===null)throw new ApiError(`${edit.leaf} is the only pane; close the tab instead`,"LAST_LEAF");return next});if(after===before)return{tab,leaf:edit.leaf,changed:!1};return await killTaskSessions(host.rpc,[splitLeafPtyKey(tabPtyKeyFor(taskId,tab),edit.leaf)]),{tab,leaf:edit.leaf,changed:!0}}case"rename":{let{tab,before,after}=await editTree(client,taskId,tabId,(tree)=>renameLeaf(tree,edit.leaf,edit.title));return{tab,leaf:edit.leaf,changed:after!==before}}case"reset":{let{tab}=await editTree(client,taskId,tabId,(tree)=>tree),shellTab=tab.kind==="command";if(!shellTab&&edit.leaf==="leaf-1")throw new ApiError("reset respawns a login shell; this pane runs an engine","RESET_ENGINE",{hint:"close the engine tab and open a new one; shell tabs and split shells reset"});let key=splitLeafPtyKey(tabPtyKeyFor(taskId,tab),edit.leaf);return await killTaskSessions(host.rpc,[key],{wait:!0}),await openLeafShell(host.rpc,key,worktree,{size:edit.size,identity:shellTab&&edit.leaf==="leaf-1"?shellIdentityInput(taskId,tab.id):void 0}),{tab,leaf:edit.leaf,changed:!1}}}}finally{host.close()}}function hasLiveEngineTab(snapshot,taskId,sessions,engineAlive,engineBin){let labelled=new Set((snapshot?.tabs??[]).filter((t)=>t.kind==="engine").map((t)=>t.id));return sessions.some((s)=>{if(s.alive!==!0||!isHostedTaskKey(s.key,taskId))return!1;if(engineAlive?.get(s.key)===!1)return!1;if(s.key===`${taskId}::tab-1`)return!0;let tabId=s.key.slice(taskId.length+2);return labelled.has(tabId)||sessionArgvNamesEngine(s.command,engineBin)})}async function ensureWorktree(client,target){if(target.worktreePath)return target.worktreePath;let res=await client.request("task.ensureWorktree",{taskId:target.id});if(!res.worktreePath)throw new ApiError(`task ${target.id} has no worktree`,"NO_WORKTREE");return res.worktreePath}async function deliverHosted(client,target,worktree,prompt){let host=await ensureHostFor(target.id,"no PTY host to run the engine in \u2014 nothing was started; check `rove daemon status`, then retry the same send");try{if(target.tab){let engineBin=engineLaunchArgv({command:target.command,vendor:target.vendor,effort:target.modelEffort,model:target.model})[0],tabId=target.tab,respawnRepos=target.respawn&&target.multiRepo?await launchReposOf(client,target.id):void 0;return await deliverToExactTab(host.rpc,target.id,tabId,worktree,prompt,{engineBin,maxLiveEngines:persistedMaxLiveEngines(),...target.respawn?{respawn:()=>restoredTabLaunch({...target,repos:respawnRepos},tabId,worktree,resolveSessionShell())}:{}})}let{argv,sessionId}=withPinnedSessionId(engineLaunchArgv({command:target.command,vendor:target.vendor,effort:target.modelEffort,model:target.model}),target.vendor);trustEngineWorktree(target.vendor,worktree);let repos=target.multiRepo?await launchReposOf(client,target.id):void 0;trustExtraRepos(target.vendor,repos);let launch=buildEngineSessionLaunch({task:{id:target.id,kind:target.kind,vendor:target.vendor,repo:target.repo,repos},worktreePath:worktree,shell:resolveSessionShell(),argv,promptIntent:target.newTask?{kind:"new-task",prompt}:{kind:"explicit",prompt}}),result=await deliverHostedPrompt(host.rpc,{id:target.id,engineBin:argv[0],scope:await ptyScopeOf(client,{id:target.id}),...target.firstConversation?{firstConversation:!0}:{}},worktree,prompt,launch,{maxLiveEngines:persistedMaxLiveEngines(),retryArgs:["api","send","--task-id",target.id,"--plain","--prompt",prompt]});if(result.started&&!result.delivered)throw sessionFailed(target.id,`failed to start hosted engine session for ${target.id}`,"the session was created but no engine ran in it \u2014 fix the task's launch command (`api update --command`), then retry the send",{session:result.session,engineReady:result.engineReady,...result.reason?{reason:result.reason}:{}});if(await publishCliTabSnapshot(client,target.id,result.started?sessionId:void 0),result.started&&sessionId){let startedTab=result.session.split("::")[1];if(startedTab)await markCliTabSession(client,target.id,startedTab,sessionId)}return result}catch(error){if(error instanceof ApiError)throw error;throw sessionFailed(target.id,`hosted engine session failed for ${target.id}: ${error instanceof Error?error.message:String(error)}`,"the hosted session threw while starting or delivering \u2014 read its terminal tail for the cause, then retry the send")}finally{host.close()}}var realPromptDeliveryOps={deliverHosted};async function closeHeadlessTerminalTab(client,taskId,tabId){let host=await openPtyHost();try{let sessions=host?await listSessions(host.rpc):[],saved=(await readDaemonTabs(client,taskId))?.tabs.find((tab)=>tab.id===tabId),directKey=`${taskId}::${tabId}`,unregisteredAlive=sessions.some((session)=>session.key===directKey&&session.alive);if(!saved&&!unregisteredAlive)throw new ApiError(`tab ${tabId} does not exist on task ${taskId}`,"TAB_NOT_FOUND",{hint:"refresh the task's tab ids with get-task, then retry with one of its .tabs[].id values",nextCommandArgs:["api","get-task","--task-id",taskId]});let closing=saved?await closeTabsSnapshot(client,taskId,tabId):void 0;if(saved&&!closing)throw new ApiError(`tab ${tabId} no longer exists on task ${taskId}`,"TAB_NOT_FOUND",{hint:"the tab closed while this command was running; refresh with get-task before retrying",nextCommandArgs:["api","get-task","--task-id",taskId]});let baseKey=closing?tabPtyKeyFor(taskId,closing):directKey,keys=!(closing?.kind==="engine"&&closing.ptyTask&&closing.ptyTask.tabId===void 0)?sessions.filter((session)=>session.key===baseKey||session.key.startsWith(`${baseKey}::`)).map((session)=>session.key):[],wasAlive=sessions.some((session)=>keys.includes(session.key)&&session.alive);if(host)await killTaskSessions(host.rpc,keys);return{kind:closing?.kind??"engine",wasAlive}}finally{host?.close()}}async function deliverPrompt(client,target,prompt,ops=realPromptDeliveryOps){let worktree=await ensureWorktree(client,target);if(target.newTask)await client.request("task.observeLanguage",{taskId:target.id,text:prompt}).catch(()=>{});let hosted=await ops.deliverHosted(client,target,worktree,prompt);if(!hosted)throw sessionFailed(target.id,`failed to start hosted engine session for ${target.id}`,"delivery returned nothing \u2014 the task exists but has no session; retry with `api send --tab new`");return hosted}async function readLiveTaskIds(tasks){let listed=await handlePtyList();if(!listed?.sessions)return null;let live=new Set;for(let row of listed.sessions){if(row.alive===!1||typeof row.key!=="string")continue;let[taskId,tabId]=row.key.split("::");if(taskId)live.add(resolvePtyOwner(tasks,taskId,tabId))}return live}var defaultApiRuntime={liveTaskIds:readLiveTaskIds,isTaskRunning:async(taskId,engineArgv,scope)=>(await defaultApiRuntime.taskTabs(taskId,engineArgv,scope)).running,taskTabs:async(taskId,engineArgv,scope)=>{let listed=null,host=await openPtyHost();if(host)try{listed=await listSessionsOrNull(host.rpc)}finally{host.close()}let visible=listed?unclaimedSessions(listed,scope):null,sessions=visible??[],hostReachable=listed!==null,liveVendors,engineAlive;try{let{engineProcessIn,foregroundEngineIn:foregroundEngineIn2,parsePsSnapshot:parsePsSnapshot2,psSnapshot:psSnapshot2}=await import("./chunk-sakkdjyn.js"),walkable=sessions.filter((s)=>s.alive&&typeof s.pid==="number"&&s.pid>0);if(walkable.length>0){let rows=parsePsSnapshot2(await psSnapshot2(walkable.map((s)=>s.pid)));liveVendors=new Map(walkable.map((s)=>[s.key,foregroundEngineIn2(rows,s.pid)?.vendor??null])),engineAlive=new Map(walkable.map((s)=>[s.key,engineProcessIn(rows,s.pid,engineArgv)]))}else engineAlive=new Map}catch{}let exits={};try{exits=(await import("./chunk-6f9ypgbs.js")).readPtyExitRecords()}catch{}let snapshot=readTabsSnapshot(taskId),sessionIds=new Map((snapshot?.tabs??[]).map((t)=>[t.id,t.sessionId??void 0]));return{tabs:joinTaskTabs(snapshot,taskId,visible,exits,liveVendors,engineAlive).map((row)=>{let sessionId=sessionIds.get(row.id);return sessionId?{...row,sessionId}:row}),running:hostReachable?hasLiveEngineTab(snapshot,scope?.alias?.taskId??taskId,scope?.alias?sessions.filter((s)=>isUnderKey(s.key,aliasKey(scope.alias))):sessions,engineAlive,engineArgv?.[0]):null}},closeTerminalTab:closeHeadlessTerminalTab,deliverPrompt:(client,target,prompt)=>deliverPrompt(client,target,prompt),openTab:async(client,target,kind,opts)=>openNewTab(client,target,await ensureWorktree(client,target),kind,opts),launchTab:(client,spec)=>launchTab(client,spec,(taskId,tabId,worktree,pane)=>splitTab(client,taskId,tabId,worktree,{kind:"open",orientation:"row",from:"",command:{argv:pane.argv,title:pane.title}})),splitTab,reviveTab,resolveRepoRoot:async(absPath)=>(await import("./chunk-hv79ys32.js")).resolveMainRepoRoot(absPath),isUsableRepo:async(absPath)=>{let{isGitRepo,isRemoteRepoKey:isRemoteRepoKey2}=await import("./chunk-hv79ys32.js");return isRemoteRepoKey2(absPath)||isGitRepo(absPath)},isValidBranchName:async(branch)=>(await import("./chunk-hv79ys32.js")).isValidBranchName(branch),defaultVendor:async(repo)=>{let{getGlobalDefaultVendor,getRepoLastActiveVendor}=await import("./chunk-x1ghdmp1.js");return(repo?getRepoLastActiveVendor(repo):void 0)??getGlobalDefaultVendor()},readWorktreeChanges:async(worktreePath)=>(await import("./chunk-5yfffvqe.js")).readWorktreeChanges(worktreePath),readBranchSignals:async(worktreePath,recordedBaseRef)=>(await import("./chunk-9xtg2k54.js")).readBranchSignals(worktreePath,recordedBaseRef),tearDownSession:async(taskId,scope)=>{let host=await openPtyHost();if(host)try{await killTaskSessions(host.rpc,taskKeys(await listSessions(host.rpc),taskId,scope))}catch{}finally{host.close()}},listeningPorts:async()=>(await import("./chunk-b95q6zhk.js")).scanListeningPorts(),measureCheckout:async(path2)=>{let{measureCheckout}=await import("./chunk-cqrr5g2e.js"),{execHostForWorktreePath}=await import("./chunk-teh40faw.js");return measureCheckout(execHostForWorktreePath(path2),path2)}};async function checkMenu(daemon,taskId,tab,fallback){try{let reply=await daemon.request("send.check",{taskId,...tab?{tabId:tab}:{}});return{waiting:reply.awaiting.length>0?reply.awaiting:null,settleMs:reply.settleMs}}catch{}let tabs;try{tabs=(await daemon.request("status.list")).tasks[taskId]?.tabs}catch{return{waiting:fallback?.state==="permission_needed"?tab?[tab]:[]:null,settleMs:0}}let waiting=Object.entries(tabs??{}).filter(([id,s])=>s.kind==="needs-input"&&(tab===void 0||id===tab)).map(([id])=>id);return{waiting:waiting.length>0?waiting:null,settleMs:0}}async function tabsAwaitingChoice(daemon,taskId,tab,fallback){let check=await checkMenu(daemon,taskId,tab,fallback);if(check.waiting===null&&check.settleMs>0){let{promise,resolve:resolve3}=Promise.withResolvers();setTimeout(resolve3,check.settleMs),await promise,check=await checkMenu(daemon,taskId,tab,fallback)}return check.waiting}function awaitingChoiceError(taskId,tabs){let where=tabs.length>0?` (${tabs.join(", ")})`:"";return new ApiError(`not sent: task ${taskId}${where} is showing an approval or question menu (or came to rest straight from one); a paste would land in it and Enter would confirm the highlighted option`,"AWAITING_PERMISSION",{taskId,...tabs.length>0?{tabIds:tabs}:{},hint:"answer the menu with keys in the task's terminal (the TUI, or the web page's keys), then send again; read the menu with read-output --source terminal",nextCommandArgs:["api","read-output","--task-id",taskId,"--source","terminal"]})}async function spawnSharedChild(daemon,parentTaskId,command,title){let vendor=command?resolveCommandProtocol(command):void 0;return(await daemon.request("task.spawn",{parentTaskId,worktree:!1,...title?{title}:{},...command?{command}:{},...vendor?{vendor}:{}})).task}var FIRST_CONVERSATION_LOCK_MS=120000;function withFirstConversationLock(taskId,fn){return withDeliveryLock(`${taskId}::new-conversation`,fn,{timeoutMs:FIRST_CONVERSATION_LOCK_MS})}async function engineStarted(daemon,runtime,task){if(task.ptyAlias)return!0;let engines=((await readDaemonTabs(daemon,task.id))?.tabs??[]).filter((tab)=>tab.kind==="engine");if(engines.length===0)return!1;if(engines.some((tab)=>tab.spawned))return!0;let{tabs:rows}=await runtime.taskTabs(task.id,taskEngineArgv(task),await ptyScopeOf(daemon,task));return rows.find((row)=>row.id===engines[0]?.id)?.alive===!0}async function conversationHome(daemon,runtime,task,command,prompt){let title=prompt?deriveTitleFromPrompt(prompt):"";if(await engineStarted(daemon,runtime,task))return{task:await spawnSharedChild(daemon,task.id,command,title),child:!0};if(command&&command!==task.command){let vendor=resolveCommandProtocol(command);await daemon.request("task.setCommand",{taskId:task.id,command,...vendor?{vendor}:{}})}if(title&&task.title===PLACEHOLDER_TASK_TITLE)await daemon.request("task.rename",{taskId:task.id,title}).catch(()=>{return});return{task:(await daemon.request("task.get",{taskId:task.id})).task,child:!1}}var ENGINE_REFUSALS={ENGINE_LIMIT:!0,ENGINE_ADMISSION_BUSY:!0,ENGINE_ADMISSION_UNAVAILABLE:!0};async function failSharedChild(daemon,err,childTaskId,retryArgs){if(!(err instanceof ApiError))throw err;if(ENGINE_REFUSALS[err.code])throw await daemon.request("task.delete",{taskId:childTaskId}).catch(()=>{return}),new ApiError(err.message,err.code,{...err.data,nextCommandArgs:retryArgs});throw new ApiError(err.message,err.code,{...err.data,childTaskId})}async function issueUpdate(ctx){let title=ctx.args.str("title"),body=ctx.args.str("body"),task=ctx.args.str("task"),status=ctx.args.enumOf("status");if(title===void 0&&body===void 0&&task===void 0&&status===void 0)throw new ApiError("issue-update requires --title, --body, --task, and/or --status","MISSING_FLAG");let repoRoot=ctx.args.requireRepo("repo"),id=ctx.args.int("id"),state;if(title!==void 0||body!==void 0||task!==void 0)state=await simpleRpc(ctx,"issue.mutate",{repoRoot,op:{type:"update",id,title,body,...task===void 0?{}:{taskId:task==="none"?null:task}}});if(status!==void 0)state=await simpleRpc(ctx,"issue.mutate",{repoRoot,op:{type:"setStatus",id,status}});return state}function requirePromptText(ctx,verb){let text=ctx.args.promptText();if(text===void 0)throw new ApiError("--prompt (or --prompt-file) is required","MISSING_FLAG",helpStep(verb));return text}async function resolveSendTask(ctx,daemon,tab){let explicit=ctx.args.str("task-id");if(explicit)return{taskId:explicit,tab};let dispatcher=await readOwnDispatcher(daemon);if(dispatcher)return{taskId:dispatcher.taskId,tab:tab??await resolveDispatcherTab(ctx.runtime,daemon,dispatcher)};let active=await resolveActiveTaskId(daemon);if(!active)throw new ApiError("no --task-id given and no active task \u2014 open a task first or pass --task-id","MISSING_TARGET");return{taskId:active,tab}}async function send(ctx){let rollback={};try{if(ctx.args.str("tab")!=="new")return await sendNow(ctx,rollback);let{taskId}=await resolveSendTask(ctx,daemonOf(ctx),"new");return await withFirstConversationLock(taskId,()=>sendNow(ctx,rollback))}catch(err){throw await rollback.undo?.().catch(()=>{}),err}}async function sendNow(ctx,rollback){let daemon=daemonOf(ctx),handoffFrom=ctx.args.str("handoff-from"),tab=ctx.args.str("tab");if(handoffFrom&&tab!=="new")throw new ApiError(`--handoff-from starts a new conversation; pass --tab new (got --tab ${tab??"<canonical>"})`,"BAD_FLAG",helpStep("send"));let replace=ctx.args.bool("replace")===!0;if(replace&&!handoffFrom)throw new ApiError("--replace takes over a tab for a handoff; pass --handoff-from tab-N","BAD_FLAG",helpStep("send"));let prompt=handoffFrom?ctx.args.promptText()??"":requirePromptText(ctx,"send");if(tab&&tab!=="new"&&!/^tab-[A-Za-z0-9-]+$/.test(tab))throw new ApiError(`--tab must be "new" or a tab id like tab-2 (got ${JSON.stringify(tab)})`,"BAD_TAB");let tabCommand=ctx.args.str("command");if(tabCommand&&tab!=="new")throw new ApiError(`--command only applies to a new tab; pass --tab new (got --tab ${tab??"<canonical>"})`,"BAD_FLAG",helpStep("send"));let respawn=ctx.args.bool("respawn");if(assertQueueFlags(ctx,tab),respawn&&(tab===void 0||tab==="new"))throw new ApiError(`--respawn addresses one frozen tab; pass --tab tab-N (got --tab ${tab??"<canonical>"})`,"BAD_FLAG",helpStep("send"));let sendTo=await resolveSendTask(ctx,daemon,tab),taskId=sendTo.taskId;tab=sendTo.tab;let res=await daemon.request("task.get",{taskId});if(handoffFrom)prompt=[await handoffBrief(ctx,res.task,handoffFrom),prompt].filter(Boolean).join(`
|
|
5
5
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{resolveLoginShell}from"./chunk-tn9gtf18.js";import{recommendedGlobalInstallCommand}from"./chunk-
|
|
2
|
+
import{resolveLoginShell}from"./chunk-tn9gtf18.js";import{recommendedGlobalInstallCommand}from"./chunk-2wrt80ft.js";function updaterShell(deps={}){let platform=deps.platform??process.platform;if(platform!=="win32")return"sh";return resolveLoginShell({fallback:"/bin/sh",platform,env:deps.env,exists:deps.exists})}function updaterShellFailureHint(deps={}){if((deps.platform??process.platform)!=="win32")return null;return["The update script is POSIX shell. Rove runs it through Git for Windows'","bash \u2014 the same shell every engine and terminal tab launches through.","Install Git for Windows (https://git-scm.com/download/win), or update","by hand:",` ${recommendedGlobalInstallCommand()}`,""].join(`
|
|
3
3
|
`)}
|
|
4
4
|
export{updaterShell,updaterShellFailureHint};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{defaultFixRuntime}from"./chunk-am5cpb9n.js";import{INBOUND_CLASSES,deniedClasses,setInbound}from"./chunk-
|
|
2
|
+
import{defaultFixRuntime}from"./chunk-am5cpb9n.js";import{INBOUND_CLASSES,deniedClasses,setInbound}from"./chunk-qzhfs668.js";import"./chunk-txvjg1g9.js";import"./chunk-k2j0tg1h.js";import"./chunk-kdnk8m5j.js";import"./chunk-qcjkactr.js";import"./chunk-rjfdzjhj.js";import"./chunk-zpxpwgds.js";import"./chunk-agvtzads.js";import"./chunk-pm91e38v.js";import"./chunk-2xsxcdp6.js";import"./chunk-17e2tgyg.js";import"./chunk-1vxtd8rh.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-2pfh3zm0.js";import{primaryCheckouts,repoIdOf,repoIdentity,setPrimaryCheckout}from"./chunk-p11emdb2.js";import{addMachine,defaultMachineAlias,discoverMachine,duplicateAliasOf,getMachine,isValidMachineAlias,isWindowsMachine,learnedFrom,listMachines,machineSocketDir,machineSshArgs,parseSshTarget,readMachines,remoteRove,removeMachine,sanitizeAlias,setMachineIdentity,sshServerIsWindows,sshTargetOf,updateMachine,windowsAuthorizeKeySteps}from"./chunk-vytrhm50.js";import"./chunk-vp29jgbt.js";import"./chunk-gq36nzg8.js";import"./chunk-sq6zj3fb.js";import"./chunk-qkehg2c1.js";import"./chunk-s1xn6wav.js";import"./chunk-nv8eyjep.js";import"./chunk-z43e08kw.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import"./chunk-f7egph8g.js";import"./chunk-rxqdw6s5.js";import"./chunk-kxp04jnp.js";import"./chunk-3hxm56h6.js";import"./chunk-qecygh3f.js";import"./chunk-rjq38twt.js";import"./chunk-r5j8fycq.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-ggnq2vvk.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import{shQuote}from"./chunk-y1xnjx8x.js";import"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-5rgrde6b.js";import"./chunk-4gjvmfa9.js";import"./chunk-2tfnscxk.js";import"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import"./chunk-9rj2fx6v.js";import"./chunk-rfp0ayra.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-kg9kmwt9.js";import"./chunk-6xppe9bj.js";import{CURRENT_VERSION}from"./chunk-2wrt80ft.js";import{argvHasFlag}from"./chunk-zsfyj36g.js";import"./chunk-2r1fgng9.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import{loadStateFile}from"./chunk-32j6y5d1.js";import"./chunk-nqwza8b0.js";import"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import"./chunk-hz1x3hak.js";import"./chunk-x1jxxmtc.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import{homeDir}from"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__require}from"./chunk-91sykzqq.js";import{spawn}from"child_process";import{appendFileSync,chmodSync,existsSync,mkdirSync}from"fs";import{homedir}from"os";import{dirname}from"path";function parseSshG(stdout,home=homedir()){let values=new Map;for(let line of stdout.split(`
|
|
3
3
|
`)){let space=line.indexOf(" ");if(space>0)values.set(line.slice(0,space).toLowerCase(),line.slice(space+1).trim())}let hostname=values.get("hostname")??"",port=Number(values.get("port")??"22")||22,files=(key)=>(values.get(key)??"").split(/\s+/).filter((f)=>f&&f!=="none").map((f)=>f.startsWith("~/")?`${home}${f.slice(1)}`:f),alias=values.get("hostkeyalias"),proxy=(key)=>{let v=values.get(key);return v!==void 0&&v!=="none"};return{knownHostsName:alias&&alias!=="none"?alias:port===22?hostname:`[${hostname}]:${port}`,hostname,port,userKnownHosts:files("userknownhostsfile"),globalKnownHosts:files("globalknownhostsfile"),proxied:proxy("proxyjump")||proxy("proxycommand")}}async function checkHostKey(config){let target=sshTargetOf(config),resolved=await run(["ssh","-G",...config.port?["-p",String(config.port)]:[],target]);if(resolved.code!==0)return{state:"skipped",reason:"ssh -G failed"};let destination=parseSshG(resolved.stdout);if(!destination.hostname)return{state:"skipped",reason:"ssh -G named no host"};if(destination.proxied)return{state:"skipped",reason:"reached through a proxy"};for(let file of[...destination.userKnownHosts,...destination.globalKnownHosts]){if(!existsSync(file))continue;if((await run(["ssh-keygen","-F",destination.knownHostsName,"-f",file])).code===0)return{state:"known"}}let keys=(await run(["ssh-keyscan","-T","5","-p",String(destination.port),destination.hostname])).stdout.split(`
|
|
4
4
|
`).filter((line)=>line.trim()&&!line.startsWith("#"));if(keys.length===0)return{state:"skipped",reason:"the host offered no key"};let named=keys.map((line)=>line.replace(/^\S+/,destination.knownHostsName)),fingerprints=(await run(["ssh-keygen","-l","-f","-"],`${named.join(`
|
|
5
5
|
`)}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{submitFeedback}from"./chunk-
|
|
2
|
+
import{submitFeedback}from"./chunk-2pfh3zm0.js";import"./chunk-2wrt80ft.js";import"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-91sykzqq.js";import{readFileSync}from"fs";var CLI_NAME=ROVE_PRODUCT_NAME,FEEDBACK_USAGE=[`Usage: ${CLI_NAME} feedback --title <text> (--body <text> | --body-file <path>) [--category <slug>]`,"","Create a GitHub Discussion in the Rove repository using the GitHub CLI.","","Requires:"," gh auth login","","Options:"," --title <text> Discussion title"," --body <text> Discussion body"," --body-file <path> Read the Discussion body from a file; use - for stdin"," --category <slug> Discussion category slug (default: feedback)"," -h, --help Print this help",""].join(`
|
|
3
3
|
`);function usageError(message){process.stderr.write(`${CLI_NAME} feedback: ${message}
|
|
4
4
|
|
|
5
5
|
${FEEDBACK_USAGE}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{MachineFeed}from"./chunk-1pcqw0x7.js";import{COLORBLIND_KEY,DEFAULT_BASE_REF,DEFAULT_COLORBLIND,DEFAULT_GLYPHS,DEFAULT_GLYPH_SET,DEFAULT_PREFIX_TAP_PRESENTATION,DEFAULT_RUNNING_TITLE,DEFAULT_SCROLLBACK_ROWS,DEFAULT_TASK_COLORS,DEFAULT_WORKING_BORDER,GLYPH_SETS,GLYPH_SET_KEY,PREFIX_TAP_PRESENTATIONS,PREFIX_TAP_PRESENTATION_KEY,RUNNING_TITLE_KEY,SCROLLBACK_ROWS_KEY,SCROLLBACK_ROWS_MAX,SCROLLBACK_ROWS_MIN,SPLIT_STYLE_KEY,TAB_STRIP_HIDE_SINGLE_KEY,TAB_STRIP_MODES,TAB_STRIP_MODE_KEY,TASK_COLORS_KEY,WORKING_BORDER_KEY,appearanceChoices,buildPRPrompt,cloneRepo,conversationTitleOf,createKeybindingsFile,deriveFolderName,detailFragment,detectWorktreeOpener,diffCommentsKey,displayEndpoint,engineIntegrations,findAvailableFolderName,formatDiffComments,getCurrentBranch,issueChatTaskTitle,issueProjectPrompt,issueWorktreePrompt,listLocalBranches,normalizeColorblind,normalizeGlyphSet,normalizePrefixTapPresentation,normalizeRunningTitle,normalizeScrollbackRows,normalizeSplitStyle,normalizeTaskColors,normalizeWorkingBorder,openExternally,openWorktree,prChip,readPluginRows,resolveCloneTarget,resolveTabStripMode,setPluginEnabled,spawnDetached,taskColor,unsentComments,validateCloneTarget,validateGitUrl,validateRepoPath,worktreeRowLabel}from"./chunk-vbvbwjad.js";import"./chunk-c25vea1q.js";import"./chunk-p2cbtrzg.js";import"./chunk-hg8c3ze3.js";import{buildCIPromptForWorktree}from"./chunk-vkz6kkmm.js";import{checkFrame,ghText,isLoopbackHost,parseFailedRunLog,runIdFromDetailsUrl}from"./chunk-1g6vhgfe.js";import{tabStatus,taskStatus}from"./chunk-6hcyvg0m.js";import{installSkillErrors,missingSkillNames}from"./chunk-y7mjhjby.js";import{invokeVerb}from"./chunk-mfp8ax3c.js";import{argvToParams,executeVerb}from"./chunk-phmt9a1k.js";import{DEFAULT_SOUND_VOLUME,FINISHED_ALERTS_KEY,RAIL_FOLD_STYLE_KEY,RoveKeymap,SOUND_VOLUME_KEY,SOUND_VOLUME_STEPS,ZEN_ACTIVE_KEY,ZEN_DEFAULT,attentionEdges,attentionKindFor,normalizeSoundVolume,prefixFirstStrokes,readKeybindingsFile,resetKeybindingsFileCache,resolveUserKeybindings}from"./chunk-x85rcep5.js";import{RemoteOrchestrator,liveRowTokens}from"./chunk-apgfbg20.js";import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{UPDATE_CHANNEL_KEY,UPDATE_NOTIFY_KEY,normalizeReleaseChannel,preferredReleaseChannel}from"./chunk-cydytp2v.js";import{HOSTED_THEMES,ThemeInstallError,hostedThemeUrl,parseTheme,writeUserTheme}from"./chunk-wfgrn8p2.js";import{buildContext,checkRef,worktreeDiff,worktreeRefs}from"./chunk-q3wzpn85.js";import{AUTO_ROUTING_TIERS,autoRoutingKey,describeTierBlock,listFiles,liveSourceProtocol,loadPreviewData,planWorktreeHandoff,readAutoRoutingTable,readClassifierConfig,resolveBase,secretStatus,tierBlock}from"./chunk-k2j0tg1h.js";import{ensurePluginEnginesLoaded}from"./chunk-kdnk8m5j.js";import"./chunk-qcjkactr.js";import{listPaneLaunches}from"./chunk-rjfdzjhj.js";import{detectEngineStatus,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-zpxpwgds.js";import{DEFAULT_EDITOR_KIND,EDITOR_CUSTOM_KEY,EDITOR_KINDS,EDITOR_KIND_KEY,normalizeEditorKind}from"./chunk-agvtzads.js";import"./chunk-pm91e38v.js";import{deriveTitleFromPrompt}from"./chunk-2xsxcdp6.js";import"./chunk-17e2tgyg.js";import{PROJECT_SIBLING_BASE,WORKTREE_BASE_CUSTOM_KEY,worktreeBaseKindOf}from"./chunk-1vxtd8rh.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import{loadPluginRegistry}from"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-v3yf3gmy.js";import{forwardVerb,invokeRouted,machineDaemonSocket,requireMachine}from"./chunk-p11emdb2.js";import{localPtySocketPath}from"./chunk-vytrhm50.js";import{repoIdOf}from"./chunk-vp29jgbt.js";import{WORKTREE_BASE_KEY}from"./chunk-gq36nzg8.js";import"./chunk-sq6zj3fb.js";import"./chunk-qkehg2c1.js";import"./chunk-s1xn6wav.js";import{resolveThemeSlotHex}from"./chunk-nv8eyjep.js";import{ensurePtyHostReachable}from"./chunk-z43e08kw.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import{DEFAULT_THEME,DEFAULT_THEME_MODE,FOCUS_ACCENT_SLOTS,THEME_MODE_PREFERENCES,defaultTransparentBackground,diffInks,resolveTheme}from"./chunk-f7egph8g.js";import"./chunk-rxqdw6s5.js";import{BUNDLED_THEME_JSONS,loadUserThemes,userThemesDir}from"./chunk-kxp04jnp.js";import{conversationTitle,expandHome,filterSubdirs,initialTabs,listSubdirs,moveTab,splitPathForDirSuggest,stripTrailingSlash,tabPtyKeyFor}from"./chunk-3hxm56h6.js";import{AUTO_STATUS_KEY,DISPATCHER_KEY}from"./chunk-qecygh3f.js";import{defaultEngineCommand,engineDisplayName,engineRenamedFrom,protocolEntry,roveApiInvocation}from"./chunk-rjq38twt.js";import{ApiError,REMOTE_CALLER}from"./chunk-r5j8fycq.js";import{BUILTIN_MODS,installedBuiltinMods,isBuiltinModId,setBuiltinModInstalled}from"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-ggnq2vvk.js";import"./chunk-hpay0ax8.js";import{isNonEmptyRepoFile}from"./chunk-catrr0z3.js";import{terminalTabsKey}from"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import"./chunk-y1xnjx8x.js";import{ensureDaemonReachable}from"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-5rgrde6b.js";import{engineEntry,vendorsWithTurnReader}from"./chunk-4gjvmfa9.js";import"./chunk-2tfnscxk.js";import{installedEngineIds}from"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import{resolvePreferredVendor,setRepoLastActiveVendor}from"./chunk-9rj2fx6v.js";import{getDisabledEngineIds,getSavedRepos,resolveMainRepoRoot}from"./chunk-rfp0ayra.js";import"./chunk-0r1jf8m9.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-kg9kmwt9.js";import"./chunk-6xppe9bj.js";import{CURRENT_VERSION,RELEASE_CHANNELS,channelOf,checkLatestVersion,fetchReleaseNotes,fetchReleaseNotesRange}from"./chunk-4a82zjaq.js";import"./chunk-zsfyj36g.js";import"./chunk-2r1fgng9.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import{loadStateFile,replaceStateFile,updateStateFile}from"./chunk-32j6y5d1.js";import"./chunk-nqwza8b0.js";import{DEFAULT_LOCALE,LOCALES,isLocaleId}from"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import{RoveDaemonClient,isDaemonVersionStale}from"./chunk-qzzmd63x.js";import{MOD_INPUT_MAX,MOD_KEY_PATTERN,MOD_PANE_ID_PATTERN,ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import{roveCliInvocation}from"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import"./chunk-hz1x3hak.js";import{MULTI_REPO_CAP,rollupPr}from"./chunk-x1jxxmtc.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";import{ALL_VENDORS,isBuiltinVendor}from"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import{defaultUiPrefsStatePath,promptAttachmentsDir,resolveProductHomeDir,roveStateDir}from"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import{samePath}from"./chunk-pn5ygqn6.js";import{defaultDaemonSocketPath,defaultPtyHostSocketPath}from"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__commonJS,__require,__toESM}from"./chunk-91sykzqq.js";var require_ms=__commonJS((exports,module)=>{var s=1000,m=s*60,h=m*60,d=h*24,w=d*7,y=d*365.25;module.exports=function(val,options){options=options||{};var type=typeof val;if(type==="string"&&val.length>0)return parse(val);else if(type==="number"&&isFinite(val))return options.long?fmtLong(val):fmtShort(val);throw Error("val is not a non-empty string or a valid number. val="+JSON.stringify(val))};function parse(str){if(str=String(str),str.length>100)return;var match=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);if(!match)return;var n=parseFloat(match[1]),type=(match[2]||"ms").toLowerCase();switch(type){case"years":case"year":case"yrs":case"yr":case"y":return n*y;case"weeks":case"week":case"w":return n*w;case"days":case"day":case"d":return n*d;case"hours":case"hour":case"hrs":case"hr":case"h":return n*h;case"minutes":case"minute":case"mins":case"min":case"m":return n*m;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}function fmtShort(ms){var msAbs=Math.abs(ms);if(msAbs>=d)return Math.round(ms/d)+"d";if(msAbs>=h)return Math.round(ms/h)+"h";if(msAbs>=m)return Math.round(ms/m)+"m";if(msAbs>=s)return Math.round(ms/s)+"s";return ms+"ms"}function fmtLong(ms){var msAbs=Math.abs(ms);if(msAbs>=d)return plural(ms,msAbs,d,"day");if(msAbs>=h)return plural(ms,msAbs,h,"hour");if(msAbs>=m)return plural(ms,msAbs,m,"minute");if(msAbs>=s)return plural(ms,msAbs,s,"second");return ms+" ms"}function plural(ms,msAbs,n,name){var isPlural=msAbs>=n*1.5;return Math.round(ms/n)+" "+name+(isPlural?"s":"")}});var require_common=__commonJS((exports,module)=>{function setup(env){createDebug.debug=createDebug,createDebug.default=createDebug,createDebug.coerce=coerce,createDebug.disable=disable,createDebug.enable=enable,createDebug.enabled=enabled,createDebug.humanize=require_ms(),createDebug.destroy=destroy,Object.keys(env).forEach((key)=>{createDebug[key]=env[key]}),createDebug.names=[],createDebug.skips=[],createDebug.formatters={};function selectColor(namespace){let hash=0;for(let i=0;i<namespace.length;i++)hash=(hash<<5)-hash+namespace.charCodeAt(i),hash|=0;return createDebug.colors[Math.abs(hash)%createDebug.colors.length]}createDebug.selectColor=selectColor;function createDebug(namespace){let prevTime,enableOverride=null,namespacesCache,enabledCache;function debug(...args){if(!debug.enabled)return;let self=debug,curr=Number(new Date),ms=curr-(prevTime||curr);if(self.diff=ms,self.prev=prevTime,self.curr=curr,prevTime=curr,args[0]=createDebug.coerce(args[0]),typeof args[0]!=="string")args.unshift("%O");let index=0;args[0]=args[0].replace(/%([a-zA-Z%])/g,(match,format)=>{if(match==="%%")return"%";index++;let formatter=createDebug.formatters[format];if(typeof formatter==="function"){let val=args[index];match=formatter.call(self,val),args.splice(index,1),index--}return match}),createDebug.formatArgs.call(self,args),(self.log||createDebug.log).apply(self,args)}if(debug.namespace=namespace,debug.useColors=createDebug.useColors(),debug.color=createDebug.selectColor(namespace),debug.extend=extend,debug.destroy=createDebug.destroy,Object.defineProperty(debug,"enabled",{enumerable:!0,configurable:!1,get:()=>{if(enableOverride!==null)return enableOverride;if(namespacesCache!==createDebug.namespaces)namespacesCache=createDebug.namespaces,enabledCache=createDebug.enabled(namespace);return enabledCache},set:(v)=>{enableOverride=v}}),typeof createDebug.init==="function")createDebug.init(debug);return debug}function extend(namespace,delimiter){let newDebug=createDebug(this.namespace+(typeof delimiter>"u"?":":delimiter)+namespace);return newDebug.log=this.log,newDebug}function enable(namespaces){createDebug.save(namespaces),createDebug.namespaces=namespaces,createDebug.names=[],createDebug.skips=[];let split=(typeof namespaces==="string"?namespaces:"").trim().replace(/\s+/g,",").split(",").filter(Boolean);for(let ns of split)if(ns[0]==="-")createDebug.skips.push(ns.slice(1));else createDebug.names.push(ns)}function matchesTemplate(search,template){let searchIndex=0,templateIndex=0,starIndex=-1,matchIndex=0;while(searchIndex<search.length)if(templateIndex<template.length&&(template[templateIndex]===search[searchIndex]||template[templateIndex]==="*"))if(template[templateIndex]==="*")starIndex=templateIndex,matchIndex=searchIndex,templateIndex++;else searchIndex++,templateIndex++;else if(starIndex!==-1)templateIndex=starIndex+1,matchIndex++,searchIndex=matchIndex;else return!1;while(templateIndex<template.length&&template[templateIndex]==="*")templateIndex++;return templateIndex===template.length}function disable(){let namespaces=[...createDebug.names,...createDebug.skips.map((namespace)=>"-"+namespace)].join(",");return createDebug.enable(""),namespaces}function enabled(name){for(let skip of createDebug.skips)if(matchesTemplate(name,skip))return!1;for(let ns of createDebug.names)if(matchesTemplate(name,ns))return!0;return!1}function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}function destroy(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return createDebug.enable(createDebug.load()),createDebug}module.exports=setup});var require_browser=__commonJS((exports,module)=>{exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.storage=localstorage();exports.destroy=(()=>{let warned=!1;return()=>{if(!warned)warned=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}})();exports.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function useColors(){if(typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs))return!0;if(typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let m;return typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&(m=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(m[1],10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function formatArgs(args){if(args[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+args[0]+(this.useColors?"%c ":" ")+"+"+module.exports.humanize(this.diff),!this.useColors)return;let c="color: "+this.color;args.splice(1,0,c,"color: inherit");let index=0,lastC=0;args[0].replace(/%[a-zA-Z%]/g,(match)=>{if(match==="%%")return;if(index++,match==="%c")lastC=index}),args.splice(lastC,0,c)}exports.log=console.debug||console.log||(()=>{});function save(namespaces){try{if(namespaces)exports.storage.setItem("debug",namespaces);else exports.storage.removeItem("debug")}catch(error){}}function load(){let r;try{r=exports.storage.getItem("debug")||exports.storage.getItem("DEBUG")}catch(error){}if(!r&&typeof process<"u"&&"env"in process)r=process.env.DEBUG;return r}function localstorage(){try{return localStorage}catch(error){}}module.exports=require_common()(exports);var{formatters}=module.exports;formatters.j=function(v){try{return JSON.stringify(v)}catch(error){return"[UnexpectedJSONParseError]: "+error.message}}});var require_has_flag=__commonJS((exports,module)=>{module.exports=(flag,argv=process.argv)=>{let prefix=flag.startsWith("-")?"":flag.length===1?"-":"--",position=argv.indexOf(prefix+flag),terminatorPosition=argv.indexOf("--");return position!==-1&&(terminatorPosition===-1||position<terminatorPosition)}});var require_supports_color=__commonJS((exports,module)=>{var os=__require("os"),tty=__require("tty"),hasFlag=require_has_flag(),{env}=process,forceColor;if(hasFlag("no-color")||hasFlag("no-colors")||hasFlag("color=false")||hasFlag("color=never"))forceColor=0;else if(hasFlag("color")||hasFlag("colors")||hasFlag("color=true")||hasFlag("color=always"))forceColor=1;if("FORCE_COLOR"in env)if(env.FORCE_COLOR==="true")forceColor=1;else if(env.FORCE_COLOR==="false")forceColor=0;else forceColor=env.FORCE_COLOR.length===0?1:Math.min(parseInt(env.FORCE_COLOR,10),3);function translateLevel(level){if(level===0)return!1;return{level,hasBasic:!0,has256:level>=2,has16m:level>=3}}function supportsColor(haveStream,streamIsTTY){if(forceColor===0)return 0;if(hasFlag("color=16m")||hasFlag("color=full")||hasFlag("color=truecolor"))return 3;if(hasFlag("color=256"))return 2;if(haveStream&&!streamIsTTY&&forceColor===void 0)return 0;let min=forceColor||0;if(env.TERM==="dumb")return min;if(process.platform==="win32"){let osRelease=os.release().split(".");if(Number(osRelease[0])>=10&&Number(osRelease[2])>=10586)return Number(osRelease[2])>=14931?3:2;return 1}if("CI"in env){if(["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","GITHUB_ACTIONS","BUILDKITE"].some((sign)=>(sign in env))||env.CI_NAME==="codeship")return 1;return min}if("TEAMCITY_VERSION"in env)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION)?1:0;if(env.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in env){let version=parseInt((env.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(env.TERM_PROGRAM){case"iTerm.app":return version>=3?3:2;case"Apple_Terminal":return 2}}if(/-256(color)?$/i.test(env.TERM))return 2;if(/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM))return 1;if("COLORTERM"in env)return 1;return min}function getSupportLevel(stream){let level=supportsColor(stream,stream&&stream.isTTY);return translateLevel(level)}module.exports={supportsColor:getSupportLevel,stdout:translateLevel(supportsColor(!0,tty.isatty(1))),stderr:translateLevel(supportsColor(!0,tty.isatty(2)))}});var require_node=__commonJS((exports,module)=>{var tty=__require("tty"),util=__require("util");exports.init=init;exports.log=log;exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.destroy=util.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");exports.colors=[6,2,3,4,5,1];try{let supportsColor=require_supports_color();if(supportsColor&&(supportsColor.stderr||supportsColor).level>=2)exports.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221]}catch(error){}exports.inspectOpts=Object.keys(process.env).filter((key)=>{return/^debug_/i.test(key)}).reduce((obj,key)=>{let prop=key.substring(6).toLowerCase().replace(/_([a-z])/g,(_,k)=>{return k.toUpperCase()}),val=process.env[key];if(/^(yes|on|true|enabled)$/i.test(val))val=!0;else if(/^(no|off|false|disabled)$/i.test(val))val=!1;else if(val==="null")val=null;else val=Number(val);return obj[prop]=val,obj},{});function useColors(){return"colors"in exports.inspectOpts?Boolean(exports.inspectOpts.colors):tty.isatty(process.stderr.fd)}function formatArgs(args){let{namespace:name,useColors:useColors2}=this;if(useColors2){let c=this.color,colorCode="\x1B[3"+(c<8?c:"8;5;"+c),prefix=` ${colorCode};1m${name} \x1B[0m`;args[0]=prefix+args[0].split(`
|
|
2
|
+
import{MachineFeed}from"./chunk-hd1szhba.js";import{COLORBLIND_KEY,DEFAULT_BASE_REF,DEFAULT_COLORBLIND,DEFAULT_GLYPHS,DEFAULT_GLYPH_SET,DEFAULT_PREFIX_TAP_PRESENTATION,DEFAULT_RUNNING_TITLE,DEFAULT_SCROLLBACK_ROWS,DEFAULT_TASK_COLORS,DEFAULT_WORKING_BORDER,GLYPH_SETS,GLYPH_SET_KEY,PREFIX_TAP_PRESENTATIONS,PREFIX_TAP_PRESENTATION_KEY,RUNNING_TITLE_KEY,SCROLLBACK_ROWS_KEY,SCROLLBACK_ROWS_MAX,SCROLLBACK_ROWS_MIN,SPLIT_STYLE_KEY,TAB_STRIP_HIDE_SINGLE_KEY,TAB_STRIP_MODES,TAB_STRIP_MODE_KEY,TASK_COLORS_KEY,WORKING_BORDER_KEY,appearanceChoices,buildPRPrompt,cloneRepo,conversationTitleOf,createKeybindingsFile,deriveFolderName,detailFragment,detectWorktreeOpener,diffCommentsKey,displayEndpoint,engineIntegrations,findAvailableFolderName,formatDiffComments,getCurrentBranch,issueChatTaskTitle,issueProjectPrompt,issueWorktreePrompt,listLocalBranches,normalizeColorblind,normalizeGlyphSet,normalizePrefixTapPresentation,normalizeRunningTitle,normalizeScrollbackRows,normalizeSplitStyle,normalizeTaskColors,normalizeWorkingBorder,openExternally,openWorktree,prChip,readPluginRows,resolveCloneTarget,resolveTabStripMode,setPluginEnabled,spawnDetached,taskColor,unsentComments,validateCloneTarget,validateGitUrl,validateRepoPath,worktreeRowLabel}from"./chunk-vbvbwjad.js";import"./chunk-c25vea1q.js";import"./chunk-p2cbtrzg.js";import"./chunk-rvjnafyt.js";import{buildCIPromptForWorktree}from"./chunk-vkz6kkmm.js";import{checkFrame,ghText,isLoopbackHost,parseFailedRunLog,runIdFromDetailsUrl}from"./chunk-1g6vhgfe.js";import{tabStatus,taskStatus}from"./chunk-6hcyvg0m.js";import{installSkillErrors,missingSkillNames}from"./chunk-y7mjhjby.js";import{invokeVerb}from"./chunk-7nnpp89t.js";import{argvToParams,executeVerb}from"./chunk-zkby63ej.js";import{DEFAULT_SOUND_VOLUME,FINISHED_ALERTS_KEY,RAIL_FOLD_STYLE_KEY,RoveKeymap,SOUND_VOLUME_KEY,SOUND_VOLUME_STEPS,ZEN_ACTIVE_KEY,ZEN_DEFAULT,attentionEdges,attentionKindFor,normalizeSoundVolume,prefixFirstStrokes,readKeybindingsFile,resetKeybindingsFileCache,resolveUserKeybindings}from"./chunk-x85rcep5.js";import{RemoteOrchestrator,liveRowTokens}from"./chunk-j54c5a0a.js";import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{UPDATE_CHANNEL_KEY,UPDATE_NOTIFY_KEY,normalizeReleaseChannel,preferredReleaseChannel}from"./chunk-4z1a65bz.js";import{HOSTED_THEMES,ThemeInstallError,hostedThemeUrl,parseTheme,writeUserTheme}from"./chunk-wfgrn8p2.js";import{buildContext,checkRef,worktreeDiff,worktreeRefs}from"./chunk-txvjg1g9.js";import{AUTO_ROUTING_TIERS,autoRoutingKey,describeTierBlock,listFiles,liveSourceProtocol,loadPreviewData,planWorktreeHandoff,readAutoRoutingTable,readClassifierConfig,resolveBase,secretStatus,tierBlock}from"./chunk-k2j0tg1h.js";import{ensurePluginEnginesLoaded}from"./chunk-kdnk8m5j.js";import"./chunk-qcjkactr.js";import{listPaneLaunches}from"./chunk-rjfdzjhj.js";import{detectEngineStatus,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-zpxpwgds.js";import{DEFAULT_EDITOR_KIND,EDITOR_CUSTOM_KEY,EDITOR_KINDS,EDITOR_KIND_KEY,normalizeEditorKind}from"./chunk-agvtzads.js";import"./chunk-pm91e38v.js";import{deriveTitleFromPrompt}from"./chunk-2xsxcdp6.js";import"./chunk-17e2tgyg.js";import{PROJECT_SIBLING_BASE,WORKTREE_BASE_CUSTOM_KEY,worktreeBaseKindOf}from"./chunk-1vxtd8rh.js";import"./chunk-q8ffd1pc.js";import"./chunk-4hestsjp.js";import"./chunk-qgrg9a5n.js";import"./chunk-2bgmby1d.js";import{loadPluginRegistry}from"./chunk-n0rdn2fn.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-2pfh3zm0.js";import{forwardVerb,invokeRouted,machineDaemonSocket,requireMachine}from"./chunk-p11emdb2.js";import{localPtySocketPath}from"./chunk-vytrhm50.js";import{repoIdOf}from"./chunk-vp29jgbt.js";import{WORKTREE_BASE_KEY}from"./chunk-gq36nzg8.js";import"./chunk-sq6zj3fb.js";import"./chunk-qkehg2c1.js";import"./chunk-s1xn6wav.js";import{resolveThemeSlotHex}from"./chunk-nv8eyjep.js";import{ensurePtyHostReachable}from"./chunk-z43e08kw.js";import"./chunk-w77s2df8.js";import"./chunk-mqfvzdpr.js";import{DEFAULT_THEME,DEFAULT_THEME_MODE,FOCUS_ACCENT_SLOTS,THEME_MODE_PREFERENCES,defaultTransparentBackground,diffInks,resolveTheme}from"./chunk-f7egph8g.js";import"./chunk-rxqdw6s5.js";import{BUNDLED_THEME_JSONS,loadUserThemes,userThemesDir}from"./chunk-kxp04jnp.js";import{conversationTitle,expandHome,filterSubdirs,initialTabs,listSubdirs,moveTab,splitPathForDirSuggest,stripTrailingSlash,tabPtyKeyFor}from"./chunk-3hxm56h6.js";import{AUTO_STATUS_KEY,DISPATCHER_KEY}from"./chunk-qecygh3f.js";import{defaultEngineCommand,engineDisplayName,engineRenamedFrom,protocolEntry,roveApiInvocation}from"./chunk-rjq38twt.js";import{ApiError,REMOTE_CALLER}from"./chunk-r5j8fycq.js";import{BUILTIN_MODS,installedBuiltinMods,isBuiltinModId,setBuiltinModInstalled}from"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-ggnq2vvk.js";import"./chunk-hpay0ax8.js";import{isNonEmptyRepoFile}from"./chunk-catrr0z3.js";import{terminalTabsKey}from"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import"./chunk-y1xnjx8x.js";import{ensureDaemonReachable}from"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-5rgrde6b.js";import{engineEntry,vendorsWithTurnReader}from"./chunk-4gjvmfa9.js";import"./chunk-2tfnscxk.js";import{installedEngineIds}from"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-etfh8f4z.js";import{resolvePreferredVendor,setRepoLastActiveVendor}from"./chunk-9rj2fx6v.js";import{getDisabledEngineIds,getSavedRepos,resolveMainRepoRoot}from"./chunk-rfp0ayra.js";import"./chunk-0r1jf8m9.js";import"./chunk-t7j8g9f6.js";import"./chunk-dmzg9zdc.js";import"./chunk-40dgv828.js";import"./chunk-kg9kmwt9.js";import"./chunk-6xppe9bj.js";import{CURRENT_VERSION,RELEASE_CHANNELS,channelOf,checkLatestVersion,fetchReleaseNotes,fetchReleaseNotesRange}from"./chunk-2wrt80ft.js";import"./chunk-zsfyj36g.js";import"./chunk-2r1fgng9.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import{loadStateFile,replaceStateFile,updateStateFile}from"./chunk-32j6y5d1.js";import"./chunk-nqwza8b0.js";import{DEFAULT_LOCALE,LOCALES,isLocaleId}from"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import{RoveDaemonClient,isDaemonVersionStale}from"./chunk-qzzmd63x.js";import{MOD_INPUT_MAX,MOD_KEY_PATTERN,MOD_PANE_ID_PATTERN,ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import{roveCliInvocation}from"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import"./chunk-hz1x3hak.js";import{MULTI_REPO_CAP,rollupPr}from"./chunk-x1jxxmtc.js";import{DEFAULT_TASK_VENDOR}from"./chunk-xy8be792.js";import{ALL_VENDORS,isBuiltinVendor}from"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import{defaultUiPrefsStatePath,promptAttachmentsDir,resolveProductHomeDir,roveStateDir}from"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import{samePath}from"./chunk-pn5ygqn6.js";import{defaultDaemonSocketPath,defaultPtyHostSocketPath}from"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import{__commonJS,__require,__toESM}from"./chunk-91sykzqq.js";var require_ms=__commonJS((exports,module)=>{var s=1000,m=s*60,h=m*60,d=h*24,w=d*7,y=d*365.25;module.exports=function(val,options){options=options||{};var type=typeof val;if(type==="string"&&val.length>0)return parse(val);else if(type==="number"&&isFinite(val))return options.long?fmtLong(val):fmtShort(val);throw Error("val is not a non-empty string or a valid number. val="+JSON.stringify(val))};function parse(str){if(str=String(str),str.length>100)return;var match=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);if(!match)return;var n=parseFloat(match[1]),type=(match[2]||"ms").toLowerCase();switch(type){case"years":case"year":case"yrs":case"yr":case"y":return n*y;case"weeks":case"week":case"w":return n*w;case"days":case"day":case"d":return n*d;case"hours":case"hour":case"hrs":case"hr":case"h":return n*h;case"minutes":case"minute":case"mins":case"min":case"m":return n*m;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}function fmtShort(ms){var msAbs=Math.abs(ms);if(msAbs>=d)return Math.round(ms/d)+"d";if(msAbs>=h)return Math.round(ms/h)+"h";if(msAbs>=m)return Math.round(ms/m)+"m";if(msAbs>=s)return Math.round(ms/s)+"s";return ms+"ms"}function fmtLong(ms){var msAbs=Math.abs(ms);if(msAbs>=d)return plural(ms,msAbs,d,"day");if(msAbs>=h)return plural(ms,msAbs,h,"hour");if(msAbs>=m)return plural(ms,msAbs,m,"minute");if(msAbs>=s)return plural(ms,msAbs,s,"second");return ms+" ms"}function plural(ms,msAbs,n,name){var isPlural=msAbs>=n*1.5;return Math.round(ms/n)+" "+name+(isPlural?"s":"")}});var require_common=__commonJS((exports,module)=>{function setup(env){createDebug.debug=createDebug,createDebug.default=createDebug,createDebug.coerce=coerce,createDebug.disable=disable,createDebug.enable=enable,createDebug.enabled=enabled,createDebug.humanize=require_ms(),createDebug.destroy=destroy,Object.keys(env).forEach((key)=>{createDebug[key]=env[key]}),createDebug.names=[],createDebug.skips=[],createDebug.formatters={};function selectColor(namespace){let hash=0;for(let i=0;i<namespace.length;i++)hash=(hash<<5)-hash+namespace.charCodeAt(i),hash|=0;return createDebug.colors[Math.abs(hash)%createDebug.colors.length]}createDebug.selectColor=selectColor;function createDebug(namespace){let prevTime,enableOverride=null,namespacesCache,enabledCache;function debug(...args){if(!debug.enabled)return;let self=debug,curr=Number(new Date),ms=curr-(prevTime||curr);if(self.diff=ms,self.prev=prevTime,self.curr=curr,prevTime=curr,args[0]=createDebug.coerce(args[0]),typeof args[0]!=="string")args.unshift("%O");let index=0;args[0]=args[0].replace(/%([a-zA-Z%])/g,(match,format)=>{if(match==="%%")return"%";index++;let formatter=createDebug.formatters[format];if(typeof formatter==="function"){let val=args[index];match=formatter.call(self,val),args.splice(index,1),index--}return match}),createDebug.formatArgs.call(self,args),(self.log||createDebug.log).apply(self,args)}if(debug.namespace=namespace,debug.useColors=createDebug.useColors(),debug.color=createDebug.selectColor(namespace),debug.extend=extend,debug.destroy=createDebug.destroy,Object.defineProperty(debug,"enabled",{enumerable:!0,configurable:!1,get:()=>{if(enableOverride!==null)return enableOverride;if(namespacesCache!==createDebug.namespaces)namespacesCache=createDebug.namespaces,enabledCache=createDebug.enabled(namespace);return enabledCache},set:(v)=>{enableOverride=v}}),typeof createDebug.init==="function")createDebug.init(debug);return debug}function extend(namespace,delimiter){let newDebug=createDebug(this.namespace+(typeof delimiter>"u"?":":delimiter)+namespace);return newDebug.log=this.log,newDebug}function enable(namespaces){createDebug.save(namespaces),createDebug.namespaces=namespaces,createDebug.names=[],createDebug.skips=[];let split=(typeof namespaces==="string"?namespaces:"").trim().replace(/\s+/g,",").split(",").filter(Boolean);for(let ns of split)if(ns[0]==="-")createDebug.skips.push(ns.slice(1));else createDebug.names.push(ns)}function matchesTemplate(search,template){let searchIndex=0,templateIndex=0,starIndex=-1,matchIndex=0;while(searchIndex<search.length)if(templateIndex<template.length&&(template[templateIndex]===search[searchIndex]||template[templateIndex]==="*"))if(template[templateIndex]==="*")starIndex=templateIndex,matchIndex=searchIndex,templateIndex++;else searchIndex++,templateIndex++;else if(starIndex!==-1)templateIndex=starIndex+1,matchIndex++,searchIndex=matchIndex;else return!1;while(templateIndex<template.length&&template[templateIndex]==="*")templateIndex++;return templateIndex===template.length}function disable(){let namespaces=[...createDebug.names,...createDebug.skips.map((namespace)=>"-"+namespace)].join(",");return createDebug.enable(""),namespaces}function enabled(name){for(let skip of createDebug.skips)if(matchesTemplate(name,skip))return!1;for(let ns of createDebug.names)if(matchesTemplate(name,ns))return!0;return!1}function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}function destroy(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return createDebug.enable(createDebug.load()),createDebug}module.exports=setup});var require_browser=__commonJS((exports,module)=>{exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.storage=localstorage();exports.destroy=(()=>{let warned=!1;return()=>{if(!warned)warned=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}})();exports.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function useColors(){if(typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs))return!0;if(typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let m;return typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&(m=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(m[1],10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function formatArgs(args){if(args[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+args[0]+(this.useColors?"%c ":" ")+"+"+module.exports.humanize(this.diff),!this.useColors)return;let c="color: "+this.color;args.splice(1,0,c,"color: inherit");let index=0,lastC=0;args[0].replace(/%[a-zA-Z%]/g,(match)=>{if(match==="%%")return;if(index++,match==="%c")lastC=index}),args.splice(lastC,0,c)}exports.log=console.debug||console.log||(()=>{});function save(namespaces){try{if(namespaces)exports.storage.setItem("debug",namespaces);else exports.storage.removeItem("debug")}catch(error){}}function load(){let r;try{r=exports.storage.getItem("debug")||exports.storage.getItem("DEBUG")}catch(error){}if(!r&&typeof process<"u"&&"env"in process)r=process.env.DEBUG;return r}function localstorage(){try{return localStorage}catch(error){}}module.exports=require_common()(exports);var{formatters}=module.exports;formatters.j=function(v){try{return JSON.stringify(v)}catch(error){return"[UnexpectedJSONParseError]: "+error.message}}});var require_has_flag=__commonJS((exports,module)=>{module.exports=(flag,argv=process.argv)=>{let prefix=flag.startsWith("-")?"":flag.length===1?"-":"--",position=argv.indexOf(prefix+flag),terminatorPosition=argv.indexOf("--");return position!==-1&&(terminatorPosition===-1||position<terminatorPosition)}});var require_supports_color=__commonJS((exports,module)=>{var os=__require("os"),tty=__require("tty"),hasFlag=require_has_flag(),{env}=process,forceColor;if(hasFlag("no-color")||hasFlag("no-colors")||hasFlag("color=false")||hasFlag("color=never"))forceColor=0;else if(hasFlag("color")||hasFlag("colors")||hasFlag("color=true")||hasFlag("color=always"))forceColor=1;if("FORCE_COLOR"in env)if(env.FORCE_COLOR==="true")forceColor=1;else if(env.FORCE_COLOR==="false")forceColor=0;else forceColor=env.FORCE_COLOR.length===0?1:Math.min(parseInt(env.FORCE_COLOR,10),3);function translateLevel(level){if(level===0)return!1;return{level,hasBasic:!0,has256:level>=2,has16m:level>=3}}function supportsColor(haveStream,streamIsTTY){if(forceColor===0)return 0;if(hasFlag("color=16m")||hasFlag("color=full")||hasFlag("color=truecolor"))return 3;if(hasFlag("color=256"))return 2;if(haveStream&&!streamIsTTY&&forceColor===void 0)return 0;let min=forceColor||0;if(env.TERM==="dumb")return min;if(process.platform==="win32"){let osRelease=os.release().split(".");if(Number(osRelease[0])>=10&&Number(osRelease[2])>=10586)return Number(osRelease[2])>=14931?3:2;return 1}if("CI"in env){if(["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","GITHUB_ACTIONS","BUILDKITE"].some((sign)=>(sign in env))||env.CI_NAME==="codeship")return 1;return min}if("TEAMCITY_VERSION"in env)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION)?1:0;if(env.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in env){let version=parseInt((env.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(env.TERM_PROGRAM){case"iTerm.app":return version>=3?3:2;case"Apple_Terminal":return 2}}if(/-256(color)?$/i.test(env.TERM))return 2;if(/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM))return 1;if("COLORTERM"in env)return 1;return min}function getSupportLevel(stream){let level=supportsColor(stream,stream&&stream.isTTY);return translateLevel(level)}module.exports={supportsColor:getSupportLevel,stdout:translateLevel(supportsColor(!0,tty.isatty(1))),stderr:translateLevel(supportsColor(!0,tty.isatty(2)))}});var require_node=__commonJS((exports,module)=>{var tty=__require("tty"),util=__require("util");exports.init=init;exports.log=log;exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.destroy=util.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");exports.colors=[6,2,3,4,5,1];try{let supportsColor=require_supports_color();if(supportsColor&&(supportsColor.stderr||supportsColor).level>=2)exports.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221]}catch(error){}exports.inspectOpts=Object.keys(process.env).filter((key)=>{return/^debug_/i.test(key)}).reduce((obj,key)=>{let prop=key.substring(6).toLowerCase().replace(/_([a-z])/g,(_,k)=>{return k.toUpperCase()}),val=process.env[key];if(/^(yes|on|true|enabled)$/i.test(val))val=!0;else if(/^(no|off|false|disabled)$/i.test(val))val=!1;else if(val==="null")val=null;else val=Number(val);return obj[prop]=val,obj},{});function useColors(){return"colors"in exports.inspectOpts?Boolean(exports.inspectOpts.colors):tty.isatty(process.stderr.fd)}function formatArgs(args){let{namespace:name,useColors:useColors2}=this;if(useColors2){let c=this.color,colorCode="\x1B[3"+(c<8?c:"8;5;"+c),prefix=` ${colorCode};1m${name} \x1B[0m`;args[0]=prefix+args[0].split(`
|
|
3
3
|
`).join(`
|
|
4
4
|
`+prefix),args.push(colorCode+"m+"+module.exports.humanize(this.diff)+"\x1B[0m")}else args[0]=getDate()+name+" "+args[0]}function getDate(){if(exports.inspectOpts.hideDate)return"";return new Date().toISOString()+" "}function log(...args){return process.stderr.write(util.formatWithOptions(exports.inspectOpts,...args)+`
|
|
5
5
|
`)}function save(namespaces){if(namespaces)process.env.DEBUG=namespaces;else delete process.env.DEBUG}function load(){return process.env.DEBUG}function init(debug){debug.inspectOpts={};let keys=Object.keys(exports.inspectOpts);for(let i=0;i<keys.length;i++)debug.inspectOpts[keys[i]]=exports.inspectOpts[keys[i]]}module.exports=require_common()(exports);var{formatters}=module.exports;formatters.o=function(v){return this.inspectOpts.colors=this.useColors,util.inspect(v,this.inspectOpts).split(`
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{REPEAT_SEP,VerbArgs,defaultApiRuntime,findVerb,parseFlags,unknownVerbError,validateAgainstSpec}from"./chunk-
|
|
2
|
+
import{REPEAT_SEP,VerbArgs,defaultApiRuntime,findVerb,parseFlags,unknownVerbError,validateAgainstSpec}from"./chunk-txvjg1g9.js";import{ensurePluginEnginesLoaded}from"./chunk-kdnk8m5j.js";import{ApiError,cliCaller,requireVerbInstalled,splitDaemonCode}from"./chunk-r5j8fycq.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{ROVE_API_VERSION}from"./chunk-96kvwzj8.js";function toApiError(err){if(err instanceof ApiError)return err;let message=errorMessage(err);if(/task not found/i.test(message))return new ApiError(message,"TASK_NOT_FOUND",{hint:"that task id does not exist (deleted or mistyped) \u2014 list live tasks and retry with a real id",nextCommandArgs:["api","list"]});if(/unknown daemon request:/i.test(message))return versionSkewError(message);let coded=splitDaemonCode(message);if(coded)return new ApiError(coded.rest,coded.code);return new ApiError(message,"RPC_ERROR")}function versionSkewError(message){return new ApiError(message,"DAEMON_VERSION_SKEW",{hint:"the running daemon is a different build than this CLI, so it does not serve this verb \u2014 restart the daemon to pick up this build, then retry (if the verb is gone for good, `rove api schema` lists what this daemon actually serves)",nextCommandArgs:["daemon","restart"]})}function errorBody(err){return{message:err.message,code:err.code,...err.data}}function successEnvelope(result){return{apiVersion:ROVE_API_VERSION,ok:!0,result}}function errorEnvelope(err){return{apiVersion:ROVE_API_VERSION,ok:!1,error:errorBody(toApiError(err))}}function flagText(name,spec,value){let type=spec?.type;if(typeof value==="string")return value;if(spec?.repeatable&&Array.isArray(value)&&value.every((item)=>typeof item==="string"))return value.join(REPEAT_SEP);if(typeof value==="boolean"&&(type==="bool"||type===void 0))return String(value);if(typeof value==="number"&&(type==="int"||type==="uint"||type===void 0))return String(value);if(Array.isArray(value)&&(type==="csv"||type===void 0)){if(!value.every((item)=>typeof item==="string"&&!item.includes(",")))throw new ApiError(`param ${name} must be a list of strings without ","`,"BAD_FLAG");return value.join(",")}throw new ApiError(`param ${name} does not fit its ${type} flag`,"BAD_FLAG")}function paramsToFlags(verb,params){let flags=new Map;for(let[name,value]of Object.entries(params))flags.set(name,flagText(name,verb.flags.find((f)=>f.name===name),value));return flags}function booleanFlagsOf(verb){return new Set(verb.flags.filter((f)=>f.type==="bool").map((f)=>f.name))}function repeatableFlagsOf(verb){return new Set(verb.flags.filter((f)=>f.repeatable).map((f)=>f.name))}async function callVerb(verb,flags,deps){requireVerbInstalled(verb);let caller=deps.caller??cliCaller();try{return await verb.handler({args:new VerbArgs(verb,flags,caller),caller,client:deps.client,runtime:deps.runtime??defaultApiRuntime})}catch(err){throw toApiError(err)}}async function runVerb(verbName,input,deps){ensurePluginEnginesLoaded();let verb=findVerb(verbName);if(!verb)throw unknownVerbError(verbName);if(verb.cliOnly&&!(deps.caller??cliCaller()).cli)throw new ApiError(`"${verbName}" streams over stdout/stdin, so only \`rove api\` can run it`,"CLI_ONLY_VERB",{hint:"run it as a CLI command on the machine whose daemon you are talking to"});let flags="argv"in input?parseFlags(input.argv,booleanFlagsOf(verb),repeatableFlagsOf(verb)).flags:paramsToFlags(verb,input.params);return validateAgainstSpec(verb,flags),callVerb(verb,flags,deps)}async function executeVerb(verbName,input,deps){try{return successEnvelope(await runVerb(verbName,input,deps))}catch(err){return errorEnvelope(err)}}function argvToParams(verbName,argv){let verb=findVerb(verbName);if(!verb)throw unknownVerbError(verbName);let{flags}=parseFlags(argv,booleanFlagsOf(verb),repeatableFlagsOf(verb));return Object.fromEntries(flags)}
|
|
3
3
|
export{toApiError,errorBody,successEnvelope,errorEnvelope,paramsToFlags,booleanFlagsOf,repeatableFlagsOf,callVerb,runVerb,executeVerb,argvToParams};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{__require}from"./chunk-91sykzqq.js";var welcomeWrite=Promise.resolve();function trackWelcomeWrite(write){welcomeWrite=write}async function launchTui(){let{startTui}=await import("./chunk-
|
|
2
|
+
import{__require}from"./chunk-91sykzqq.js";var welcomeWrite=Promise.resolve();function trackWelcomeWrite(write){welcomeWrite=write}async function launchTui(){let{startTui}=await import("./chunk-5dq0n3h7.js");await startTui(),await welcomeWrite;let{runPendingWelcomeInstalls}=await import("./chunk-w2tcb3rn.js");runPendingWelcomeInstalls()}
|
|
3
3
|
export{trackWelcomeWrite,launchTui};
|