@sma1lboy/rove 0.9.277-next.2 → 0.9.277-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/cli/{chunk-671ak750.js → chunk-0t6j1skp.js} +1 -1
  2. package/dist/cli/{chunk-n94vzkbe.js → chunk-1cyeyw6g.js} +1 -1
  3. package/dist/cli/{chunk-vwpf55cr.js → chunk-2569f2kc.js} +2 -2
  4. package/dist/cli/{chunk-j1qy79fd.js → chunk-2drde6sc.js} +1 -1
  5. package/dist/cli/{chunk-vpsarakj.js → chunk-4xr4pv54.js} +1 -1
  6. package/dist/cli/{chunk-z3qz6enf.js → chunk-6cfs0nqe.js} +1 -1
  7. package/dist/cli/{chunk-d552cvb2.js → chunk-73zg0mrb.js} +1 -1
  8. package/dist/cli/{chunk-rmsdybs3.js → chunk-7ks7rrnr.js} +2 -2
  9. package/dist/cli/{chunk-ys6v36ph.js → chunk-8j3b5m5h.js} +1 -1
  10. package/dist/cli/{chunk-fgtc1xq9.js → chunk-8jn2axtz.js} +1 -1
  11. package/dist/cli/{chunk-mxx0y791.js → chunk-9s7q3432.js} +1 -1
  12. package/dist/cli/{chunk-gbd5j3dv.js → chunk-aefvcbng.js} +1 -1
  13. package/dist/cli/{chunk-3y0z478f.js → chunk-am5cpb9n.js} +1 -1
  14. package/dist/cli/{chunk-37fas9aj.js → chunk-byh66pd6.js} +1 -1
  15. package/dist/cli/{chunk-pqr6td4z.js → chunk-cgmqnhjn.js} +1 -1
  16. package/dist/cli/{chunk-9x2xd1rz.js → chunk-ck9jdarp.js} +1 -1
  17. package/dist/cli/{chunk-tw9tfs1d.js → chunk-d6j2d6fk.js} +1 -1
  18. package/dist/cli/{chunk-0rvydb9q.js → chunk-e04pp8f5.js} +1 -1
  19. package/dist/cli/{chunk-3dhv5n19.js → chunk-exp78r1c.js} +1 -1
  20. package/dist/cli/{chunk-cf3vpsm5.js → chunk-f7egph8g.js} +1 -1
  21. package/dist/cli/{chunk-jejmt4k0.js → chunk-hdzsswee.js} +3 -3
  22. package/dist/cli/{chunk-kag7cfbr.js → chunk-hzvb6xsd.js} +1 -1
  23. package/dist/cli/{chunk-j9tsdn1d.js → chunk-j30488hn.js} +1 -1
  24. package/dist/cli/{chunk-rztqccs3.js → chunk-jgkdxj5f.js} +1 -1
  25. package/dist/cli/{chunk-748656h7.js → chunk-k2j2tjvd.js} +2 -2
  26. package/dist/cli/{chunk-ta1p2nwa.js → chunk-k9jhy3yx.js} +1 -1
  27. package/dist/cli/{chunk-zpwvjt14.js → chunk-kgpj4k4z.js} +1 -1
  28. package/dist/cli/chunk-m98jd1fz.js +3 -0
  29. package/dist/cli/{chunk-shtm72c0.js → chunk-mcxvazp4.js} +1 -1
  30. package/dist/cli/{chunk-vkv1v3xn.js → chunk-nhd4y1dw.js} +2 -2
  31. package/dist/cli/{chunk-yzdrhytj.js → chunk-np398f2a.js} +1 -1
  32. package/dist/cli/{chunk-mjyhy152.js → chunk-nqwza8b0.js} +1 -1
  33. package/dist/cli/{chunk-ca4x8s96.js → chunk-nv6dz5wy.js} +2 -2
  34. package/dist/cli/{chunk-2vph030z.js → chunk-nvcq93bp.js} +1 -1
  35. package/dist/cli/{chunk-36eyrv4r.js → chunk-p7v3w8ys.js} +1 -1
  36. package/dist/cli/{chunk-6wfhq8xd.js → chunk-qwwt4ch2.js} +1 -1
  37. package/dist/cli/{chunk-g9xknhjq.js → chunk-sh37tm44.js} +1 -1
  38. package/dist/cli/{chunk-nw092jak.js → chunk-t2p22ww7.js} +1 -1
  39. package/dist/cli/{chunk-9fdy8vne.js → chunk-t99295wq.js} +1 -1
  40. package/dist/cli/{chunk-5yh5trgy.js → chunk-v4bax7cf.js} +1 -1
  41. package/dist/cli/{chunk-wzss4pzh.js → chunk-ve76p2mx.js} +1 -1
  42. package/dist/cli/{chunk-bykqhbvy.js → chunk-vwmwmycs.js} +1 -1
  43. package/dist/cli/{chunk-zrf93zrx.js → chunk-w2tcb3rn.js} +1 -1
  44. package/dist/cli/{chunk-rjy900p4.js → chunk-wac6eaxn.js} +1 -1
  45. package/dist/cli/{chunk-5apxck3d.js → chunk-was6vqxt.js} +7 -7
  46. package/dist/cli/{chunk-z3wrbtcq.js → chunk-ym0zghjh.js} +2 -2
  47. package/dist/cli/{chunk-tnatqcy7.js → chunk-z1y9gys2.js} +1 -1
  48. package/dist/cli/index.js +2 -2
  49. package/dist/web/assets/{index-BakEtMcK.js → index-c14wNHdR.js} +29 -29
  50. package/dist/web/index.html +1 -1
  51. package/package.json +1 -1
  52. package/dist/cli/chunk-m4z6kepz.js +0 -3
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{MachineFeed}from"./chunk-9zswhjkv.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-vkv1v3xn.js";import"./chunk-c25vea1q.js";import"./chunk-x89zw7br.js";import"./chunk-qs359899.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-5vrg6h71.js";import{invokeVerb}from"./chunk-671ak750.js";import{argvToParams,executeVerb}from"./chunk-fgtc1xq9.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-v6v272b3.js";import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{HOSTED_THEMES,ThemeInstallError,hostedThemeUrl,parseTheme,writeUserTheme}from"./chunk-wfgrn8p2.js";import{buildContext,checkRef,worktreeDiff,worktreeRefs}from"./chunk-z3wrbtcq.js";import{AUTO_ROUTING_TIERS,autoRoutingKey,describeTierBlock,listFiles,liveSourceProtocol,loadPreviewData,planWorktreeHandoff,readAutoRoutingTable,readClassifierConfig,resolveBase,runWorktreeGit,secretStatus,tierBlock}from"./chunk-zpwvjt14.js";import{ensurePluginEnginesLoaded}from"./chunk-kdnk8m5j.js";import"./chunk-qcjkactr.js";import{listPaneLaunches}from"./chunk-rjfdzjhj.js";import{detectEngineStatus,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-r2bb8b11.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-tt58819p.js";import{forwardVerb,invokeRouted,machineDaemonSocket,requireMachine}from"./chunk-ta1p2nwa.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-shtm72c0.js";import{resolveThemeSlotHex}from"./chunk-j1qy79fd.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-cf3vpsm5.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-tw9tfs1d.js";import{AUTO_STATUS_KEY,DISPATCHER_KEY}from"./chunk-61cn88e7.js";import{defaultEngineCommand,engineDisplayName,engineRenamedFrom,protocolEntry,roveApiInvocation}from"./chunk-atg13xab.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-vvqwgcge.js";import{engineEntry,vendorsWithTurnReader}from"./chunk-x83xbzjd.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,checkLatestVersion,fetchReleaseNotes,fetchReleaseNotesRange}from"./chunk-9ckvdy0j.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-mjyhy152.js";import{DEFAULT_LOCALE,LOCALES,isLocaleId}from"./chunk-wzss4pzh.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-9zswhjkv.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-nhd4y1dw.js";import"./chunk-c25vea1q.js";import"./chunk-x89zw7br.js";import"./chunk-qs359899.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-5vrg6h71.js";import{invokeVerb}from"./chunk-0t6j1skp.js";import{argvToParams,executeVerb}from"./chunk-8jn2axtz.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-v6v272b3.js";import{startFileWatchTrigger}from"./chunk-r3s2t9af.js";import"./chunk-6xr1prk6.js";import{UPDATE_CHANNEL_KEY,UPDATE_NOTIFY_KEY,normalizeReleaseChannel,preferredReleaseChannel}from"./chunk-m98jd1fz.js";import{HOSTED_THEMES,ThemeInstallError,hostedThemeUrl,parseTheme,writeUserTheme}from"./chunk-wfgrn8p2.js";import{buildContext,checkRef,worktreeDiff,worktreeRefs}from"./chunk-ym0zghjh.js";import{AUTO_ROUTING_TIERS,autoRoutingKey,describeTierBlock,listFiles,liveSourceProtocol,loadPreviewData,planWorktreeHandoff,readAutoRoutingTable,readClassifierConfig,resolveBase,runWorktreeGit,secretStatus,tierBlock}from"./chunk-kgpj4k4z.js";import{ensurePluginEnginesLoaded}from"./chunk-kdnk8m5j.js";import"./chunk-qcjkactr.js";import{listPaneLaunches}from"./chunk-rjfdzjhj.js";import{detectEngineStatus,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-r2bb8b11.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-tt58819p.js";import{forwardVerb,invokeRouted,machineDaemonSocket,requireMachine}from"./chunk-k9jhy3yx.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-mcxvazp4.js";import{resolveThemeSlotHex}from"./chunk-2drde6sc.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-d6j2d6fk.js";import{AUTO_STATUS_KEY,DISPATCHER_KEY}from"./chunk-61cn88e7.js";import{defaultEngineCommand,engineDisplayName,engineRenamedFrom,protocolEntry,roveApiInvocation}from"./chunk-atg13xab.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-vvqwgcge.js";import{engineEntry,vendorsWithTurnReader}from"./chunk-x83xbzjd.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-9ckvdy0j.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(`
@@ -92,7 +92,7 @@ usage: rove-bridge [--preset tailscale|cf|relay] [--host <addr>]... [--port <n>]
92
92
  --unlock lift a password-login lockout, then exit
93
93
 
94
94
  --cf-team, --cf-aud, --public-host and --relay-server may also live in
95
- <ROVE_HOME>/.rove/bridge/config.json as cfTeam, cfAud, publicHost, relayServer.`)}if(preset==="cf")publicHost??=config.publicHost??null;if(publicHost!==null&&!/^[A-Za-z0-9.-]+$/.test(publicHost))throw Error(`--public-host must be a bare hostname (no scheme, port or path), got ${publicHost}`);if(preset!=="none"&&hosts.length>0)throw Error("--host cannot be combined with --preset; the preset picks the address");let base={port,rotateToken,rotateRelay,relayShellDir,qr,device,action,relayServer:null};if(preset==="tailscale"){let ts=deps.tailscale?.()??{ipv4:null,dnsName:null};if(!ts.ipv4)throw Error("--preset tailscale: `tailscale ip -4` returned no address \u2014 is Tailscale installed and up?");return{...base,preset,hosts:[ts.ipv4],publicHost:publicHost??ts.dnsName,tls:publicHost!==null,cloudflare:null}}if(preset==="cf"){if(!cfTeam||!cfAud)throw Error("--preset cf needs --cf-team and --cf-aud (or cfTeam/cfAud in bridge/config.json)");if(!publicHost)throw Error("--preset cf needs --public-host: the tunnel hostname the phone dials");return{...base,preset,hosts:["127.0.0.1"],publicHost,tls:!0,cloudflare:{teamDomain:teamDomainOf(cfTeam),aud:cfAud.trim()}}}if(preset==="relay"){if(!relayServer)throw Error("--preset relay needs --relay-server <url> (or relayServer in bridge/config.json)");if(publicHost!==null)throw Error("--public-host cannot be combined with --preset relay");return{...base,preset,hosts:["127.0.0.1"],publicHost:null,tls:!1,cloudflare:null,relayServer:relayOriginOf(relayServer)}}return{...base,preset,hosts:hosts.length>0?[...new Set(hosts)]:["127.0.0.1"],publicHost,tls:publicHost!==null,cloudflare:null}}function isSnapshot(value){return!!value&&typeof value==="object"&&"rows"in value&&Array.isArray(value.rows)&&"rev"in value&&typeof value.rev==="number"}class DispatchFeed{client;snapshot=null;listeners=new Set;constructor(client){this.client=client;client.on("dispatch.snapshot",(frame)=>this.accept(frame.payload,!1))}current(){return this.snapshot}async resync(){this.accept(await this.client.request("dispatch.list").catch(()=>null),!0)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}accept(value,whole){if(!isSnapshot(value))return;if(!whole&&this.snapshot&&value.rev<=this.snapshot.rev)return;this.snapshot=value;for(let listener of this.listeners)listener(value)}}class TaskFeed{read;now;latest=null;latestKey="";listeners=new Set;timer=null;inflight=null;constructor(read,now=Date.now){this.read=read;this.now=now}get active(){return this.listeners.size>0}poke(){if(this.listeners.size===0||this.timer)return;this.timer=setTimeout(()=>{this.timer=null,this.refresh().catch(()=>{})},250)}refresh(){if(this.inflight)return this.inflight;let p=this.read().then((payload)=>{this.latest={payload,readAt:this.now()};let key=JSON.stringify(payload,(k,v)=>k==="forMs"?void 0:v);if(key!==this.latestKey){this.latestKey=key;for(let listener of this.listeners)listener(payload)}return payload});this.inflight=p;let clear=()=>{if(this.inflight===p)this.inflight=null};return p.then(clear,clear),p}current(){if(!this.latest)return this.refresh();let elapsed=Math.max(0,this.now()-this.latest.readAt),{payload}=this.latest;return Promise.resolve({...payload,tasks:payload.tasks.map((t)=>t.activity?{...t,activity:{...t.activity,forMs:t.activity.forMs+elapsed}}:t)})}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}var STALE_NOTICE_MS=1e4;class NoticeFeed{now;listeners=new Set;lastAt=0;constructor(now=Date.now){this.now=now}push(notice){if(!notice||typeof notice.title!=="string"||typeof notice.at!=="number")return;if(notice.at<=this.lastAt)return;if(this.lastAt=notice.at,this.now()-notice.at>1e4)return;let{title,body,kind,taskId,source,at}=notice,clean={title,kind:typeof kind==="string"?kind:"done",at,...body?{body}:{},...taskId?{taskId}:{},...source?{source}:{}};for(let listener of this.listeners)listener(clean)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}var BRIDGE_PROTOCOL_VERSION=1,OPS=["hello","api.invoke","tasks.subscribe","tasks.list","engines.list","repos.list","task.create","task.delete","task.land","task.tabs","tab.new","tab.close","term.attach","term.input","term.resize","term.detach","term.ack","term.revive","diff.files","diff.file","diff.refs","attention.dismiss","ui.viewing","push.key","push.status","push.subscribe","push.unsubscribe"];function isCoreOp(op){return OPS.includes(op)}class BridgeError extends Error{code;detail;constructor(code,message,detail){super(message);this.code=code;this.detail=detail;this.name="BridgeError"}}function parseRequest(raw,known=isCoreOp){let frame;try{frame=JSON.parse(raw)}catch{throw new BridgeError("BAD_FRAME","frame is not JSON")}if(!frame||typeof frame!=="object"||Array.isArray(frame))throw new BridgeError("BAD_FRAME","frame is not an object");let{id,op,args}=frame;if(typeof id!=="number"||!Number.isSafeInteger(id))throw new BridgeError("BAD_FRAME","frame needs an integer id");if(typeof op!=="string"||!known(op))throw Object.assign(new BridgeError("UNKNOWN_OP",`unknown op: ${String(op)}`),{requestId:id});if(args!==void 0&&(args===null||typeof args!=="object"||Array.isArray(args)))throw Object.assign(new BridgeError("BAD_ARGS","args must be an object"),{requestId:id});return{id,op,args:args??{}}}function requestIdOf(err){let id=err&&typeof err==="object"&&"requestId"in err?err.requestId:null;return typeof id==="number"?id:null}function str(args,name){let v=args[name];if(typeof v!=="string"||v.length===0)throw new BridgeError("BAD_ARGS",`${name} must be a non-empty string`);return v}function optStr(args,name){let v=args[name];if(v===void 0||v===null||v==="")return;if(typeof v!=="string")throw new BridgeError("BAD_ARGS",`${name} must be a string`);return v}function optInt(args,name,min,max){let v=args[name];if(v===void 0||v===null)return;if(typeof v!=="number"||!Number.isInteger(v)||v<min||v>max)throw new BridgeError("BAD_ARGS",`${name} must be an integer in ${min}..${max}`);return v}function optBool(args,name){let v=args[name];if(v===void 0||v===null)return!1;if(typeof v!=="boolean")throw new BridgeError("BAD_ARGS",`${name} must be a boolean`);return v}function responseOk(id,result){return JSON.stringify({id,ok:!0,result:result??{}})}function responseError(id,code,message,detail){return JSON.stringify({id,ok:!1,error:{...detail,code,message}})}function pushEvent(event,data){return JSON.stringify({event,data})}function asBridgeError(err,fallback){let code=err&&typeof err==="object"&&"code"in err?err.code:void 0,data=err instanceof ApiError?err.data:void 0;return new BridgeError(typeof code==="string"?code:fallback,err instanceof Error?err.message:String(err),data)}function taskIdOf(argv){for(let i=0;i<argv.length;i++){let arg=argv[i];if(arg==="--task-id")return argv[i+1];if(arg?.startsWith("--task-id="))return arg.slice(10)}return}function createBridgeApi(client,remote){return{machineOf:(taskId)=>remote?.machineOf(taskId),async verb(name,argv,machine){if(machine!==void 0&&machine!=="local"&&!remote)throw new BridgeError("UNKNOWN_MACHINE",`this bridge serves no machine named "${machine}"`);let taskId=taskIdOf(argv),alias=machine!==void 0&&machine!=="local"?machine:taskId===void 0?void 0:remote?.machineOf(taskId);if(alias!==void 0&&remote){let envelope;try{envelope=await remote.forward(alias,name,argvToParams(name,argv))}catch(err){throw asBridgeError(err,"RPC_ERROR")}if(envelope.ok)return envelope.result;let{code,message,...data}=envelope.error;throw new BridgeError(code,message,data)}try{return await invokeVerb(name,argv,{client})}catch(err){throw asBridgeError(err,"RPC_ERROR")}},async rpc(name,payload){try{return await client.request(name,payload)}catch(err){throw asBridgeError(err,"RPC_ERROR")}}}}var REASON_BY_CODE={MACHINE_UNREACHABLE:"offline",MACHINE_VERSION_SKEW:"outdated",UNKNOWN_VERB:"outdated",INBOUND_DENIED:"denied"};async function attempt(call){try{return{ok:!0,result:await call}}catch(err){if(!(err instanceof BridgeError))throw err;return{ok:!1,reason:Object.hasOwn(REASON_BY_CODE,err.code)?REASON_BY_CODE[err.code]:"failed",message:err.message}}}function machineOf(args){let machine=optStr(args,"machine");if(machine!==void 0&&machine.length>64)throw new BridgeError("BAD_ARGS","machine is too long");return machine==="local"?void 0:machine}function repoRows(raw){let rows=raw?.repos;if(!Array.isArray(rows))return[];return rows.flatMap((row)=>typeof row?.id==="string"&&Array.isArray(row.checkouts)?[{id:row.id,primary:typeof row.primary==="string"?row.primary:null,checkouts:row.checkouts.filter((c)=>typeof c==="string")}]:[])}class MachineStore{rows=[];set(statuses){this.rows=statuses.filter((s)=>!s.duplicateOf).map((s)=>({alias:s.alias,hostLabel:s.hostLabel,state:s.state,version:s.version??null,reason:s.state==="online"?null:s.reason??null}))}get(){return this.rows}}var machineStore=new MachineStore;function createMachineOps(store=machineStore){return{"machines.list":{kind:"read",destructive:!1,wraps:"MachineFeed.machinesSignal (the daemon's machines channel, as the TUI sidebar shows it)",async run(){return{machines:store.get()}}},"machines.repos":{kind:"read",destructive:!1,wraps:"repo-list (on `machine`): that machine's repos by id, with their checkouts",async run(args,ctx){let machine=machineOf(args);if(!machine)throw new BridgeError("BAD_ARGS","machine must name a registered machine");let state=store.get().find((row)=>row.alias===machine)?.state;if(state!==void 0&&state!=="online")return{repos:[],reason:state==="mismatch"||state==="unsupported"?"outdated":"offline",message:`machine "${machine}" is ${state}`};let out=await attempt(ctx.api.verb("repo-list",[],machine));return out.ok?{repos:repoRows(out.result)}:{repos:[],reason:out.reason,message:out.message}}}}}var machineOps=createMachineOps();var KEY_HINTS_ENABLED_KEY="hints.keyboard.enabled",PANE_HINT_USED_KEYS=["hints.sidebar.used","hints.files.used"],RAIL_FOLD_STYLES=appearanceChoices("railFold",[]).map((c)=>c.value),bool=(key,fallback,extra)=>({kind:"bool",read:(s)=>typeof s[key]==="boolean"?s[key]:fallback,write:(v)=>({[key]:v,...extra?.(v)})}),choice=(key,choices,read,stored=(v)=>v)=>({kind:"enum",choices:()=>choices,read:(s)=>read(s[key]),write:(v)=>({[key]:stored(v)})}),appearance=(setting)=>appearanceChoices(setting,[]).map((c)=>c.value),text=(raw)=>typeof raw==="string"?raw.trim():"";function worktreeKind(state){return worktreeBaseKindOf(text(state[WORKTREE_BASE_KEY]))}function worktreeCustomPath(state){return text(state[WORKTREE_BASE_CUSTOM_KEY])||(worktreeKind(state)==="custom"?text(state[WORKTREE_BASE_KEY]):"")}var WORKTREE_KINDS=["default","nextToProject","custom"],PREF_DEFS={locale:choice("locale",LOCALES.map((l)=>l.id),(raw)=>isLocaleId(raw)?raw:DEFAULT_LOCALE),theme:{kind:"enum",choices:(themes)=>themes,read:(s)=>typeof s.activeTheme==="string"&&s.activeTheme?s.activeTheme:DEFAULT_THEME,write:(v)=>({activeTheme:v})},themeMode:choice("themeMode",THEME_MODE_PREFERENCES,(raw)=>THEME_MODE_PREFERENCES.includes(raw)?raw:DEFAULT_THEME_MODE),transparent:bool("transparentBackground",defaultTransparentBackground()),focusAccent:choice("focusAccent",FOCUS_ACCENT_SLOTS,(raw)=>FOCUS_ACCENT_SLOTS.includes(raw)?raw:"primary"),splitStyle:choice(SPLIT_STYLE_KEY,appearance("splitStyle"),normalizeSplitStyle),railFold:choice(RAIL_FOLD_STYLE_KEY,RAIL_FOLD_STYLES,(raw)=>RAIL_FOLD_STYLES.includes(raw)?raw:"glyphs"),workingBorder:choice(WORKING_BORDER_KEY,appearance("workingBorder"),(raw)=>normalizeWorkingBorder(raw??DEFAULT_WORKING_BORDER)),taskColors:choice(TASK_COLORS_KEY,appearance("taskColors"),(raw)=>normalizeTaskColors(raw??DEFAULT_TASK_COLORS)),glyphSet:choice(GLYPH_SET_KEY,appearance("glyphSet"),(raw)=>normalizeGlyphSet(raw??DEFAULT_GLYPH_SET)),colorblind:choice(COLORBLIND_KEY,appearance("colorblind"),(raw)=>normalizeColorblind(raw??DEFAULT_COLORBLIND)),runningTitle:choice(RUNNING_TITLE_KEY,appearance("runningTitle"),(raw)=>normalizeRunningTitle(raw??DEFAULT_RUNNING_TITLE)),toast:bool("notifications.toast.enabled",!0),sound:bool("notifications.sound.enabled",!0),soundVolume:choice(SOUND_VOLUME_KEY,SOUND_VOLUME_STEPS,(raw)=>normalizeSoundVolume(raw??DEFAULT_SOUND_VOLUME)),crossTask:bool("notifications.crossTask.enabled",!0),finishedAlerts:bool(FINISHED_ALERTS_KEY,!0),keyHints:bool(KEY_HINTS_ENABLED_KEY,!0,(on)=>on?Object.fromEntries(PANE_HINT_USED_KEYS.map((k)=>[k,!1])):{}),zen:bool(ZEN_ACTIVE_KEY,ZEN_DEFAULT),editorKind:choice(EDITOR_KIND_KEY,EDITOR_KINDS,(raw)=>normalizeEditorKind(raw??DEFAULT_EDITOR_KIND)),worktreeBase:{kind:"enum",choices:()=>WORKTREE_KINDS,read:(s)=>worktreeKind(s),write:(kind,s)=>{let current=text(s[WORKTREE_BASE_KEY]),remember=worktreeKind(s)==="custom"&&kind!=="custom"?{[WORKTREE_BASE_CUSTOM_KEY]:current}:{};if(kind==="default")return{...remember,[WORKTREE_BASE_KEY]:""};if(kind==="nextToProject")return{...remember,[WORKTREE_BASE_KEY]:PROJECT_SIBLING_BASE};let custom=worktreeCustomPath(s);if(!custom)throw new BridgeError("BAD_ARGS","no custom worktree base is remembered; set one in the TUI");return{[WORKTREE_BASE_KEY]:custom}}},scrollbackRows:{kind:"int",min:SCROLLBACK_ROWS_MIN,max:SCROLLBACK_ROWS_MAX,read:(s)=>normalizeScrollbackRows(s[SCROLLBACK_ROWS_KEY]??DEFAULT_SCROLLBACK_ROWS),write:(v)=>({[SCROLLBACK_ROWS_KEY]:normalizeScrollbackRows(v)})},tabStrip:{kind:"enum",choices:()=>TAB_STRIP_MODES,read:(s)=>resolveTabStripMode(s[TAB_STRIP_MODE_KEY],s[TAB_STRIP_HIDE_SINGLE_KEY]),write:(v)=>({[TAB_STRIP_MODE_KEY]:v})},prefixTap:choice(PREFIX_TAP_PRESENTATION_KEY,PREFIX_TAP_PRESENTATIONS,(raw)=>normalizePrefixTapPresentation(raw??DEFAULT_PREFIX_TAP_PRESENTATION)),remoteProjects:bool("experimental.remoteProjects",!1),autoStatus:bool(AUTO_STATUS_KEY,!1),dispatcher:bool(DISPATCHER_KEY,!1)};function prefInfo(state){return{editorCustomSet:text(state[EDITOR_CUSTOM_KEY]).length>0,worktreeCustomPath:worktreeCustomPath(state)}}function checkPrefValue(name,def,value,themes){let bad=(why)=>{throw new BridgeError("BAD_ARGS",`${name} ${why}`)};if(def.kind==="bool")return typeof value==="boolean"?value:bad("must be a boolean");if(def.kind==="int"){if(typeof value!=="number"||!Number.isInteger(value))return bad("must be an integer");return value<def.min||value>def.max?bad(`must be ${def.min}\u2013${def.max}`):value}let choices=def.choices(themes);if((typeof value==="string"||typeof value==="number")&&choices.includes(value))return value;return bad(`must be one of ${choices.join("|")}`)}var VIEWS=["browser","files","diff"];class PanelFeed{now;listeners=new Set;lastKey="";lastAt=0;constructor(now=Date.now){this.now=now}push(panel){if(!panel||typeof panel.taskId!=="string"||typeof panel.at!=="number"||!VIEWS.includes(panel.view))return;let{taskId,view,url,path,at}=panel,key=JSON.stringify([at,taskId,view,url,path]);if(at<this.lastAt||key===this.lastKey)return;if(this.lastAt=at,this.lastKey=key,this.now()-at>STALE_NOTICE_MS)return;let clean={taskId,view,at,...typeof url==="string"?{url}:{},...typeof path==="string"?{path}:{}};for(let listener of this.listeners)listener(clean)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}import{randomBytes as randomBytes2,scrypt,timingSafeEqual as timingSafeEqual3}from"crypto";import{chmodSync as chmodSync2,existsSync as existsSync2,mkdirSync as mkdirSync2,readFileSync as readFileSync2,renameSync,rmSync,writeFileSync as writeFileSync2}from"fs";import{dirname as dirname2,join}from"path";var COST={N:32768,r:8,p:1},KEY_LENGTH=32,MIN_PASSWORD_LENGTH=8,MAX_PASSWORD_LENGTH=1024;function webPasswordPaths(bridgeDir){return{password:join(bridgeDir,"web-password.json"),lockout:join(bridgeDir,"web-login-lock.json")}}function derive(password,salt,cost){return new Promise((resolve,reject)=>{scrypt(password,salt,KEY_LENGTH,{...cost,maxmem:256*cost.N*cost.r},(err,key)=>err?reject(err):resolve(key))})}async function hashPassword(password){let salt=randomBytes2(16),key=await derive(password,salt,COST);return{algo:"scrypt",...COST,salt:salt.toString("base64"),hash:key.toString("base64")}}async function verifyPassword(record,password){let expected=Buffer.from(record.hash,"base64"),key=await derive(password,Buffer.from(record.salt,"base64"),record);return key.length===expected.length&&timingSafeEqual3(key,expected)}function writeOwnerOnly(path,body){mkdirSync2(dirname2(path),{recursive:!0,mode:448}),chmodSync2(dirname2(path),448);let tmp=`${path}.${process.pid}.tmp`;writeFileSync2(tmp,body,{mode:384}),chmodSync2(tmp,384),renameSync(tmp,path)}function readPassword(path){if(!existsSync2(path))return null;try{let raw=JSON.parse(readFileSync2(path,"utf8")),pow2=(n)=>typeof n==="number"&&Number.isInteger(Math.log2(n));if(raw.algo!=="scrypt"||!pow2(raw.N)||raw.N<COST.N||raw.N>1048576)return null;if(typeof raw.r!=="number"||typeof raw.p!=="number")return null;if(typeof raw.salt!=="string"||typeof raw.hash!=="string")return null;return raw}catch{return null}}function writePassword(path,record){writeOwnerOnly(path,`${JSON.stringify(record,null,2)}
95
+ <ROVE_HOME>/.rove/bridge/config.json as cfTeam, cfAud, publicHost, relayServer.`)}if(preset==="cf")publicHost??=config.publicHost??null;if(publicHost!==null&&!/^[A-Za-z0-9.-]+$/.test(publicHost))throw Error(`--public-host must be a bare hostname (no scheme, port or path), got ${publicHost}`);if(preset!=="none"&&hosts.length>0)throw Error("--host cannot be combined with --preset; the preset picks the address");let base={port,rotateToken,rotateRelay,relayShellDir,qr,device,action,relayServer:null};if(preset==="tailscale"){let ts=deps.tailscale?.()??{ipv4:null,dnsName:null};if(!ts.ipv4)throw Error("--preset tailscale: `tailscale ip -4` returned no address \u2014 is Tailscale installed and up?");return{...base,preset,hosts:[ts.ipv4],publicHost:publicHost??ts.dnsName,tls:publicHost!==null,cloudflare:null}}if(preset==="cf"){if(!cfTeam||!cfAud)throw Error("--preset cf needs --cf-team and --cf-aud (or cfTeam/cfAud in bridge/config.json)");if(!publicHost)throw Error("--preset cf needs --public-host: the tunnel hostname the phone dials");return{...base,preset,hosts:["127.0.0.1"],publicHost,tls:!0,cloudflare:{teamDomain:teamDomainOf(cfTeam),aud:cfAud.trim()}}}if(preset==="relay"){if(!relayServer)throw Error("--preset relay needs --relay-server <url> (or relayServer in bridge/config.json)");if(publicHost!==null)throw Error("--public-host cannot be combined with --preset relay");return{...base,preset,hosts:["127.0.0.1"],publicHost:null,tls:!1,cloudflare:null,relayServer:relayOriginOf(relayServer)}}return{...base,preset,hosts:hosts.length>0?[...new Set(hosts)]:["127.0.0.1"],publicHost,tls:publicHost!==null,cloudflare:null}}function isSnapshot(value){return!!value&&typeof value==="object"&&"rows"in value&&Array.isArray(value.rows)&&"rev"in value&&typeof value.rev==="number"}class DispatchFeed{client;snapshot=null;listeners=new Set;constructor(client){this.client=client;client.on("dispatch.snapshot",(frame)=>this.accept(frame.payload,!1))}current(){return this.snapshot}async resync(){this.accept(await this.client.request("dispatch.list").catch(()=>null),!0)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}accept(value,whole){if(!isSnapshot(value))return;if(!whole&&this.snapshot&&value.rev<=this.snapshot.rev)return;this.snapshot=value;for(let listener of this.listeners)listener(value)}}class TaskFeed{read;now;latest=null;latestKey="";listeners=new Set;timer=null;inflight=null;constructor(read,now=Date.now){this.read=read;this.now=now}get active(){return this.listeners.size>0}poke(){if(this.listeners.size===0||this.timer)return;this.timer=setTimeout(()=>{this.timer=null,this.refresh().catch(()=>{})},250)}refresh(){if(this.inflight)return this.inflight;let p=this.read().then((payload)=>{this.latest={payload,readAt:this.now()};let key=JSON.stringify(payload,(k,v)=>k==="forMs"?void 0:v);if(key!==this.latestKey){this.latestKey=key;for(let listener of this.listeners)listener(payload)}return payload});this.inflight=p;let clear=()=>{if(this.inflight===p)this.inflight=null};return p.then(clear,clear),p}current(){if(!this.latest)return this.refresh();let elapsed=Math.max(0,this.now()-this.latest.readAt),{payload}=this.latest;return Promise.resolve({...payload,tasks:payload.tasks.map((t)=>t.activity?{...t,activity:{...t.activity,forMs:t.activity.forMs+elapsed}}:t)})}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}var STALE_NOTICE_MS=1e4;class NoticeFeed{now;listeners=new Set;lastAt=0;constructor(now=Date.now){this.now=now}push(notice){if(!notice||typeof notice.title!=="string"||typeof notice.at!=="number")return;if(notice.at<=this.lastAt)return;if(this.lastAt=notice.at,this.now()-notice.at>1e4)return;let{title,body,kind,taskId,source,at}=notice,clean={title,kind:typeof kind==="string"?kind:"done",at,...body?{body}:{},...taskId?{taskId}:{},...source?{source}:{}};for(let listener of this.listeners)listener(clean)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}var BRIDGE_PROTOCOL_VERSION=1,OPS=["hello","api.invoke","tasks.subscribe","tasks.list","engines.list","repos.list","task.create","task.delete","task.land","task.tabs","tab.new","tab.close","term.attach","term.input","term.resize","term.detach","term.ack","term.revive","diff.files","diff.file","diff.refs","attention.dismiss","ui.viewing","push.key","push.status","push.subscribe","push.unsubscribe"];function isCoreOp(op){return OPS.includes(op)}class BridgeError extends Error{code;detail;constructor(code,message,detail){super(message);this.code=code;this.detail=detail;this.name="BridgeError"}}function parseRequest(raw,known=isCoreOp){let frame;try{frame=JSON.parse(raw)}catch{throw new BridgeError("BAD_FRAME","frame is not JSON")}if(!frame||typeof frame!=="object"||Array.isArray(frame))throw new BridgeError("BAD_FRAME","frame is not an object");let{id,op,args}=frame;if(typeof id!=="number"||!Number.isSafeInteger(id))throw new BridgeError("BAD_FRAME","frame needs an integer id");if(typeof op!=="string"||!known(op))throw Object.assign(new BridgeError("UNKNOWN_OP",`unknown op: ${String(op)}`),{requestId:id});if(args!==void 0&&(args===null||typeof args!=="object"||Array.isArray(args)))throw Object.assign(new BridgeError("BAD_ARGS","args must be an object"),{requestId:id});return{id,op,args:args??{}}}function requestIdOf(err){let id=err&&typeof err==="object"&&"requestId"in err?err.requestId:null;return typeof id==="number"?id:null}function str(args,name){let v=args[name];if(typeof v!=="string"||v.length===0)throw new BridgeError("BAD_ARGS",`${name} must be a non-empty string`);return v}function optStr(args,name){let v=args[name];if(v===void 0||v===null||v==="")return;if(typeof v!=="string")throw new BridgeError("BAD_ARGS",`${name} must be a string`);return v}function optInt(args,name,min,max){let v=args[name];if(v===void 0||v===null)return;if(typeof v!=="number"||!Number.isInteger(v)||v<min||v>max)throw new BridgeError("BAD_ARGS",`${name} must be an integer in ${min}..${max}`);return v}function optBool(args,name){let v=args[name];if(v===void 0||v===null)return!1;if(typeof v!=="boolean")throw new BridgeError("BAD_ARGS",`${name} must be a boolean`);return v}function responseOk(id,result){return JSON.stringify({id,ok:!0,result:result??{}})}function responseError(id,code,message,detail){return JSON.stringify({id,ok:!1,error:{...detail,code,message}})}function pushEvent(event,data){return JSON.stringify({event,data})}function asBridgeError(err,fallback){let code=err&&typeof err==="object"&&"code"in err?err.code:void 0,data=err instanceof ApiError?err.data:void 0;return new BridgeError(typeof code==="string"?code:fallback,err instanceof Error?err.message:String(err),data)}function taskIdOf(argv){for(let i=0;i<argv.length;i++){let arg=argv[i];if(arg==="--task-id")return argv[i+1];if(arg?.startsWith("--task-id="))return arg.slice(10)}return}function createBridgeApi(client,remote){return{machineOf:(taskId)=>remote?.machineOf(taskId),async verb(name,argv,machine){if(machine!==void 0&&machine!=="local"&&!remote)throw new BridgeError("UNKNOWN_MACHINE",`this bridge serves no machine named "${machine}"`);let taskId=taskIdOf(argv),alias=machine!==void 0&&machine!=="local"?machine:taskId===void 0?void 0:remote?.machineOf(taskId);if(alias!==void 0&&remote){let envelope;try{envelope=await remote.forward(alias,name,argvToParams(name,argv))}catch(err){throw asBridgeError(err,"RPC_ERROR")}if(envelope.ok)return envelope.result;let{code,message,...data}=envelope.error;throw new BridgeError(code,message,data)}try{return await invokeVerb(name,argv,{client})}catch(err){throw asBridgeError(err,"RPC_ERROR")}},async rpc(name,payload){try{return await client.request(name,payload)}catch(err){throw asBridgeError(err,"RPC_ERROR")}}}}var REASON_BY_CODE={MACHINE_UNREACHABLE:"offline",MACHINE_VERSION_SKEW:"outdated",UNKNOWN_VERB:"outdated",INBOUND_DENIED:"denied"};async function attempt(call){try{return{ok:!0,result:await call}}catch(err){if(!(err instanceof BridgeError))throw err;return{ok:!1,reason:Object.hasOwn(REASON_BY_CODE,err.code)?REASON_BY_CODE[err.code]:"failed",message:err.message}}}function machineOf(args){let machine=optStr(args,"machine");if(machine!==void 0&&machine.length>64)throw new BridgeError("BAD_ARGS","machine is too long");return machine==="local"?void 0:machine}function repoRows(raw){let rows=raw?.repos;if(!Array.isArray(rows))return[];return rows.flatMap((row)=>typeof row?.id==="string"&&Array.isArray(row.checkouts)?[{id:row.id,primary:typeof row.primary==="string"?row.primary:null,checkouts:row.checkouts.filter((c)=>typeof c==="string")}]:[])}class MachineStore{rows=[];set(statuses){this.rows=statuses.filter((s)=>!s.duplicateOf).map((s)=>({alias:s.alias,hostLabel:s.hostLabel,state:s.state,version:s.version??null,reason:s.state==="online"?null:s.reason??null}))}get(){return this.rows}}var machineStore=new MachineStore;function createMachineOps(store=machineStore){return{"machines.list":{kind:"read",destructive:!1,wraps:"MachineFeed.machinesSignal (the daemon's machines channel, as the TUI sidebar shows it)",async run(){return{machines:store.get()}}},"machines.repos":{kind:"read",destructive:!1,wraps:"repo-list (on `machine`): that machine's repos by id, with their checkouts",async run(args,ctx){let machine=machineOf(args);if(!machine)throw new BridgeError("BAD_ARGS","machine must name a registered machine");let state=store.get().find((row)=>row.alias===machine)?.state;if(state!==void 0&&state!=="online")return{repos:[],reason:state==="mismatch"||state==="unsupported"?"outdated":"offline",message:`machine "${machine}" is ${state}`};let out=await attempt(ctx.api.verb("repo-list",[],machine));return out.ok?{repos:repoRows(out.result)}:{repos:[],reason:out.reason,message:out.message}}}}}var machineOps=createMachineOps();var KEY_HINTS_ENABLED_KEY="hints.keyboard.enabled",PANE_HINT_USED_KEYS=["hints.sidebar.used","hints.files.used"],RAIL_FOLD_STYLES=appearanceChoices("railFold",[]).map((c)=>c.value),bool=(key,fallback,extra)=>({kind:"bool",read:(s)=>typeof s[key]==="boolean"?s[key]:fallback,write:(v)=>({[key]:v,...extra?.(v)})}),choice=(key,choices,read,stored=(v)=>v)=>({kind:"enum",choices:()=>choices,read:(s)=>read(s[key]),write:(v)=>({[key]:stored(v)})}),appearance=(setting)=>appearanceChoices(setting,[]).map((c)=>c.value),text=(raw)=>typeof raw==="string"?raw.trim():"";function worktreeKind(state){return worktreeBaseKindOf(text(state[WORKTREE_BASE_KEY]))}function worktreeCustomPath(state){return text(state[WORKTREE_BASE_CUSTOM_KEY])||(worktreeKind(state)==="custom"?text(state[WORKTREE_BASE_KEY]):"")}var WORKTREE_KINDS=["default","nextToProject","custom"],PREF_DEFS={locale:choice("locale",LOCALES.map((l)=>l.id),(raw)=>isLocaleId(raw)?raw:DEFAULT_LOCALE),theme:{kind:"enum",choices:(themes)=>themes,read:(s)=>typeof s.activeTheme==="string"&&s.activeTheme?s.activeTheme:DEFAULT_THEME,write:(v)=>({activeTheme:v})},themeMode:choice("themeMode",THEME_MODE_PREFERENCES,(raw)=>THEME_MODE_PREFERENCES.includes(raw)?raw:DEFAULT_THEME_MODE),transparent:bool("transparentBackground",defaultTransparentBackground()),focusAccent:choice("focusAccent",FOCUS_ACCENT_SLOTS,(raw)=>FOCUS_ACCENT_SLOTS.includes(raw)?raw:"primary"),splitStyle:choice(SPLIT_STYLE_KEY,appearance("splitStyle"),normalizeSplitStyle),railFold:choice(RAIL_FOLD_STYLE_KEY,RAIL_FOLD_STYLES,(raw)=>RAIL_FOLD_STYLES.includes(raw)?raw:"glyphs"),workingBorder:choice(WORKING_BORDER_KEY,appearance("workingBorder"),(raw)=>normalizeWorkingBorder(raw??DEFAULT_WORKING_BORDER)),taskColors:choice(TASK_COLORS_KEY,appearance("taskColors"),(raw)=>normalizeTaskColors(raw??DEFAULT_TASK_COLORS)),glyphSet:choice(GLYPH_SET_KEY,appearance("glyphSet"),(raw)=>normalizeGlyphSet(raw??DEFAULT_GLYPH_SET)),colorblind:choice(COLORBLIND_KEY,appearance("colorblind"),(raw)=>normalizeColorblind(raw??DEFAULT_COLORBLIND)),runningTitle:choice(RUNNING_TITLE_KEY,appearance("runningTitle"),(raw)=>normalizeRunningTitle(raw??DEFAULT_RUNNING_TITLE)),toast:bool("notifications.toast.enabled",!0),sound:bool("notifications.sound.enabled",!0),soundVolume:choice(SOUND_VOLUME_KEY,SOUND_VOLUME_STEPS,(raw)=>normalizeSoundVolume(raw??DEFAULT_SOUND_VOLUME)),crossTask:bool("notifications.crossTask.enabled",!0),finishedAlerts:bool(FINISHED_ALERTS_KEY,!0),keyHints:bool(KEY_HINTS_ENABLED_KEY,!0,(on)=>on?Object.fromEntries(PANE_HINT_USED_KEYS.map((k)=>[k,!1])):{}),zen:bool(ZEN_ACTIVE_KEY,ZEN_DEFAULT),editorKind:choice(EDITOR_KIND_KEY,EDITOR_KINDS,(raw)=>normalizeEditorKind(raw??DEFAULT_EDITOR_KIND)),worktreeBase:{kind:"enum",choices:()=>WORKTREE_KINDS,read:(s)=>worktreeKind(s),write:(kind,s)=>{let current=text(s[WORKTREE_BASE_KEY]),remember=worktreeKind(s)==="custom"&&kind!=="custom"?{[WORKTREE_BASE_CUSTOM_KEY]:current}:{};if(kind==="default")return{...remember,[WORKTREE_BASE_KEY]:""};if(kind==="nextToProject")return{...remember,[WORKTREE_BASE_KEY]:PROJECT_SIBLING_BASE};let custom=worktreeCustomPath(s);if(!custom)throw new BridgeError("BAD_ARGS","no custom worktree base is remembered; set one in the TUI");return{[WORKTREE_BASE_KEY]:custom}}},scrollbackRows:{kind:"int",min:SCROLLBACK_ROWS_MIN,max:SCROLLBACK_ROWS_MAX,read:(s)=>normalizeScrollbackRows(s[SCROLLBACK_ROWS_KEY]??DEFAULT_SCROLLBACK_ROWS),write:(v)=>({[SCROLLBACK_ROWS_KEY]:normalizeScrollbackRows(v)})},tabStrip:{kind:"enum",choices:()=>TAB_STRIP_MODES,read:(s)=>resolveTabStripMode(s[TAB_STRIP_MODE_KEY],s[TAB_STRIP_HIDE_SINGLE_KEY]),write:(v)=>({[TAB_STRIP_MODE_KEY]:v})},prefixTap:choice(PREFIX_TAP_PRESENTATION_KEY,PREFIX_TAP_PRESENTATIONS,(raw)=>normalizePrefixTapPresentation(raw??DEFAULT_PREFIX_TAP_PRESENTATION)),remoteProjects:bool("experimental.remoteProjects",!1),autoStatus:bool(AUTO_STATUS_KEY,!1),dispatcher:bool(DISPATCHER_KEY,!1),updateChannel:choice(UPDATE_CHANNEL_KEY,RELEASE_CHANNELS,(raw)=>normalizeReleaseChannel(raw)??channelOf()),updateNotify:bool(UPDATE_NOTIFY_KEY,!0)};function prefInfo(state){return{editorCustomSet:text(state[EDITOR_CUSTOM_KEY]).length>0,worktreeCustomPath:worktreeCustomPath(state)}}function checkPrefValue(name,def,value,themes){let bad=(why)=>{throw new BridgeError("BAD_ARGS",`${name} ${why}`)};if(def.kind==="bool")return typeof value==="boolean"?value:bad("must be a boolean");if(def.kind==="int"){if(typeof value!=="number"||!Number.isInteger(value))return bad("must be an integer");return value<def.min||value>def.max?bad(`must be ${def.min}\u2013${def.max}`):value}let choices=def.choices(themes);if((typeof value==="string"||typeof value==="number")&&choices.includes(value))return value;return bad(`must be one of ${choices.join("|")}`)}var VIEWS=["browser","files","diff"];class PanelFeed{now;listeners=new Set;lastKey="";lastAt=0;constructor(now=Date.now){this.now=now}push(panel){if(!panel||typeof panel.taskId!=="string"||typeof panel.at!=="number"||!VIEWS.includes(panel.view))return;let{taskId,view,url,path,at}=panel,key=JSON.stringify([at,taskId,view,url,path]);if(at<this.lastAt||key===this.lastKey)return;if(this.lastAt=at,this.lastKey=key,this.now()-at>STALE_NOTICE_MS)return;let clean={taskId,view,at,...typeof url==="string"?{url}:{},...typeof path==="string"?{path}:{}};for(let listener of this.listeners)listener(clean)}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}}import{randomBytes as randomBytes2,scrypt,timingSafeEqual as timingSafeEqual3}from"crypto";import{chmodSync as chmodSync2,existsSync as existsSync2,mkdirSync as mkdirSync2,readFileSync as readFileSync2,renameSync,rmSync,writeFileSync as writeFileSync2}from"fs";import{dirname as dirname2,join}from"path";var COST={N:32768,r:8,p:1},KEY_LENGTH=32,MIN_PASSWORD_LENGTH=8,MAX_PASSWORD_LENGTH=1024;function webPasswordPaths(bridgeDir){return{password:join(bridgeDir,"web-password.json"),lockout:join(bridgeDir,"web-login-lock.json")}}function derive(password,salt,cost){return new Promise((resolve,reject)=>{scrypt(password,salt,KEY_LENGTH,{...cost,maxmem:256*cost.N*cost.r},(err,key)=>err?reject(err):resolve(key))})}async function hashPassword(password){let salt=randomBytes2(16),key=await derive(password,salt,COST);return{algo:"scrypt",...COST,salt:salt.toString("base64"),hash:key.toString("base64")}}async function verifyPassword(record,password){let expected=Buffer.from(record.hash,"base64"),key=await derive(password,Buffer.from(record.salt,"base64"),record);return key.length===expected.length&&timingSafeEqual3(key,expected)}function writeOwnerOnly(path,body){mkdirSync2(dirname2(path),{recursive:!0,mode:448}),chmodSync2(dirname2(path),448);let tmp=`${path}.${process.pid}.tmp`;writeFileSync2(tmp,body,{mode:384}),chmodSync2(tmp,384),renameSync(tmp,path)}function readPassword(path){if(!existsSync2(path))return null;try{let raw=JSON.parse(readFileSync2(path,"utf8")),pow2=(n)=>typeof n==="number"&&Number.isInteger(Math.log2(n));if(raw.algo!=="scrypt"||!pow2(raw.N)||raw.N<COST.N||raw.N>1048576)return null;if(typeof raw.r!=="number"||typeof raw.p!=="number")return null;if(typeof raw.salt!=="string"||typeof raw.hash!=="string")return null;return raw}catch{return null}}function writePassword(path,record){writeOwnerOnly(path,`${JSON.stringify(record,null,2)}
96
96
  `)}function clearPassword(path){if(!existsSync2(path))return!1;return rmSync(path,{force:!0}),!0}var IP_FAILURE_LIMIT=5,IP_LOCK_MS=900000,GLOBAL_FAILURE_LIMIT=20,GLOBAL_WINDOW_MS=86400000,EMPTY_LOCKOUT={ips:{},failures:[],globalLocked:!1};function lockOf(state,ip,now){if(state.globalLocked)return{kind:"global"};let until=state.ips[ip]?.lockedUntil;return until&&until>now?{kind:"ip",retryAfterMs:until-now}:null}function prune(state,now){let ips={};for(let[ip,rec]of Object.entries(state.ips))if(rec.lockedUntil!==null&&rec.lockedUntil>now||now-rec.last<GLOBAL_WINDOW_MS)ips[ip]=rec;return{...state,ips,failures:state.failures.filter((t)=>now-t<GLOBAL_WINDOW_MS)}}function recordFailure(prev,ip,now){let state=prune(prev,now),old=state.ips[ip],failures=(old&&old.lockedUntil!==null&&old.lockedUntil<=now?0:old?.failures??0)+1,lockedUntil=failures>=IP_FAILURE_LIMIT?now+IP_LOCK_MS:null,all=[...state.failures,now],next={ips:{...state.ips,[ip]:{failures,lockedUntil,last:now}},failures:all,globalLocked:state.globalLocked||all.length>=GLOBAL_FAILURE_LIMIT};return{state:next,lock:lockOf(next,ip,now)}}function recordSuccess(state,ip){let{[ip]:_,...rest}=state.ips;return{...state,ips:rest}}function readLockout(path){if(!existsSync2(path))return EMPTY_LOCKOUT;try{let raw=JSON.parse(readFileSync2(path,"utf8")),ips={};for(let[ip,rec]of Object.entries(raw.ips??{}))if(rec&&typeof rec.failures==="number"&&typeof rec.last==="number")ips[ip]={failures:rec.failures,last:rec.last,lockedUntil:rec.lockedUntil??null};let failures=Array.isArray(raw.failures)?raw.failures.filter((t)=>typeof t==="number"):[];return{ips,failures,globalLocked:raw.globalLocked===!0}}catch{return{...EMPTY_LOCKOUT,globalLocked:!0}}}function writeLockout(path,state){writeOwnerOnly(path,`${JSON.stringify(state)}
97
97
  `)}function promptHidden(question){let stdin=process.stdin;if(!stdin.isTTY)return Promise.reject(Error("--set-password needs an interactive terminal"));return process.stdout.write(question),stdin.setRawMode(!0),stdin.setEncoding("utf8"),stdin.resume(),new Promise((resolve,reject)=>{let value="",finish=()=>{stdin.off("data",onData),stdin.setRawMode(!1),stdin.pause(),process.stdout.write(`
98
98
  `)},onData=(chunk)=>{for(let ch of chunk){if(ch==="\r"||ch===`
@@ -114,7 +114,7 @@ each login gets its own device token (see --list-devices).`),0}class PromptFeed{
114
114
  }
115
115
  }`,str2=(v)=>typeof v==="string"?v:"",num=(v)=>typeof v==="number"&&Number.isFinite(v)?v:0;function checksOf(raw){let state=raw.commits?.nodes?.[0]?.commit?.statusCheckRollup?.state;if(state==="SUCCESS")return"passing";if(state==="FAILURE"||state==="ERROR")return"failing";if(state==="PENDING"||state==="EXPECTED")return"pending";return}function parseQueue(stdout){let parsed;try{parsed=JSON.parse(stdout)}catch{return null}let nodes=parsed?.data?.search?.nodes;return Array.isArray(nodes)?nodes:null}async function knownProjects(ctx){let paths=new Set(taskOpDeps.savedRepos()),{tasks}=await ctx.api.rpc("task.list");for(let task of tasks)paths.add(task.repo);let byId=new Map;for(let path of paths){let id=taskOpDeps.repoId(path);if(id&&!byId.has(id))byId.set(id,path)}return byId}function createReviewOps(now=Date.now){let cached=null;return{"review.queue":{kind:"read",destructive:!1,wraps:"gh api graphql (one fixed read-only search query: open PRs awaiting your review), the machine's own gh login",async run(args,ctx){if(!optBool(args,"refresh")&&cached&&now()-cached.at<=TTL_MS)return shape(cached.raw,await knownProjects(ctx));let res=await taskOpDeps.gh(["api","graphql","-F",`n=${LIMIT}`,"-f",`q=${SEARCH}`,"-f",`query=${QUERY}`],GH_TIMEOUT_MS);if(!res.ok)return{prs:[],other:0,reason:res.reason};let raw=parseQueue(res.stdout);if(!raw)return{prs:[],other:0,reason:"failed"};return cached={at:now(),raw},shape(raw,await knownProjects(ctx))}},"review.prepare":{kind:"write",destructive:!1,wraps:"git fetch origin +refs/pull/<number>/head:refs/rove/pr/<number> (local refs only; nothing is written to GitHub)",async run(args,ctx){let repo=await knownRepo(args,ctx),number=optInt(args,"number",1,1e9);if(number===void 0)throw new BridgeError("BAD_ARGS","number must be a pull request number");let res=await taskOpDeps.fetchPullHead(repo,number);if(!res.ok)throw new BridgeError("FETCH_FAILED",res.error);return{ref:res.ref}}}}}function shape(raw,projects){let prs=[],other=0;for(let pr of raw){let nameWithOwner=str2(pr.repository?.nameWithOwner);if(typeof pr.number!=="number"||typeof pr.title!=="string"||!nameWithOwner)continue;let repo=projects.get(`github.com/${nameWithOwner}`.toLowerCase());if(!repo){other++;continue}let checks=checksOf(pr);prs.push({repo,nameWithOwner,number:pr.number,title:pr.title,url:str2(pr.url),...str2(pr.author?.login)?{author:str2(pr.author?.login)}:{},isDraft:pr.isDraft===!0,createdAt:str2(pr.createdAt),updatedAt:str2(pr.updatedAt),additions:num(pr.additions),deletions:num(pr.deletions),headRef:str2(pr.headRefName),baseRef:str2(pr.baseRefName),fork:pr.isCrossRepository===!0,...checks?{checks}:{}})}return{prs,other}}var reviewOps=createReviewOps();var NAME_MAX2=60,realDeps5={load:loadStateFile,update:(compute)=>{updateStateFile((state)=>{for(let[key,value]of Object.entries(compute(state)))if(value===void 0)delete state[key];else state[key]=value;return})},installed:installedEngineIds,statuses:detectEngineStatuses,integrations:engineIntegrations,engineName:engineDisplayName,defaultCommand:defaultEngineCommand,installSkill:()=>installSkillErrors(),skillMissing:async()=>missingSkillNames(await installedEngineIds())};function strings(state,key){let raw=state[key];return Array.isArray(raw)?raw.filter((s)=>typeof s==="string"&&s.trim().length>0):[]}function trimmed(state,key){let raw=state[key];return typeof raw==="string"?raw.trim():""}async function engineIds(deps,state){return[...new Set([...ALL_VENDORS,...strings(state,"customEngineIds"),...await deps.installed()])]}function canBeDefault(state,id){return isBuiltinVendor(id)||strings(state,"customEngineIds").includes(id)}function effectiveDefault(state,ids){let off=strings(state,"disabledEngineIds"),stored=trimmed(state,"defaultVendor");if(stored&&canBeDefault(state,stored)&&!off.includes(stored))return stored;return ids.find((id)=>canBeDefault(state,id)&&!off.includes(id))??null}function listedId(args,ids){let id=text2(args,"id",64);if(!ids.includes(id))throw new BridgeError("BAD_ARGS",`${id} is not a listed engine`);return id}function createEngineOps(deps){let without=(list,id)=>list.filter((x)=>x!==id);function afterLeaving(state,ids,id,off){let remaining=ids.filter((x)=>x!==id&&!off.includes(x));if(remaining.length===0)throw new BridgeError("LAST_ENGINE","this is the last enabled engine; it stays on");if(effectiveDefault(state,ids)!==id)return{};let next=remaining.find((x)=>canBeDefault(state,x));if(!next)throw new BridgeError("LAST_ENGINE","no other enabled engine can take over as the default");return{defaultVendor:next}}return{"engines.settings":{kind:"read",destructive:!1,wraps:"settings Engines section: registry + detectEngineStatuses + engineIntegrations + state.json switches",async run(){let state=deps.load(),ids=await engineIds(deps,state),[statuses,integrations]=await Promise.all([deps.statuses(ids).catch(()=>[]),Promise.resolve(deps.integrations(ids)).catch(()=>[])]),off=strings(state,"disabledEngineIds"),custom=strings(state,"customEngineIds"),current=effectiveDefault(state,ids);return{defaultId:current,engines:ids.map((id)=>{let status=statuses.find((s)=>s.vendor===id),integration=integrations.find((i)=>i.vendor===id),override=trimmed(state,`engineCommand.${id}`),command=override?override.split(/\s+/):deps.defaultCommand(id),account=status?.account;return{id,name:deps.engineName(id),builtin:isBuiltinVendor(id),custom:custom.includes(id),enabled:!off.includes(id),isDefault:id===current,canBeDefault:canBeDefault(state,id),binary:command[0]??null,customized:override.length>0||trimmed(state,`engineName.${id}`).length>0,renamedFrom:engineRenamedFrom(id,trimmed(state,`engineName.${id}`))??null,protocol:trimmed(state,`engineProtocol.${id}`)||null,binaryFound:status?status.binary.found:null,binaryPath:status?.binary.found?status.binary.path??null:null,login:!status||account===null||account===void 0||status.accountError?"unknown":account.kind==="none"?"no":"yes",hooks:integration?.hooksSupported?integration.hookState:"unsupported",markers:integration?.markers??!1,screen:integration?.screen??!1,...integration?.configIssue?{configIssue:integration.configIssue}:{},skill:integration?.skillDir?integration.skillState:"unsupported"}})}}},"skill.install":{kind:"write",destructive:!0,wraps:"installSkillErrors (lib/skill-install.ts), as Settings \u2192 Engines Rove agent skill",async run(){return{error:deps.installSkill()}}},"skill.missing":{kind:"read",destructive:!1,wraps:"missingSkillNames (lib/skill-install.ts): runnable engines with no skill copy, for the persistent banner",async run(){return{engines:await deps.skillMissing()}}},"engine.setEnabled":{kind:"write",destructive:!0,wraps:"state.json disabledEngineIds (+ defaultVendor handoff), as Settings \u2192 Engines `space`",async run(args){let state=deps.load(),ids=await engineIds(deps,state),id=listedId(args,ids),enabled=bool2(args,"enabled");return deps.update((fresh)=>{let off=strings(fresh,"disabledEngineIds");if(enabled)return{disabledEngineIds:without(off,id)};if(off.includes(id))return{};return{disabledEngineIds:[...off,id],...afterLeaving(fresh,ids,id,off)}}),{id,enabled}}},"engine.setDefault":{kind:"write",destructive:!0,wraps:"state.json defaultVendor (+ re-enables it), as Settings \u2192 Engines `d`",async run(args){let state=deps.load(),ids=await engineIds(deps,state),id=listedId(args,ids);if(!canBeDefault(state,id))throw new BridgeError("BAD_ARGS",`${id} cannot be the default; only built-in and custom engines can`);return deps.update((fresh)=>{let off=strings(fresh,"disabledEngineIds");return{defaultVendor:id,...off.includes(id)?{disabledEngineIds:without(off,id)}:{}}}),{id}}},"engine.rename":{kind:"write",destructive:!0,wraps:"state.json engineName.<id>, as Settings \u2192 Engines `r` (blank clears)",async run(args){let state=deps.load(),id=listedId(args,await engineIds(deps,state)),raw=typeof args.name==="string"?args.name.trim():"";if(raw.length>NAME_MAX2||/[\u0000-\u001f\u007f]/.test(raw))throw new BridgeError("BAD_ARGS",`name must be at most ${NAME_MAX2} printable characters`);return deps.update(()=>({[`engineName.${id}`]:raw.length>0?raw:void 0})),{id,name:raw.length>0?raw:deps.engineName(id)}}},"engine.reset":{kind:"write",destructive:!0,wraps:"state.json engineCommand/engineName/engineProtocol/customEngineIds, as Settings \u2192 Engines `x`",async run(args){let state=deps.load(),ids=await engineIds(deps,state),id=listedId(args,ids),clear={[`engineCommand.${id}`]:void 0,[`engineName.${id}`]:void 0},removed=!1;return deps.update((fresh)=>{let custom=strings(fresh,"customEngineIds");if(!custom.includes(id))return clear;removed=!0;let off=strings(fresh,"disabledEngineIds"),handoff=off.includes(id)?{}:afterLeaving(fresh,ids,id,off);return{...clear,[`engineProtocol.${id}`]:void 0,customEngineIds:without(custom,id),disabledEngineIds:without(off,id),...handoff}}),{id,removed}}}}}var engineOps=createEngineOps(realDeps5);var MODE_KEY="autoRouting.classifier",ENDPOINT_KEY="autoRouting.classifierEndpoint",CLASSIFIER_MODES=["off","jev","custom"],real={...realDeps5,secret:(name)=>secretStatus(name).source},str3=(v)=>typeof v==="string"?v.trim():"";async function pickable(deps,ids){return ids.map((id)=>{let entry=protocolEntry(id);return{id,name:deps.engineName(id),effortLevels:entry.effortLevels??[],takesModel:Boolean(entry.modelArgv)}})}function classifierView(deps,state){let config=readClassifierConfig((key)=>state[key]),mode=config.mode.kind==="url"?"custom":config.mode.kind==="jev"?"jev":"off",endpoint=displayEndpoint(config.mode.kind,str3(state[MODE_KEY]),str3(state[ENDPOINT_KEY])),host="";try{host=endpoint?new URL(endpoint).host:""}catch{host=""}return{mode,endpointHost:host,canCustom:str3(state[ENDPOINT_KEY]).length>0&&readClassifierConfig((k)=>k===MODE_KEY?state[ENDPOINT_KEY]:state[k]).mode.kind==="url",threshold:config.threshold,keyConfigured:config.keyEnv!==void 0,keySource:config.keyEnv?deps.secret(config.keyEnv):"none",...config.keyEnv?{keyEnv:config.keyEnv}:{}}}function createRoutingOps(deps){return{"autoRouting.get":{kind:"read",destructive:!1,wraps:"settings Auto routing section: readAutoRoutingTable + tierBlock over the engine statuses + readClassifierConfig",async run(){let state=deps.load(),ids=await engineIds(deps,state),statuses=await deps.statuses(ids).catch(()=>[]),table=readAutoRoutingTable((key)=>state[key]),engineSet=new Set(ids);return{configured:table!==null,tiers:table?AUTO_ROUTING_TIERS.map((tier)=>{let target=table[tier],block=tierBlock(target,{engineIds:engineSet,accountKind:(engine)=>statuses.find((s)=>s.vendor===engine)?.account?.kind??null});return{tier,engine:target.engine,engineName:deps.engineName(target.engine),model:target.model??null,effort:target.effort??null,block:block?describeTierBlock(block):null}}):[],engines:await pickable(deps,ids),classifier:classifierView(deps,state)}}},"autoRouting.setTier":{kind:"write",destructive:!0,wraps:"state.json autoRouting.<tier>.engine|model|effort, as the Auto routing row's engine picker",async run(args){let tier=oneOf(args,"tier",AUTO_ROUTING_TIERS),state=deps.load(),engine=(await pickable(deps,await engineIds(deps,state))).find((e)=>e.id===args.engine);if(!engine)throw new BridgeError("BAD_ARGS","engine is not a listed engine");let model2=optModel(args,"model")??"";if(model2&&!engine.takesModel)throw new BridgeError("BAD_ARGS",`${engine.id} takes no model`);let effort=typeof args.effort==="string"?args.effort:"";if(effort&&!engine.effortLevels.includes(effort))throw new BridgeError("BAD_ARGS",`effort must be one of ${engine.effortLevels.join("|")||"(none)"}`);return deps.update(()=>({[autoRoutingKey(tier,"engine")]:engine.id,[autoRoutingKey(tier,"model")]:model2,[autoRoutingKey(tier,"effort")]:effort})),{tier,engine:engine.id,model:model2||null,effort:effort||null}}},"autoRouting.setClassifier":{kind:"write",destructive:!0,wraps:"state.json autoRouting.classifier: off | jev | the endpoint the TUI remembered (never a client-sent URL)",async run(args){let mode=oneOf(args,"mode",CLASSIFIER_MODES);return deps.update((fresh)=>{if(mode==="custom"){if(!classifierView(deps,fresh).canCustom)throw new BridgeError("BAD_ARGS","no custom endpoint is remembered; set one in the TUI");return{[MODE_KEY]:str3(fresh[ENDPOINT_KEY])}}let live=str3(fresh[MODE_KEY]);return{...classifierView(deps,fresh).mode==="custom"&&live?{[ENDPOINT_KEY]:live}:{},[MODE_KEY]:mode}}),{mode}}}}}var routingOps=createRoutingOps(real);import{createServer}from"net";import{join as join3}from"path";var RUN_TASKS_KEY="run.tasks",BASE_KEY="run.portBase",COUNT_KEY="run.portCount",DEFAULT_BASE=4100,DEFAULT_COUNT=900,SCRIPT=".rove/run.sh",TAB_TITLE="run",realDeps6={load:loadStateFile,update:(compute)=>void updateStateFile((state)=>{for(let[key,value]of Object.entries(compute(state)))state[key]=value;return}),portFree:(port)=>{let{promise,resolve}=Promise.withResolvers(),probe=createServer();return probe.once("error",()=>resolve(!1)),probe.listen(port,()=>probe.close(()=>resolve(!0))),promise},hasScript:(worktree)=>isNonEmptyRepoFile(join3(worktree,SCRIPT))};function readRecords(state){let raw=state[RUN_TASKS_KEY];if(!raw||typeof raw!=="object"||Array.isArray(raw))return{};let out={};for(let[id,value]of Object.entries(raw)){let r=value;if(!r||typeof r.port!=="number"||!Number.isInteger(r.port))continue;out[id]={port:r.port,...typeof r.session==="string"?{session:r.session}:{},...typeof r.taskId==="string"?{taskId:r.taskId}:{},...typeof r.tabId==="string"?{tabId:r.tabId}:{}}}return out}function portRange(state){let base=state[BASE_KEY],count=state[COUNT_KEY],okBase=typeof base==="number"&&Number.isInteger(base)&&base>=1024&&base<=65535,okCount=typeof count==="number"&&Number.isInteger(count)&&count>=1,start=okBase?base:DEFAULT_BASE;return{base:start,count:Math.max(1,Math.min(okCount?count:DEFAULT_COUNT,65536-start))}}async function pickPort(range,taken,own,running,portFree){if(own!==void 0&&(running||await portFree(own)))return own;for(let port=range.base;port<range.base+range.count;port++)if(!taken.has(port)&&port!==own&&await portFree(port))return port;throw new BridgeError("NO_PORT",`no free port in ${range.base}-${range.base+range.count-1}`)}async function worktreeOf3(api,id){return(await api.verb("get-task",[flag("task-id",id)])).task?.worktreePath||void 0}function runOps(deps=realDeps6){async function state(api,id){let worktree=api.machineOf?.(id)===void 0?await worktreeOf3(api,id):void 0,script=!!worktree&&deps.hasScript(worktree),record=readRecords(deps.load())[id],port=record?.port??null;if(!script)return{script,running:!1,port,listening:!1,url:null,record};let running=!1;if(record?.session){let{sessions}=await api.verb("pty-list",[]);running=!!sessions?.some((s)=>s.key===record.session&&s.alive)}let listening=!1;if(running&&record)listening=!!(await api.verb("ports",["--all"])).ports?.some((p)=>p.port===record.port);let url=listening&&record?`http://localhost:${record.port}`:null;return{script,running,port,listening,url,record}}let answer2=({script,running,port,listening,url})=>({script,running,port,listening,url});return{"run.status":{kind:"read",destructive:!1,wraps:"rove api get-task + pty-list + ports --all (is `.rove/run.sh` there, is its tab alive, does its port listen)",async run(a,{api}){return answer2(await state(api,taskId(a)))}},"run.start":{kind:"write",destructive:!1,wraps:"rove api tab-new --kind shell --type `env PORT=<port> sh .rove/run.sh` (the repo's own committed file; no client text)",async run(a,{api}){let id=taskId(a),now=await state(api,id);if(!now.script)throw new BridgeError("NO_RUN_SCRIPT",`this task's repo has no ${SCRIPT}`);if(now.running)return answer2(now);let all=readRecords(deps.load()),taken=new Set(Object.entries(all).flatMap(([other,r])=>other===id?[]:[r.port])),port=await pickPort(portRange(deps.load()),taken,now.record?.port,!1,deps.portFree),line=`env PORT=${port} ROVE_PORT=${port} sh ${SCRIPT}`,opened=await api.verb("tab-new",[flag("task-id",id),flag("kind","shell"),flag("type",line)]);if(!opened.tabId||!opened.session)throw new BridgeError("SESSION_FAILED","the run tab did not open");let owner=opened.childTaskId??id;return await api.verb("update",[flag("task-id",owner),flag("tab",opened.tabId),flag("title",`${TAB_TITLE} :${port}`)]).catch(()=>{}),deps.update((fresh)=>({[RUN_TASKS_KEY]:{...readRecords(fresh),[id]:{port,session:opened.session,taskId:owner,tabId:opened.tabId}}})),{script:!0,running:!0,port,listening:!1,url:null}}},"run.stop":{kind:"write",destructive:!1,wraps:"rove api tab-close on the run tab (its shell and the server under it end), then archive on the empty `shell` row `run.start` made; the task keeps its port",async run(a,{api}){let id=taskId(a),record=readRecords(deps.load())[id];if(record?.session&&record.taskId&&record.tabId){if(await api.verb("tab-close",[flag("task-id",record.taskId),flag("tab",record.tabId)]).catch(()=>{}),record.taskId!==id)await api.verb("archive",[flag("task-id",record.taskId)]).catch(()=>{});deps.update((fresh)=>({[RUN_TASKS_KEY]:{...readRecords(fresh),[id]:{port:record.port}}}))}return answer2(await state(api,id))}}}}var RUN_OPS=runOps();class UsageStore{rows=null;sessions=null;set(snapshot){this.rows=snapshot===null?null:[...snapshot.entries()].map(([vendor,usage])=>({vendor,capturedAt:usage.capturedAt,windows:usage.windows.map(({kind,label,percent,resetsAt})=>({kind,label,percent,resetsAt}))})).sort((a,b)=>a.vendor.localeCompare(b.vendor))}get(){return this.rows}setContext(map){this.sessions=map}context(session){return this.sessions?.get(session)??null}}var usageStore=new UsageStore;var PLUGIN_ID2=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,CATEGORY=/^[a-z0-9][a-z0-9-]{0,39}$/,realDeps7={usage:usageStore,bridgeVersion:CURRENT_VERSION,engineName:engineDisplayName,listPlugins:()=>readPluginRows(),pluginIds:()=>loadPluginRegistry().plugins.map((p)=>p.id),setPluginEnabled:(id,enabled)=>setPluginEnabled(id,enabled),installedMods:()=>installedBuiltinMods(),setModInstalled:(id,installed)=>setBuiltinModInstalled(id,installed)};function createSettingsOps(deps){return{"usage.get":{kind:"read",destructive:!1,wraps:"the orchestrator's usageSnapshotSignal (daemon usage.snapshot) and, given taskId+tabId, its contextUsageSignal for that session; both held by the bridge",async run(args){let rows=deps.usage.get(),usage=rows===null?null:rows.map((row)=>({...row,name:deps.engineName(row.vendor)}));if(args.taskId===void 0)return{usage};return{usage,context:deps.usage.context(`${taskId(args)}::${tabId(args)}`)}}},"daemon.info":{kind:"read",destructive:!1,wraps:"daemon RPC daemon.status, compared with the bridge's own Rove build (isDaemonVersionStale)",async run(_args,{api}){let status=await api.rpc("daemon.status",{});return{daemonVersion:status.roveVersion??null,bridgeVersion:deps.bridgeVersion,stale:isDaemonVersionStale(status.roveVersion,deps.bridgeVersion),...status.uptimeMs!==void 0?{uptimeMs:status.uptimeMs}:{},...status.startedAt!==void 0?{startedAt:status.startedAt}:{},...status.taskCount!==void 0?{taskCount:status.taskCount}:{},...status.attachedClients!==void 0?{attachedClients:status.attachedClients}:{},...status.automationHold!==void 0?{automationHold:status.automationHold}:{}}}},"plugins.list":{kind:"read",destructive:!1,wraps:"settings Plugins section's readPluginRows (registry + manifest + last run)",async run(){return{plugins:deps.listPlugins().map((p)=>({id:p.id,version:p.version,enabled:p.enabled,linked:p.linked,platformOk:p.platformOk,hooksDeclared:p.hooksDeclared,updateAvailable:p.updateAvailable,declares:p.declares,lastRun:p.lastRun?{at:p.lastRun.at,label:p.lastRun.label,ok:p.lastRun.ok,running:p.lastRun.running}:null}))}}},"plugin.setEnabled":{kind:"write",destructive:!0,wraps:"settings Plugins section's setPluginEnabled (plugins.json; the daemon file-watches it)",async run(args){let id=text2(args,"id",64);if(!PLUGIN_ID2.test(id)||!deps.pluginIds().includes(id))throw new BridgeError("BAD_ARGS",`${id} is not an installed plugin`);let enabled=bool2(args,"enabled");return deps.setPluginEnabled(id,enabled),{id,enabled}}},"builtinMods.list":{kind:"read",destructive:!1,wraps:"builtin-mods.json: the first-party mods (Kanban, Issues) and which are installed",async run(){let installed=new Set(deps.installedMods());return{mods:BUILTIN_MODS.map((mod)=>({id:mod.id,name:mod.name,description:mod.description,installed:installed.has(mod.id)}))}}},"builtinMod.setInstalled":{kind:"write",destructive:!1,wraps:"builtin-mods.json (the TUI, the daemon and `rove api` read the same file)",async run(args){let id=text2(args,"id",64);if(!isBuiltinModId(id))throw new BridgeError("BAD_ARGS",`${id} is not a first-party mod`);let installed=bool2(args,"installed");return deps.setModInstalled(id,installed),{id,installed}}},"feedback.send":{kind:"write",destructive:!0,wraps:"rove api feedback (GitHub Discussion in the Rove repo's Feedback category, via gh)",run(args,{api}){let argv=[flag("title",text2(args,"title",200).trim()),flag("body",text2(args,"body",1e4))],category=optText(args,"category",40);if(category!==void 0){if(!CATEGORY.test(category))throw new BridgeError("BAD_ARGS","category is not a category slug");argv.push(flag("category",category))}return api.verb("feedback",argv)}}}}var settingsOps=createSettingsOps(realDeps7);var SNIPPETS_KEY="prompt.snippets",SNIPPET_NAME=/^[A-Za-z0-9][\w-]{0,31}$/,SNIPPET_TEXT_MAX=8000,SNIPPETS_MAX=100;function readSnippets(state){let raw=state[SNIPPETS_KEY];if(!Array.isArray(raw))return[];let out=[];for(let item of raw){if(!item||typeof item!=="object")continue;let{name,text:body}=item;if(typeof name==="string"&&SNIPPET_NAME.test(name)&&typeof body==="string"&&body.length>0)out.push({name,text:body})}return out}var same2=(a,b)=>a.toLowerCase()===b.toLowerCase(),realDeps8={load:loadStateFile,update:(compute)=>void updateStateFile((state)=>{let next=compute(state);for(let[key,value]of Object.entries(next))state[key]=value;return})};function name(a){let value=text2(a,"name",32);if(!SNIPPET_NAME.test(value))throw new BridgeError("BAD_ARGS","name must be letters, digits, - or _ (up to 32), starting with a letter or digit");return value}function createSnippetOps(deps){return{"snippets.get":{kind:"read",destructive:!1,wraps:"state.json prompt.snippets (name and text pairs)",async run(){return{snippets:readSnippets(deps.load())}}},"snippets.save":{kind:"write",destructive:!1,wraps:"state.json prompt.snippets: adds a snippet, or replaces the one with that name (case-insensitive)",async run(a){let key=name(a),body=text2(a,"text",SNIPPET_TEXT_MAX);return deps.update((fresh)=>{let all=readSnippets(fresh),index=all.findIndex((s)=>same2(s.name,key));if(index<0&&all.length>=SNIPPETS_MAX)throw new BridgeError("BAD_ARGS",`at most ${SNIPPETS_MAX} snippets`);if(index<0)all.push({name:key,text:body});else all[index]={name:key,text:body};return{[SNIPPETS_KEY]:all}}),{snippets:readSnippets(deps.load())}}},"snippets.remove":{kind:"write",destructive:!0,wraps:"state.json prompt.snippets: drops the snippet with that name (case-insensitive)",async run(a){let key=name(a);return deps.update((fresh)=>({[SNIPPETS_KEY]:readSnippets(fresh).filter((s)=>!same2(s.name,key))})),{snippets:readSnippets(deps.load())}}}}}var snippetOps=createSnippetOps(realDeps8);import{existsSync as existsSync4,realpathSync,statSync}from"fs";import{homedir}from"os";import{extname,join as join4,sep}from"path";var SUBDIR_CAP=200,PATH_MAX3=1000;async function reorderDaemonTab(taskId2,tab,delta,api){let{state}=await api.rpc("tabs.get",{taskId:taskId2});if(!state||!Array.isArray(state.tabs))return!1;let current={...state,activeId:state.activeId??""},next=moveTab(current,tab,delta);if(next===current)return!1;let ops=[{op:"order",ids:next.tabs.map((t)=>t.id)}];return await api.rpc("tabs.apply",{taskId:taskId2,ops}),!0}function canonical(path){try{return realpathSync(path)}catch{return null}}function runnable(path){let info=statSync(path);return!info.isFile()||(info.mode&73)!==0}var OPENABLE=new Set("pdf png jpg jpeg gif webp bmp tif tiff heic svg ico mp3 wav m4a aac flac ogg mp4 m4v mov webm mkv avi ttf otf".split(" ")),realDeps9={openExternal:openExternally,detectOpener:detectWorktreeOpener,openWorktree,exists:existsSync4,canonical,runnable,homeDir:homedir,buildCIPrompt:buildCIPromptForWorktree,prPrompt:buildPRPrompt,reorderTab:reorderDaemonTab};function typedPath(args,name2){let v=args[name2];if(typeof v!=="string"||v.length>PATH_MAX3||v.includes("\x00"))throw new BridgeError("BAD_ARGS",`${name2} must be a path`);let trimmed2=v.trim();if(!(trimmed2.startsWith("/")||trimmed2.startsWith("~")))throw new BridgeError("BAD_ARGS",`${name2} must be absolute or start with ~`);return trimmed2}function clearable(args,name2,check){let v=args[name2];if(v===void 0||v===null)return;return v===""?"":check(args,name2)}async function worktreeAndBranch(ctx,id){let res=await ctx.api.verb("get-task",[flag("task-id",id)]),{worktreePath,branch,prStatus}=res.task;if(!worktreePath)throw new BridgeError("NO_WORKTREE",`task ${id} has no worktree yet`);return{worktree:worktreePath,branch:branch??"",prNumber:prStatus?.number,baseRef:prStatus?.baseRef}}var PR_PROMPT_KINDS=["commit","createPR","fixCI","conflicts","comments"];function conflictsPrompt(pr,base){return`${pr} has merge conflicts with ${base}. Fetch, merge ${base} into this branch, resolve every conflict keeping the intent of both sides, run the project's checks, then commit the merge and push.`}function commentsPrompt(pr){return`${pr} has review feedback to address. Read it with \`gh pr view --comments\` and \`gh api repos/{owner}/{repo}/pulls/<number>/comments\`, make a change for each point (reply only where you disagree and say why), run the project's checks, then commit and push.`}var COMMIT_PROMPT="Commit the uncommitted changes in this worktree. Review them with `git status` and `git diff`, split them into logical commits when they are unrelated, write each message in the style of this repo's recent `git log`, and do not push.";function taskOps(deps=realDeps9){return{"task.landPreflight":{kind:"read",destructive:!1,wraps:"rpc task.landPreflight",async run(a,{api}){return(await api.rpc("task.landPreflight",{taskId:taskId(a)})).result}},"task.syncBase":{kind:"write",destructive:!1,wraps:"rpc task.syncBase (merge base into the worktree)",async run(a,{api}){let res=await api.rpc("task.syncBase",{taskId:taskId(a)}),failed=res.result.repos?.find((r)=>!r.ok);if(failed)throw Error(failed.error??"sync failed");return{baseRef:res.result.baseRef,alreadyCurrent:res.result.alreadyCurrent===!0}}},"task.fixChecks":{kind:"write",destructive:!1,wraps:"rpc pr.failingChecks + buildCIPromptForWorktree + rove api send --plain",async run(a,ctx){let id=taskId(a),{worktree,branch,prNumber}=await worktreeAndBranch(ctx,id),read=await ctx.api.rpc("pr.failingChecks",{taskId:id}),checks=read.checks??[];if(read.unavailable)return{outcome:"unavailable",detail:read.unavailable.detail};if(checks.length===0)return{outcome:"none"};let state={checks,totalFailing:read.totalFailing??checks.length},prompt=await deps.buildCIPrompt(worktree,{branch:branch||"HEAD",...prNumber===void 0?{}:{prNumber},...state}),argv=[flag("task-id",id),"--plain",flag("prompt",prompt)];if(a.tabId!==void 0&&a.tabId!==null)argv.push(flag("tab",tabId(a)));return await ctx.api.verb("send",argv),{outcome:"sent"}}},"task.prompt":{kind:"read",destructive:!1,wraps:"buildPRPrompt | rpc pr.failingChecks + buildCIPromptForWorktree | fixed text (commit, conflicts, comments); returns the prompt, sends nothing",async run(a,ctx){let id=taskId(a),kind=oneOf(a,"kind",PR_PROMPT_KINDS),{worktree,branch,prNumber,baseRef}=await worktreeAndBranch(ctx,id),pr=prNumber===void 0?"This task's PR":`PR #${prNumber}`;if(kind==="createPR")return{outcome:"ok",prompt:await deps.prPrompt(worktree)};if(kind==="commit")return{outcome:"ok",prompt:COMMIT_PROMPT};if(kind==="conflicts")return{outcome:"ok",prompt:conflictsPrompt(pr,baseRef||"its base branch")};if(kind==="comments")return{outcome:"ok",prompt:commentsPrompt(pr)};let read=await ctx.api.rpc("pr.failingChecks",{taskId:id}),checks=read.checks??[];if(read.unavailable)return{outcome:"unavailable",detail:read.unavailable.detail};if(checks.length===0)return{outcome:"none"};return{outcome:"ok",prompt:await deps.buildCIPrompt(worktree,{branch:branch||"HEAD",...prNumber===void 0?{}:{prNumber},checks,totalFailing:read.totalFailing??checks.length})}}},"task.openEditor":{kind:"write",destructive:!1,wraps:"helpers detectWorktreeOpener + openWorktree (the TUI's `o`) on the task's worktree, via ensure-worktree",async run(a,{api}){let id=taskId(a),path=(await api.verb("get-task",[flag("task-id",id)])).task.worktreePath??"";if(!path||!deps.exists(path))path=(await api.verb("ensure-worktree",[flag("task-id",id)])).worktreePath??"";if(!path||!deps.exists(path))throw new BridgeError("NO_WORKTREE","this task has no worktree on disk");let opener=deps.detectOpener();if(!opener)return{outcome:"noEditor"};if(!deps.openWorktree(path,opener))return{outcome:"failed",label:opener.label};return{outcome:"opened",label:opener.label}}},"task.openScratch":{kind:"write",destructive:!1,wraps:"rpc task.openDir {dir: $HOME, scratch: true}",async run(a,ctx){let home=deps.homeDir(),picked=optStr(a,"engine")===void 0?void 0:await engineId(a,"engine",ctx),res=await ctx.api.rpc("task.openDir",{dir:home,scratch:!0,vendor:picked??taskOpDeps.preferredEngine(home)});if(picked)taskOpDeps.rememberEngine(home,picked);return{taskId:res.taskId}}},"task.setEngine":{kind:"write",destructive:!1,wraps:"rpc task.setVendor (engine + reasoning level + model; '' clears)",async run(a,ctx){let id=taskId(a),vendor=await engineId(a,"engine",ctx),effort=clearable(a,"effort",(args,n)=>effortLevel(args,n)),mdl=clearable(a,"model",(args,n)=>model(args,n));return await ctx.api.rpc("task.setVendor",{taskId:id,vendor,...effort===void 0?{}:{effort},...mdl===void 0?{}:{model:mdl}}),{}}},"tab.move":{kind:"write",destructive:!1,wraps:"rpc tabs.apply order (the TUI's moveTab on tabs.get)",async run(a,{api}){let direction=oneOf(a,"direction",["up","down"]);return{moved:await deps.reorderTab(taskId(a),tabId(a),direction==="up"?-1:1,api)}}},"file.openExternal":{kind:"write",destructive:!1,wraps:"helper openExternally (the Mac's `open`) on a media/document file inside the task's worktree",async run(a,{api}){let rel=optStr(a,"path")??"";if(!rel||rel.length>PATH_MAX3||rel.startsWith("/")||rel.includes("\x00")||rel.split(/[\\/]/).includes(".."))throw new BridgeError("BAD_ARGS","path must be relative to the worktree");let worktree=(await api.verb("get-task",[flag("task-id",taskId(a))])).task.worktreePath;if(!worktree)throw new BridgeError("NO_WORKTREE","this task has no worktree yet");let root=deps.canonical(worktree),abs=deps.canonical(join4(worktree,rel));if(!root||!abs)throw new BridgeError("NOT_FOUND",`${rel} does not exist`);if(abs!==root&&!abs.startsWith(root.endsWith(sep)?root:root+sep))throw new BridgeError("BAD_ARGS","path is outside the worktree");if(!OPENABLE.has(extname(abs).slice(1).toLowerCase())||deps.runnable(abs))throw new BridgeError("NOT_OPENABLE","only images, audio, video, PDFs and fonts open in the system app");return deps.openExternal(abs),{}}},"fs.subdirs":{kind:"read",destructive:!1,wraps:"helpers splitPathForDirSuggest + listSubdirs + filterSubdirs",async run(a){let split=splitPathForDirSuggest(typedPath(a,"path")),names=filterSubdirs(listSubdirs(split.base),split.filter);return{base:split.base,home:deps.homeDir(),names:names.slice(0,SUBDIR_CAP)}}},"repo.probe":{kind:"read",destructive:!1,wraps:"helpers validateRepoPath + listLocalBranches + getCurrentBranch (+ rpc worktree.discoverAdoptable)",async run(a,{api}){let repo=stripTrailingSlash(expandHome(typedPath(a,"path"))),reason=taskOpDeps.validateRepoPath(repo);if(reason)return{ok:!1,repo,reason};let out={ok:!0,repo,branches:taskOpDeps.listLocalBranches(repo),current:taskOpDeps.getCurrentBranch(repo)};if(a.adoptable===!0){let found=await api.rpc("worktree.discoverAdoptable",{repo});out.worktrees=found.worktrees??[]}return out}}}}var TASKOPS_OPS=taskOps();async function commandFromTask(args,ctx,where){if(args.commandFrom===void 0||args.commandFrom===null||args.commandFrom==="")return null;let id=taskId(args,"commandFrom");if(where.machine)throw new BridgeError("BAD_ARGS","commandFrom needs a task on this machine");if(where.parallel)throw new BridgeError("BAD_ARGS","commandFrom conflicts with count and agents");if(!where.engine)throw new BridgeError("BAD_ARGS","commandFrom needs the engine the source task runs");if(ctx.api.machineOf?.(id))throw new BridgeError("BAD_ARGS","commandFrom needs a task on this machine");let{task}=await ctx.api.verb("get-task",[flag("task-id",id)]);if(task.vendor!==where.engine)throw new BridgeError("BAD_ARGS","commandFrom is only for the engine that task runs; pick that engine or drop it");return task.command??null}var STATUSES=["backlog","in_progress","in_review","done","canceled","error"],DIRECTIONS=["up","down","top"],PROMPT_MAX2=1e5;function extraRepos(args){let raw=args.extraRepos;if(raw===void 0||raw===null)return[];if(!Array.isArray(raw))throw new BridgeError("BAD_ARGS","extraRepos must be an array");if(raw.length+1>MULTI_REPO_CAP)throw new BridgeError("BAD_ARGS",`a task spans at most ${MULTI_REPO_CAP} repos`);return raw.map((entry,i)=>{let item=typeof entry==="object"&&entry!==null?entry:{},repo=absPath(item,"repo"),baseRef=optGitRef(item,"baseRef");if(!repo)throw new BridgeError("BAD_ARGS",`extraRepos[${i}].repo is required`);return{repo,...baseRef?{baseRef}:{}}})}function write(wraps,run,destructive=!1){return{kind:"write",destructive,wraps,run:async(args,ctx)=>run(args,ctx)}}async function done(call){return await call,{}}async function spawn(args,ctx){let machine=optText(args,"machine",64),repo=machine?remoteRepoRef(args,"repo"):absPath(args,"repo"),title=optText(args,"title",200),prompt=optText(args,"prompt",PROMPT_MAX2),branch=optGitRef(args,"branch"),baseBranch=optGitRef(args,"baseBranch"),mdl=optModel(args),effort=args.effort===void 0||args.effort===null||args.effort===""?void 0:effortLevel(args,"effort"),count=optInt(args,"count",1,10),agentsGiven=args.agents!==void 0&&args.agents!==null&&args.agents!=="",status=optOneOf(args,"status",STATUSES),pin=optBool(args,"pin"),engineGiven=args.engine!==void 0&&args.engine!==null&&args.engine!=="",extras=extraRepos(args),clone=optBool(args,"clone");if(clone&&!machine)throw new BridgeError("BAD_ARGS","clone needs a machine");if(clone&&repo.startsWith("/"))throw new BridgeError("BAD_ARGS","clone needs a repo id, not a path");if(extras.length>0&&machine)throw new BridgeError("BAD_ARGS","a multi-repo task must keep every repo on this machine");let parallel=count!==void 0||agentsGiven;if(count!==void 0&&agentsGiven)throw new BridgeError("BAD_ARGS","count and agents are exclusive");if(parallel&&!prompt)throw new BridgeError("BAD_ARGS","count/agents need a prompt");if(parallel&&branch)throw new BridgeError("BAD_ARGS","branch cannot be shared by parallel tasks");if(agentsGiven&&engineGiven)throw new BridgeError("BAD_ARGS","engine conflicts with agents");let plan=agentsGiven?parseAgents(args):void 0;if(plan&&!machine)await checkAgentEngines(plan,ctx);let engine=!engineGiven?void 0:machine?text2(args,"engine",64):await engineId(args,"engine",ctx),carried=await commandFromTask(args,ctx,{engine,machine,parallel}),argv=[flag("repo",repo)];if(clone)argv.push(flag("clone","true"));for(let extra of extras)argv.push(flag("repo",extra.repo));for(let extra of extras)if(extra.baseRef)argv.push(flag("base-for",`${extra.repo}=${extra.baseRef}`));if(title)argv.push(flag("title",title));if(branch)argv.push(flag("branch",branch));if(baseBranch)argv.push(flag("base-branch",baseBranch));if(engine)argv.push(flag("command",carried??engine));if(effort)argv.push(flag("effort",effort));if(mdl)argv.push(flag("model",mdl));if(count!==void 0)argv.push(flag("count",count));if(plan)argv.push(flag("agents",plan.map((p)=>`${p.id}:${p.n}`).join(",")));if(status)argv.push(flag("status",status));if(pin)argv.push(flag("pin","true"));if(prompt)argv.push(flag("prompt",prompt));let res=await ctx.api.verb("add",argv,machine);if(engine&&!machine)taskOpDeps.rememberEngine(repo,engine);if(Array.isArray(res.tasks))return{taskIds:res.tasks.flatMap((t)=>typeof t.taskId==="string"?[t.taskId]:[]),...res.groupId?{groupId:res.groupId}:{}};if(typeof res.taskId!=="string")throw new BridgeError("BAD_RESULT","add returned no task id");return{taskIds:[res.taskId]}}var PROGRESS_GAP_MS=150;async function clone(args,ctx){let url=await cloneSource(args),parentDir=absPath(args,"parentDir"),urlProblem=taskOpDeps.validateGitUrl(url);if(urlProblem)throw new BridgeError("BAD_ARGS",urlProblem);let given2=optStr(args,"folder"),folder=cloneFolder(given2??taskOpDeps.findAvailableFolderName(parentDir,taskOpDeps.deriveFolderName(url))),targetProblem=taskOpDeps.validateCloneTarget(parentDir,folder);if(targetProblem)throw new BridgeError("BAD_ARGS",targetProblem);let lastSent=0,result=await taskOpDeps.cloneRepo(url,taskOpDeps.resolveCloneTarget(parentDir,folder),(line)=>{let now=Date.now();if(now-lastSent<PROGRESS_GAP_MS)return;lastSent=now,ctx.progress?.(line)});if(!result.ok)throw new BridgeError("CLONE_FAILED",result.error);return{path:result.path}}async function adopt(args,ctx){let repo=await knownRepo(args,ctx),worktreePath=absPath(args,"worktreePath"),branch=optGitRef(args,"branch"),title=optText(args,"title",200),engine=args.engine===void 0||args.engine===null||args.engine===""?void 0:await engineId(args,"engine",ctx);if(!((await ctx.api.rpc("worktree.discoverAdoptable",{repo})).worktrees??[]).some((w)=>w.path===worktreePath))throw new BridgeError("NOT_ADOPTABLE",`${worktreePath} is not an adoptable worktree of ${repo}`);return{taskId:(await ctx.api.rpc("worktree.adopt",{repo,worktreePath,...branch?{branch}:{},...title?{title}:{},...engine?{vendor:engine}:{}})).task.id}}async function archive(args,ctx){let id=taskId(args),archived=bool2(args,"archived"),argv=[flag("task-id",id)];if(archived&&optBool(args,"force"))argv.push(flag("force","true"));return{ids:(await ctx.api.verb(archived?"archive":"unarchive",argv)).ids??[]}}var TASK_WRITE_OPS={"task.spawn":write("verb add",spawn),"task.rename":write("verb update --task-id --title",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("title",text2(a,"title",200))]))),"task.setBranch":write("verb update --task-id --branch",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("branch",gitRef(a,"branch"))]))),"task.moveToProject":write("verb update --task-id --project",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("project",absPath(a,"repo"))]))),"task.setCommand":write("verb update --task-id --command=<engine id>",async(a,c)=>{let id=taskId(a),engine=await engineId(a,"engine",c),res=await c.api.verb("update",[flag("task-id",id),flag("command",engine)]);return res.protocol?{protocol:res.protocol}:{}}),"task.setModel":write("verb update --task-id --model",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("model",model(a))]))),"task.setEffort":write("verb update --task-id --effort",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("effort",effortLevel(a))]))),"task.setStatus":write("verb update --task-id --status",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("status",oneOf(a,"status",STATUSES))]))),"task.pin":write("verb update --task-id --pinned",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("pinned",String(bool2(a,"pinned")))]))),"task.keep":write("verb update --task-id --kept",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("kept",String(bool2(a,"kept")))]))),"task.notes":write("rpc task.notes (notes replace + todo ops, applied together)",(a,c)=>{let notes=optText(a,"notes",20000),ops=a.ops;if(ops!==void 0&&(!Array.isArray(ops)||ops.length>50))throw new BridgeError("BAD_ARGS","ops must be a list of at most 50");return c.api.rpc("task.notes",{taskId:taskId(a),...notes!==void 0?{notes}:{},...ops?{ops}:{}})}),"task.scheduleStart":write("rpc task.scheduleStart",async(a,c)=>{let at=text2(a,"at",40);if(!Number.isFinite(Date.parse(at)))throw new BridgeError("BAD_ARGS","at must be an ISO-8601 time");return c.api.rpc("task.scheduleStart",{taskId:taskId(a),at,prompt:text2(a,"prompt",PROMPT_MAX2)})}),"task.cancelScheduledStart":write("rpc task.cancelScheduledStart",(a,c)=>done(c.api.rpc("task.cancelScheduledStart",{taskId:taskId(a)}))),"task.startScheduledNow":write("rpc task.startScheduledNow",(a,c)=>c.api.rpc("task.startScheduledNow",{taskId:taskId(a)})),"task.autoFixCi":write("verb update --task-id --auto-fix-ci",(a,c)=>done(c.api.verb("update",[flag("task-id",taskId(a)),flag("auto-fix-ci",bool2(a,"enabled")?"on":"off")]))),"task.archive":write("verb archive|unarchive --task-id [--force]",archive),"task.move":write("rpc task.move",(a,c)=>done(c.api.rpc("task.move",{taskId:taskId(a),direction:oneOf(a,"direction",DIRECTIONS)}))),"project.forget":write("rpc project.forget",async(a,c)=>done(c.api.rpc("project.forget",{repo:await knownRepo(a,c)})),!0),"notes.delete":write("verb note-delete --repo --id",async(a,c)=>{let repo=await knownRepo(a,c),id=optInt(a,"id",1,Number.MAX_SAFE_INTEGER);if(id===void 0)throw new BridgeError("BAD_ARGS","id must be an integer in 1..");return{deleted:(await c.api.verb("note-delete",[flag("repo",repo),flag("id",id)])).deleted===!0}},!0),"task.openMain":write("rpc task.ensureMain",async(a,c)=>{let repo=absPath(a,"repo"),problem=taskOpDeps.validateRepoPath(repo);if(problem)throw new BridgeError("BAD_ARGS",problem);return{taskId:(await c.api.rpc("task.ensureMain",{repo})).task.id}}),"task.openCheckout":write("rpc task.ensureMain + task.openDir {dir: the project root}",async(a,c)=>{let repo=absPath(a,"repo"),problem=taskOpDeps.validateRepoPath(repo);if(problem)throw new BridgeError("BAD_ARGS",problem);let title=optText(a,"title",200),engine=a.engine!==void 0&&a.engine!==null&&a.engine!==""?await engineId(a,"engine",c):void 0,main=await c.api.rpc("task.ensureMain",{repo}),res=await c.api.rpc("task.openDir",{dir:main.task.repo,vendor:engine??taskOpDeps.preferredEngine(main.task.repo),...title?{title}:{}});if(engine)taskOpDeps.rememberEngine(main.task.repo,engine);return{taskId:res.taskId}}),"worktree.adopt":write("rpc worktree.adopt",adopt),"repo.clone":write("helper cloneRepo (git clone, fixed argv)",clone),"task.ensureWorktree":write("verb ensure-worktree --task-id",async(a,c)=>{let res=await c.api.verb("ensure-worktree",[flag("task-id",taskId(a))]);if(typeof res.worktreePath!=="string")throw new BridgeError("BAD_RESULT","ensure-worktree returned no path");return{worktreePath:res.worktreePath}}),"task.removeWorktree":write("verb remove-worktree --task-id --force",async(a,c)=>{let argv=[flag("task-id",taskId(a))];if(optBool(a,"force"))argv.push(flag("force","true"));let res=await c.api.verb("remove-worktree",argv);return{removed:res.removed===!0,...res.worktreePath?{worktreePath:res.worktreePath}:{},...res.branch?{branch:res.branch}:{}}},!0)};var TAIL_MAX=2000;function read(wraps,run){return{kind:"read",destructive:!1,wraps,run}}async function taskGet(args,ctx){let t=(await ctx.api.verb("get-task",[flag("task-id",taskId(args))])).task,pr=rollupPr(t);return{task:{id:t.id,title:t.title,repo:t.repo,branch:t.branch,worktreePath:t.worktreePath,kind:t.kind??"task",status:t.status,pinned:t.pinned===!0,...t.archived?{archived:!0}:{},...t.vendor?{engine:t.vendor}:{},...t.command?{command:t.command}:{},...t.model?{model:t.model}:{},...t.modelEffort?{effort:t.modelEffort}:{},...t.prompt?{prompt:t.prompt}:{},...t.baseRef?{baseRef:t.baseRef}:{},...t.groupId?{groupId:t.groupId}:{},...t.extraRepos?.length?{extraRepos:t.extraRepos.map((r)=>({repo:r.repo,...r.baseRef?{baseRef:r.baseRef}:{}}))}:{},createdAt:t.createdAt,updatedAt:t.updatedAt,...pr?{pr:{...pr.number!==void 0?{number:pr.number}:{},...pr.url?{url:pr.url}:{},lifecycle:pr.lifecycle,checkState:pr.checkState,...pr.reviewDecision?{reviewDecision:pr.reviewDecision}:{},...pr.mergeable?{mergeable:pr.mergeable}:{},...pr.baseRef?{baseRef:pr.baseRef}:{}}}:{},...t.report?{report:{summary:t.report.summary??"",at:t.report.at}}:{}}}}async function taskInfo(args,ctx){let id=taskId(args),row=(await ctx.api.verb("collect",[flag("task-ids",id)])).tasks?.[0];if(!row)throw new BridgeError("NOT_FOUND",`no task ${id}`);return{taskId:row.taskId,running:row.running??null,activity:row.activity?{state:row.activity.state,forMs:row.activity.forMs}:null,changes:row.changes?{added:row.changes.added,deleted:row.changes.deleted}:null,base:row.base?{baseRef:row.base.baseRef,ahead:row.base.ahead,behind:row.base.behind}:null,tabs:(row.tabs??[]).map((tab)=>{let exit=tab.exit,tail=exit?.tail?.join(`
116
116
  `).slice(-TAIL_MAX);return{id:tab.id,kind:tab.kind,alive:tab.alive??null,...exit?{exit:{code:exit.code,signal:exit.signal,...exit.layer?{cause:exit.layer}:{}}}:{},...tail?{tail}:{}}})}}async function repoBranches(args,ctx){let repo=await knownRepo(args,ctx);return{branches:taskOpDeps.listLocalBranches(repo),current:taskOpDeps.getCurrentBranch(repo)}}async function notesList(args,ctx){let repo=await knownRepo(args,ctx);return{notes:(await ctx.api.verb("note-list",[flag("repo",repo)])).notes??[]}}async function worktreeAdoptable(args,ctx){let repo=await knownRepo(args,ctx),res=await ctx.api.rpc("worktree.discoverAdoptable",{repo});return{worktrees:res.worktrees??[],unreadable:res.unreadable??[]}}var TASK_OPS={"task.get":read("verb get-task --task-id",taskGet),"task.info":read("verb collect --task-ids (first row, trimmed)",taskInfo),"repo.branches":read("helpers listLocalBranches + getCurrentBranch",repoBranches),"notes.list":read("verb note-list --repo",notesList),"worktree.adoptable":read("rpc worktree.discoverAdoptable",worktreeAdoptable),...TASK_WRITE_OPS};import{randomBytes as randomBytes4}from"crypto";import{mkdirSync as mkdirSync3,writeFileSync as writeFileSync3}from"fs";import{join as join5}from"path";var ATTACHMENT_TYPES={"image/png":{ext:"png",kind:"image",magic:[137,80,78,71,13,10,26,10]},"image/jpeg":{ext:"jpg",kind:"image",magic:[255,216,255]},"image/gif":{ext:"gif",kind:"image",magic:[71,73,70,56]},"image/webp":{ext:"webp",kind:"image",magic:[82,73,70,70]},"application/pdf":{ext:"pdf",kind:"pdf",magic:[37,80,68,70]}},MAX_ATTACHMENT_BYTES=5242880,MAX_ATTEMPTS=5,PROMPT_MAX3=1e5,realDeps10={attachmentsDir:promptAttachmentsDir,now:()=>new Date,nonce:()=>randomBytes4(4).toString("hex"),writeFile(path,bytes){mkdirSync3(join5(path,".."),{recursive:!0,mode:448}),writeFileSync3(path,bytes,{mode:384})},readTab(task,tab){return loadStateFile()[terminalTabsKey(task)]?.tabs?.find((t)=>t.id===tab)},planHandoff:planWorktreeHandoff,prPrompt:buildPRPrompt};function gitRef2(args,name2){let v=args[name2];if(!(typeof v==="string"&&v.length<=200&&/^[A-Za-z0-9][A-Za-z0-9._/@+-]*$/.test(v)&&!v.includes("..")&&!v.includes("//")&&!v.endsWith("/")&&!v.endsWith(".")&&!v.endsWith(".lock")&&!v.includes("@{")))throw new BridgeError("BAD_ARGS",`${name2} is not a branch name`);return v}function engineId2(args,name2="engine"){let v=optStr(args,name2);if(v===void 0)return;if(!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(v))throw new BridgeError("BAD_ARGS",`${name2} is not an engine id`);return v}function tabTitle(args){let title=text2(args,"title",80).trim();if(/[\u0000-\u001f\u007f]/.test(title))throw new BridgeError("BAD_ARGS","title must be one line");return title}async function worktreeOf4(api,id){let res=await api.verb("get-task",[flag("task-id",id)]);if(!res.task.worktreePath)throw new BridgeError("NO_WORKTREE",`task ${id} has no worktree yet`);return{task:res.task,worktree:res.task.worktreePath}}function matchesMagic(mime,bytes){let{magic}=ATTACHMENT_TYPES[mime];if(bytes.length<magic.length||!magic.every((b,i)=>bytes[i]===b))return!1;return mime!=="image/webp"||Buffer.from(bytes.subarray(8,12)).toString("ascii")==="WEBP"}function terminalOps(deps=realDeps10){return{"tab.states":{kind:"read",destructive:!1,wraps:"daemon RPC debug.inspect (activity.tabs of one task)",async run(a,{api}){let id=taskId(a),res=await api.rpc("debug.inspect"),tabs={};for(let[tab,entry]of Object.entries(res?.activity?.tabs?.[id]??{}))if(typeof entry?.state==="string"&&typeof entry.at==="number")tabs[tab]={state:entry.state,at:entry.at};return{tabs}}},"tab.rename":{kind:"write",destructive:!1,wraps:"rove api update --tab",async run(a,{api}){return await api.verb("update",[flag("task-id",taskId(a)),flag("tab",tabId(a)),flag("title",tabTitle(a))]),{}}},"tab.interrupt":{kind:"write",destructive:!1,wraps:"rove api interrupt",async run(a,{api}){let argv=[flag("task-id",taskId(a))];if(a.tabId!==void 0&&a.tabId!==null)argv.push(flag("tab",tabId(a)));return await api.verb("interrupt",argv),{}}},"tab.forkTask":{kind:"write",destructive:!1,wraps:"rove api add --fork (one attempt, from the task's branch), else --base-branch (--count for attempts)",async run(a,{api}){let count=optInt(a,"count",1,MAX_ATTEMPTS)??1,repo=absPath(a,"repo"),baseBranch=gitRef2(a,"baseBranch"),prompt=text2(a,"prompt",PROMPT_MAX3),engine=engineId2(a),title=optText(a,"title",200),tail=[flag("prompt",prompt),...engine?[flag("command",engine)]:[]],forkFrom=count===1&&a.forkFrom!==void 0&&a.forkFrom!==null?taskId(a,"forkFrom"):void 0,forkRefused;if(forkFrom)try{let res2=await api.verb("add",[flag("fork",forkFrom),flag("title",title??deriveTitleFromPrompt(prompt)),...tail]);if(res2.taskId){if(engine)taskOpDeps.rememberEngine(repo,engine);return{taskIds:[res2.taskId],forked:!0}}}catch(err){if(!(err instanceof BridgeError)||err.code!=="FORK_UNSUPPORTED")throw err;forkRefused=err.message.replace("FORK_UNSUPPORTED: ","")}let argv=[flag("repo",repo),flag("base-branch",baseBranch),...tail];if(title)argv.push(flag("title",title));if(count>1)argv.push(flag("count",count));let res=await api.verb("add",argv),taskIds=res.tasks?res.tasks.map((t)=>t.taskId):res.taskId?[res.taskId]:[];if(taskIds.length===0)throw new BridgeError("ADD_FAILED","no task was created");if(engine)taskOpDeps.rememberEngine(repo,engine);return{taskIds,...count>1&&res.groupId?{groupId:res.groupId}:{},...forkRefused?{forkRefused}:{}}}},"tab.handoff":{kind:"read",destructive:!1,wraps:"planWorktreeHandoff (transcript handoff prompt)",async run(a,{api}){let id=taskId(a),tab=tabId(a),{task,worktree}=await worktreeOf4(api,id),active=deps.readTab(id,tab)??initialTabs().tabs[0],tabVendor=(active.kind==="engine"?active.vendor:void 0)??task.vendor,plan=await deps.planHandoff(active,liveSourceProtocol(active,tabVendor),worktree,task.title);return plan.kind==="handoff"?{kind:"handoff",prompt:plan.prompt}:plan.kind==="no-transcript"?{kind:plan.kind,engine:plan.engine}:{kind:plan.kind}}},"tab.requestPR":{kind:"write",destructive:!1,wraps:"buildPRPrompt + rove api send --plain",async run(a,{api}){let id=taskId(a),{worktree}=await worktreeOf4(api,id),argv=[flag("task-id",id),"--plain",flag("prompt",await deps.prPrompt(worktree))];if(a.tabId!==void 0&&a.tabId!==null)argv.push(flag("tab",tabId(a)));return await api.verb("send",argv),{}}},"tab.send":{kind:"write",destructive:!1,wraps:"rove api send --plain [--queue] (a message typed in the page's composer, pasted and submitted by the engine's own composer; with `queue`, held for a busy tab until its turn ends)",async run(a,{api}){let argv=[flag("task-id",taskId(a)),"--plain",flag("prompt",text2(a,"prompt",PROMPT_MAX3))];if(a.tabId!==void 0&&a.tabId!==null)argv.push(flag("tab",tabId(a)));if(a.queue===!0)argv.push("--queue");let res=await api.verb("send",argv);if(res.queued===!0)return{delivered:!1,queued:!0,queueId:res.queueId,position:res.position};if(res.delivered===!0)return{delivered:!0};return{delivered:!1,reason:sendReason(res.targetDetail??res.reason)??"not confirmed"}}},"queue.list":{kind:"read",destructive:!1,wraps:"rove api queue-list --task-id (prompts held for a busy tab, oldest first)",async run(a,{api}){return await api.verb("queue-list",[flag("task-id",taskId(a))])}},"queue.edit":{kind:"write",destructive:!1,wraps:"rove api queue-edit --id --prompt (rewrite a held prompt in place)",async run(a,{api}){let id=str(a,"id");if(!/^q-\d+$/.test(id))throw new BridgeError("BAD_ARGS","id must look like q-N");return await api.verb("queue-edit",[flag("id",id),flag("prompt",str(a,"text"))])}},"queue.cancel":{kind:"write",destructive:!1,wraps:"rove api queue-cancel --id (take back a held prompt before it is pasted)",async run(a,{api}){let id=str(a,"id");if(!/^q-\d+$/.test(id))throw new BridgeError("BAD_ARGS","id must look like q-N");return await api.verb("queue-cancel",[flag("id",id)])}},"attachment.put":{kind:"write",destructive:!1,wraps:"writes ~/.rove/attachments/<generated name> (tui/lib/attachments.ts layout)",async run(a){let mime=str(a,"mime");if(!Object.hasOwn(ATTACHMENT_TYPES,mime))throw new BridgeError("BAD_ARGS",`mime must be one of ${Object.keys(ATTACHMENT_TYPES).join("|")}`);let type=ATTACHMENT_TYPES[mime],encoded=str(a,"data");if(encoded.length>Math.ceil(MAX_ATTACHMENT_BYTES*4/3)+4)throw new BridgeError("TOO_LARGE",`attachment is larger than ${MAX_ATTACHMENT_BYTES} bytes`);let bytes=Buffer.from(encoded,"base64");if(bytes.length===0)throw new BridgeError("BAD_ARGS","data is empty");if(bytes.length>MAX_ATTACHMENT_BYTES)throw new BridgeError("TOO_LARGE",`attachment is larger than ${MAX_ATTACHMENT_BYTES} bytes`);if(!matchesMagic(mime,bytes))throw new BridgeError("BAD_ARGS",`data is not a ${type.ext} file`);let stamp=deps.now().toISOString().slice(0,10).replaceAll("-",""),path=join5(deps.attachmentsDir(),`attach-${stamp}-${deps.nonce()}.${type.ext}`);return deps.writeFile(path,bytes),{path,kind:type.kind,bytes:bytes.length}}}}}var TERMINAL_OPS=terminalOps();var FETCH_TIMEOUT_MS=8000,realDeps11={async fetchText(url){let res=await fetch(url,{signal:AbortSignal.timeout(FETCH_TIMEOUT_MS)});if(!res.ok)throw Error(`HTTP ${res.status}`);return res.text()},installed:()=>loadUserThemes().map((t)=>t.name),write:(name2,theme)=>{writeUserTheme(name2,theme,!1)}};function createHostedThemeOps(deps){let cache2=new Map,load=async(name2)=>{let known=cache2.get(name2);if(known)return known;let theme=parseTheme(await deps.fetchText(hostedThemeUrl(name2)));return cache2.set(name2,theme),theme};return{"theme.hosted":{kind:"read",destructive:!1,wraps:"the rove.run theme catalogue, each theme resolved to #rrggbb for dark and light, whether it is installed, and the user themes directory",async run(){let installed=new Set(deps.installed()),settled=await Promise.allSettled(HOSTED_THEMES.map(load)),themes=[],unavailable=[];for(let[i,name2]of HOSTED_THEMES.entries()){let got=settled[i];if(got?.status!=="fulfilled"){unavailable.push(name2);continue}themes.push({name:name2,installed:installed.has(name2),dark:palette(got.value,"dark"),light:palette(got.value,"light")})}return{themes,unavailable,dir:userThemesDir()}}},"theme.install":{kind:"write",destructive:!1,wraps:"rove theme add https://rove.run/themes/<name>.json, for a catalogue name only; never overwrites",async run(args){let name2=HOSTED_THEMES.find((n)=>n===args.name);if(!name2)throw new BridgeError("BAD_ARGS",`name must be one of ${HOSTED_THEMES.join("|")}`);if(deps.installed().includes(name2))return{name:name2,installed:!1};let theme;try{theme=await load(name2)}catch(err){let reason=err instanceof Error?err.message:String(err);throw new BridgeError("UNAVAILABLE",`could not fetch ${hostedThemeUrl(name2)}: ${reason}`)}try{deps.write(name2,theme)}catch(err){if(err instanceof ThemeInstallError)throw new BridgeError("CONFLICT",err.message);throw err}return{name:name2,installed:!0}}}}}var hostedThemeOps=createHostedThemeOps(realDeps11);var DEFAULT_LIMIT=60,COMMIT_LIMIT=30,SEP="\x1F",realDeps12={base:(worktree,prBaseRef)=>resolveBase(worktree,prBaseRef),async commits(worktree,base){let res=await runWorktreeGit(worktree,["log",`${base}..HEAD`,`--format=%H${SEP}%ct${SEP}%s`,"-n",String(COMMIT_LIMIT)]);if(res.status!==0)return[];return(res.stdout??"").split(`
117
- `).filter((line)=>line.length>0).flatMap((line)=>{let[sha,secs,...subject]=line.split(SEP),at=Number(secs)*1000;return sha&&Number.isFinite(at)?[{sha,at,subject:subject.join(SEP)}]:[]})}},NOISE={"tool-pre":!0,"tool-post":!0};function eventTail(event){let d=event.detail,fragment=d?.tool?.name||d?.compact?.trigger||d?.subagent?.type||d?.note||"";return[fragment.length>60?`${fragment.slice(0,59)}\u2026`:fragment,event.vendor??""].filter((part)=>part.length>0).join(" \xB7 ")}function mergeTimeline(events,commits,limit){return[...events.filter((event)=>!NOISE[event.kind]).map((event)=>({kind:event.kind,at:event.at,tail:eventTail(event),...event.tabId?{tabId:event.tabId}:{}})),...commits.map((commit)=>({kind:"commit",at:commit.at,tail:commit.subject,sha:commit.sha}))].sort((a,b)=>b.at-a.at).slice(0,limit)}function timelineOps(deps=realDeps12){return{"task.timeline":{kind:"read",destructive:!1,wraps:"rpc task.recentEvents (tool calls dropped) + git log <base>..HEAD, merged newest first",async run(a,{api}){let id=taskId(a),limit=optInt(a,"limit",1,200)??DEFAULT_LIMIT,events=await api.rpc("task.recentEvents",{taskId:id}).then((res)=>res.events).catch((err)=>{if(err instanceof Error&&/task not found/i.test(err.message))return[];throw err}),got=await api.verb("get-task",[flag("task-id",id)]),worktree=got.task.worktreePath,base=worktree?await deps.base(worktree,got.task.prStatus?.baseRef):null,commits=worktree&&base?await deps.commits(worktree,base):[];return{entries:mergeTimeline(events,commits,limit)}}}}}var TIMELINE_OPS=timelineOps();var VERSION=/^\d+\.\d+\.\d+$/,LOCALES2=["en","zh"],realDeps13={current:CURRENT_VERSION,check:(force)=>checkLatestVersion({force}),notesRange:(current,latest,locale)=>fetchReleaseNotesRange({current,latest,locale}),notes:fetchReleaseNotes};function createUpdateOps(deps=realDeps13){return{"update.check":{kind:"read",destructive:!1,wraps:"checkLatestVersion + fetchReleaseNotesRange (npm registry, GitHub releases)",async run(args){let info=await deps.check(optBool(args,"force")===!0),locale=optOneOf(args,"locale",LOCALES2)??"en",notes=info?.hasUpdate?await deps.notesRange(info.current,info.latest,locale):[];return{current:deps.current,info,notes}}},"release.notes":{kind:"read",destructive:!1,wraps:"fetchReleaseNotes (GitHub release notes for vX.Y.Z, in `locale` when translated)",async run(args){let version=text2(args,"version",32);if(!VERSION.test(version))throw new BridgeError("BAD_ARGS","version must be x.y.z");return{notes:await deps.notes(version,optOneOf(args,"locale",LOCALES2)??"en")}}}}}var updateOps=createUpdateOps();import{basename}from"path";var chip=(id)=>({id,name:engineDisplayName(id)}),welcomeDeps={cwd:()=>process.cwd(),gitOnPath:()=>Bun.which("git")!==null,async engines(){return probeableEngineIds().then(detectEngineStatuses).then(summarizeEngines).catch(()=>({usable:[],signedOut:[]}))},repoOf(dir){try{return validateRepoPath(dir)===null?resolveMainRepoRoot(dir):null}catch{return null}},branchOf:(dir)=>getCurrentBranch(dir),preferredEngine:(repo)=>resolvePreferredVendor(repo)},welcomeOps={"welcome.env":{kind:"read",destructive:!1,wraps:"helpers probeableEngineIds + detectEngineStatuses, firstTaskRepo",async run(){let[{usable,signedOut},git]=await Promise.all([welcomeDeps.engines(),welcomeDeps.gitOnPath()]),dir=welcomeDeps.cwd(),repo=welcomeDeps.repoOf(dir),start=null;if(repo!==null&&git&&usable.length>0){let pref=welcomeDeps.preferredEngine(repo);start={repo,label:basename(repo),baseRef:welcomeDeps.branchOf(dir)??welcomeDeps.branchOf(repo)??DEFAULT_BASE_REF,engine:usable.includes(pref)?pref:usable[0]??pref}}return{engines:usable.map(chip),signedOut:signedOut.map(chip),git,start}}}};var LEAF=/^leaf-\d{1,4}$/,TITLE_MAX2=80;function leafId(a){let v=a.leafId;if(v===void 0||v===null||v==="")return;if(typeof v!=="string"||!LEAF.test(v))throw new BridgeError("BAD_ARGS","leafId is not a pane id");return v}function paneTitle(a){let v=a.title;if(v===void 0||v===null)return"";if(typeof v!=="string"||v.length>TITLE_MAX2||/[\u0000-\u001f\u007f]/.test(v))throw new BridgeError("BAD_ARGS",`title must be one line of at most ${TITLE_MAX2} characters`);return v.trim()}var WORKSPACE_OPS={"tab.split":{kind:"write",destructive:!0,wraps:"rove api tab-split",async run(a,{api}){let action=oneOf(a,"action",["open","close","rename","reset"]),leaf=leafId(a);if(action!=="open"&&!leaf)throw new BridgeError("BAD_ARGS",`leafId is required to ${action}`);let cols=optInt(a,"cols",1,1000),rows=optInt(a,"rows",1,500);if(cols===void 0!==(rows===void 0))throw new BridgeError("BAD_ARGS","cols and rows go together");let argv=[flag("task-id",taskId(a)),flag("tab",tabId(a)),flag("action",action)];if(leaf)argv.push(flag("leaf",leaf));if(action==="open")argv.push(flag("direction",optOneOf(a,"direction",["right","down"])??"right"));if(action==="rename")argv.push(flag("title",paneTitle(a)));if(cols!==void 0&&rows!==void 0)argv.push(flag("cols",cols),flag("rows",rows));let res=await api.verb("tab-split",argv);return{leaf:res.leaf,changed:res.changed,split:res.split}}}};function mergeOpTables(...tables){let merged={};for(let table of tables)for(let[name2,spec2]of Object.entries(table)){if(name2 in merged)throw new BridgeError("DUPLICATE_OP",`op ${name2} is registered twice`);merged[name2]=spec2}return merged}var AREA_OPS=mergeOpTables(TASK_OPS,TERMINAL_OPS,filesOps,GATE_OPS,pagesOps,settingsOps,engineOps,insightOps,updateOps,machineOps,devOps,prefsOps,hostedThemeOps,routingOps,TASKOPS_OPS,WORKSPACE_OPS,welcomeOps,keybindingsOps,launchOps,modsOps,promptOps,snippetOps,panelOps,githubOps,reviewOps,githubAuthOps,TIMELINE_OPS,PR_CHECKS_OPS,RUN_OPS);function peerOf(req,address,deps){let surface=offersWebSubprotocol(req)?"web":"phone",origin=req.headers.get("origin"),viaTunnel=deps.access!==void 0||deps.tokenInQuery===!0;if(origin!==null&&deps.publicHost)try{viaTunnel||=new URL(origin).hostname===deps.publicHost.toLowerCase()}catch{viaTunnel=!0}let tunnelHeader=["cf-connecting-ip","cf-access-jwt-assertion","x-forwarded-for","forwarded"].some((name2)=>req.headers.has(name2)),loopback=address!==void 0&&isLoopbackHost(address.replace(/^::ffff:/i,""));return{surface,local:loopback&&!viaTunnel&&!tunnelHeader}}function viewingFields(args,peer){let flag2=(key)=>typeof args[key]==="boolean"?args[key]:void 0,[panel,panelOpen,narrow]=[flag2("panel"),flag2("panelOpen"),flag2("narrow")];return{surface:peer.surface,local:peer.local,...panel!==void 0&&peer.surface==="web"?{panel}:{},...panelOpen!==void 0?{panelOpen}:{},...narrow!==void 0?{narrow}:{}}}var PATH=/^\/hooks\/routines\/([A-Za-z0-9-]+)$/;var STATUS={fired:202,pong:200,not_found:404,bad_signature:401,disabled:409};async function routineHook(api,req,log){let match=PATH.exec(new URL(req.url).pathname);if(!match)return null;if(req.method!=="POST")return new Response(`POST only
117
+ `).filter((line)=>line.length>0).flatMap((line)=>{let[sha,secs,...subject]=line.split(SEP),at=Number(secs)*1000;return sha&&Number.isFinite(at)?[{sha,at,subject:subject.join(SEP)}]:[]})}},NOISE={"tool-pre":!0,"tool-post":!0};function eventTail(event){let d=event.detail,fragment=d?.tool?.name||d?.compact?.trigger||d?.subagent?.type||d?.note||"";return[fragment.length>60?`${fragment.slice(0,59)}\u2026`:fragment,event.vendor??""].filter((part)=>part.length>0).join(" \xB7 ")}function mergeTimeline(events,commits,limit){return[...events.filter((event)=>!NOISE[event.kind]).map((event)=>({kind:event.kind,at:event.at,tail:eventTail(event),...event.tabId?{tabId:event.tabId}:{}})),...commits.map((commit)=>({kind:"commit",at:commit.at,tail:commit.subject,sha:commit.sha}))].sort((a,b)=>b.at-a.at).slice(0,limit)}function timelineOps(deps=realDeps12){return{"task.timeline":{kind:"read",destructive:!1,wraps:"rpc task.recentEvents (tool calls dropped) + git log <base>..HEAD, merged newest first",async run(a,{api}){let id=taskId(a),limit=optInt(a,"limit",1,200)??DEFAULT_LIMIT,events=await api.rpc("task.recentEvents",{taskId:id}).then((res)=>res.events).catch((err)=>{if(err instanceof Error&&/task not found/i.test(err.message))return[];throw err}),got=await api.verb("get-task",[flag("task-id",id)]),worktree=got.task.worktreePath,base=worktree?await deps.base(worktree,got.task.prStatus?.baseRef):null,commits=worktree&&base?await deps.commits(worktree,base):[];return{entries:mergeTimeline(events,commits,limit)}}}}}var TIMELINE_OPS=timelineOps();var VERSION=/^\d+\.\d+\.\d+$/,LOCALES2=["en","zh"],realDeps13={current:CURRENT_VERSION,check:(force,channel)=>checkLatestVersion({force,channel:channel??preferredReleaseChannel(loadStateFile())}),notesRange:(current,latest,locale)=>fetchReleaseNotesRange({current,latest,locale}),notes:fetchReleaseNotes};function createUpdateOps(deps=realDeps13){return{"update.check":{kind:"read",destructive:!1,wraps:"checkLatestVersion + fetchReleaseNotesRange (npm registry, GitHub releases)",async run(args){let info=await deps.check(optBool(args,"force")===!0,normalizeReleaseChannel(args.channel)),locale=optOneOf(args,"locale",LOCALES2)??"en",notes=info?.hasUpdate?await deps.notesRange(info.current,info.latest,locale):[];return{current:deps.current,info,notes}}},"release.notes":{kind:"read",destructive:!1,wraps:"fetchReleaseNotes (GitHub release notes for vX.Y.Z, in `locale` when translated)",async run(args){let version=text2(args,"version",32);if(!VERSION.test(version))throw new BridgeError("BAD_ARGS","version must be x.y.z");return{notes:await deps.notes(version,optOneOf(args,"locale",LOCALES2)??"en")}}}}}var updateOps=createUpdateOps();import{basename}from"path";var chip=(id)=>({id,name:engineDisplayName(id)}),welcomeDeps={cwd:()=>process.cwd(),gitOnPath:()=>Bun.which("git")!==null,async engines(){return probeableEngineIds().then(detectEngineStatuses).then(summarizeEngines).catch(()=>({usable:[],signedOut:[]}))},repoOf(dir){try{return validateRepoPath(dir)===null?resolveMainRepoRoot(dir):null}catch{return null}},branchOf:(dir)=>getCurrentBranch(dir),preferredEngine:(repo)=>resolvePreferredVendor(repo)},welcomeOps={"welcome.env":{kind:"read",destructive:!1,wraps:"helpers probeableEngineIds + detectEngineStatuses, firstTaskRepo",async run(){let[{usable,signedOut},git]=await Promise.all([welcomeDeps.engines(),welcomeDeps.gitOnPath()]),dir=welcomeDeps.cwd(),repo=welcomeDeps.repoOf(dir),start=null;if(repo!==null&&git&&usable.length>0){let pref=welcomeDeps.preferredEngine(repo);start={repo,label:basename(repo),baseRef:welcomeDeps.branchOf(dir)??welcomeDeps.branchOf(repo)??DEFAULT_BASE_REF,engine:usable.includes(pref)?pref:usable[0]??pref}}return{engines:usable.map(chip),signedOut:signedOut.map(chip),git,start}}}};var LEAF=/^leaf-\d{1,4}$/,TITLE_MAX2=80;function leafId(a){let v=a.leafId;if(v===void 0||v===null||v==="")return;if(typeof v!=="string"||!LEAF.test(v))throw new BridgeError("BAD_ARGS","leafId is not a pane id");return v}function paneTitle(a){let v=a.title;if(v===void 0||v===null)return"";if(typeof v!=="string"||v.length>TITLE_MAX2||/[\u0000-\u001f\u007f]/.test(v))throw new BridgeError("BAD_ARGS",`title must be one line of at most ${TITLE_MAX2} characters`);return v.trim()}var WORKSPACE_OPS={"tab.split":{kind:"write",destructive:!0,wraps:"rove api tab-split",async run(a,{api}){let action=oneOf(a,"action",["open","close","rename","reset"]),leaf=leafId(a);if(action!=="open"&&!leaf)throw new BridgeError("BAD_ARGS",`leafId is required to ${action}`);let cols=optInt(a,"cols",1,1000),rows=optInt(a,"rows",1,500);if(cols===void 0!==(rows===void 0))throw new BridgeError("BAD_ARGS","cols and rows go together");let argv=[flag("task-id",taskId(a)),flag("tab",tabId(a)),flag("action",action)];if(leaf)argv.push(flag("leaf",leaf));if(action==="open")argv.push(flag("direction",optOneOf(a,"direction",["right","down"])??"right"));if(action==="rename")argv.push(flag("title",paneTitle(a)));if(cols!==void 0&&rows!==void 0)argv.push(flag("cols",cols),flag("rows",rows));let res=await api.verb("tab-split",argv);return{leaf:res.leaf,changed:res.changed,split:res.split}}}};function mergeOpTables(...tables){let merged={};for(let table of tables)for(let[name2,spec2]of Object.entries(table)){if(name2 in merged)throw new BridgeError("DUPLICATE_OP",`op ${name2} is registered twice`);merged[name2]=spec2}return merged}var AREA_OPS=mergeOpTables(TASK_OPS,TERMINAL_OPS,filesOps,GATE_OPS,pagesOps,settingsOps,engineOps,insightOps,updateOps,machineOps,devOps,prefsOps,hostedThemeOps,routingOps,TASKOPS_OPS,WORKSPACE_OPS,welcomeOps,keybindingsOps,launchOps,modsOps,promptOps,snippetOps,panelOps,githubOps,reviewOps,githubAuthOps,TIMELINE_OPS,PR_CHECKS_OPS,RUN_OPS);function peerOf(req,address,deps){let surface=offersWebSubprotocol(req)?"web":"phone",origin=req.headers.get("origin"),viaTunnel=deps.access!==void 0||deps.tokenInQuery===!0;if(origin!==null&&deps.publicHost)try{viaTunnel||=new URL(origin).hostname===deps.publicHost.toLowerCase()}catch{viaTunnel=!0}let tunnelHeader=["cf-connecting-ip","cf-access-jwt-assertion","x-forwarded-for","forwarded"].some((name2)=>req.headers.has(name2)),loopback=address!==void 0&&isLoopbackHost(address.replace(/^::ffff:/i,""));return{surface,local:loopback&&!viaTunnel&&!tunnelHeader}}function viewingFields(args,peer){let flag2=(key)=>typeof args[key]==="boolean"?args[key]:void 0,[panel,panelOpen,narrow]=[flag2("panel"),flag2("panelOpen"),flag2("narrow")];return{surface:peer.surface,local:peer.local,...panel!==void 0&&peer.surface==="web"?{panel}:{},...panelOpen!==void 0?{panelOpen}:{},...narrow!==void 0?{narrow}:{}}}var PATH=/^\/hooks\/routines\/([A-Za-z0-9-]+)$/;var STATUS={fired:202,pong:200,not_found:404,bad_signature:401,disabled:409};async function routineHook(api,req,log){let match=PATH.exec(new URL(req.url).pathname);if(!match)return null;if(req.method!=="POST")return new Response(`POST only
118
118
  `,{status:405,headers:{allow:"POST"}});if(Number(req.headers.get("content-length")??0)>1048576)return new Response(`too large
119
119
  `,{status:413});let body=await req.text();if(body.length>1048576)return new Response(`too large
120
120
  `,{status:413});let id=match[1],res;try{res=await api.rpc("automation.webhook",{id,body,event:req.headers.get("x-github-event"),signature:req.headers.get("x-hub-signature-256")})}catch(err){return log(`[rove-bridge] routine hook ${id}: ${err instanceof Error?err.message:String(err)}`),new Response(`daemon unavailable
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{__require}from"./chunk-91sykzqq.js";var CHANNEL_LOADERS={weixin:async()=>(await import("./chunk-pqr6td4z.js")).default};async function runChannelCli(id,argv){let load=CHANNEL_LOADERS[id];if(!load)throw Error(`no chat channel "${id}"`);await(await load()).runCli(argv)}async function startChatChannels(ctx){let started=[];for(let[id,load]of Object.entries(CHANNEL_LOADERS))try{let channel=(await load()).createChannel();await channel.start(ctx),started.push(channel)}catch(err){ctx.log("channel",`${id} did not start: ${err instanceof Error?err.message:String(err)}`)}return started}
2
+ import{__require}from"./chunk-91sykzqq.js";var CHANNEL_LOADERS={weixin:async()=>(await import("./chunk-cgmqnhjn.js")).default};async function runChannelCli(id,argv){let load=CHANNEL_LOADERS[id];if(!load)throw Error(`no chat channel "${id}"`);await(await load()).runCli(argv)}async function startChatChannels(ctx){let started=[];for(let[id,load]of Object.entries(CHANNEL_LOADERS))try{let channel=(await load()).createChannel();await channel.start(ctx),started.push(channel)}catch(err){ctx.log("channel",`${id} did not start: ${err instanceof Error?err.message:String(err)}`)}return started}
3
3
  export{runChannelCli,startChatChannels};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{AUTO_MACHINE,LOCAL_MACHINE,forwardVerb,invokeRouted,machineDaemonSocket,machinePtySocket,machineTasks,pickMachine,repoHosts,repoWanted,requireMachine,routeTarget}from"./chunk-ta1p2nwa.js";import"./chunk-vytrhm50.js";import"./chunk-vp29jgbt.js";import"./chunk-gq36nzg8.js";import"./chunk-sq6zj3fb.js";import"./chunk-tw9tfs1d.js";import"./chunk-61cn88e7.js";import"./chunk-atg13xab.js";import"./chunk-r5j8fycq.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-ggnq2vvk.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import"./chunk-y1xnjx8x.js";import"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-vvqwgcge.js";import"./chunk-x83xbzjd.js";import"./chunk-2tfnscxk.js";import"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-rfp0ayra.js";import"./chunk-40dgv828.js";import"./chunk-zsfyj36g.js";import"./chunk-2r1fgng9.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import"./chunk-mjyhy152.js";import"./chunk-wzss4pzh.js";import"./chunk-cmp64q4j.js";import"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import"./chunk-hz1x3hak.js";import"./chunk-x1jxxmtc.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import"./chunk-91sykzqq.js";export{routeTarget,requireMachine,repoWanted,repoHosts,pickMachine,machineTasks,machinePtySocket,machineDaemonSocket,invokeRouted,forwardVerb,LOCAL_MACHINE,AUTO_MACHINE};
2
+ import{AUTO_MACHINE,LOCAL_MACHINE,forwardVerb,invokeRouted,machineDaemonSocket,machinePtySocket,machineTasks,pickMachine,repoHosts,repoWanted,requireMachine,routeTarget}from"./chunk-k9jhy3yx.js";import"./chunk-vytrhm50.js";import"./chunk-vp29jgbt.js";import"./chunk-gq36nzg8.js";import"./chunk-sq6zj3fb.js";import"./chunk-d6j2d6fk.js";import"./chunk-61cn88e7.js";import"./chunk-atg13xab.js";import"./chunk-r5j8fycq.js";import"./chunk-xfgqae9t.js";import"./chunk-j1z9kgyd.js";import"./chunk-g9ba25q5.js";import"./chunk-ggnq2vvk.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-mdc7b01e.js";import"./chunk-tn9gtf18.js";import"./chunk-895yqjjz.js";import"./chunk-sak1tphp.js";import"./chunk-y1xnjx8x.js";import"./chunk-e58kj4gm.js";import"./chunk-0a65j1zj.js";import"./chunk-bcyex84w.js";import"./chunk-vvqwgcge.js";import"./chunk-x83xbzjd.js";import"./chunk-2tfnscxk.js";import"./chunk-hzz020xx.js";import"./chunk-w7zv47mp.js";import"./chunk-rfp0ayra.js";import"./chunk-40dgv828.js";import"./chunk-zsfyj36g.js";import"./chunk-2r1fgng9.js";import"./chunk-2brn8e1y.js";import"./chunk-7mwvvj46.js";import"./chunk-32j6y5d1.js";import"./chunk-nqwza8b0.js";import"./chunk-ve76p2mx.js";import"./chunk-cmp64q4j.js";import"./chunk-qzzmd63x.js";import"./chunk-96kvwzj8.js";import"./chunk-7bakcyes.js";import"./chunk-8qkyd589.js";import"./chunk-7kysxgbq.js";import"./chunk-hz1x3hak.js";import"./chunk-x1jxxmtc.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-7ghwdjdc.js";import"./chunk-8t7qbr1e.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import"./chunk-zt7wfnva.js";import"./chunk-0g4wc808.js";import"./chunk-pn5ygqn6.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import"./chunk-pxk2c2vj.js";import"./chunk-91sykzqq.js";export{routeTarget,requireMachine,repoWanted,repoHosts,pickMachine,machineTasks,machinePtySocket,machineDaemonSocket,invokeRouted,forwardVerb,LOCAL_MACHINE,AUTO_MACHINE};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{findVerb}from"./chunk-z3wrbtcq.js";import{VERB_GROUP_IDS}from"./chunk-r5j8fycq.js";import{loadStateFile,updateStateFile}from"./chunk-32j6y5d1.js";var INBOUND_KEY="machineInbound",INBOUND_CLASSES=[...VERB_GROUP_IDS,"land","credentials"],LAND_VERBS=new Set(["land","publish"]),CREDENTIAL_VERBS={"github-login":!0,"github-logout":!0,"github-sync":!0,"github-apply":!0};function inboundClassOf(verb){if(LAND_VERBS.has(verb))return"land";if(Object.hasOwn(CREDENTIAL_VERBS,verb))return"credentials";return findVerb(verb)?.group??null}function deniedClasses(state=loadStateFile()){let raw=state[INBOUND_KEY],deny=raw&&typeof raw==="object"?raw.deny:void 0;return Array.isArray(deny)?deny.filter((c)=>typeof c==="string"):[]}function inboundRefusal(verb,state){let cls=inboundClassOf(verb);return cls&&deniedClasses(state).includes(cls)?cls:null}function setInbound(cls,allow){let next=[];return updateStateFile((state)=>{let current=new Set(deniedClasses(state));if(allow)current.delete(cls);else current.add(cls);return next=[...current].sort(),state[INBOUND_KEY]={deny:next},!0}),next}
2
+ import{findVerb}from"./chunk-ym0zghjh.js";import{VERB_GROUP_IDS}from"./chunk-r5j8fycq.js";import{loadStateFile,updateStateFile}from"./chunk-32j6y5d1.js";var INBOUND_KEY="machineInbound",INBOUND_CLASSES=[...VERB_GROUP_IDS,"land","credentials"],LAND_VERBS=new Set(["land","publish"]),CREDENTIAL_VERBS={"github-login":!0,"github-logout":!0,"github-sync":!0,"github-apply":!0};function inboundClassOf(verb){if(LAND_VERBS.has(verb))return"land";if(Object.hasOwn(CREDENTIAL_VERBS,verb))return"credentials";return findVerb(verb)?.group??null}function deniedClasses(state=loadStateFile()){let raw=state[INBOUND_KEY],deny=raw&&typeof raw==="object"?raw.deny:void 0;return Array.isArray(deny)?deny.filter((c)=>typeof c==="string"):[]}function inboundRefusal(verb,state){let cls=inboundClassOf(verb);return cls&&deniedClasses(state).includes(cls)?cls:null}function setInbound(cls,allow){let next=[];return updateStateFile((state)=>{let current=new Set(deniedClasses(state));if(allow)current.delete(cls);else current.add(cls);return next=[...current].sort(),state[INBOUND_KEY]={deny:next},!0}),next}
3
3
  export{INBOUND_KEY,INBOUND_CLASSES,inboundClassOf,deniedClasses,inboundRefusal,setInbound};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{preferredReleaseChannel,rememberReleaseChannel}from"./chunk-m4z6kepz.js";import{updaterShell,updaterShellFailureHint}from"./chunk-xte4phd1.js";import"./chunk-tn9gtf18.js";import{BREAKING_VERSIONS,CURRENT_VERSION,DEFAULT_RELEASE_CHANNEL,RELEASE_CHANNELS,UPDATE_COMMAND,UPDATE_SCRIPT_URL,breakingVersionsCrossed,channelOf,checkLatestVersion,fetchReleaseSummaries,recommendedGlobalInstallCommand,updateCommandFor}from"./chunk-9ckvdy0j.js";import"./chunk-32j6y5d1.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{spawnSync}from"child_process";var CLI_NAME=ROVE_PRODUCT_NAME;function updatePlan(target){let shell=updateCommandFor(target);return{command:updaterShell(),args:["-c",shell],display:shell}}var VERSION_SHAPE=/^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function isReleaseChannel(value){return RELEASE_CHANNELS.includes(value)}var CHANNEL_FLAGS={"--nightly":"nightly","--next":"next","--stable":"latest","--latest":"latest",stable:"latest"};function parseUpdateArgs(args){let dryRun=!1,list=!1,version,channel;for(let i=0;i<args.length;i+=1){let arg=args[i];if(arg===void 0)continue;if(arg==="--help"||arg==="-h"||arg==="help")return{help:!0,dryRun,list,version,channel};if(arg==="dry-run"||arg==="--dry-run"){dryRun=!0;continue}if(arg==="list"||arg==="--list"){list=!0;continue}if(arg==="--channel"||arg.startsWith("--channel=")){let value=(arg.startsWith("--channel=")?arg.slice(10):void 0)??args[++i];if(value===void 0||!isReleaseChannel(value))process.stderr.write(`${CLI_NAME} update: --channel expects one of ${RELEASE_CHANNELS.join(", ")}${value===void 0?"":` (got "${value}")`}
2
+ import{preferredReleaseChannel,rememberReleaseChannel}from"./chunk-m98jd1fz.js";import{updaterShell,updaterShellFailureHint}from"./chunk-xte4phd1.js";import"./chunk-tn9gtf18.js";import{BREAKING_VERSIONS,CURRENT_VERSION,DEFAULT_RELEASE_CHANNEL,RELEASE_CHANNELS,UPDATE_COMMAND,UPDATE_SCRIPT_URL,breakingVersionsCrossed,channelOf,checkLatestVersion,fetchReleaseSummaries,recommendedGlobalInstallCommand,updateCommandFor}from"./chunk-9ckvdy0j.js";import"./chunk-32j6y5d1.js";import"./chunk-bejhca6z.js";import"./chunk-br8r72bf.js";import"./chunk-yt15y085.js";import"./chunk-z1nj22va.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-eqdbfgq5.js";import"./chunk-f8gg8cqh.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-91sykzqq.js";import{spawnSync}from"child_process";var CLI_NAME=ROVE_PRODUCT_NAME;function updatePlan(target){let shell=updateCommandFor(target);return{command:updaterShell(),args:["-c",shell],display:shell}}var VERSION_SHAPE=/^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function isReleaseChannel(value){return RELEASE_CHANNELS.includes(value)}var CHANNEL_FLAGS={"--nightly":"nightly","--next":"next","--stable":"latest","--latest":"latest",stable:"latest"};function parseUpdateArgs(args){let dryRun=!1,list=!1,version,channel;for(let i=0;i<args.length;i+=1){let arg=args[i];if(arg===void 0)continue;if(arg==="--help"||arg==="-h"||arg==="help")return{help:!0,dryRun,list,version,channel};if(arg==="dry-run"||arg==="--dry-run"){dryRun=!0;continue}if(arg==="list"||arg==="--list"){list=!0;continue}if(arg==="--channel"||arg.startsWith("--channel=")){let value=(arg.startsWith("--channel=")?arg.slice(10):void 0)??args[++i];if(value===void 0||!isReleaseChannel(value))process.stderr.write(`${CLI_NAME} update: --channel expects one of ${RELEASE_CHANNELS.join(", ")}${value===void 0?"":` (got "${value}")`}
3
3
 
4
4
  `),printUsage(process.stderr),process.exit(2);channel=value;continue}let flagged=CHANNEL_FLAGS[arg];if(channel===void 0&&flagged!==void 0){channel=flagged;continue}if(channel===void 0&&isReleaseChannel(arg)){channel=arg;continue}if(version===void 0&&VERSION_SHAPE.test(arg)){version=arg;continue}process.stderr.write(`${CLI_NAME} update: unknown argument "${arg}"
5
5
 
@@ -10,7 +10,7 @@ import{preferredReleaseChannel,rememberReleaseChannel}from"./chunk-m4z6kepz.js";
10
10
  install one with: ${CLI_NAME} update <version>
11
11
  `)}async function warnBreakingCrossings(target,channel,io){if(BREAKING_VERSIONS.length===0)return;let resolved=target??(await checkLatestVersion({force:!0,channel}))?.latest;if(!resolved)return;let crossed=breakingVersionsCrossed(CURRENT_VERSION,resolved);if(crossed.length===0)return;io.stderr.write([`warning: ${CURRENT_VERSION} -> ${resolved} crosses breaking version(s): ${crossed.join(", ")}.`,`After this update, Rove will refuse to start until you run \`${CLI_NAME} reset\``,"(worktrees are never touched; add --hard only to also wipe the task index).",""].join(`
12
12
  `))}var FOLLOW_UP_NOTE=["",`${CLI_NAME}: installed. Two background processes are still running the old build:`,` daemon \u2192 \`${CLI_NAME} daemon restart\` (safe; never touches live sessions)`,` pty host \u2192 only \`${CLI_NAME} reset\` replaces it, and that ends every live`," terminal and engine session \u2014 do it when you can afford to.",`Run \`${CLI_NAME} doctor\` to see which of the two is actually stale.`,""].join(`
13
- `);async function runUpdateSubcommand(args,deps){let io={spawn:deps?.spawn??spawnSync,stdout:deps?.stdout??process.stdout,stderr:deps?.stderr??process.stderr,exit:deps?.exit??((code)=>process.exit(code)),channel:deps?.channel??{get:()=>preferredReleaseChannel(),remember:rememberReleaseChannel}},parsed=parseUpdateArgs(args);if(parsed.help){printUsage(io.stdout);return}if(parsed.list){if(deps===void 0&&process.stdout.isTTY){let{startVersionsHost}=await import("./chunk-d552cvb2.js");await startVersionsHost();return}await printVersionList(io);return}let channel=parsed.channel??io.channel.get(),target=parsed.version??(channel===DEFAULT_RELEASE_CHANNEL?void 0:channel),plan=updatePlan(target),switching=parsed.version===void 0&&channel!==channelOf();if(io.stdout.write(`${CLI_NAME} ${CURRENT_VERSION} -> ${target??channel}
13
+ `);async function runUpdateSubcommand(args,deps){let io={spawn:deps?.spawn??spawnSync,stdout:deps?.stdout??process.stdout,stderr:deps?.stderr??process.stderr,exit:deps?.exit??((code)=>process.exit(code)),channel:deps?.channel??{get:()=>preferredReleaseChannel(),remember:rememberReleaseChannel}},parsed=parseUpdateArgs(args);if(parsed.help){printUsage(io.stdout);return}if(parsed.list){if(deps===void 0&&process.stdout.isTTY){let{startVersionsHost}=await import("./chunk-73zg0mrb.js");await startVersionsHost();return}await printVersionList(io);return}let channel=parsed.channel??io.channel.get(),target=parsed.version??(channel===DEFAULT_RELEASE_CHANNEL?void 0:channel),plan=updatePlan(target),switching=parsed.version===void 0&&channel!==channelOf();if(io.stdout.write(`${CLI_NAME} ${CURRENT_VERSION} -> ${target??channel}
14
14
  `),switching)io.stdout.write(`switching channel: ${channelOf()} -> ${channel}
15
15
  `);if(io.stdout.write(`running: ${plan.display}
16
16
  `),await warnBreakingCrossings(parsed.version,channel,io),parsed.dryRun)return;let result=io.spawn(plan.command,plan.args,{stdio:"inherit"});if(result.error){io.stderr.write(`${CLI_NAME} update: failed to run ${plan.command}: ${result.error.message}
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{dedupeMachines,discoverMachine,ensureForwards,learnedFrom,listMachines,localDaemonSocketPath,localPtySocketPath,updateMachine}from"./chunk-vytrhm50.js";import{DISPATCH_PROMPT_HEAD_CHARS,normalizeRemoteUrl,resolvePtyOwner}from"./chunk-vp29jgbt.js";import{taskEngineArgv}from"./chunk-tw9tfs1d.js";import{roveApiInvocation}from"./chunk-atg13xab.js";import{ApiError}from"./chunk-r5j8fycq.js";import{ptyScopeFor}from"./chunk-g9ba25q5.js";import{connectIfRunning}from"./chunk-e58kj4gm.js";import{getSavedRepos,isRemoteRepoKey}from"./chunk-rfp0ayra.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{loadStateFile,updateStateFile}from"./chunk-32j6y5d1.js";import{RoveDaemonClient}from"./chunk-qzzmd63x.js";import{ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{__require}from"./chunk-91sykzqq.js";import{hostname}from"os";async function ptyScopeOf(daemon,task){let listed=await daemon.request("task.list",{}).catch(()=>({tasks:[]})),scope=ptyScopeFor(listed.tasks,task.id);return task.ptyAlias?{...scope,alias:task.ptyAlias}:scope}async function recordSend(daemon,sent){let self=await ownSession(daemon).catch(()=>null);await daemon.request("dispatch.record",{taskId:sent.taskId,...sent.tabId?{tabId:sent.tabId}:{},promptHead:sent.prompt.slice(0,DISPATCH_PROMPT_HEAD_CHARS),delivered:sent.delivered,...sent.deliveryId?{deliveryId:sent.deliveryId}:{},...self?{fromTaskId:self.taskId,fromTabId:self.tabId}:{}}).catch(()=>{})}var selfSessionOnce,identityWarning=null;async function realProbe(){let[{openPtyHost,listSessions},{psSnapshot}]=await Promise.all([import("./chunk-3dhv5n19.js"),import("./chunk-5xpvd182.js")]);return{sessions:async()=>{let host=await openPtyHost();if(!host)return[];try{return await listSessions(host.rpc)}finally{host.close()}},ps:psSnapshot,pid:process.pid}}async function verifiedSelfSession(env=process.env,probe){if(!probe&&selfSessionOnce)return selfSessionOnce;let run=resolveSelfSession(env,probe);return selfSessionOnce=run,run}async function resolveSelfSession(env,probe){let taskId=env.ROVE_TASK_ID;if(!taskId)return null;let tabId=env.ROVE_TAB_ID||"tab-1";try{let p=probe??await realProbe(),key=`${taskId}::${tabId}`,session=(await p.sessions()).find((s)=>s.key===key&&s.alive);if(session?.pid){let{hasAncestor,parsePsSnapshot}=await import("./chunk-5xpvd182.js");if(hasAncestor(parsePsSnapshot(await p.ps([session.pid,p.pid])),p.pid,session.pid))return identityWarning=null,{taskId,tabId}}}catch{}return identityWarning=`$ROVE_TASK_ID/$ROVE_TASK_ID names task ${taskId} ${tabId}, but this process is not running inside that tab (an inherited env, not an identity) \u2014 dispatcher/peer provenance omitted`,null}function takeIdentityWarning(){let warning=identityWarning;return identityWarning=null,warning}async function ownSession(daemon,env=process.env,probe){let self=await verifiedSelfSession(env,probe);if(!self)return null;let listed=await daemon.request("task.list",{}).catch(()=>({tasks:[]}));return{...self,taskId:resolvePtyOwner(listed.tasks,self.taskId,self.tabId)}}async function dispatcherEnvPayload(daemon,env=process.env,probe){let self=await ownSession(daemon,env,probe);if(!self)return{};return{dispatcherTaskId:self.taskId,dispatcherTabId:self.tabId}}async function readOwnDispatcher(daemon){let self=await ownSession(daemon);if(!self)return null;try{return(await daemon.request("task.get",{taskId:self.taskId})).task.dispatcher??null}catch{return null}}async function resolveDispatcherTab(runtime,daemon,dispatcher){let task=await daemon.request("task.get",{taskId:dispatcher.taskId}).then((res)=>res.task).catch(()=>null),{tabs,running}=await runtime.taskTabs(dispatcher.taskId,void 0,task?await ptyScopeOf(daemon,task):void 0);if(tabs.some((t)=>t.id===dispatcher.tabId&&t.alive))return dispatcher.tabId;if(running)return;throw new ApiError(`dispatcher tab ${dispatcher.tabId} on task ${dispatcher.taskId} is dead and the task has no live engine tab \u2014 the reply has nowhere to land`,"DISPATCHER_UNREACHABLE",{dispatcher,hint:`address an alive target explicitly with --task-id/--tab (see \`${ROVE_PRODUCT_NAME} api pty-list\`), or notify the user with \`${ROVE_PRODUCT_NAME} api notify\``,nextCommandArgs:["api","pty-list"]})}async function replyTabOf(runtime,daemon,taskId){let self=await ownSession(daemon);if(self?.taskId===taskId)return self.tabId;let task=await daemon.request("task.get",{taskId}).then((res)=>res.task).catch(()=>null);if(!task)return;let{tabs}=await runtime.taskTabs(taskId,taskEngineArgv(task),await ptyScopeOf(daemon,task));return tabs.find((t)=>t.kind==="engine"&&t.alive===!0&&t.engineAlive!==!1)?.id}async function withPeerProvenance(daemon,targetTaskId,prompt){let self=await ownSession(daemon),senderId=self?.taskId;if(!self||!senderId||senderId===targetTaskId)return prompt;let label=senderId;try{let res=await daemon.request("task.get",{taskId:senderId});label=res.task.title||res.task.branch||senderId}catch{}let api=roveApiInvocation(),replyTarget=`--task-id ${senderId} --tab ${self.tabId}`;return`[ROVE PEER] from "${label}" (task ${senderId} \u2014 Rove agent skill /rove, read it once per session; reply only if it changes what I do next: \`${api} send ${replyTarget} --prompt "<text>"\`; verb reference: \`${api} schema\`)
2
+ import{dedupeMachines,discoverMachine,ensureForwards,learnedFrom,listMachines,localDaemonSocketPath,localPtySocketPath,updateMachine}from"./chunk-vytrhm50.js";import{DISPATCH_PROMPT_HEAD_CHARS,normalizeRemoteUrl,resolvePtyOwner}from"./chunk-vp29jgbt.js";import{taskEngineArgv}from"./chunk-d6j2d6fk.js";import{roveApiInvocation}from"./chunk-atg13xab.js";import{ApiError}from"./chunk-r5j8fycq.js";import{ptyScopeFor}from"./chunk-g9ba25q5.js";import{connectIfRunning}from"./chunk-e58kj4gm.js";import{getSavedRepos,isRemoteRepoKey}from"./chunk-rfp0ayra.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{loadStateFile,updateStateFile}from"./chunk-32j6y5d1.js";import{RoveDaemonClient}from"./chunk-qzzmd63x.js";import{ROVE_API_VERSION}from"./chunk-96kvwzj8.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{__require}from"./chunk-91sykzqq.js";import{hostname}from"os";async function ptyScopeOf(daemon,task){let listed=await daemon.request("task.list",{}).catch(()=>({tasks:[]})),scope=ptyScopeFor(listed.tasks,task.id);return task.ptyAlias?{...scope,alias:task.ptyAlias}:scope}async function recordSend(daemon,sent){let self=await ownSession(daemon).catch(()=>null);await daemon.request("dispatch.record",{taskId:sent.taskId,...sent.tabId?{tabId:sent.tabId}:{},promptHead:sent.prompt.slice(0,DISPATCH_PROMPT_HEAD_CHARS),delivered:sent.delivered,...sent.deliveryId?{deliveryId:sent.deliveryId}:{},...self?{fromTaskId:self.taskId,fromTabId:self.tabId}:{}}).catch(()=>{})}var selfSessionOnce,identityWarning=null;async function realProbe(){let[{openPtyHost,listSessions},{psSnapshot}]=await Promise.all([import("./chunk-exp78r1c.js"),import("./chunk-5xpvd182.js")]);return{sessions:async()=>{let host=await openPtyHost();if(!host)return[];try{return await listSessions(host.rpc)}finally{host.close()}},ps:psSnapshot,pid:process.pid}}async function verifiedSelfSession(env=process.env,probe){if(!probe&&selfSessionOnce)return selfSessionOnce;let run=resolveSelfSession(env,probe);return selfSessionOnce=run,run}async function resolveSelfSession(env,probe){let taskId=env.ROVE_TASK_ID;if(!taskId)return null;let tabId=env.ROVE_TAB_ID||"tab-1";try{let p=probe??await realProbe(),key=`${taskId}::${tabId}`,session=(await p.sessions()).find((s)=>s.key===key&&s.alive);if(session?.pid){let{hasAncestor,parsePsSnapshot}=await import("./chunk-5xpvd182.js");if(hasAncestor(parsePsSnapshot(await p.ps([session.pid,p.pid])),p.pid,session.pid))return identityWarning=null,{taskId,tabId}}}catch{}return identityWarning=`$ROVE_TASK_ID/$ROVE_TASK_ID names task ${taskId} ${tabId}, but this process is not running inside that tab (an inherited env, not an identity) \u2014 dispatcher/peer provenance omitted`,null}function takeIdentityWarning(){let warning=identityWarning;return identityWarning=null,warning}async function ownSession(daemon,env=process.env,probe){let self=await verifiedSelfSession(env,probe);if(!self)return null;let listed=await daemon.request("task.list",{}).catch(()=>({tasks:[]}));return{...self,taskId:resolvePtyOwner(listed.tasks,self.taskId,self.tabId)}}async function dispatcherEnvPayload(daemon,env=process.env,probe){let self=await ownSession(daemon,env,probe);if(!self)return{};return{dispatcherTaskId:self.taskId,dispatcherTabId:self.tabId}}async function readOwnDispatcher(daemon){let self=await ownSession(daemon);if(!self)return null;try{return(await daemon.request("task.get",{taskId:self.taskId})).task.dispatcher??null}catch{return null}}async function resolveDispatcherTab(runtime,daemon,dispatcher){let task=await daemon.request("task.get",{taskId:dispatcher.taskId}).then((res)=>res.task).catch(()=>null),{tabs,running}=await runtime.taskTabs(dispatcher.taskId,void 0,task?await ptyScopeOf(daemon,task):void 0);if(tabs.some((t)=>t.id===dispatcher.tabId&&t.alive))return dispatcher.tabId;if(running)return;throw new ApiError(`dispatcher tab ${dispatcher.tabId} on task ${dispatcher.taskId} is dead and the task has no live engine tab \u2014 the reply has nowhere to land`,"DISPATCHER_UNREACHABLE",{dispatcher,hint:`address an alive target explicitly with --task-id/--tab (see \`${ROVE_PRODUCT_NAME} api pty-list\`), or notify the user with \`${ROVE_PRODUCT_NAME} api notify\``,nextCommandArgs:["api","pty-list"]})}async function replyTabOf(runtime,daemon,taskId){let self=await ownSession(daemon);if(self?.taskId===taskId)return self.tabId;let task=await daemon.request("task.get",{taskId}).then((res)=>res.task).catch(()=>null);if(!task)return;let{tabs}=await runtime.taskTabs(taskId,taskEngineArgv(task),await ptyScopeOf(daemon,task));return tabs.find((t)=>t.kind==="engine"&&t.alive===!0&&t.engineAlive!==!1)?.id}async function withPeerProvenance(daemon,targetTaskId,prompt){let self=await ownSession(daemon),senderId=self?.taskId;if(!self||!senderId||senderId===targetTaskId)return prompt;let label=senderId;try{let res=await daemon.request("task.get",{taskId:senderId});label=res.task.title||res.task.branch||senderId}catch{}let api=roveApiInvocation(),replyTarget=`--task-id ${senderId} --tab ${self.tabId}`;return`[ROVE PEER] from "${label}" (task ${senderId} \u2014 Rove agent skill /rove, read it once per session; reply only if it changes what I do next: \`${api} send ${replyTarget} --prompt "<text>"\`; verb reference: \`${api} schema\`)
3
3
 
4
4
  ${prompt}`}import{spawnSync}from"child_process";import{existsSync}from"fs";import{join}from"path";function git(cwd,args){let res=spawnSync("git",["-C",cwd,...args],{encoding:"utf8",timeout:5000});return res.status===0?res.stdout.trim():null}function repoIdentity(path){if(!existsSync(path)||git(path,["rev-parse","--git-dir"])===null)return null;let origin=git(path,["remote","get-url","origin"]),root=git(path,["rev-list","--max-parents=0","HEAD"])?.split(`
5
5
  `).filter(Boolean).sort()[0];return{...origin?{origin:normalizeRemoteUrl(origin)}:{},...root?{root}:{}}}function isLocalCheckout(path){return existsSync(join(path,".git"))||existsSync(path)&&git(path,["rev-parse","--git-dir"])!==null}function unpushedCommits(path,ref){if(git(path,["rev-parse","--verify","--quiet",`${ref}^{commit}`])===null)return null;let ahead=git(path,["rev-list","--count",`${ref}@{upstream}..${ref}`]);if(ahead!==null)return Number.parseInt(ahead,10)||0;let lone=git(path,["rev-list","--count",ref,"--not","--remotes"]);return lone===null?null:Number.parseInt(lone,10)||0}import{spawnSync as spawnSync2}from"child_process";import{existsSync as existsSync2,mkdirSync}from"fs";import{homedir}from"os";import{dirname,isAbsolute,join as join2,resolve}from"path";var URL_LIKE=/^[a-z][a-z0-9+.-]*:\/\//i,SCP_LIKE=/^[^@/\s]+@[^:/\s]+:[^\s]+$/,SEGMENT=/^[A-Za-z0-9_.-]+$/;function parseRepoRef(raw,cwd=process.cwd(),exists=existsSync2){let value=raw.trim(),asPath={kind:"path",path:value};if(value===""||isRemoteRepoKey(value))return asPath;if(URL_LIKE.test(value)||SCP_LIKE.test(value))return{kind:"id",id:normalizeRemoteUrl(value),cloneUrl:value};if(isAbsolute(value)||/^[A-Za-z]:[\\/]/.test(value)||/^[~.\\]/.test(value))return asPath;if(exists(resolve(cwd,value)))return asPath;let parts=value.replace(/\.git$/i,"").split("/");if(!parts.every((p)=>SEGMENT.test(p)))return asPath;if(parts.length===2){let id=`github.com/${parts.join("/")}`.toLowerCase();return{kind:"id",id,cloneUrl:`https://${id}.git`}}if(parts.length>=3&&parts[0]?.includes(".")){let id=parts.join("/").toLowerCase();return{kind:"id",id,cloneUrl:`https://${id}.git`}}return asPath}function repoIdOf(identity){if(!identity)return null;if(identity.origin)return identity.origin;return identity.root?`root:${identity.root}`:null}function findCheckouts(want,candidates){let out=[];for(let c of candidates){let sameRoot=Boolean(want.root&&c.identity.root===want.root),sameOrigin=Boolean(want.origin&&c.identity.origin===want.origin);if(!sameRoot&&!sameOrigin)continue;let fork=sameRoot&&!sameOrigin&&Boolean(want.origin&&c.identity.origin);out.push({path:c.path,via:sameRoot?"root":"origin",fork})}return out}function pickCheckout(matches,opts){let usable=matches.filter((m)=>opts.allowFork||!m.fork);if(usable.length===0){let fork=matches.find((m)=>m.fork)?.path;return fork?{path:null,fork}:{path:null}}let primary=usable.find((m)=>m.path===opts.primary);if(primary)return{path:primary.path};if(usable.length>1&&opts.isClean){let clean=usable.find((m)=>opts.isClean?.(m.path));if(clean)return{path:clean.path}}return{path:usable[0]?.path??null}}function isCleanCheckout(path){let res=spawnSync2("git",["-C",path,"status","--porcelain","--untracked-files=no"],{encoding:"utf8",timeout:5000});return res.status===0&&res.stdout.trim()===""}var REPO_PRIMARY_KEY="repoPrimary";function primaryCheckouts(state=loadStateFile()){let raw=state[REPO_PRIMARY_KEY],out={};if(raw&&typeof raw==="object"){for(let[id,path]of Object.entries(raw))if(typeof path==="string")out[id]=path}return out}function setPrimaryCheckout(id,path){updateStateFile((state)=>{let next=primaryCheckouts(state);if(path===null)Reflect.deleteProperty(next,id);else next[id]=path;return state[REPO_PRIMARY_KEY]=next,!0})}function cloneDirFor(id,home=homedir()){return join2(home,".rove","repos",...id.split("/"))}function cloneRepo(ref,home){let dir=cloneDirFor(ref.id,home);if(repoIdentity(dir))return dir;mkdirSync(dirname(dir),{recursive:!0});let res=spawnSync2("git",["clone",ref.cloneUrl,dir],{encoding:"utf8",timeout:600000,env:{...process.env,GIT_TERMINAL_PROMPT:"0"}});if(res.status!==0)throw Error((res.stderr||res.stdout||"git clone failed").trim());return dir}var LOCAL_MACHINE="local";async function machineDaemonSocket(entry){let socketPath=localDaemonSocketPath(entry.alias);if(await answers(socketPath))return socketPath;if(!entry.sockets||!await forward(entry,entry.sockets))return null;if(await answers(socketPath))return socketPath;let found=await discoverMachine(entry.alias,entry);if(!found.ok)return null;let learned=learnedFrom(found);return updateMachine(entry.alias,learned),await forward({...entry,...learned},learned.sockets)&&await answers(socketPath)?socketPath:null}function forward(entry,sockets){return ensureForwards({alias:entry.alias,config:{...entry,sockets},remoteDaemonSocket:sockets.daemon,remotePtySocket:sockets.pty})}async function answers(socketPath){let client=new RoveDaemonClient(socketPath);try{return await client.request("hello",{}),!0}catch{return!1}finally{client.close()}}async function machineTasks(entry){let socketPath=await machineDaemonSocket(entry);if(!socketPath)return null;let client=new RoveDaemonClient(socketPath);try{return(await client.request("task.list")).tasks??[]}catch{return null}finally{client.close()}}function requireMachine(alias){let entry=listMachines().find((m)=>m.alias===alias);if(entry)return entry;throw new ApiError(`no machine named "${alias}"`,"UNKNOWN_MACHINE",{hint:"list the registered machines and retry with one of their aliases, or register it first",nextCommandArgs:["machine","list"]})}var AUTO_MACHINE="auto",busy=(tasks)=>tasks.filter((task)=>task.status==="in_progress").length;async function pickMachine(localTasks,readTasks=machineTasks,machines=dedupeMachines(listMachines()),hosts){let[local,...remote]=await Promise.all([localTasks().catch(()=>[]),...machines.map((entry)=>readTasks(entry))]),loads={[LOCAL_MACHINE]:busy(local)};machines.forEach((entry,i)=>{let tasks=remote[i];if(tasks)loads[entry.alias]=busy(tasks)});let pool=[null,...machines.filter((entry)=>loads[entry.alias]!==void 0)],skipped;if(hosts){let ok=await Promise.all(pool.map((entry)=>hosts(entry).catch(()=>!1)));if(ok.some(Boolean))skipped=pool.filter((_,i)=>!ok[i]).map((entry)=>entry?.alias??LOCAL_MACHINE),pool=pool.filter((_,i)=>ok[i])}let best=null,bestLoad=Number.POSITIVE_INFINITY;for(let entry of pool){let load=loads[entry?.alias??LOCAL_MACHINE]??0;if(load<bestLoad)best=entry,bestLoad=load}return{entry:best,loads,...skipped?{skipped}:{}}}function repoWanted(repo){if(typeof repo!=="string")return null;let ref=parseRepoRef(repo);if(ref.kind==="id")return{origin:ref.id};return isLocalCheckout(ref.path)?repoIdentity(ref.path):null}function repoHosts(params){if(flagOn(params.clone))return;let want=repoWanted(params.repo);if(!want||!want.origin&&!want.root)return;return async(entry)=>{if(entry===null){if(typeof params.repo==="string"&&parseRepoRef(params.repo).kind==="path")return!0;return getSavedRepos().some((path)=>findCheckouts(want,[{path,identity:repoIdentity(path)??{}}]).length)}let socket=await machineDaemonSocket(entry);if(!socket)return!1;let client=new RoveDaemonClient(socket);try{let res=await client.request("api.invoke",{verb:"repo-match",params:{...want.origin?{origin:want.origin}:{},...want.root?{root:want.root}:{}},forwarded:!0,from:hostname()});return res.ok&&Boolean(res.result.repo)}finally{client.close()}}}async function routeTarget(args){if(args.machine===AUTO_MACHINE){let hosts=args.params?repoHosts(args.params):void 0;return(await pickMachine(args.localTasks??(async()=>[]),machineTasks,void 0,hosts)).entry}if(args.machine!==void 0&&args.machine!==LOCAL_MACHINE)return requireMachine(args.machine);if(args.machine===LOCAL_MACHINE||!args.taskId)return null;let machines=dedupeMachines(listMachines());if(machines.length===0||await args.isLocalTask(args.taskId))return null;for(let entry of machines)if((await machineTasks(entry))?.some((task)=>task.id===args.taskId))return entry;return null}async function forwardVerb(entry,verb,params,socketPath){let target=socketPath??await machineDaemonSocket(entry);if(!target)return offline(entry.alias);let client=new RoveDaemonClient(target);try{let repo=await translateRepo(client,entry.alias,params);if(repo.failure)return repo.failure;if(verb==="land"&&params["dry-run"]===void 0){let published=await client.request("api.invoke",{verb:"publish",params:{"task-id":params["task-id"]},forwarded:!0,from:hostname()});if(published.ok||published.error.code!=="UNKNOWN_VERB")return published}let envelope=await client.request("api.invoke",{verb,params:repo.params,forwarded:!0,from:hostname()});return await recordHere(verb,params,envelope),envelope}catch(err){let message=errorMessage(err);if(/unknown daemon request:/i.test(message))return tooOld(entry.alias);return failure("MACHINE_UNREACHABLE",`machine "${entry.alias}": ${message}`,{hint:"check the machine is up and reachable over ssh, then retry",nextCommandArgs:["machine","list"]})}finally{client.close()}}async function recordHere(verb,params,envelope){if(verb!=="send"&&verb!=="dispatch"||!envelope.ok||typeof params.prompt!=="string")return;let sent=envelope.result,taskId=typeof sent.childTaskId==="string"?sent.childTaskId:sent.taskId;if(typeof taskId!=="string")return;let tabId=typeof sent.tabId==="string"?sent.tabId:typeof sent.session==="string"?sent.session.split("::")[1]:void 0,local=await connectIfRunning().catch(()=>null);if(!local)return;try{await recordSend(local,{taskId,...tabId?{tabId}:{},prompt:params.prompt,delivered:sent.delivered===!0})}finally{local.close()}}async function translateRepo(client,alias,params){let repo=params.repo;if(typeof repo!=="string")return{params};let ref=parseRepoRef(repo),local=ref.kind==="path"&&isLocalCheckout(ref.path);if(ref.kind==="path"&&!local)return{params};let identity=ref.kind==="id"?{origin:ref.id}:repoIdentity(repo);if(!identity?.origin&&!identity?.root)return{params};let allowFork=flagOn(params["allow-fork"]),ask=await client.request("api.invoke",{verb:"repo-match",params:{...identity.origin?{origin:identity.origin}:{},...identity.root?{root:identity.root}:{},...allowFork?{"allow-fork":!0}:{}},forwarded:!0,from:hostname()});if(!ask.ok)return ask.error.code==="UNKNOWN_VERB"?{params}:{failure:ask};let answer=ask.result,found=answer.repo;if(found){let base=params["base-branch"],unpushed=local&&typeof base==="string"?unpushedCommits(repo,base):null;if(typeof base==="string"&&unpushed)return{failure:failure("UNPUSHED_BASE",`${base} has ${unpushed} commit${unpushed===1?"":"s"} no remote has; ${alias} cannot base a task on it`,{hint:`push it first (\`git -C ${repo} push -u origin ${base}\`), then dispatch again`})};return{params:{...params,repo:found}}}if(answer.fork)return{failure:failure("FORK_MATCH",`machine "${alias}" only has ${answer.fork}, a fork of ${identity.origin??repo} (same history, other origin)`,{hint:"pass --allow-fork to use it, or --clone with the repo id to fetch the repo itself there"})};if(flagOn(params.clone)&&identity.origin)return{params:{...params,repo:ref.kind==="id"?repo:identity.origin}};return{failure:failure("NO_REMOTE_CHECKOUT",`machine "${alias}" has no checkout of ${identity.origin??repo}`,{hint:identity.origin?`pass --clone to clone it on ${alias}, or --repo with ${alias}'s own path`:`clone it on ${alias} (and open it there once so Rove knows it), or pass --repo with ${alias}'s own path`})}}var flagOn=(value)=>value===!0||value==="true";function offline(alias){return failure("MACHINE_UNREACHABLE",`machine "${alias}" did not answer`,{hint:`check \`ssh ${alias} true\` works without a prompt, then retry`,nextCommandArgs:["machine","list"]})}function tooOld(alias){return failure("MACHINE_VERSION_SKEW",`machine "${alias}" runs a Rove too old to accept forwarded verbs`,{hint:`upgrade Rove on ${alias} (\`rove update\` there), then retry`})}function failure(code,message,data){return{apiVersion:ROVE_API_VERSION,ok:!1,error:{message,code,...data}}}async function invokeRouted(args){if(args.forwarded)return args.runHere();let taskId=args.params["task-id"],target;try{target=await routeTarget({machine:args.machine,taskId:typeof taskId==="string"?taskId:void 0,isLocalTask:args.isLocalTask,...args.localTasks?{localTasks:args.localTasks}:{},params:args.params})}catch(err){if(!(err instanceof ApiError))throw err;return failure(err.code,err.message,err.data??{})}return target?forwardVerb(target,args.verb,args.params):args.runHere()}async function machinePtySocket(alias){let entry=requireMachine(alias);if(!await machineDaemonSocket(entry))throw new ApiError(`machine "${alias}" did not answer`,"MACHINE_UNREACHABLE");return localPtySocketPath(alias)}
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{readTabsSnapshot}from"./chunk-tw9tfs1d.js";import{engineCanFork,engineDisplayName,getEngineProtocol,protocolEntry,sessionProtocol}from"./chunk-atg13xab.js";import{execHostForWorktreePath}from"./chunk-895yqjjz.js";import{supportsStructuredHistory}from"./chunk-x83xbzjd.js";import{getPersistedString,getPersistedValue}from"./chunk-rfp0ayra.js";import{parseNumstatRows}from"./chunk-t7j8g9f6.js";import{parsePorcelainRows,unquoteGitPath}from"./chunk-dmzg9zdc.js";import{recordSpawn}from"./chunk-40dgv828.js";import{readHeadSha,resolveGitDirs}from"./chunk-kg9kmwt9.js";import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{t}from"./chunk-mjyhy152.js";import{rollupPr}from"./chunk-x1jxxmtc.js";import{isObject}from"./chunk-7ghwdjdc.js";import{acquireSync,releaseSync}from"./chunk-bejhca6z.js";import{secretsPath}from"./chunk-z1nj22va.js";import{readFile,stat}from"fs/promises";var PER_SESSION=3,SNIPPET_RADIUS=60,READ_BATCH=8,READ_BUDGET_MS=1500;function snippetOf(text,needle){let flat=text.replace(/\s+/g," "),want=needle.replace(/\s+/g," "),at=flat.toLowerCase().indexOf(want.toLowerCase());if(at<0)return null;let start=Math.max(0,at-SNIPPET_RADIUS),end=Math.min(flat.length,at+want.length+SNIPPET_RADIUS);return`${start>0?"\u2026":""}${flat.slice(start,end).trim()}${end<flat.length?"\u2026":""}`}function matchMessages(messages,needle,max){let out=[];for(let m of messages){if(m.role!=="user"&&m.role!=="assistant")continue;for(let b of m.blocks){if(b.type!=="text")continue;let snippet=snippetOf(b.text,needle);if(snippet===null)continue;out.push({role:m.role,at:m.timestamp,snippet});break}if(out.length>=max)break}return out}function prefilterToken(query){return query.split(/["\\\s]+/).reduce((a,b)=>b.length>a.length?b:a,"")}async function candidatesOf(tasks,skipped){let claimed=new Set,pinned=[],unpinned=[],sharedDirs=new Map;for(let t2 of tasks)if(t2.worktreePath)sharedDirs.set(t2.worktreePath,(sharedDirs.get(t2.worktreePath)??0)+1);for(let task of tasks){if(task.origin){skipped.push({taskId:task.id,reason:"other-machine"});continue}let vendor=task.vendor,tabs=(readTabsSnapshot(task.id)?.tabs??[]).filter((t2)=>t2.kind==="engine"),any=!1;for(let tab of tabs){let tabVendor=tab.vendor??vendor;if(!tabVendor||!supportsStructuredHistory(sessionProtocol(tabVendor))||!tab.sessionId)continue;if(claimed.has(tab.sessionId))continue;claimed.add(tab.sessionId);let reader=protocolEntry(tabVendor).history;pinned.push({task,reader,sessionId:tab.sessionId,tabId:tab.id,path:null,mtimeMs:0}),any=!0}if(any)continue;if(!vendor||!supportsStructuredHistory(sessionProtocol(vendor))){skipped.push({taskId:task.id,reason:"engine-unsupported"});continue}let worktree=task.worktreePath;if(worktree&&(sharedDirs.get(worktree)??0)===1)unpinned.push({task,reader:protocolEntry(vendor).history,worktree})}let listed=await Promise.all(unpinned.map(async({task,reader,worktree})=>(await reader.listSessionIdsForWorktree(worktree)).filter((id)=>!claimed.has(id)).map((sessionId)=>({task,reader,sessionId,path:null,mtimeMs:0})))),all=[...pinned,...listed.flat()];return Promise.all(all.map(async(c)=>{let worktree=c.task.worktreePath||c.task.repo,path=await c.reader.transcriptPath(c.sessionId,worktree).catch(()=>null),mtimeMs=path?await stat(path).then((s)=>s.mtimeMs,()=>0):0;return{...c,path,mtimeMs}}))}async function filesContaining(paths,token){if(paths.length===0||token==="")return new Set(paths);let rg=Bun.which("rg");if(rg){let proc=Bun.spawn([rg,"-l","-i","-F","--no-messages","--",token,...paths],{stdout:"pipe",stderr:"ignore"}),out=await new Response(proc.stdout).text();return await proc.exited,new Set(out.split(`
2
+ import{readTabsSnapshot}from"./chunk-d6j2d6fk.js";import{engineCanFork,engineDisplayName,getEngineProtocol,protocolEntry,sessionProtocol}from"./chunk-atg13xab.js";import{execHostForWorktreePath}from"./chunk-895yqjjz.js";import{supportsStructuredHistory}from"./chunk-x83xbzjd.js";import{getPersistedString,getPersistedValue}from"./chunk-rfp0ayra.js";import{parseNumstatRows}from"./chunk-t7j8g9f6.js";import{parsePorcelainRows,unquoteGitPath}from"./chunk-dmzg9zdc.js";import{recordSpawn}from"./chunk-40dgv828.js";import{readHeadSha,resolveGitDirs}from"./chunk-kg9kmwt9.js";import{READ_ONLY_GIT_ENV}from"./chunk-6xppe9bj.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{t}from"./chunk-nqwza8b0.js";import{rollupPr}from"./chunk-x1jxxmtc.js";import{isObject}from"./chunk-7ghwdjdc.js";import{acquireSync,releaseSync}from"./chunk-bejhca6z.js";import{secretsPath}from"./chunk-z1nj22va.js";import{readFile,stat}from"fs/promises";var PER_SESSION=3,SNIPPET_RADIUS=60,READ_BATCH=8,READ_BUDGET_MS=1500;function snippetOf(text,needle){let flat=text.replace(/\s+/g," "),want=needle.replace(/\s+/g," "),at=flat.toLowerCase().indexOf(want.toLowerCase());if(at<0)return null;let start=Math.max(0,at-SNIPPET_RADIUS),end=Math.min(flat.length,at+want.length+SNIPPET_RADIUS);return`${start>0?"\u2026":""}${flat.slice(start,end).trim()}${end<flat.length?"\u2026":""}`}function matchMessages(messages,needle,max){let out=[];for(let m of messages){if(m.role!=="user"&&m.role!=="assistant")continue;for(let b of m.blocks){if(b.type!=="text")continue;let snippet=snippetOf(b.text,needle);if(snippet===null)continue;out.push({role:m.role,at:m.timestamp,snippet});break}if(out.length>=max)break}return out}function prefilterToken(query){return query.split(/["\\\s]+/).reduce((a,b)=>b.length>a.length?b:a,"")}async function candidatesOf(tasks,skipped){let claimed=new Set,pinned=[],unpinned=[],sharedDirs=new Map;for(let t2 of tasks)if(t2.worktreePath)sharedDirs.set(t2.worktreePath,(sharedDirs.get(t2.worktreePath)??0)+1);for(let task of tasks){if(task.origin){skipped.push({taskId:task.id,reason:"other-machine"});continue}let vendor=task.vendor,tabs=(readTabsSnapshot(task.id)?.tabs??[]).filter((t2)=>t2.kind==="engine"),any=!1;for(let tab of tabs){let tabVendor=tab.vendor??vendor;if(!tabVendor||!supportsStructuredHistory(sessionProtocol(tabVendor))||!tab.sessionId)continue;if(claimed.has(tab.sessionId))continue;claimed.add(tab.sessionId);let reader=protocolEntry(tabVendor).history;pinned.push({task,reader,sessionId:tab.sessionId,tabId:tab.id,path:null,mtimeMs:0}),any=!0}if(any)continue;if(!vendor||!supportsStructuredHistory(sessionProtocol(vendor))){skipped.push({taskId:task.id,reason:"engine-unsupported"});continue}let worktree=task.worktreePath;if(worktree&&(sharedDirs.get(worktree)??0)===1)unpinned.push({task,reader:protocolEntry(vendor).history,worktree})}let listed=await Promise.all(unpinned.map(async({task,reader,worktree})=>(await reader.listSessionIdsForWorktree(worktree)).filter((id)=>!claimed.has(id)).map((sessionId)=>({task,reader,sessionId,path:null,mtimeMs:0})))),all=[...pinned,...listed.flat()];return Promise.all(all.map(async(c)=>{let worktree=c.task.worktreePath||c.task.repo,path=await c.reader.transcriptPath(c.sessionId,worktree).catch(()=>null),mtimeMs=path?await stat(path).then((s)=>s.mtimeMs,()=>0):0;return{...c,path,mtimeMs}}))}async function filesContaining(paths,token){if(paths.length===0||token==="")return new Set(paths);let rg=Bun.which("rg");if(rg){let proc=Bun.spawn([rg,"-l","-i","-F","--no-messages","--",token,...paths],{stdout:"pipe",stderr:"ignore"}),out=await new Response(proc.stdout).text();return await proc.exited,new Set(out.split(`
3
3
  `).filter(Boolean))}let needle=token.toLowerCase(),hits=new Set;for(let p of paths)if((await readFile(p,"utf8").catch(()=>"")).toLowerCase().includes(needle))hits.add(p);return hits}async function searchTasks(tasks,query,limit,budgetMs=READ_BUDGET_MS){let started=Date.now(),skipped=[],candidates=await candidatesOf(tasks,skipped),withPath=candidates.filter((c)=>c.path!==null).map((c)=>c.path),hits=await filesContaining(withPath,prefilterToken(query)),toRead=candidates.filter((c)=>c.path===null||hits.has(c.path)).sort((a,b)=>b.mtimeMs-a.mtimeMs),matches=[],scanned=0;while(scanned<toRead.length&&matches.length<limit&&Date.now()-started<budgetMs){let batch=toRead.slice(scanned,scanned+READ_BATCH),read=await Promise.all(batch.map((c)=>c.reader.readHistory(c.sessionId).catch(()=>[])));for(let[i,messages]of read.entries()){let c=batch[i];scanned++;for(let m of matchMessages(messages,query,Math.min(PER_SESSION,limit-matches.length)))matches.push({taskId:c.task.id,title:c.task.title,...c.tabId?{tabId:c.tabId}:{},...m});if(matches.length>=limit)break}}return{query,matches,skipped,truncated:scanned<toRead.length}}async function runWorktreeGit(worktreePath,args,options={}){if(!worktreePath)return{stdout:"",stderr:"worktreePath is required",status:-1};let exec=(options.execForPath??execHostForWorktreePath)(worktreePath),controller=options.timeoutMs&&options.timeoutMs>0?new AbortController:null,timedOut=!1,timer=controller?setTimeout(()=>{timedOut=!0,controller.abort()},options.timeoutMs):null,signal=controller&&options.signal?AbortSignal.any([controller.signal,options.signal]):controller?.signal??options.signal,result;try{recordSpawn("worktree.content",["git",...args],worktreePath),result=await exec.run(["git",...args],{cwd:worktreePath,env:READ_ONLY_GIT_ENV,signal})}catch(err){if(timer)clearTimeout(timer);return{stdout:"",stderr:errorMessage(err),status:-1}}if(timer)clearTimeout(timer);if(timedOut&&result.exitCode===-1&&!result.stderr)return{stdout:result.stdout,stderr:`git ${args.join(" ")} timed out after ${options.timeoutMs}ms`,status:-1};return{stdout:result.stdout,stderr:result.stderr,status:result.exitCode}}function readLocalWorktreeHead(worktreePath,deps={}){if(!worktreePath||(deps.execForPath??execHostForWorktreePath)(worktreePath).isRemote)return null;try{let dirs=resolveGitDirs(worktreePath);return dirs?readHeadSha(dirs):null}catch{return null}}function worktreeFilePath(worktreePath,relPath){if(!worktreePath||!relPath)return null;if(/^[/\\]/.test(relPath)||/^[a-zA-Z]:[/\\]/.test(relPath))return null;if(relPath.split(/[/\\]/).some((part)=>part===".."))return null;let parts=relPath.split("/");return`${worktreePath.replace(/\/+$/,"")}/${parts.filter(Boolean).join("/")}`}async function worktreeFileSize(worktreePath,relPath,deps={}){let path=worktreeFilePath(worktreePath,relPath);if(!path)return null;let exec=(deps.execForPath??execHostForWorktreePath)(worktreePath);try{let res=await exec.run(["wc","-c",path]);if(res.exitCode!==0)return null;let n=Number.parseInt(res.stdout.trim().split(/\s+/)[0]??"",10);return Number.isFinite(n)?n:null}catch{return null}}async function readWorktreeFile(worktreePath,relPath,deps={}){let path=worktreeFilePath(worktreePath,relPath);if(!path)return null;let exec=(deps.execForPath??execHostForWorktreePath)(worktreePath);try{return await exec.readFile(path)}catch{return null}}function filetypeOf(relPath,firstLine){let leaf=relPath.slice(relPath.lastIndexOf("/")+1),dot=leaf.lastIndexOf(".");if(dot<=0)return firstLine===void 0?void 0:shebangFiletype(firstLine);switch(leaf.slice(dot+1).toLowerCase()){case"ts":case"tsx":case"mts":case"cts":return"typescript";case"js":case"jsx":case"mjs":case"cjs":return"javascript";case"md":case"markdown":return"markdown";case"zig":return"zig";default:return}}var SHEBANG_INTERPRETERS=new Map([["node","javascript"],["nodejs","javascript"],["bun","typescript"],["deno","typescript"],["tsx","typescript"],["ts-node","typescript"]]);function shebangFiletype(line){if(!line.startsWith("#!"))return;let words=line.slice(2).trim().split(/\s+/),first=words[0]??"",program=first.slice(first.lastIndexOf("/")+1);if(program==="env"){let i=1;for(;i<words.length;i++){let word=words[i]??"";if(word==="--"){i++;break}if(["-u","--unset","-C","--chdir","-P","-a","--argv0"].includes(word)){i++;continue}if(!word.startsWith("-")&&!word.includes("="))break}let command=words[i]??"";program=command.slice(command.lastIndexOf("/")+1)}return SHEBANG_INTERPRETERS.get(program)}function patchFirstLine(patch){let lines=patch.split(`
4
4
  `),at=lines.findIndex((l)=>/^@@ -\d+(?:,\d+)? \+1(?:,\d+)? @@/.test(l));if(at<0)return;return lines.slice(at+1).find((l)=>l.startsWith(" ")||l.startsWith("+"))?.slice(1)}function contentFirstLine(text){let nl=text.indexOf(`
5
5
  `);return nl<0?text:text.slice(0,nl)}function isCombinedPathspec(relPath){return relPath==="."||relPath.endsWith("/")}function hunklessPatchNote(patch){if(/^@@/m.test(patch))return null;let binary=!1,from,to,renameFrom,renameTo,emptyChange;for(let line of patch.split(`