@sma1lboy/rove 0.9.246 → 0.9.247
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/chunk-09y7gspe.js +4 -0
- package/dist/cli/{chunk-1wt1esef.js → chunk-0b5mec1c.js} +1 -1
- package/dist/cli/{chunk-g2kb61q5.js → chunk-1kprhx82.js} +2 -2
- package/dist/cli/{chunk-xx166cdv.js → chunk-1s93zcnx.js} +1 -1
- package/dist/cli/{chunk-9x980fd4.js → chunk-2md5j9ws.js} +1 -1
- package/dist/cli/{chunk-xnsk57ta.js → chunk-466djpa8.js} +1 -1
- package/dist/cli/{chunk-9nm43nw4.js → chunk-4a2veqfk.js} +1 -1
- package/dist/cli/{chunk-cgt8wmd7.js → chunk-4fgpzkaq.js} +1 -1
- package/dist/cli/{chunk-c5rb17k9.js → chunk-4hm0smvv.js} +1 -1
- package/dist/cli/{chunk-skf7y627.js → chunk-4nt1gnwq.js} +1 -0
- package/dist/cli/{chunk-jj460xsw.js → chunk-4qytyfmt.js} +1 -1
- package/dist/cli/{chunk-qdfxk8pt.js → chunk-4r3s1z14.js} +1 -1
- package/dist/cli/{chunk-xvdk2b8e.js → chunk-5c57gz48.js} +1 -1
- package/dist/cli/{chunk-9m5g6t5k.js → chunk-5zw9xngg.js} +1 -1
- package/dist/cli/chunk-60fy3ckp.js +3 -0
- package/dist/cli/{chunk-g8eh5jd4.js → chunk-6eb945nc.js} +1 -1
- package/dist/cli/{chunk-4ayqnz4j.js → chunk-73x2hszy.js} +1 -1
- package/dist/cli/{chunk-qdmzsx2z.js → chunk-7axwr3a5.js} +1 -1
- package/dist/cli/{chunk-8manew0x.js → chunk-7j6escfh.js} +24 -23
- package/dist/cli/{chunk-6nk7h22s.js → chunk-8p579jct.js} +1 -1
- package/dist/cli/{chunk-1zxheb0c.js → chunk-8vbcj8xx.js} +1 -1
- package/dist/cli/{chunk-tkbdgh2k.js → chunk-9sk0w5be.js} +1 -1
- package/dist/cli/{chunk-7za7dj9z.js → chunk-a10bkevn.js} +1 -1
- package/dist/cli/{chunk-84h387qb.js → chunk-a5vhekme.js} +1 -1
- package/dist/cli/chunk-c1j22psa.js +3 -0
- package/dist/cli/{chunk-wpvxfzb9.js → chunk-c9js0wd7.js} +1 -1
- package/dist/cli/chunk-ctkf2m9h.js +9 -0
- package/dist/cli/{chunk-gpan2g7d.js → chunk-ctmbj2y3.js} +1 -1
- package/dist/cli/{chunk-33dt8jkh.js → chunk-dbs8p34d.js} +2 -2
- package/dist/cli/{chunk-gxdfyn42.js → chunk-dqvy3kxk.js} +1 -1
- package/dist/cli/{chunk-zh6fadgw.js → chunk-e5k2j2x8.js} +1 -1
- package/dist/cli/{chunk-efq3j5v8.js → chunk-f3gedc7r.js} +1 -1
- package/dist/cli/{chunk-taf0014q.js → chunk-g655yb7d.js} +4 -2
- package/dist/cli/{chunk-1brfxbvg.js → chunk-grr2fn38.js} +1 -1
- package/dist/cli/{chunk-k5py2g4y.js → chunk-h29wy8y3.js} +1 -1
- package/dist/cli/{chunk-nem2x959.js → chunk-h86p4zzr.js} +1 -1
- package/dist/cli/{chunk-ca3bfxd9.js → chunk-hkbdrwtg.js} +1 -1
- package/dist/cli/{chunk-qgck9n3y.js → chunk-hv77tgmh.js} +1 -1
- package/dist/cli/{chunk-8ztzk7tg.js → chunk-j8evwrp3.js} +1 -1
- package/dist/cli/chunk-jxyvk9c0.js +3 -0
- package/dist/cli/{chunk-66cew8sb.js → chunk-kjhhwhs4.js} +1 -1
- package/dist/cli/{chunk-74v6dm9n.js → chunk-kme8knh8.js} +1 -1
- package/dist/cli/{chunk-6c5hh9zq.js → chunk-knpr38z6.js} +1 -1
- package/dist/cli/chunk-m9q1whep.js +3 -0
- package/dist/cli/{chunk-kxpfm6mb.js → chunk-ntkfhrbw.js} +3 -3
- package/dist/cli/{chunk-j3783bf2.js → chunk-pa6teq2c.js} +1 -1
- package/dist/cli/{chunk-aq04rqv7.js → chunk-pmszj74t.js} +1 -1
- package/dist/cli/{chunk-fcfh9xsq.js → chunk-qqz6nxfe.js} +2 -2
- package/dist/cli/{chunk-2whnrjrr.js → chunk-ry54qsbg.js} +3 -3
- package/dist/cli/{chunk-ybw6wah4.js → chunk-s9d6vjmc.js} +1 -1
- package/dist/cli/{chunk-2zrphhdf.js → chunk-szx3wehf.js} +1 -1
- package/dist/cli/{chunk-9xq1r084.js → chunk-t45c781p.js} +1 -1
- package/dist/cli/{chunk-rn1kwc71.js → chunk-t64hwtzt.js} +2 -2
- package/dist/cli/{chunk-q4qxhh4d.js → chunk-tnghx1kw.js} +1 -1
- package/dist/cli/chunk-vq6q30tg.js +8 -0
- package/dist/cli/{chunk-ncxfyfb5.js → chunk-vrzb7s42.js} +1 -1
- package/dist/cli/{chunk-3yd0ty84.js → chunk-wam8sr6a.js} +1 -1
- package/dist/cli/{chunk-pb4cc1vy.js → chunk-wd2k83dv.js} +3 -3
- package/dist/cli/{chunk-0xrdy726.js → chunk-wh734g12.js} +1 -1
- package/dist/cli/{chunk-dgt1yq74.js → chunk-wvwkmj3t.js} +1 -1
- package/dist/cli/{chunk-e3g79zpp.js → chunk-xt92ptzx.js} +1 -1
- package/dist/cli/index.js +7 -5
- package/dist/cli/pty-host-node.mjs +10 -1
- package/dist/cli/rove-run.js +1 -1
- package/dist/cli/rove.js +2 -2
- package/dist/skills/rove/SKILL.md +3 -3
- package/dist/skills/rove/references/api-flags.md +2 -2
- package/package.json +2 -2
- package/dist/cli/chunk-q0av0rvg.js +0 -9
- package/dist/cli/chunk-t3682s5j.js +0 -3
- package/dist/cli/chunk-t6zw81pp.js +0 -8
- package/dist/cli/chunk-x1d1mq5c.js +0 -3
- package/dist/cli/chunk-xnn96zvb.js +0 -3
- package/dist/cli/chunk-yexx8nec.js +0 -3
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{t}from"./chunk-wvwkmj3t.js";function failureHint(error,cliName="rove"){let details=typeof error==="object"&&error!==null?error:null,hint=details&&"hint"in details&&typeof details.hint==="string"?details.hint:null,args=details&&"nextCommandArgs"in details?details.nextCommandArgs:null,command=Array.isArray(args)&&args.length>0&&args.every((arg)=>typeof arg==="string")?[cliName,...args].map((arg)=>/^[\w./:@=-]+$/.test(arg)?arg:`'${arg.replaceAll("'","'\\''")}'`).join(" "):null;return[hint,command].filter(Boolean).join(`
|
|
3
|
+
`)||t("common.failureHint",{command:`${cliName} doctor`})}
|
|
4
|
+
export{failureHint};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{runChannelCli,startChatChannels}from"./chunk-
|
|
2
|
+
import{runChannelCli,startChatChannels}from"./chunk-73x2hszy.js";import"./chunk-wqfp8d9w.js";export{startChatChannels,runChannelCli};
|
|
@@ -4,5 +4,5 @@ import{generateCompletions,isShellKind,mergeSubVerbs,shippedCompletionsPath}from
|
|
|
4
4
|
|
|
5
5
|
${usage}`),process.exit(2)};if(rest.some((arg)=>HELP_WORDS.includes(arg))){process.stdout.write(usage);return}let flags=rest.filter((arg)=>arg.startsWith("-")),shells=rest.filter((arg)=>!arg.startsWith("-")),unknownFlag=flags.find((flag)=>flag!=="--path"&&flag!=="--install");if(unknownFlag)fail(`unknown option "${unknownFlag}"`);if(new Set(flags).size>1)fail("--path and --install are different things; pass one");let shell=shells.length===1?shells[0]:void 0;if(!isShellKind(shell))fail(`unknown shell "${shells.join(" ")}"`);let scriptPath=shippedCompletionsPath(shell,cliName,deps.shippedDir),shipped=existsSync(scriptPath)?scriptPath:null;if(flags[0]==="--path"){if(!shipped)fail(`no pre-generated ${shell} script at ${scriptPath}
|
|
6
6
|
${cliName} completions ${shell} # print the script to stdout instead`);process.stdout.write(`${shipped}
|
|
7
|
-
`);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-
|
|
8
|
-
`);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-
|
|
7
|
+
`);return}if(flags[0]==="--install"){let[{installCompletions,settleWelcomeInstall},{t}]=await Promise.all([import("./chunk-f3gedc7r.js"),import("./chunk-knpr38z6.js")]),completion=installCompletions(shell,deps.home,cliName,shipped);settleWelcomeInstall("completions",shell);let line=completion.installed?"onboarding.appliedCompletions":"onboarding.keptCompletions";process.stdout.write(`${t(line,{path:completion.path})}
|
|
8
|
+
`);return}if(shipped){process.stdout.write(readFileSync(shipped,"utf8"));return}let{API_VERBS}=await import("./chunk-6eb945nc.js");process.stdout.write(generateCompletions(shell,cliName,mergeSubVerbs(API_VERBS)))}export{runCompletionsSubcommand};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{loadPluginRegistry,pluginConfigDir,pluginDataDir,pluginLogPath,pluginRegistryPath,pluginStateDir,pluginsRootDir}from"./chunk-rqyaf0dw.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE}from"./chunk-yt15y085.js";import{chmodSync}from"fs";function tighten(path,mode){try{chmodSync(path,mode)}catch{}}function tightenPluginPermissions(id,homeDir){tighten(pluginDataDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginConfigDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginStateDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(`${pluginConfigDir(id,homeDir)}/.env`,OWNER_ONLY_FILE_MODE),tighten(pluginLogPath(id,homeDir),OWNER_ONLY_FILE_MODE)}function tightenInstalledPluginPermissions(homeDir){tighten(pluginsRootDir(homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginRegistryPath(homeDir),OWNER_ONLY_FILE_MODE);for(let entry of loadPluginRegistry(homeDir).plugins)tightenPluginPermissions(entry.id,homeDir)}var MONTH_NAMES=new Map([["JAN",1],["FEB",2],["MAR",3],["APR",4],["MAY",5],["JUN",6],["JUL",7],["AUG",8],["SEP",9],["OCT",10],["NOV",11],["DEC",12]]),DAY_NAMES=new Map([["SUN",0],["MON",1],["TUE",2],["WED",3],["THU",4],["FRI",5],["SAT",6]]);function fieldNumber(raw,names,field){let token=raw.toUpperCase(),named=names?.get(token);if(named!==void 0)return named;if(!/^\d+$/.test(token))throw Error(`invalid cron ${field}: ${raw}`);return Number(token)}function parseField(args){let out=new Set;for(let part of args.value.split(",")){if(part.length===0)throw Error(`invalid cron ${args.field}: ${args.value}`);let[spec,stepRaw,...extra]=part.split("/");if(extra.length>0||spec===void 0)throw Error(`invalid cron ${args.field}: ${part}`);let step=1;if(stepRaw!==void 0){if(!/^\d+$/.test(stepRaw))throw Error(`invalid cron ${args.field} step: ${part}`);if(step=Number(stepRaw),step<1)throw Error(`invalid cron ${args.field} step: ${part}`)}let lo,hi;if(spec==="*")lo=args.min,hi=args.max;else if(spec.includes("-")){let[loRaw,hiRaw,...rest]=spec.split("-");if(rest.length>0||loRaw===void 0||hiRaw===void 0)throw Error(`invalid cron ${args.field} range: ${part}`);lo=fieldNumber(loRaw,args.names,args.field),hi=fieldNumber(hiRaw,args.names,args.field)}else lo=fieldNumber(spec,args.names,args.field),hi=stepRaw===void 0?lo:args.max;if(lo<args.min||hi>args.max||lo>hi)throw Error(`cron ${args.field} out of range: ${part}`);for(let v=lo;v<=hi;v+=step)out.add(args.normalize?args.normalize(v):v)}return out}function parseCron(expression){if(expression.length>256)throw Error("cron expression is too long");let fields=expression.trim().split(/\s+/).filter(Boolean);if(fields.length!==5)throw Error(`cron expression needs 5 fields (minute hour day month weekday), got ${fields.length}`);let[minute,hour,dayOfMonth,month,dayOfWeek]=fields;return{minutes:parseField({value:minute,min:0,max:59,field:"minute"}),hours:parseField({value:hour,min:0,max:23,field:"hour"}),daysOfMonth:parseField({value:dayOfMonth,min:1,max:31,field:"day-of-month"}),months:parseField({value:month,min:1,max:12,field:"month",names:MONTH_NAMES}),daysOfWeek:parseField({value:dayOfWeek,min:0,max:7,field:"weekday",names:DAY_NAMES,normalize:(v)=>v%7}),dayOfMonthRestricted
|
|
2
|
+
import{loadPluginRegistry,pluginConfigDir,pluginDataDir,pluginLogPath,pluginRegistryPath,pluginStateDir,pluginsRootDir}from"./chunk-rqyaf0dw.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE}from"./chunk-yt15y085.js";import{chmodSync}from"fs";function tighten(path,mode){try{chmodSync(path,mode)}catch{}}function tightenPluginPermissions(id,homeDir){tighten(pluginDataDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginConfigDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginStateDir(id,homeDir),OWNER_ONLY_DIR_MODE),tighten(`${pluginConfigDir(id,homeDir)}/.env`,OWNER_ONLY_FILE_MODE),tighten(pluginLogPath(id,homeDir),OWNER_ONLY_FILE_MODE)}function tightenInstalledPluginPermissions(homeDir){tighten(pluginsRootDir(homeDir),OWNER_ONLY_DIR_MODE),tighten(pluginRegistryPath(homeDir),OWNER_ONLY_FILE_MODE);for(let entry of loadPluginRegistry(homeDir).plugins)tightenPluginPermissions(entry.id,homeDir)}var MONTH_NAMES=new Map([["JAN",1],["FEB",2],["MAR",3],["APR",4],["MAY",5],["JUN",6],["JUL",7],["AUG",8],["SEP",9],["OCT",10],["NOV",11],["DEC",12]]),DAY_NAMES=new Map([["SUN",0],["MON",1],["TUE",2],["WED",3],["THU",4],["FRI",5],["SAT",6]]);function fieldNumber(raw,names,field){let token=raw.toUpperCase(),named=names?.get(token);if(named!==void 0)return named;if(!/^\d+$/.test(token))throw Error(`invalid cron ${field}: ${raw}`);return Number(token)}function parseField(args){let out=new Set;for(let part of args.value.split(",")){if(part.length===0)throw Error(`invalid cron ${args.field}: ${args.value}`);let[spec,stepRaw,...extra]=part.split("/");if(extra.length>0||spec===void 0)throw Error(`invalid cron ${args.field}: ${part}`);let step=1;if(stepRaw!==void 0){if(!/^\d+$/.test(stepRaw))throw Error(`invalid cron ${args.field} step: ${part}`);if(step=Number(stepRaw),step<1)throw Error(`invalid cron ${args.field} step: ${part}`)}let lo,hi;if(spec==="*")lo=args.min,hi=args.max;else if(spec.includes("-")){let[loRaw,hiRaw,...rest]=spec.split("-");if(rest.length>0||loRaw===void 0||hiRaw===void 0)throw Error(`invalid cron ${args.field} range: ${part}`);lo=fieldNumber(loRaw,args.names,args.field),hi=fieldNumber(hiRaw,args.names,args.field)}else lo=fieldNumber(spec,args.names,args.field),hi=stepRaw===void 0?lo:args.max;if(lo<args.min||hi>args.max||lo>hi)throw Error(`cron ${args.field} out of range: ${part}`);for(let v=lo;v<=hi;v+=step)out.add(args.normalize?args.normalize(v):v)}return out}function parseCron(expression){if(expression.length>256)throw Error("cron expression is too long");let fields=expression.trim().split(/\s+/).filter(Boolean);if(fields.length!==5)throw Error(`cron expression needs 5 fields (minute hour day month weekday), got ${fields.length}`);let[minute,hour,dayOfMonth,month,dayOfWeek]=fields;return{minutes:parseField({value:minute,min:0,max:59,field:"minute"}),hours:parseField({value:hour,min:0,max:23,field:"hour"}),daysOfMonth:parseField({value:dayOfMonth,min:1,max:31,field:"day-of-month"}),months:parseField({value:month,min:1,max:12,field:"month",names:MONTH_NAMES}),daysOfWeek:parseField({value:dayOfWeek,min:0,max:7,field:"weekday",names:DAY_NAMES,normalize:(v)=>v%7}),dayOfMonthRestricted:!dayOfMonth.startsWith("*"),dayOfWeekRestricted:!dayOfWeek.startsWith("*")}}function isValidCron(expression){try{return parseCron(expression),!0}catch{return!1}}function instantOf(d,hour,minute){return new Date(d.year,d.month-1,d.day,hour,minute,0,0).getTime()}function localDayOf(ms){let d=new Date(ms);return{year:d.getFullYear(),month:d.getMonth()+1,day:d.getDate()}}function shiftDay(d,delta){return localDayOf(new Date(d.year,d.month-1,d.day+delta,12,0,0,0).getTime())}function dayMatches(rule,d){if(!rule.months.has(d.month))return!1;let domMatch=rule.daysOfMonth.has(d.day),dowMatch=rule.daysOfWeek.has(new Date(d.year,d.month-1,d.day).getDay());if(rule.dayOfMonthRestricted&&rule.dayOfWeekRestricted)return domMatch||dowMatch;return domMatch&&dowMatch}function floorToMinute(ms){return ms-ms%60000}function sorted(values,direction){return[...values].sort((a,b)=>(a-b)*direction)}function nextCronAfter(expression,afterMs){let rule=parseCron(expression),hours=sorted(rule.hours,1),minutes=sorted(rule.minutes,1),from=new Date(floorToMinute(afterMs)+60000),day=localDayOf(from.getTime()),fromHour=from.getHours(),fromMinute=from.getMinutes();for(let i=0;i<3294;i++){if(dayMatches(rule,day))for(let hour of hours){if(hour<fromHour)continue;for(let minute of minutes){if(hour===fromHour&&minute<fromMinute)continue;let at=instantOf(day,hour,minute);if(at>afterMs)return at}}day=shiftDay(day,1),fromHour=0,fromMinute=0}throw Error(`cron expression never matches: ${expression}`)}function latestCronAtOrBefore(expression,nowMs,notBeforeMs){if(nowMs<notBeforeMs)return null;let rule=parseCron(expression),hours=sorted(rule.hours,-1),minutes=sorted(rule.minutes,-1),from=new Date(floorToMinute(nowMs)),day=localDayOf(from.getTime()),fromHour=from.getHours(),fromMinute=from.getMinutes();for(let i=0;i<3294;i++){if(instantOf(day,23,59)<notBeforeMs)return null;if(dayMatches(rule,day))for(let hour of hours){if(hour>fromHour)continue;for(let minute of minutes){if(hour===fromHour&&minute>fromMinute)continue;let at=instantOf(day,hour,minute);if(at>nowMs)continue;return at>=notBeforeMs?at:null}}day=shiftDay(day,-1),fromHour=23,fromMinute=59}return null}function countCronBetween(expression,fromMs,beforeMs,cap=500){if(!(fromMs<beforeMs))return 0;let count=0,cursor=fromMs-1;while(count<cap){let at;try{at=nextCronAfter(expression,cursor)}catch{return count}if(at>=beforeMs)return count;count+=1,cursor=at}return count}
|
|
3
3
|
export{tightenPluginPermissions,tightenInstalledPluginPermissions,isValidCron,nextCronAfter,latestCronAtOrBefore,countCronBetween};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{PS_PROBE_TIMEOUT_MS,engineProcessIn,foregroundEngine,foregroundEngineIn,hasAncestor,parsePsSnapshot,psSnapshot,psSnapshotWith,vendorFromArgv}from"./chunk-
|
|
2
|
+
import{PS_PROBE_TIMEOUT_MS,engineProcessIn,foregroundEngine,foregroundEngineIn,hasAncestor,parsePsSnapshot,psSnapshot,psSnapshotWith,vendorFromArgv}from"./chunk-wam8sr6a.js";import"./chunk-ctmbj2y3.js";import"./chunk-k4374n9t.js";import"./chunk-w7zv47mp.js";import"./chunk-2tfnscxk.js";import"./chunk-2brn8e1y.js";import"./chunk-60fy3ckp.js";import"./chunk-znjcesdr.js";import"./chunk-7kysxgbq.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import"./chunk-h9cg0j3a.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-7q43tysm.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import{PsProbeUnavailableError}from"./chunk-pxk2c2vj.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-wqfp8d9w.js";export{vendorFromArgv,psSnapshotWith,psSnapshot,parsePsSnapshot,hasAncestor,foregroundEngineIn,foregroundEngine,engineProcessIn,PsProbeUnavailableError,PS_PROBE_TIMEOUT_MS};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{protocolEntry}from"./chunk-
|
|
2
|
+
import{protocolEntry}from"./chunk-4r3s1z14.js";import{getPersistedString,getPersistedValue}from"./chunk-h9cg0j3a.js";import{acquireSync,releaseSync}from"./chunk-mw0ysrpd.js";import{secretsPath}from"./chunk-prqeddy7.js";function bottomRegion(captureText,lines){return captureText.split(`
|
|
3
3
|
`).filter((l)=>l.trim().length>0).slice(-lines)}function ruleMatches(rule,region){let haystack=region.join(`
|
|
4
4
|
`).toLowerCase();if(rule.all&&!rule.all.every((s)=>haystack.includes(s.toLowerCase())))return!1;if(rule.any&&!rule.any.some((s)=>haystack.includes(s.toLowerCase())))return!1;if(rule.lineRegex){let regexes=rule.lineRegex.map((r)=>new RegExp(r,"i"));if(!region.some((line)=>regexes.some((re)=>re.test(line))))return!1}return Boolean(rule.all||rule.any||rule.lineRegex)}function classifyScreen(manifest,captureText){for(let rule of manifest.rules){let region=bottomRegion(captureText,rule.bottomLines??12);if(region.length===0)continue;if(ruleMatches(rule,region))return rule.state}return null}var MAX_ERROR_ROWS=6;function screenErrorLine(errorLine,rows,opts={}){let filled=rows.flatMap((row,index)=>row.trim()?[index]:[]),window=filled.slice(-12);for(let k=window.length-1;k>=0;k--){let start=window[k];if(!errorLine.test(rows[start]??""))continue;let end=start+1;while(end<rows.length&&end-start<MAX_ERROR_ROWS&&rows[end]?.trim())end++;if(opts.last&&filled.some((index)=>index>=end))return;return rows.slice(start,end).map((row)=>row.trim()).join(" ")}return}var AUTO_ROUTING_TIERS=["swift","standard","deep"];function isAutoRoutingTier(value){return AUTO_ROUTING_TIERS.includes(value??"")}var DEFAULT_AUTO_ROUTING={swift:{engine:"claude",model:"sonnet"},standard:{engine:"claude",model:"opus"},deep:{engine:"claude",model:"fable"}};function autoRoutingKey(tier,field){return`autoRouting.${tier}.${field}`}function stringAt(get,key){let raw=get(key);return typeof raw==="string"?raw:void 0}function readAutoRoutingTable(get=getPersistedString){let table={};for(let tier of AUTO_ROUTING_TIERS){let base=DEFAULT_AUTO_ROUTING[tier],engine=stringAt(get,autoRoutingKey(tier,"engine"));if(engine!==void 0&&!engine.trim())return null;let model=stringAt(get,autoRoutingKey(tier,"model")),effort=stringAt(get,autoRoutingKey(tier,"effort")),resolvedModel=model===void 0?base.model:model.trim()||void 0,resolvedEffort=effort===void 0?base.effort:effort.trim()||void 0;table[tier]={engine:engine?.trim()||base.engine,...resolvedModel?{model:resolvedModel}:{},...resolvedEffort?{effort:resolvedEffort}:{}}}return table}function tierBlock(target,deps){let{engine}=target;if(!deps.engineIds.has(engine))return{kind:"engine",engine};if(deps.accountKind(engine)==="none")return{kind:"account",engine};let entry=protocolEntry(engine);if(target.model&&!entry.modelArgv)return{kind:"model",engine,model:target.model};if(target.effort){let levels=entry.effortLevels??[];if(!levels.includes(target.effort))return{kind:"effort",engine,effort:target.effort,levels}}return null}function describeTierBlock(block){switch(block.kind){case"engine":return`engine ${block.engine} is not one engine-list names`;case"account":return`engine ${block.engine} is not logged in`;case"model":return`engine ${block.engine} declares no model flag, so model ${JSON.stringify(block.model)} cannot be passed`;case"effort":return block.levels.length===0?`engine ${block.engine} declares no reasoning effort levels`:`engine ${block.engine} does not accept effort ${JSON.stringify(block.effort)} \u2014 it declares ${block.levels.join(", ")}`}}import{mkdirSync,readFileSync,readdirSync,renameSync,unlinkSync,writeFileSync}from"fs";import{basename,dirname,join}from"path";var HINT_TAIL=4;function readStored(path){let raw;try{raw=readFileSync(path,"utf8")}catch{return{}}try{let parsed=JSON.parse(raw);if(typeof parsed==="object"&&parsed!==null&&!Array.isArray(parsed))return parsed}catch{}return"corrupt"}function readAll(){let stored=readStored(secretsPath());if(stored==="corrupt")return{};let out={};for(let[k,v]of Object.entries(stored))if(typeof v==="string")out[k]=v;return out}function stagingPath(path){return`${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`}function sweepStagingFiles(path){let dir=dirname(path),prefix=`${basename(path)}.`,entries;try{entries=readdirSync(dir)}catch{return}for(let entry of entries){if(!entry.startsWith(prefix)||!entry.endsWith(".tmp"))continue;try{unlinkSync(join(dir,entry))}catch{}}}function transact(mutate){let path=secretsPath();mkdirSync(dirname(path),{recursive:!0,mode:448});let lockPath=`${path}.lock`,token=acquireSync(lockPath);try{sweepStagingFiles(path);let secrets=readStored(path);if(secrets==="corrupt")renameSync(path,`${path}.corrupt-${Date.now()}`),secrets={};if(mutate(secrets),Object.keys(secrets).length===0){try{unlinkSync(path)}catch(err){if(err?.code!=="ENOENT")throw err}return}let tmp=stagingPath(path);writeFileSync(tmp,JSON.stringify(secrets),{encoding:"utf8",mode:384}),renameSync(tmp,path)}finally{releaseSync(lockPath,token)}}function readSecret(name){let v=readAll()[name];return v?.trim()?v.trim():void 0}function resolveSecret(name,env=process.env){return env[name]?.trim()||readSecret(name)}function secretStatus(name,env=process.env){let stored=readAll()[name]?.trim(),hint=stored?secretHint(stored):"";if(env[name]?.trim())return{source:"env",hint};return{source:stored?"file":"none",hint}}function secretHint(value){let v=value.trim();return v.length<=HINT_TAIL?"\u2026":`\u2026${v.slice(-HINT_TAIL)}`}function writeSecret(name,value){transact((secrets)=>{let v=value.trim();if(v)secrets[name]=v;else delete secrets[name]})}var SUM_TOLERANCE=0.02,bad=(why)=>({ok:!1,why});function isRecord(v){return typeof v==="object"&&v!==null&&!Array.isArray(v)}function readConfidence(v){return typeof v==="number"&&Number.isFinite(v)&&v>=0&&v<=1?v:void 0}function readChoiceAnswer(answer){if(!isRecord(answer))return bad("answer is not an object");let choice=answer.choice;if(typeof choice!=="string"||!isAutoRoutingTier(choice))return bad(`choice ${JSON.stringify(choice)} is not one of the offered tiers`);let probs=answer.probabilities;if(!isRecord(probs))return bad("probabilities is not an object");let keys=Object.keys(probs).sort(),expected=[...AUTO_ROUTING_TIERS].sort();if(keys.length!==expected.length||keys.some((k,i)=>k!==expected[i]))return bad(`probabilities keys ${keys.join(",")} do not match the offered tiers`);let values={},sum=0;for(let tier of AUTO_ROUTING_TIERS){let p=probs[tier];if(typeof p!=="number"||!Number.isFinite(p)||p<0||p>1)return bad(`probability for ${tier} is not a number in [0,1]`);values[tier]=p,sum+=p}if(Math.abs(sum-1)>SUM_TOLERANCE)return bad(`probabilities sum to ${sum.toFixed(3)}`);for(let tier of AUTO_ROUTING_TIERS)if(values[tier]>values[choice])return bad(`choice ${choice} is not the most likely tier`);let confidence=readConfidence(answer.confidence);if(confidence===void 0)return bad("confidence is missing or out of range");return{ok:!0,value:{tier:choice,confidence,probabilities:values}}}function readJevAnswer(payload){if(!isRecord(payload))return bad("response is not an object");let answers=payload.answers;if(!isRecord(answers))return bad("response has no answers");return readChoiceAnswer(answers.verdict)}function readPlainAnswer(payload){if(!isRecord(payload))return bad("response is not an object");let tier=payload.tier;if(typeof tier!=="string"||!isAutoRoutingTier(tier))return bad(`tier ${JSON.stringify(tier)} is not one of ${AUTO_ROUTING_TIERS.join(", ")}`);let confidence=readConfidence(payload.confidence);if(confidence===void 0)return bad("confidence is missing or not a number in [0,1]");return{ok:!0,value:{tier,confidence}}}var DEFAULT_TIER_RUBRIC={role:"\u4F60\u5728\u7ED9\u4E00\u6761\u300C\u7528\u6237\u65B0\u5EFA coding task \u65F6\u5199\u7684\u7B2C\u4E00\u53E5\u8BDD\u300D\u6253\u6DF1\u5EA6\u6863\u3002",criterion:"\u53EA\u6709\u4E00\u4E2A\u5224\u636E\uFF1A\u7528\u6237\u7684\u6307\u4EE4\u91CC\uFF0C\u6709\u591A\u5C11\u6D41\u7A0B\u9700\u8981\u6A21\u578B\u81EA\u5DF1\u63A8\u7406\u51FA\u6765\u3002\u4E0D\u770B\u5DE5\u4F5C\u91CF\uFF0C\u4E0D\u770B\u96BE\u5EA6\uFF0C\u4E0D\u770B\u6587\u672C\u957F\u77ED\uFF0C\u4E0D\u770B\u8BED\u8A00\u3002\u4E09\u6863\u6CA1\u6709\u76EE\u6807\u6BD4\u4F8B\u3002",criteria:{swift:{what:`- \u8BF4\u4E86\u600E\u4E48\u505A\uFF1Astep-by-step\u3001\u6307\u5230\u4E86\u6587\u4EF6/\u914D\u7F6E/\u9009\u9879\u3001\u7ED9\u4E86\u53C2\u8003\u5B9E\u73B0\uFF08\u300C\u53C2\u8003 vuetify \u540C\u540D prop\u300D\u300C\u50CF fzf \u90A3\u6837\u300D\uFF09\u3002
|
|
5
5
|
- \u7528\u6237\u5DF2\u7ECF\u5B9A\u4F4D\u8FC7\u4E86\uFF1A\u300Cprofile \u4E86\u4E00\u4E0B\u53D1\u73B0\u662F X\uFF0C\u7F13\u5B58\u4E00\u4E0B\u5427\u300D\u2014\u2014\u539F\u56E0\u627E\u5230\u4E86\uFF0C\u5269\u4E0B\u7167\u505A\u3002
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{PLUGIN_MANIFEST_FILENAMES,currentPluginPlatform,loadPluginRegistry,parsePluginManifest,pluginCheckoutDir,pluginConfigDir,pluginManifestPath,pluginStateDir,pluginsRootDir,savePluginRegistry,supportsPlatform,upsertPluginEntry}from"./chunk-rqyaf0dw.js";import{CURRENT_VERSION,compareSemver}from"./chunk-
|
|
2
|
+
import{PLUGIN_MANIFEST_FILENAMES,currentPluginPlatform,loadPluginRegistry,parsePluginManifest,pluginCheckoutDir,pluginConfigDir,pluginManifestPath,pluginStateDir,pluginsRootDir,savePluginRegistry,supportsPlatform,upsertPluginEntry}from"./chunk-rqyaf0dw.js";import{CURRENT_VERSION,compareSemver}from"./chunk-8p579jct.js";import{spawn}from"child_process";import{cpSync,existsSync,mkdirSync,readFileSync,renameSync,rmSync}from"fs";import{mkdtempSync}from"fs";import{basename,join,resolve}from"path";import{createInterface}from"readline/promises";var GITHUB_SPEC_RE=/^([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)(\/.+)?$/;class PluginCliError extends Error{}function fail(message){throw new PluginCliError(message)}function readManifestAt(root){let path=pluginManifestPath(root);if(!path)fail(`no ${PLUGIN_MANIFEST_FILENAMES.join(" or ")} found at ${root}`);let source=readFileSync(path,"utf8");return{...parsePluginManifest(source,basename(path)),manifestPath:path,manifestSource:source}}function checkVersionGate(parsed){let min=parsed.manifest.minRoveVersion;if(compareSemver(CURRENT_VERSION,min)<0)fail(`plugin requires Rove >= ${min} (this is ${CURRENT_VERSION}); update Rove first`)}function commandLines(parsed){let m=parsed.manifest,lines=[];for(let c of m.build)lines.push(`build: ${c.command.join(" ")}`);for(let c of m.startup)lines.push(`startup: ${c.command.join(" ")}`);for(let a of m.actions)lines.push(`action ${a.id}: ${a.command.join(" ")}`);for(let e of m.events)lines.push(`on ${e.on}: ${e.command.join(" ")}`);return lines}var CAPTURE_TAIL_BYTES=4096;function run(cmd,args,opts){return new Promise((resolve2)=>{let child=spawn(cmd,args,{cwd:opts.cwd,stdio:opts.inherit?["ignore","inherit","inherit"]:["ignore","pipe","pipe"]}),output="",collect=(chunk)=>{output=`${output}${String(chunk)}`.slice(-CAPTURE_TAIL_BYTES)};child.stdout?.on("data",collect),child.stderr?.on("data",collect),child.on("error",(err)=>resolve2({code:null,output:`${output}${err.message}`})),child.on("close",(code)=>resolve2({code,output}))})}function outputTail(output){let trimmed=output.trim();return trimmed?`: ${trimmed.split(`
|
|
3
3
|
`).slice(-3).join(" / ")}`:""}async function git(args,opts){let{code,output}=await run("git",args,opts);if(code!==0)fail(`git ${args[0]} failed${outputTail(output)}`)}async function runBuildCommands(parsed,root,opts){let platform=currentPluginPlatform();for(let[i,step]of parsed.manifest.build.entries()){if(!supportsPlatform(step,parsed.manifest,platform))continue;let[cmd,...args]=step.command;if(opts.inherit)console.log(`build[${i}]: ${step.command.join(" ")}`);let{code,output}=await run(cmd,args,{cwd:root,inherit:opts.inherit});if(code!==0)fail(`build[${i}] failed (exit ${code??"spawn error"}); plugin not registered${outputTail(output)}`)}}function makeStagingDir(){let root=pluginsRootDir();return mkdirSync(root,{recursive:!0}),mkdtempSync(join(root,".staging-"))}function movePluginTree(from,to){try{renameSync(from,to)}catch(err){if(err.code!=="EXDEV")throw err;cpSync(from,to,{recursive:!0,verbatimSymlinks:!0}),rmSync(from,{recursive:!0,force:!0})}}function register(entry){savePluginRegistry(upsertPluginEntry(loadPluginRegistry(),entry)),mkdirSync(pluginConfigDir(entry.id),{recursive:!0,mode:448}),mkdirSync(pluginStateDir(entry.id),{recursive:!0,mode:448})}async function preparePluginInstall(spec,opts={}){let match=spec.match(GITHUB_SPEC_RE);if(!match)fail(`install takes GitHub shorthand (owner/repo[/subdir]), got \`${spec}\``);let[,owner,repo,subdirRaw]=match,subdir=subdirRaw?.replace(/^\//,""),inherit=opts.inherit??!1,tmp=makeStagingDir();try{let url=`https://github.com/${owner}/${repo}.git`;if(inherit)console.log(`cloning ${url}${opts.ref?` @ ${opts.ref}`:""}`);if(opts.ref)await git(["clone","--quiet",url,tmp],{inherit}),await git(["checkout","--quiet",opts.ref],{cwd:tmp,inherit});else await git(["clone","--quiet","--depth","1",url,tmp],{inherit});let rootInClone=subdir?join(tmp,subdir):tmp,parsed=readManifestAt(rootInClone);checkVersionGate(parsed);let id=parsed.manifest.id,existing=loadPluginRegistry().plugins.find((p)=>p.id===id);if(existing?.source.kind==="link")fail(`\`${id}\` is locally linked at ${existing.root}; unlink it first`);if(!supportsPlatform({},parsed.manifest,currentPluginPlatform()))fail(`plugin declares platforms [${parsed.manifest.platforms?.join(", ")}]; this machine is unsupported`);return{preview:{id,name:parsed.manifest.name,version:parsed.manifest.version,description:parsed.manifest.description??null,source:`github.com/${owner}/${repo}${subdir?`/${subdir}`:""}`,commands:commandLines(parsed),warnings:parsed.warnings},commit:async()=>{try{await runBuildCommands(parsed,rootInClone,{inherit});let manifestPath=pluginManifestPath(rootInClone);if(!manifestPath)fail("manifest disappeared during build; aborting");if(manifestPath!==parsed.manifestPath)fail("manifest changed during build; aborting");if(readFileSync(manifestPath,"utf8")!==parsed.manifestSource)fail("manifest changed during build; aborting");let checkout=pluginCheckoutDir(id);return rmSync(checkout,{recursive:!0,force:!0}),mkdirSync(join(checkout,".."),{recursive:!0}),movePluginTree(tmp,checkout),register({id,source:{kind:"github",spec},root:subdir?join(checkout,subdir):checkout,enabled:!0,version:parsed.manifest.version,installedAt:Date.now()}),id}finally{rmSync(tmp,{recursive:!0,force:!0})}},discard:()=>rmSync(tmp,{recursive:!0,force:!0})}}catch(err){throw rmSync(tmp,{recursive:!0,force:!0}),err}}function printPreview(preview){console.log(`
|
|
4
4
|
${preview.name} (${preview.id}) v${preview.version} \u2014 ${preview.description??"no description"}`),console.log(`source: ${preview.source}`);for(let line of preview.commands)console.log(` ${line}`);for(let w of preview.warnings)console.log(` warning: ${w}`);console.log("")}async function confirmOrBail(yes){if(yes)return;if(!process.stdin.isTTY)fail("refusing to install without confirmation in a non-interactive terminal; pass --yes");let rl=createInterface({input:process.stdin,output:process.stdout}),answer=(await rl.question("Install this plugin and run its build commands? [y/N] ")).trim().toLowerCase();if(rl.close(),answer!=="y"&&answer!=="yes")fail("aborted")}async function installPlugin(spec,opts){let prepared=await preparePluginInstall(spec,{ref:opts.ref,inherit:!0});printPreview(prepared.preview);try{await confirmOrBail(opts.yes)}catch(err){throw prepared.discard(),err}let id=await prepared.commit();return console.log(`installed ${id} v${prepared.preview.version}`),id}function linkPlugin(dir){let root=resolve(dir);if(!existsSync(root))fail(`no such directory: ${root}`);let parsed=readManifestAt(root);checkVersionGate(parsed);let id=parsed.manifest.id;if(loadPluginRegistry().plugins.find((p)=>p.id===id)?.source.kind==="github")fail(`\`${id}\` is installed from GitHub; uninstall it before linking a local copy`);for(let w of parsed.warnings)console.log(`warning: ${w}`);if(!supportsPlatform({},parsed.manifest,currentPluginPlatform()))console.log(`warning: declares platforms [${parsed.manifest.platforms?.join(", ")}]; nothing will run on this machine`);register({id,source:{kind:"link"},root,enabled:!0,version:parsed.manifest.version,installedAt:Date.now()}),console.log(`linked ${id} v${parsed.manifest.version} \u2192 ${root}`)}
|
|
5
5
|
export{PluginCliError,preparePluginInstall,installPlugin,linkPlugin};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{LAST_RUN_VERSION_KEY}from"./chunk-
|
|
2
|
+
import{LAST_RUN_VERSION_KEY}from"./chunk-kjhhwhs4.js";import{isShellKind,shippedCompletionsPath}from"./chunk-6ms5chc3.js";import{isNpxMissing,markSkillHintSeen,npxSkillsArgv,npxSkillsCommand}from"./chunk-dbs8p34d.js";import{loadStateFile,patchStateFile}from"./chunk-7q43tysm.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{t}from"./chunk-wvwkmj3t.js";import{spawnSync}from"child_process";import{appendFileSync,existsSync,mkdirSync,readFileSync,writeFileSync}from"fs";import{homedir}from"os";import{basename,join}from"path";var WELCOMED_KEY="welcomed",PENDING_SKILL_KEY="welcomePendingSkillInstall";function shouldWelcome(state){if(state[WELCOMED_KEY]===!0)return!1;return typeof state[LAST_RUN_VERSION_KEY]!=="string"}function takeWelcome(){if(!shouldWelcome(loadStateFile()))return null;try{patchStateFile({[WELCOMED_KEY]:!0})}catch{}return{shell:detectShell()}}var PENDING_COMPLETIONS_KEY="welcomePendingCompletions";function detectShell(env=process.env){let shell=basename(env.SHELL??"");return shell==="zsh"||shell==="bash"||shell==="fish"?shell:null}function completionHook(shell,cli,shipped){if(shipped===null)return legacyCompletionHook(shell,cli);return shell==="fish"?`test -f "${shipped}"; and source "${shipped}"`:`[ -f "${shipped}" ] && source "${shipped}"`}function legacyCompletionHook(shell,cli){return shell==="fish"?`${cli} completions fish | source`:`command -v ${cli} >/dev/null && source <(${cli} completions ${shell})`}function shippedScriptFor(shell,cli){let path=shippedCompletionsPath(shell,cli);return existsSync(path)?path:null}function installCompletions(shell,home=homedir(),cli=ROVE_PRODUCT_NAME,shipped=shippedScriptFor(shell,cli)){let hook=completionHook(shell,cli,shipped);if(shell==="fish"){let dir=join(home,".config","fish","completions"),path=join(dir,`${cli}.fish`);return mkdirSync(dir,{recursive:!0}),writeFileSync(path,`${hook}
|
|
3
3
|
`),{path,installed:!0}}let rc=join(home,shell==="zsh"?".zshrc":".bashrc"),existing=existsSync(rc)?readFileSync(rc,"utf8"):"";if(existing.includes(hook))return{path:rc,installed:!1};let legacy=legacyCompletionHook(shell,cli);if(existing.includes(legacy))return writeFileSync(rc,existing.replace(legacy,hook)),{path:rc,installed:!0};if(existing.includes(`${cli} completions`))return{path:rc,installed:!1};return appendFileSync(rc,`
|
|
4
4
|
# ${cli} completions
|
|
5
5
|
${hook}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{formatBytes,hookConfigIssues}from"./chunk-
|
|
2
|
+
import{applyFixes,daemonRestartFix,defaultFixRuntime,engineTabsManualFix,formatBytes,hookConfigIssues,humanOnlyFix,killOrphansManualFix,noEngineFix,reinstallManualFix,resetManualFix,skillInstallFix,spawnHelperFix}from"./chunk-c1j22psa.js";import{inspectLegacyTmux,legacyTmuxDoctorLines}from"./chunk-gkdfct7t.js";import"./chunk-5c57gz48.js";import"./chunk-1s93zcnx.js";import"./chunk-axsm0gn5.js";import"./chunk-k67vbszb.js";import{describeAccount,detectEngineStatuses,probeableEngineIds,summarizeEngines}from"./chunk-pa6teq2c.js";import"./chunk-4hestsjp.js";import"./chunk-2bgmby1d.js";import"./chunk-rqyaf0dw.js";import"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import{resolveNodeBinary}from"./chunk-4r3s1z14.js";import{formatDaemonInfo}from"./chunk-rxqdw6s5.js";import"./chunk-vjvkkrzc.js";import"./chunk-wam8sr6a.js";import"./chunk-ctmbj2y3.js";import"./chunk-k4374n9t.js";import"./chunk-w7zv47mp.js";import"./chunk-2tfnscxk.js";import"./chunk-w2sp489k.js";import"./chunk-etfh8f4z.js";import"./chunk-dmzg9zdc.js";import"./chunk-kg9kmwt9.js";import"./chunk-zsfyj36g.js";import{isStaleInstallError,resolveRoveSpawn}from"./chunk-96cjpssp.js";import"./chunk-9w5g7frx.js";import"./chunk-gvrtrvnz.js";import"./chunk-2brn8e1y.js";import"./chunk-60fy3ckp.js";import"./chunk-znjcesdr.js";import"./chunk-7kysxgbq.js";import{readableLegacyIndexPath}from"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import{CURRENT_VERSION,package_default}from"./chunk-8p579jct.js";import{roveSkillState,skillInstallCommand}from"./chunk-dbs8p34d.js";import"./chunk-h9cg0j3a.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-7q43tysm.js";import"./chunk-mw0ysrpd.js";import{readPidFile}from"./chunk-a7kq09ke.js";import{homeDir,kvStatePath,roveStateDir}from"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import{t}from"./chunk-wvwkmj3t.js";import"./chunk-jxyvk9c0.js";import"./chunk-nhakrm1f.js";import"./chunk-pxk2c2vj.js";import{RoveDaemonClient,isForeignDaemonHome}from"./chunk-adkva3ep.js";import"./chunk-0422g8ac.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import{defaultDaemonLogPath,defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-npwzmmv9.js";import{preRenameStateDir}from"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import{__require}from"./chunk-wqfp8d9w.js";import{existsSync,readFileSync as readFileSync2,statSync as statSync2}from"fs";import{join as join2}from"path";var MIN_BUN_VERSION=package_default.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0";function parseBunVersion(raw){return raw.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function isBunAtLeast(raw,minimum=MIN_BUN_VERSION){let found=parseBunVersion(raw),floor=parseBunVersion(minimum);if(!found||!floor)return!0;let a=found.split(".").map(Number),b=floor.split(".").map(Number);for(let i=0;i<3;i++){let av=a[i]??0,bv=b[i]??0;if(av!==bv)return av>bv}return!0}function classifyHookChannel(input){let total=0,hooked=0;for(let tabs of Object.values(input.tabs))for(let entry of Object.values(tabs))if(total++,entry.source==="hook")hooked++;if(total===0)return{kind:"no-tabs"};if(hooked===0)return{kind:"down",totalTabs:total};return{kind:"live",hookTabs:hooked,totalTabs:total}}function hookChannelDoctorLines(verdict,input,cliName){let configLines=(input.configIssues??[]).flatMap((issue)=>[` \u26A0 hook install skipped: ${issue.file}`,` ${issue.reason} \u2014 fix the file, then relaunch Rove`]);if(verdict.kind==="no-tabs")return["hooks: \u2014 no engine tabs yet (nothing to check)",...configLines];if(verdict.kind==="live")return[`hooks: \u2713 engine hook channel live (${verdict.hookTabs}/${verdict.totalTabs} tab(s) hook-sourced)`,...configLines];let out=[`hooks: \u2717 NO hook events reaching the daemon (0/${verdict.totalTabs} tab(s) hook-sourced)`," badges fall back to a ~10s poll, so activity looks seconds late",` daemon socket: ${input.socketPath}`,...configLines];return out.push(' \u2192 compare with an engine tab\'s own path: `ps eww -p <engine-pid> | tr " " "\\n" | grep DAEMON_SOCKET_PATH`',` \u2192 restart the engine tabs (they may hold a stale socket path), or run \`${cliName} daemon restart\``,` \u2192 debug one hook directly: \`ROVE_HOOK_DEBUG=1 echo '{}' | ${cliName} hook turn-start --engine claude\``),out}import{readdirSync,statSync}from"fs";import{createRequire}from"module";import{dirname,join}from"path";function installedSpawnHelpers(){let pkg;try{pkg=dirname(createRequire(import.meta.url).resolve("node-pty/package.json"))}catch{return[]}let prebuilds=join(pkg,"prebuilds"),arches;try{arches=readdirSync(prebuilds).filter((name)=>name.startsWith("darwin-"))}catch{return[]}let helpers=[];for(let arch of arches){let path=join(prebuilds,arch,"spawn-helper");try{helpers.push({path,executable:(statSync(path).mode&64)!==0})}catch{}}return helpers}function spawnHelperDoctorLines(helpers){let broken=helpers.filter((helper)=>!helper.executable).map((helper)=>helper.path);if(helpers.length===0)return{lines:["node-pty: ? no darwin spawn-helper found next to node-pty"],broken};if(broken.length===0)return{lines:[`node-pty: \u2713 spawn-helper executable (${helpers.length} arch)`],broken};return{lines:["node-pty: \u2717 spawn-helper is not executable \u2014 every node-pty PTY spawn fails",...broken.map((path)=>` ${path}`),` \u2192 chmod 755 ${broken.join(" ")}`],broken}}import{appendFileSync,readFileSync}from"fs";var PTY_MARKER="ROVE_TERMINAL_PTY=1",run=async(argv)=>{try{let proc=Bun.spawn([...argv],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),[stdout,code]=await Promise.all([new Response(proc.stdout).text().catch(()=>""),proc.exited]);return{code,stdout}}catch{return{code:127,stdout:""}}};function parsePsRows(output){let rows=[];for(let line of output.split(`
|
|
3
3
|
`)){let parts=line.trim().split(/\s+/);if(parts.length<6)continue;let[pid,ppid,pgid]=[parts[0],parts[1],parts[2]].map((value)=>Number.parseInt(value??"",10)),rssKb=Number.parseInt(parts[4]??"",10);if(!Number.isFinite(pid)||!Number.isFinite(ppid)||!Number.isFinite(pgid)||!Number.isFinite(rssKb))continue;rows.push({pid,ppid,pgid,etime:parts[3]??"",rssKb,command:parts.slice(5).join(" ")})}return rows}function pidAlive(pid,rows){return rows.some((row)=>row.pid===pid)}function orphanCandidates(rows,selfPgid,liveSessionPids){return rows.filter((row)=>row.ppid===1&&row.pgid!==selfPgid&&!liveSessionPids.has(row.pgid)&&!pidAlive(row.pgid,rows))}async function markedPids(pids,deps={}){let runProbe=deps.run??run,readEnviron=deps.readEnviron??((pid)=>readFileSync(`/proc/${pid}/environ`,"utf8")),marked=new Set;if(pids.length===0)return{marked,failed:null};if((deps.platform??process.platform)==="linux"){let refused=null;for(let pid of pids)try{if(readEnviron(pid).split("\x00").includes(PTY_MARKER))marked.add(pid)}catch(err){let code=err.code;if(code!=="ENOENT"&&code!=="ESRCH")refused??=`/proc/${pid}/environ: ${code??"unreadable"}`}return{marked,failed:refused}}let result=await runProbe(["ps","eww","-o","pid=,command=","-p",pids.join(",")]);if(result.code!==0)return{marked,failed:`ps eww exited ${result.code}`};let marker=new RegExp(`(^|\\s)${PTY_MARKER}(\\s|$)`);for(let line of result.stdout.split(`
|
|
4
4
|
`)){let pid=Number.parseInt(line.trim().split(/\s+/)[0]??"",10);if(Number.isFinite(pid)&&marker.test(line))marked.add(pid)}return{marked,failed:null}}async function ownPgid(runProbe){let result=await runProbe(["ps","-o","pgid=","-p",String(process.pid)]),pgid=Number.parseInt(result.stdout.trim(),10);return Number.isFinite(pgid)?pgid:-1}async function collectOrphans(liveSessionPids,deps={}){let runProbe=deps.run??run;if((deps.platform??process.platform)==="win32")return{orphans:[],error:null};let ps=await runProbe(["ps","-A","-o","pid=,ppid=,pgid=,etime=,rss=,command="]);if(ps.code!==0)return{orphans:[],error:`could not read the process table \u2014 ps exited ${ps.code}`};let rows=parsePsRows(ps.stdout),candidates=orphanCandidates(rows,await ownPgid(runProbe),liveSessionPids),{marked,failed}=await markedPids(candidates.map((row)=>row.pid),deps);if(failed)return{orphans:[],error:`could not read process environments \u2014 ${failed}`};return{orphans:candidates.filter((row)=>marked.has(row.pid)),error:null}}function formatMb(rssKb){return`${(rssKb/1024).toFixed(0)} MB`}function orphanDoctorLines(orphans,error,cliName,killing=!1){if(error)return[`orphans: \u2717 ${error}`];if(orphans.length===0)return["orphans: \u2713 none \u2014 no processes left behind by a dead PTY session"];let totalMb=orphans.reduce((sum,row)=>sum+row.rssKb,0)/1024,lines=[`orphans: \u26A0 ${orphans.length} process(es) outlived the PTY session that spawned them (${totalMb.toFixed(0)} MB RSS)`," each is reparented to init, carries Rove's PTY marker, and its process"," group leader is gone \u2014 no live task owns them"];for(let row of[...orphans].sort((a,b)=>b.rssKb-a.rssKb))lines.push(` pid ${row.pid} (group ${row.pgid}) up ${row.etime}, ${formatMb(row.rssKb)}: ${row.command.slice(0,90)}`);if(!killing)lines.push(` \u2192 \`${cliName} doctor --kill-orphans\` ends those process groups (SIGTERM, then SIGKILL)`," read the list first: something you backgrounded from a Rove terminal and then"," closed the tab on looks exactly like a leak, and doctor cannot tell them apart");return lines}var GROUP_EXIT_GRACE_MS=2000,GROUP_POLL_MS=100;function logOrphanKill(pgid,signal,logPath=defaultDaemonLogPath()){try{appendFileSync(logPath,formatDaemonInfo("doctor-kill-orphans",`${signal} process group ${pgid}`))}catch{}}function groupAlive(pgid){try{return process.kill(-pgid,0),!0}catch(err){return err.code!=="ESRCH"}}async function killOrphanGroups(orphans){let groups=[...new Set(orphans.map((row)=>row.pgid))];for(let pgid of groups)try{process.kill(-pgid,"SIGTERM"),logOrphanKill(pgid,"SIGTERM")}catch{}let deadline=Date.now()+GROUP_EXIT_GRACE_MS,survivors=groups.filter(groupAlive);while(survivors.length>0&&Date.now()<deadline)await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),survivors=survivors.filter(groupAlive);for(let pgid of survivors)try{process.kill(-pgid,"SIGKILL"),logOrphanKill(pgid,"SIGKILL")}catch{}return await new Promise((resolve)=>setTimeout(resolve,GROUP_POLL_MS)),{groups,survivors:survivors.filter(groupAlive)}}function multiplexerLabel(env){if(env.TMUX)return"tmux";if(env.ZELLIJ)return"zellij";if(env.STY)return"screen";return"no"}function terminalEnvLines(env){let show=(v)=>v&&v.length>0?v:"(unset)",program=env.TERM_PROGRAM?`${env.TERM_PROGRAM}${env.TERM_PROGRAM_VERSION?` v${env.TERM_PROGRAM_VERSION}`:""}`:"(unset)";return[`terminal: TERM=${show(env.TERM)} TERM_PROGRAM=${program} COLORTERM=${show(env.COLORTERM)}`,` running inside a multiplexer: ${multiplexerLabel(env)}`]}function parseKittyProbeReply(data){let kitty=data.match(/\x1b\[\?(\d+)u/);if(kitty?.[1]!==void 0)return{kind:"supported",flags:Number.parseInt(kitty[1],10)};if(/\x1b\[\?[\d;]*c/.test(data))return{kind:"unsupported"};return null}function kittyProbeLine(result){switch(result.kind){case"supported":return` kitty keyboard protocol: \u2713 answered (flags=${result.flags})`;case"unsupported":return[" kitty keyboard protocol: \u2717 not supported \u2014 legacy key path"," (ctrl+h/ctrl+j arrive as C0 backspace/linefeed bytes; the"," split chords ctrl+\\ and ctrl+= cannot be encoded at all)"].join(`
|
|
5
5
|
`);case"no-response":return" kitty keyboard protocol: ? no reply (terminal ignored both the kitty query and DA1)";case"skipped":return` kitty keyboard protocol: skipped (${result.reason})`}}async function probeKittyKeyboard(timeoutMs=300){let stdin=process.stdin;if(!stdin.isTTY||!process.stdout.isTTY)return{kind:"skipped",reason:"not an interactive terminal"};let wasRaw=stdin.isRaw===!0,buffer="";return await new Promise((resolve)=>{let done=!1,finish=(result)=>{if(done)return;if(done=!0,clearTimeout(timer),stdin.off("data",onData),stdin.pause(),!wasRaw)stdin.setRawMode(!1);resolve(result)},onData=(chunk)=>{buffer+=chunk.toString("latin1");let decided=parseKittyProbeReply(buffer);if(decided)finish(decided)},timer=setTimeout(()=>finish({kind:"no-response"}),timeoutMs);stdin.setRawMode(!0),stdin.resume(),stdin.on("data",onData),process.stdout.write("\x1B[?u\x1B[c")})}async function terminalDoctorLines(){return[...terminalEnvLines(process.env),kittyProbeLine(await probeKittyKeyboard())]}async function probeGit(){try{let proc=Bun.spawn(["git","--version"],{stdin:"ignore",stdout:"pipe",stderr:"ignore"}),text=(await new Response(proc.stdout).text()).trim();if(await proc.exited===0&&text)return{line:`git: \u2713 ${text}`,found:!0}}catch{}return{line:"git: \u2717 not found on PATH",found:!1}}function binaryLabel(binary){return binary.found?`\u2713 ${binary.path}`:`\u2717 ${binary.error}`}async function probeEngines(){let statuses=await detectEngineStatuses(await probeableEngineIds()),lines=["engines:"];for(let status of statuses){let account=describeAccount(status.account),name=`${status.vendor.padEnd(7)} `;if(lines.push(` ${name}${binaryLabel(status.binary)}${status.binary.found?` \u2014 ${account}`:""}`),status.accountError)lines.push(` \u26A0 ${status.accountError}`)}let{usable,signedOut}=summarizeEngines(statuses);return{lines,anyUsable:usable.length>0,signedOut}}var CLI_NAME=ROVE_PRODUCT_NAME;function isProcessAlive(pid){try{return process.kill(pid,0),!0}catch(err){return err.code==="EPERM"}}async function requestIfReachable(socketPath,name){let client=new RoveDaemonClient(socketPath);try{return await client.request(name,{})}catch{return null}finally{client.close()}}function fmtDuration(ms){let seconds=Math.floor(ms/1000);if(seconds<60)return`${seconds}s`;let minutes=Math.floor(seconds/60);if(minutes<60)return`${minutes}m ${seconds%60}s`;return`${Math.floor(minutes/60)}h ${minutes%60}m`}function describeFile(path){try{let stat=statSync2(path);return`present (${formatBytes(stat.size)}, modified ${stat.mtime.toISOString()})`}catch{return"absent"}}function taskCount(path){try{let parsed=JSON.parse(readFileSync2(path,"utf8"));return Array.isArray(parsed.tasks)?parsed.tasks.length:null}catch{return null}}function tailFile(path,count){try{return readFileSync2(path,"utf8").split(`
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import{BUNDLED_THEME_JSONS,userThemesDir,validateTheme}from"./chunk-pdvyfz3n.js";import{expandTilde}from"./chunk-ag3txfg2.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{SUBCOMMAND_VERBS}from"./chunk-e1x88j3k.js";import"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-pn5ygqn6.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-wqfp8d9w.js";import{existsSync,mkdirSync,readFileSync,readdirSync,unlinkSync,writeFileSync}from"fs";import{basename,join,resolve}from"path";var CLI_NAME=ROVE_PRODUCT_NAME,THEME_VERB_ALIASES={ls:"list",rm:"remove"},BUNDLED_NAMES=Object.keys(BUNDLED_THEME_JSONS);function fail(message){process.stderr.write(`${CLI_NAME} theme: ${message}
|
|
3
|
+
Run ${CLI_NAME} theme --help for valid names and options.
|
|
3
4
|
`),process.exit(1)}function failUsage(message){process.stderr.write(`${CLI_NAME} theme: ${message}
|
|
4
5
|
|
|
5
6
|
`),printUsage(),process.exit(2)}function listThemes(){let lines=[];lines.push("bundled:");for(let name of[...BUNDLED_NAMES].sort())lines.push(` ${name} [built-in]`);let dir=userThemesDir(),userFiles=[];try{userFiles=readdirSync(dir).filter((f)=>f.endsWith(".json")).sort()}catch{}if(lines.push(""),lines.push(`user (${dir}):`),userFiles.length===0)lines.push(" (none)");else for(let f of userFiles){let name=f.slice(0,-5),path=join(dir,f),overridesBundled=BUNDLED_NAMES.includes(name)?" (overrides built-in)":"";lines.push(` ${name}${overridesBundled} ${path}`)}process.stdout.write(`${lines.join(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath}from"./chunk-
|
|
2
|
+
import{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath}from"./chunk-60fy3ckp.js";import{hasRoveActivityHooks,isObject}from"./chunk-znjcesdr.js";import"./chunk-7kysxgbq.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import{installedSkillDirs}from"./chunk-dbs8p34d.js";import"./chunk-h9cg0j3a.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-7q43tysm.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-wqfp8d9w.js";import{readFileSync}from"fs";import{homedir}from"os";var PLUGIN_NAME="rove";function readSettings(path){try{let parsed=JSON.parse(readFileSync(path,"utf8"));return isObject(parsed)?parsed:null}catch{return null}}function isRovePluginEnabled(settingsFilePath=claudeSettingsPath()){let settings=readSettings(settingsFilePath);if(!settings||!isObject(settings.enabledPlugins))return!1;return Object.entries(settings.enabledPlugins).some(([key,on])=>on===!0&&key.split("@")[0]===PLUGIN_NAME)}function detectLegacyInstalls(opts={}){let settingsFilePath=opts.settingsFilePath??claudeSettingsPath(),home=opts.home??homedir(),settings=readSettings(settingsFilePath),legacyHooks=settings!==null&&(hasRoveActivityHooks(settings,CLAUDE_HOOK_EVENT_MAP)||settingsHasWorktreeWatch(settings)),legacySkillDirs=installedSkillDirs(home);return{legacyHooks,legacySkillDirs}}function settingsHasWorktreeWatch(settings){let hooks=isObject(settings.hooks)?settings.hooks:{};return Object.values(hooks).some((groups)=>Array.isArray(groups)&&groups.some((g)=>isObject(g)&&Array.isArray(g.hooks)&&g.hooks.some((h)=>isObject(h)&&typeof h.command==="string"&&h.command.includes("worktree-created")&&!h.command.includes("CLAUDE_PLUGIN_ROOT"))))}function migrationHint(findings,cliName){if(!findings.legacyHooks&&findings.legacySkillDirs.length===0)return null;let lines=[`${cliName}: the Rove Claude Code plugin is enabled, but legacy installs remain:`];if(findings.legacyHooks)lines.push(" \u2022 ~/.claude/settings.json still has the settings-managed Rove hooks (every event fires TWICE).",` Run \`${cliName} hook cleanup\` to remove them (only Rove's own entries are touched).`);for(let dir of findings.legacySkillDirs)lines.push(` \u2022 legacy skill copy at ${dir} (the plugin bundles the skill \u2014 two copies double-register).`," Remove that directory to keep the plugin's copy only.");return lines.push(" Reading this inside a session? Just ask your agent to run the cleanup for you."),`${lines.join(`
|
|
3
3
|
`)}
|
|
4
4
|
`}export{migrationHint,isRovePluginEnabled,detectLegacyInstalls};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{logDaemonInfo}from"./chunk-rxqdw6s5.js";import{vendorFromArgv}from"./chunk-
|
|
2
|
+
import{logDaemonInfo}from"./chunk-rxqdw6s5.js";import{vendorFromArgv}from"./chunk-wam8sr6a.js";import{engineEntry}from"./chunk-ctmbj2y3.js";import{isContribEngine}from"./chunk-k4374n9t.js";import{resolveRoveSpawn,testDaemonResponds}from"./chunk-96cjpssp.js";import{stopDaemonProcess}from"./chunk-9w5g7frx.js";import{spawnDetachedDaemon,windowsPowershellPath}from"./chunk-gvrtrvnz.js";import{roveCliInvocation}from"./chunk-znjcesdr.js";import{BUILTIN_VENDORS,coerceVendorId,isBuiltinVendor}from"./chunk-h2m7em1e.js";import{getCustomEngineIds,getPersistedString}from"./chunk-h9cg0j3a.js";import{isProcessAlive,readPidFile}from"./chunk-a7kq09ke.js";import{RoveDaemonClient}from"./chunk-adkva3ep.js";import{defaultPtyHostLogPath,defaultPtyHostPidPath,defaultPtyHostSocketPath}from"./chunk-npwzmmv9.js";import{spawn}from"child_process";import{existsSync}from"fs";import{rename,rm}from"fs/promises";import{basename,delimiter,dirname,join,resolve}from"path";import{fileURLToPath}from"url";var PTY_HOST_START_ARGS=["pty-host"],PTY_HOST_NODE_BUNDLE="pty-host-node.mjs",PTY_HOST_NODE_DEV_CACHE="../../.cache/pty-host-node.mjs",PTY_HOST_NODE_ENTRY="../daemon/pty-host-node-entry.ts";function resolveNodeBinary(env=process.env,exists=existsSync,platform=process.platform){let dirs=(env.PATH??env.Path??"").split(delimiter).filter((dir)=>dir.length>0),suffixes=platform==="win32"?(env.PATHEXT??".EXE;.CMD;.BAT").split(";").filter((ext)=>ext.length>0):[""];for(let dir of dirs)for(let suffix of suffixes){let candidate=join(dir,`node${suffix}`);if(exists(candidate))return candidate}return null}async function bundleWithBun(entry,outFile,io){let{build,rename:move,discard}=io??{build:(config)=>Bun.build(config),rename,discard:(path)=>rm(path,{force:!0})},staging=`${outFile}.${process.pid}.tmp`,built=await build({entrypoints:[entry],outdir:dirname(staging),target:"node",format:"esm",naming:basename(staging),external:["node-pty"]});if(!built.success)return await discard(staging).catch(()=>{}),built;return await move(staging,outFile),built}async function resolveNodePtyHostSpawn(deps={}){let platform=deps.platform??process.platform;if(platform!=="win32")return null;let here=deps.moduleDir??dirname(fileURLToPath(import.meta.url)),exists=deps.exists??existsSync,bundle=deps.bundle??bundleWithBun,node=resolveNodeBinary(deps.env??process.env,exists,platform);if(!node)throw Error("Rove: the Windows PTY host runs under node, but no node was found on PATH. "+"Install Node.js (https://nodejs.org) and restart Rove \u2014 engine and terminal sessions cannot start without it.");let packaged=resolve(here,PTY_HOST_NODE_BUNDLE);if(exists(packaged))return[node,packaged];let entry=resolve(here,PTY_HOST_NODE_ENTRY);if(!exists(entry))throw Error(`Rove: no Windows PTY host found (looked for ${packaged} and ${entry})`);let cache=resolve(here,PTY_HOST_NODE_DEV_CACHE),built=await bundle(entry,cache);if(!built.success)throw Error(`Rove: could not build the Windows PTY host \u2014 ${built.logs.map(String).join("; ")}`);return[node,cache]}var BUSY_PTY_HOST_GRACE_MS=15000,CHILD_PROBE_TIMEOUT_MS=5000;function childProbeCommand(deps={}){let env=deps.env??process.env;if((deps.platform??process.platform)!=="win32")return["ps","-A","-o","ppid="];return[windowsPowershellPath(env,deps.exists??existsSync),"-NoProfile","-NonInteractive","-Command","[Console]::OutputEncoding=[System.Text.Encoding]::UTF8; Get-CimInstance -ClassName Win32_Process -Property ParentProcessId | Select-Object -ExpandProperty ParentProcessId"]}function runChildProbe(command,timeoutMs){return new Promise((done,fail)=>{let proc=spawn(command[0]??"",command.slice(1),{stdio:["ignore","pipe","ignore"]}),out="",finish=(err)=>{clearTimeout(timer);try{proc.kill()}catch{}if(err)fail(err);else done(out)},timer=setTimeout(()=>finish(Error(`did not answer within ${timeoutMs}ms`)),timeoutMs);proc.stdout?.on("data",(chunk)=>{out+=String(chunk)}),proc.on("error",(err)=>finish(err)),proc.on("close",(code,signal)=>finish(code===0&&signal===null?null:Error(`exited with ${signal??`code ${code}`}`)))})}async function liveChildCount(pid,deps={}){let timeoutMs=deps.timeoutMs??CHILD_PROBE_TIMEOUT_MS,command=childProbeCommand(deps),run=deps.run??runChildProbe,text;try{text=await run(command,timeoutMs)}catch{return null}let rows=text.split(`
|
|
3
3
|
`).map((row)=>row.trim()).filter((row)=>row.length>0);if(rows.length===0||rows.some((row)=>!/^\d+$/.test(row)))return null;return rows.filter((row)=>Number(row)===pid).length}async function ensurePtyHostReachable(){let socketPath=defaultPtyHostSocketPath();if(await testDaemonResponds(socketPath))return socketPath;let hostPid=await readPidFile(defaultPtyHostPidPath());if(hostPid!==null&&hostPid!==process.pid&&isProcessAlive(hostPid)){let deadline2=Date.now()+BUSY_PTY_HOST_GRACE_MS;while(Date.now()<deadline2){if(await new Promise((resolveTimer)=>setTimeout(resolveTimer,250)),await testDaemonResponds(socketPath))return socketPath;if(!isProcessAlive(hostPid))break}if(isProcessAlive(hostPid)){let sessions=await liveChildCount(hostPid);if(sessions===null)throw Error(`rove: the pty host (pid ${hostPid}) is not answering and Rove could not read this machine's process table, so it cannot tell whether the host still holds live sessions \u2014 refusing to restart it, which would kill every engine running in them. Inspect it with \`rove api pty-list\`, or kill ${hostPid} yourself once you have accepted losing those sessions.`);if(sessions>0)throw Error(`rove: the pty host (pid ${hostPid}) is not answering but still holds ${sessions} live session(s) \u2014 refusing to restart it, which would kill every engine running in them. Inspect it with \`rove api pty-list\`, or kill ${hostPid} yourself once you have accepted losing those sessions.`)}}await stopDaemonProcess(socketPath,defaultPtyHostPidPath()).catch(()=>{});let[command,...args]=await resolveNodePtyHostSpawn()??resolveRoveSpawn(PTY_HOST_START_ARGS);spawnDetachedDaemon(command??"",args,process.env,defaultPtyHostLogPath());let deadline=Date.now()+5000;while(Date.now()<deadline){if(await testDaemonResponds(socketPath))return socketPath;await new Promise((resolveTimer)=>setTimeout(resolveTimer,100))}throw Error(`rove: pty host did not start (or stayed wedged) at ${socketPath}; check ${defaultPtyHostLogPath()} or run \`rove doctor\``)}async function sweepPtyHostSessions(liveTaskIds,homeDir){let client=new RoveDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let{sessions}=await client.request("pty.list"),currentTasks;for(let session of sessions){if(!currentTasks){let ids=liveTaskIds();if(ids===null)return;currentTasks=new Set(ids)}if(currentTasks.has(session.key.split("::")[0]??session.key))continue;if(!session.generation){logDaemonInfo("pty-sweep",`skipped ${session.key}: host has no session generation; restart it when sessions can be interrupted`);continue}await client.request("pty.kill",{key:session.key,expectedGeneration:session.generation}),currentTasks=void 0}}catch{}finally{client.close()}}async function ptyHostHasLiveSessions(homeDir){let client=new RoveDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let result=await client.request("pty.list");if(!Array.isArray(result.sessions)||result.sessions.some((s)=>typeof s.alive!=="boolean"))return null;return result.sessions.some((s)=>s.alive)}catch(err){if(err instanceof Error&&"code"in err&&(err.code==="ENOENT"||err.code==="ECONNREFUSED")){let pid=await readPidFile(defaultPtyHostPidPath(homeDir));return pid!==null&&isProcessAlive(pid)?null:!1}return null}finally{client.close()}}function engineCommandKey(vendor){return`engineCommand.${vendor}`}function engineNameKey(vendor){return`engineName.${vendor}`}function engineDisplayName(vendor){return getPersistedString(engineNameKey(vendor))?.trim()||engineEntry(vendor).displayName}function humanizeSlug(id){return id.split(/[-_]+/).filter((word)=>word.length>0).map((word)=>word.charAt(0).toUpperCase()+word.slice(1)).join(" ")}function defaultEngineCommand(vendor){return engineEntry(coerceVendorId(vendor)).defaultCommand}function parseEngineCommand(command){let out=[],token="",hasToken=!1,quote=null;for(let ch of command){if(quote){if(ch===quote)quote=null;else token+=ch;continue}if(ch==='"'||ch==="'"){quote=ch,hasToken=!0;continue}if(/\s/.test(ch)){if(hasToken)out.push(token),token="",hasToken=!1;continue}token+=ch,hasToken=!0}if(hasToken)out.push(token);return out}function interactiveEngineCommand(vendor,effort,model){let v=coerceVendorId(vendor),override=getPersistedString(engineCommandKey(v))?.trim(),base=(()=>{if(override){let argv=parseEngineCommand(override);if(argv.length>0)return argv}return defaultEngineCommand(v)})();return withEngineTerminalTitle(withEngineModel(withEngineEffort(base,v,effort),v,model),v)}function withEngineTerminalTitle(argv,vendor){let args=engineEntry(coerceVendorId(vendor)).terminalTitle?.launchArgs;return args&&args.length>0?[...argv,...args]:argv}function withEngineEffort(argv,vendor,effort){let trimmed=effort?.trim();if(!trimmed)return argv;let entry=engineEntry(coerceVendorId(vendor));if(!entry.effortLevels?.includes(trimmed))return argv;return entry.effortArgv?.(argv,trimmed)??argv}function withEngineModel(argv,vendor,model){let trimmed=model?.trim();if(!trimmed)return argv;return engineEntry(coerceVendorId(vendor)).modelArgv?.(argv,trimmed)??argv}function roveApiInvocation(){let quote=(a)=>/^[A-Za-z0-9_/.:=-]+$/.test(a)?a:`'${a.replace(/'/g,"'\\''")}'`;try{return[...roveCliInvocation(),"api"].map(quote).join(" ")}catch{return"rove api"}}import{randomUUID}from"crypto";function hasFlag(argv,flag){return argv.some((a)=>a===flag||a.startsWith(`${flag}=`))}function controlsOwnSession(identity,argv){return(identity?.sessionControlFlags??[]).some((flag)=>hasFlag(argv,flag))}function pinSessionArgv(identity,argv,sessionId){if(!identity?.pinFlag)return argv;if(controlsOwnSession(identity,argv))return argv;return[...argv,identity.pinFlag,sessionId]}function acceptsPinnedSession(identity,argv){return!!identity?.pinFlag&&!controlsOwnSession(identity,argv)}function resumeSessionArgv(identity,base,sessionId){if(!sessionId||!identity?.resumeArgv)return null;if(controlsOwnSession(identity,base))return null;return identity.resumeArgv(base,sessionId)}function pickUnclaimedSessionId(ids,claimed){for(let i=ids.length-1;i>=0;i--){let id=ids[i];if(id&&!claimed.has(id))return id}return null}function forkSessionArgvFor(identity,base,sourceId,newId){if(!sourceId||!identity?.forkArgv)return null;if(controlsOwnSession(identity,base))return null;return identity.forkArgv(base,sourceId,newId)}function acceptsSessionFork(identity){return!!identity?.forkArgv}var GENERIC_PROTOCOL="generic",ENGINE_PROTOCOLS=BUILTIN_VENDORS;function engineProtocolKey(id){return`engineProtocol.${id}`}function getEngineProtocol(id){if(isBuiltinVendor(id)||isContribEngine(id))return id;let raw=getPersistedString(engineProtocolKey(id))?.trim();return raw&&ENGINE_PROTOCOLS.includes(raw)?raw:void 0}function isPresetId(id){return isBuiltinVendor(id)||isContribEngine(id)||getCustomEngineIds().includes(id)}function listPresetIds(){return[...BUILTIN_VENDORS,...getCustomEngineIds()]}function describePreset(id){let command=getPersistedString(engineCommandKey(id))?.trim()||defaultEngineCommand(id).join(" ");return{id,name:engineDisplayName(id),command,protocol:getEngineProtocol(id)??GENERIC_PROTOCOL,builtin:isBuiltinVendor(id)}}function listEnginePresets(){return listPresetIds().map(describePreset)}function resolveCommandProtocol(command){let trimmed=command?.trim();if(!trimmed)return GENERIC_PROTOCOL;if(isPresetId(trimmed))return getEngineProtocol(trimmed)??GENERIC_PROTOCOL;let fromArgv=vendorFromArgv(trimmed);if(fromArgv)return fromArgv;let argv0=parseEngineCommand(trimmed)[0];if(argv0)for(let id of getCustomEngineIds()){let preset=getPersistedString(engineCommandKey(id))?.trim();if(preset&&parseEngineCommand(preset)[0]===argv0)return getEngineProtocol(id)??GENERIC_PROTOCOL}return GENERIC_PROTOCOL}function engineLaunchArgv(spec){let command=spec.command?.trim();if(!command)return interactiveEngineCommand(spec.vendor,spec.effort,spec.model);let vendor=(isPresetId(command)?getEngineProtocol(command):void 0)??resolveCommandProtocol(command),base=isPresetId(command)?presetBaseArgv(command):(()=>{let argv=parseEngineCommand(command);return argv.length>0?argv:null})();if(!base)return interactiveEngineCommand(spec.vendor,spec.effort,spec.model);return withEngineTerminalTitle(withEngineModel(withEngineEffort(base,vendor,spec.effort),vendor,spec.model),vendor)}function presetBaseArgv(id){let override=getPersistedString(engineCommandKey(id))?.trim();if(override){let argv=parseEngineCommand(override);if(argv.length>0)return argv}return defaultEngineCommand(id)}function sessionProtocol(vendor){let id=vendor?.trim();if(!id)return"claude";return getEngineProtocol(id)??id}function protocolEntry(vendor){return engineEntry(sessionProtocol(vendor))}function withPinnedSessionId(argv,vendor,newId=randomUUID){let identity=engineEntry(sessionProtocol(vendor)).sessionIdentity;if(!acceptsPinnedSession(identity,argv))return{argv,sessionId:null};let sessionId=newId();return{argv:pinSessionArgv(identity,argv,sessionId),sessionId}}function engineResumeArgv(base,vendor,sessionId){return resumeSessionArgv(engineEntry(sessionProtocol(vendor)).sessionIdentity,base,sessionId)}function engineCanFork(vendor){return acceptsSessionFork(engineEntry(sessionProtocol(vendor)).sessionIdentity)}function engineForkArgv(base,vendor,sourceId,newId){return forkSessionArgvFor(engineEntry(sessionProtocol(vendor)).sessionIdentity,base,sourceId,newId)}
|
|
4
4
|
export{engineCommandKey,engineNameKey,engineDisplayName,humanizeSlug,defaultEngineCommand,interactiveEngineCommand,roveApiInvocation,pickUnclaimedSessionId,GENERIC_PROTOCOL,ENGINE_PROTOCOLS,engineProtocolKey,getEngineProtocol,listPresetIds,describePreset,listEnginePresets,resolveCommandProtocol,engineLaunchArgv,sessionProtocol,protocolEntry,withPinnedSessionId,engineResumeArgv,engineCanFork,engineForkArgv,resolveNodeBinary,ensurePtyHostReachable,sweepPtyHostSessions,ptyHostHasLiveSessions};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{countCronBetween,isValidCron,latestCronAtOrBefore,nextCronAfter,tightenInstalledPluginPermissions}from"./chunk-
|
|
2
|
+
import{countCronBetween,isValidCron,latestCronAtOrBefore,nextCronAfter,tightenInstalledPluginPermissions}from"./chunk-1s93zcnx.js";import{buildPluginEnv}from"./chunk-axsm0gn5.js";import{ClientWriter,LineReceiver,objectPayload,optionalActivityDetail,optionalBoolean,optionalNumber,optionalString,optionalVendor,requireNumber,requireString,statusActivity}from"./chunk-k67vbszb.js";import{IssuesStore,defaultIssuesStorePath,resolveRepoRoot}from"./chunk-4hestsjp.js";import{STICKY_STATES,activityStillWorking,reduceActivity,resolveEngineStateTtlMs}from"./chunk-2bgmby1d.js";import{currentPluginPlatform,loadPluginRegistry,pluginConfigDir,pluginLogPath,pluginManifestPath,pluginRegistryPath,pluginStateDir,readPluginManifest,supportsPlatform}from"./chunk-rqyaf0dw.js";import{managedWorktreeRootsFor,readWorktreeBaseOverride}from"./chunk-41x1hrqe.js";import{serialized,writeJsonAtomic,writeTextAtomic}from"./chunk-5mhvjytn.js";import{RowTokenStore,isRowTokenTone}from"./chunk-atn06ncf.js";import{ptyHostHasLiveSessions,sweepPtyHostSessions}from"./chunk-4r3s1z14.js";import{logDaemonError,logDaemonInfo}from"./chunk-rxqdw6s5.js";import{resolveLoginShell}from"./chunk-vjvkkrzc.js";import{decodeCapturedChunks,maybeStartScheduledRun}from"./chunk-2tfnscxk.js";import{ENGINE_EXIT_BANNER,engineExitCodeFromTail,plainTail,readPtyExitRecords,readPtyExitStore,recordEngineExit}from"./chunk-w2sp489k.js";import{parsePorcelainRows}from"./chunk-dmzg9zdc.js";import{worktreeFingerprint}from"./chunk-kg9kmwt9.js";import{probeDaemonSocket}from"./chunk-96cjpssp.js";import{createSocketOwnershipGuard,isProcessAlive,listenOnUnixSocket}from"./chunk-a7kq09ke.js";import{defaultKeybindingsPath,defaultUiPrefsStatePath}from"./chunk-prqeddy7.js";import{OWNER_ONLY_DIR_MODE,OWNER_ONLY_FILE_MODE,ensureOwnerOnlyStateDir}from"./chunk-yt15y085.js";import{CHANNEL_NAMES,DAEMON_PROTOCOL_VERSION,MIN_COMPATIBLE_PROTOCOL_VERSION,ROUTINE_RESPONSE_MAX_CHARS,RoveDaemonClient,attentionInboxItemKey,automationRunNeedsAttention,displayTaskTitle,frameToLine,isAttentionInboxState,isProtocolCompatible,isRoutineInboxState,normalizeChannelFilter,parseDaemonStopReason,serializeTask}from"./chunk-adkva3ep.js";import{rotateLogIfNeeded}from"./chunk-hq9tbzqa.js";import{pathIdentity,pathSyntax,pathWithin,samePath}from"./chunk-pn5ygqn6.js";import{defaultDaemonPidPath,defaultDaemonSocketPath,defaultPtyExitsPath,defaultPtyHostSocketPath,resolveDaemonHomeDir}from"./chunk-npwzmmv9.js";import{ROVE_STATE_DIR_BASENAME,readRoveEnv,readRoveHomeDirEnv}from"./chunk-nc46gddg.js";import{__require}from"./chunk-wqfp8d9w.js";import{mkdir,unlink as unlink2}from"fs/promises";import{createServer}from"net";import{dirname as dirname2}from"path";import{statSync}from"fs";var WATCHED_FIELDS=["title","branch","worktreePath","status","pinned","vendor","command","modelEffort","model","tier","linkedWorkItem","scratch"];function same(a,b){if(a===b)return!0;if(a==null||b==null)return a==null&&b==null;if(typeof a==="object"||typeof b==="object")return JSON.stringify(a)===JSON.stringify(b);return!1}function samePr(a,b){let strip=(v)=>{if(v==null||typeof v!=="object"||Array.isArray(v))return v;let{lastCheckedAt:_a,lastError:_b,...rest}=v;return rest};return same(strip(a),strip(b))}function diffTask(prev,next){let fields=[],from={},to={};for(let field of WATCHED_FIELDS){let a=prev[field],b=next[field];if(same(a,b))continue;if(fields.push(field),a!==void 0)from[field]=a;if(b!==void 0)to[field]=b}let prChanged=!samePr(prev.prStatus,next.prStatus);if(fields.length===0&&!prChanged)return null;return{fields,from,to,prChanged,worktreeCreated:next.kind==="task"&&!prev.worktreePath&&!!next.worktreePath}}function bornWithWorktree(task){return task.kind==="task"&&!!task.worktreePath}function lifecycleEventFor(kind,detail){switch(kind){case"session-start":return"session.start";case"session-end":return"session.end";case"turn-start":return"turn.prompt";case"turn-complete":return"turn.complete";case"turn-failed":return"turn.failed";case"turn-interrupted":return"turn.interrupted";case"awaiting-input":return detail?.waiting==="input"?"attention.question":"attention.permission";case"tool-pre":return"tool.pre";case"tool-post":return"tool.post";case"tool-failed":return"tool.failed";case"pre-compact":return"context.pre-compact";case"post-compact":return"context.post-compact";case"subagent-start":return"subagent.start";case"subagent-stop":return"subagent.stop";default:return}}var AGENT_EVENT_BY_STATE={turn_complete:"agent.turn-complete",permission_needed:"agent.permission-needed",rate_limited:"agent.rate-limited",error:"agent.error",running:"agent.running",idle:"agent.idle"};function taskContext(task){if(!task)return;let{id,title,repo,branch,worktreePath,vendor,status}=task;return{id,title,repo,branch,worktreePath,vendor,status}}class PluginEventReducer{tasks;agentState=new Map;now;constructor(now=Date.now){this.now=now}contextFor(taskId){return taskContext(this.tasks?.get(taskId))}reduce(event){switch(event.channel){case"task.snapshot":return this.reduceTasks(event.payload.tasks);case"engine-state":return this.reduceEngine(event.payload);default:return[]}}reduceTasks(tasks){let next=new Map(tasks.map((t)=>[t.id,t])),prev=this.tasks;if(this.tasks=next,!prev)return[];let at=this.now(),out=[];for(let[id,task]of next){let before=prev.get(id);if(!before){if(out.push({event:"task.created",taskId:id,task:taskContext(task),at}),bornWithWorktree(task))out.push({event:"worktree.created",taskId:id,task:taskContext(task),at});continue}let diff=diffTask(before,task);if(!diff)continue;let ctx=taskContext(task);if(diff.fields.length>0)out.push({event:"task.changed",taskId:id,task:ctx,detail:{fields:diff.fields,from:diff.from,to:diff.to},at});if(diff.prChanged)out.push({event:"task.pr-changed",taskId:id,task:ctx,detail:{...before.prStatus!==void 0?{from:before.prStatus}:{},...task.prStatus!==void 0?{to:task.prStatus}:{}},at});if(diff.worktreeCreated)out.push({event:"worktree.created",taskId:id,task:ctx,at})}for(let[id,task]of prev)if(!next.has(id))out.push({event:"task.deleted",taskId:id,task:taskContext(task),at});return out}reduceEngine(payload){let key=`${payload.taskId}\x00${payload.tabId??""}`,prev=this.agentState.get(key);if(this.agentState.set(key,payload.state),prev===payload.state)return[];let event=AGENT_EVENT_BY_STATE[payload.state];if(!event)return[];return[{event,taskId:payload.taskId,task:taskContext(this.tasks?.get(payload.taskId)),...payload.tabId?{tabId:payload.tabId}:{},at:this.now()}]}}import{spawn}from"child_process";import{appendFileSync,mkdirSync}from"fs";var OUTPUT_CAP=8192,PLUGIN_LOG_CAP_BYTES=4194304,SHUTDOWN_GRACE_MS=3000,HOOK_TIMEOUT_MS=30000,HOOK_SLOW_MS=2000;function hookTimeoutMs(spec,kind){return spec.timeoutMs??(kind==="shutdown"?SHUTDOWN_GRACE_MS:HOOK_TIMEOUT_MS)}function appendRecord(pluginId,homeDir,record){try{let logPath=pluginLogPath(pluginId,homeDir);rotateLogIfNeeded(logPath,PLUGIN_LOG_CAP_BYTES),appendFileSync(logPath,`${JSON.stringify(record)}
|
|
3
3
|
`,{mode:OWNER_ONLY_FILE_MODE})}catch{}}async function runPluginHook(opts){let{pluginId,spec,kind,label,homeDir}=opts,timeoutMs=hookTimeoutMs(spec,kind),startedAt=Date.now();try{mkdirSync(pluginConfigDir(pluginId,homeDir),{recursive:!0,mode:OWNER_ONLY_DIR_MODE}),mkdirSync(pluginStateDir(pluginId,homeDir),{recursive:!0,mode:OWNER_ONLY_DIR_MODE})}catch(err){appendRecord(pluginId,homeDir,{at:startedAt,kind,label,command:spec.command,exitCode:null,durationMs:Date.now()-startedAt,spawnError:String(err)}),opts.log?.(`plugin ${pluginId} ${label}: ${String(err)}`);return}let exitCode=null,stdout="",stderr="",spawnError,timedOut=!1;if(await new Promise((resolve)=>{let[cmd,...args]=spec.command,child=spawn(cmd,args,{cwd:opts.pluginRoot,env:buildPluginEnv({homeDir,socketPath:opts.socketPath,binPath:opts.binPath,pluginId,pluginRoot:opts.pluginRoot,extra:opts.extraEnv}),stdio:["ignore","pipe","pipe"],detached:!0}),kill=()=>{try{if(child.pid)process.kill(-child.pid,"SIGKILL");else child.kill("SIGKILL")}catch{child.kill("SIGKILL")}},deadline=setTimeout(()=>{timedOut=!0,kill()},timeoutMs);deadline.unref?.();let slow=setTimeout(()=>{appendRecord(pluginId,homeDir,{at:startedAt,kind,label,command:spec.command,phase:"running",runningMs:Date.now()-startedAt,timeoutMs})},Math.min(HOOK_SLOW_MS,Math.floor(timeoutMs/2)));slow.unref?.(),opts.inFlight?.add(kill);let finish=()=>{clearTimeout(deadline),clearTimeout(slow),opts.inFlight?.delete(kill),resolve()};child.stdout.on("data",(chunk)=>{if(stdout.length<OUTPUT_CAP)stdout+=chunk.toString().slice(0,OUTPUT_CAP-stdout.length)}),child.stderr.on("data",(chunk)=>{if(stderr.length<OUTPUT_CAP)stderr+=chunk.toString().slice(0,OUTPUT_CAP-stderr.length)}),child.on("error",(err)=>{spawnError=String(err),finish()}),child.on("close",(code)=>{exitCode=code,finish()})}),appendRecord(pluginId,homeDir,{at:startedAt,kind,label,command:spec.command,exitCode,durationMs:Date.now()-startedAt,...timedOut?{timedOut:!0,timeoutMs}:{},...stdout?{stdout}:{},...stderr?{stderr}:{},...spawnError?{spawnError}:{}}),timedOut)opts.log?.(`plugin ${pluginId} ${label}: killed after ${timeoutMs}ms (hook did not exit)`);else if(spawnError||exitCode!==null&&exitCode!==0)opts.log?.(`plugin ${pluginId} ${label}: ${spawnError??`exit ${exitCode}`}`)}var RELOAD_DEBOUNCE_MS=150,REGISTRY_POLL_MS=200;function fileStamp(path){if(!path)return"absent";try{let s=statSync(path,{bigint:!0});return`${s.mtimeNs}:${s.size}:${s.ino}`}catch{return"absent"}}function startPluginHost(bus,opts){let host=new PluginHost(opts);bus.onPublish((event)=>host.handleChannel(event));for(let event of bus.snapshot())host.handleChannel(event);return host.start(),host}function maybeStartPluginHost(bus,options,socketPath,log){if(!options.plugins)return null;return startPluginHost(bus,{homeDir:options.homeDir,socketPath,binPath:options.plugins.binPath,log})}class PluginHost{opts;reducer=new PluginEventReducer;plugins=[];enabledIds=new Set;manifestStamps=new Map;pollTimer;registryStamp="";reloadTimer;inFlight=new Set;stopped=!1;constructor(opts){this.opts=opts}start(){this.watchRegistry(),this.plugins=this.loadPlugins();for(let plugin of this.plugins)for(let[i,hook]of plugin.manifest.startup.entries()){if(!supportsPlatform(hook,plugin.manifest,currentPluginPlatform()))continue;this.run(plugin,hook,"startup",{ROVE_PLUGIN_EVENT:"startup"},`startup[${i}]`)}}async stop(){if(this.stopped)return;if(this.stopped=!0,this.reloadTimer)clearTimeout(this.reloadTimer);if(this.pollTimer)clearInterval(this.pollTimer);for(let kill of[...this.inFlight])kill();let runs=[];for(let plugin of this.plugins)for(let[i,hook]of plugin.manifest.shutdown.entries()){if(!supportsPlatform(hook,plugin.manifest,currentPluginPlatform()))continue;runs.push(this.run(plugin,hook,"shutdown",{ROVE_PLUGIN_EVENT:"shutdown"},`shutdown[${i}]`))}await Promise.allSettled(runs)}handleChannel(event){if(this.stopped)return;try{for(let derived of this.reducer.reduce(event))this.dispatch(derived)}catch(err){this.opts.log?.(`plugin event reduce failed on ${event.channel} \u2014 ${String(err)}`)}}handleUiReport(report){if(this.stopped)return;try{this.dispatch({event:report.kind,...report.taskId?{taskId:report.taskId,task:this.reducer.contextFor(report.taskId)}:{},...report.detail?{detail:report.detail}:{},at:Date.now()})}catch(err){this.opts.log?.(`plugin ui-report dispatch failed for ${report.kind} \u2014 ${String(err)}`)}}handleEngineReport(report){if(this.stopped)return;let event=lifecycleEventFor(report.kind,report.detail);if(!event)return;try{this.dispatch({event,taskId:report.taskId,task:this.reducer.contextFor(report.taskId),...report.vendor?{vendor:report.vendor}:{},...report.tabId?{tabId:report.tabId}:{},...report.sessionId?{sessionId:report.sessionId}:{},...report.detail?{detail:report.detail}:{},at:Date.now()})}catch(err){this.opts.log?.(`plugin engine-report dispatch failed for ${event} \u2014 ${String(err)}`)}}dispatchTo(plugin,event){let platform=currentPluginPlatform();try{for(let hook of plugin.manifest.events){if(hook.on!==event.event)continue;if(!supportsPlatform(hook,plugin.manifest,platform))continue;this.run(plugin,hook,"event",{ROVE_PLUGIN_EVENT:event.event,ROVE_PLUGIN_EVENT_JSON:JSON.stringify(event)},hook.on)}}catch(err){this.opts.log?.(`plugin ${plugin.manifest.id}: ${event.event} dispatch failed \u2014 ${String(err)}`)}}dispatch(event){let platform=currentPluginPlatform();for(let plugin of this.plugins)try{for(let hook of plugin.manifest.events){if(hook.on!==event.event)continue;if(!supportsPlatform(hook,plugin.manifest,platform))continue;this.run(plugin,hook,"event",{ROVE_PLUGIN_EVENT:event.event,ROVE_PLUGIN_EVENT_JSON:JSON.stringify(event),...event.taskId?{ROVE_PLUGIN_TASK_ID:event.taskId}:{},...event.task?.title?{ROVE_PLUGIN_TASK_TITLE:event.task.title}:{}},hook.on)}}catch(err){this.opts.log?.(`plugin ${plugin.manifest.id}: ${event.event} dispatch failed \u2014 ${String(err)}`)}}loadPlugins(){let registry=loadPluginRegistry(this.opts.homeDir),platform=currentPluginPlatform(),out=[],enabled=new Set,stamps=new Map;for(let entry of registry.plugins){if(!entry.enabled)continue;enabled.add(entry.id),stamps.set(entry.root,fileStamp(pluginManifestPath(entry.root)));let manifest;try{manifest=readPluginManifest(entry.root).manifest}catch(err){this.opts.log?.(`plugin ${entry.id}: manifest unreadable, skipping \u2014 ${String(err)}`);continue}if(!supportsPlatform({},manifest,platform))continue;out.push({manifest,root:entry.root})}return this.enabledIds=enabled,this.manifestStamps=stamps,out}sourcesChanged(){let stamp=fileStamp(pluginRegistryPath(this.opts.homeDir));if(stamp!==this.registryStamp)return this.registryStamp=stamp,!0;for(let[root,was]of this.manifestStamps)if(fileStamp(pluginManifestPath(root))!==was)return!0;return!1}watchRegistry(){this.registryStamp=fileStamp(pluginRegistryPath(this.opts.homeDir)),this.pollTimer=setInterval(()=>{if(!this.sourcesChanged())return;if(this.reloadTimer)clearTimeout(this.reloadTimer);this.reloadTimer=setTimeout(()=>{if(this.stopped)return;try{let loadedBefore=new Map(this.plugins.map((p)=>[p.manifest.id,p])),enabledBefore=this.enabledIds;this.plugins=this.loadPlugins(),this.opts.log?.(`plugin registry reloaded (${this.plugins.length} enabled)`);let at=Date.now();for(let plugin of this.plugins)if(!enabledBefore.has(plugin.manifest.id))this.dispatchTo(plugin,{event:"plugin.enabled",detail:{pluginId:plugin.manifest.id},at});for(let[id,plugin]of loadedBefore)if(!this.enabledIds.has(id))this.dispatchTo(plugin,{event:"plugin.disabled",detail:{pluginId:id},at})}catch(err){this.opts.log?.(`plugin registry reload failed \u2014 ${String(err)}`)}},RELOAD_DEBOUNCE_MS)},REGISTRY_POLL_MS),this.pollTimer.unref?.()}run(plugin,spec,kind,extraEnv,label){return runPluginHook({pluginId:plugin.manifest.id,pluginRoot:plugin.root,spec,kind,label,extraEnv,homeDir:this.opts.homeDir,socketPath:this.opts.socketPath,binPath:this.opts.binPath,log:this.opts.log,inFlight:this.inFlight}).catch((err)=>{this.opts.log?.(`plugin ${plugin.manifest.id} ${label}: ${String(err)}`)})}}function replacementKey(frame){if(frame.type!=="event")return null;switch(frame.name){case"task.snapshot":case"active-task":case"update":case"attention.inbox":case"ui-prefs":case"worktree.changes":case"transcript.activity":case"usage.snapshot":case"usage.context":return frame.name;default:return null}}function writeFrame(client,frame){client.writer.write(frameToLine(frame),replacementKey(frame))}function broadcast(clients,frame){let channel=frame.type==="event"&&frame.name!=="daemon.stopping"?frame.name:null,replaceKey=replacementKey(frame),line=null;for(let client of clients){if(!client.subscribed&&frame.type==="event")continue;if(channel&&client.channels&&!client.channels.has(channel))continue;line??=frameToLine(frame),client.writer.write(line,replaceKey)}}function handleClientLine(client,line,onRequest){if(line.trim().length===0)return;try{let frame=JSON.parse(line);if(frame.type!=="request")throw Error("daemon only accepts request frames from clients");onRequest(frame,client)}catch(err){writeFrame(client,{type:"response",id:"parse-error",error:{message:err instanceof Error?err.message:String(err)}})}}function programStatusActivity(activity,taskExists,inbox){let seen=new Map;return async(event)=>{let[taskId,tabId,extra]=event.key.split("::");if(!taskId||!tabId||extra!==void 0||!/^tab-\d+$/.test(tabId)||!taskExists(taskId))return;let previous=seen.get(event.key);if(previous?.event.generation===event.generation&&previous.event.revision>=event.revision)return;if(previous&&previous.event.generation!==event.generation&&previous.event.at>event.at)return;let ownClaim=previous?.owns?.()===!0,next={event};if(seen.delete(event.key),seen.set(event.key,next),seen.size>4096){let first=seen.keys().next().value;if(first!==void 0)seen.delete(first)}if(event.status===null){if(ownClaim)activity.reportProgramStatus(taskId,tabId,"turn-interrupted",void 0,void 0,event.at),await inbox?.deleteEpisode(taskId,tabId);return}if(!ownClaim&&activity.hasHookSince(taskId,tabId,event.at))return;let report=statusActivity(event.status);if(next.owns=activity.reportProgramStatus(taskId,tabId,report.kind,report.detail,void 0,event.at),event.status.state==="idle")await inbox?.deleteEpisode(taskId,tabId);else await inbox?.record(taskId,report.kind,report.detail,tabId)}}function parseProgramStatusEvent(value){if(!value||typeof value!=="object"||!("key"in value)||typeof value.key!=="string"||!("generation"in value)||typeof value.generation!=="string"||!("revision"in value)||typeof value.revision!=="number"||!Number.isSafeInteger(value.revision)||value.revision<1||!("at"in value)||typeof value.at!=="number"||!Number.isFinite(value.at)||!("status"in value))return null;let raw=value.status,status=null;if(raw!==null){if(!raw||typeof raw!=="object"||!("id"in raw)||raw.id!==""||!("state"in raw)||!("at"in raw)||typeof raw.at!=="number"||!Number.isFinite(raw.at))return null;let state=raw.state;if(state!=="idle"&&state!=="working"&&state!=="done"&&state!=="blocked"&&state!=="error")return null;status={id:"",state,at:raw.at,..."kind"in raw&&(raw.kind==="permission"||raw.kind==="question"||raw.kind==="auth")?{kind:raw.kind}:{},..."msg"in raw&&typeof raw.msg==="string"?{msg:raw.msg.slice(0,2048)}:{}}}return{key:value.key,generation:value.generation,revision:value.revision,at:value.at,status}}function watchProgramStatus(receive,options={}){let stopped=!1,client,retry,connecting,baseDelay=options.retryMs??1000,delay=baseDelay,deliveries=new Set,schedule=()=>{if(stopped||retry)return;retry=setTimeout(()=>{retry=void 0,connect()},delay),retry.unref?.()},connect=()=>{if(stopped||connecting){schedule();return}let connection=new RoveDaemonClient(options.socketPath??defaultPtyHostSocketPath(options.homeDir));client=connection,connection.on("pty.programStatus",(frame)=>{if(stopped)return;let event=parseProgramStatusEvent(frame.payload);if(!event)return;let delivery=receive(event).catch((err)=>logDaemonError("program-status",err));deliveries.add(delivery),delivery.then(()=>deliveries.delete(delivery))}),connection.onLifecycle("close",schedule),connecting=connection.connect().then(async()=>{if(stopped)return;await connection.request("pty.watchStatus"),delay=baseDelay}).catch(()=>{delay=Math.min(delay*2,Math.max(baseDelay,5000)),connection.close(),schedule()}).finally(()=>{connecting=void 0})};return connect(),async()=>{if(stopped=!0,retry)clearTimeout(retry);client?.close(),await connecting,await Promise.allSettled(deliveries)}}import{statSync as statSync2}from"fs";import{basename,dirname,join}from"path";var POLL_MS=200;function startFileWatchTrigger(opts){if(opts.debounceMs<=0)return()=>{};let dir=dirname(opts.filePath),names=[...new Set([basename(opts.filePath),...opts.matchBasenames??[]])],timer=null,trigger=()=>{try{opts.onTrigger()}catch(err){opts.onError(err)}},schedule=()=>{if(timer)clearTimeout(timer);timer=setTimeout(()=>{timer=null,trigger()},opts.debounceMs),timer.unref?.()},stampOf=(name)=>{try{let s=statSync2(join(dir,name),{bigint:!0});return`${s.mtimeNs}:${s.size}:${s.ino}`}catch{return"absent"}},stamps=new Map;for(let name of names)stamps.set(name,stampOf(name));let poll=setInterval(()=>{for(let name of names){let stamp=stampOf(name);if(stamp===stamps.get(name))continue;stamps.set(name,stamp),schedule()}},POLL_MS);return poll.unref?.(),()=>{if(clearInterval(poll),timer)clearTimeout(timer),timer=null}}var DEBOUNCE_MS=250,KEY_RE=/^(.+?)::(.+)$/;function startPtyExitWatch(opts){let path=opts.path??defaultPtyExitsPath(opts.homeDir),seen=new Map,baselined=!1,sweep=()=>{let host=opts.plugins();if(!host)return;let{records,readable}=readPtyExitStore(path);if(!readable)return;for(let[storeKey,record]of Object.entries(records)){if(seen.get(storeKey)===record.at)continue;if(seen.set(storeKey,record.at),!baselined)continue;host.handleUiReport({kind:"session.exited",...exitReport(record)}),publishDeath(record)}baselined=!0;for(let key of seen.keys())if(!(key in records))seen.delete(key)},publishDeath=(record)=>{let registry=opts.activity;if(!registry&&!opts.inbox)return;let death=engineDeathOf(record);if(!death)return;let{taskId,tabId,exit,at}=death;registry?.recordEngineDeath(taskId,tabId,exit,at),opts.inbox?.recordEngineDeath(taskId,tabId,{exit},at).catch((err)=>opts.log?.(`pty-exit inbox: ${String(err)}`))},stop=startFileWatchTrigger({filePath:path,debounceMs:DEBOUNCE_MS,onTrigger:sweep,onError:(err)=>opts.log?.(`pty-exit watch: ${String(err)}`)}),initial=readPtyExitStore(path);if(initial.readable){for(let[storeKey,record]of Object.entries(initial.records))seen.set(storeKey,record.at);baselined=!0}return stop}function engineDeathOf(record){let match=KEY_RE.exec(record.key),taskId=match?.[1],tabId=match?.[2];if(!taskId||!tabId)return null;let at=Date.parse(record.at);if(!Number.isFinite(at))return null;let lastLine=lastErrorLine(record.tail);return{taskId,tabId,exit:{code:record.code,signal:record.signal,...lastLine?{lastLine}:{}},at}}function lastErrorLine(tail){let last;for(let i=tail.length-1;i>=0;i--){let line=(tail[i]??"").trim();if(line.length===0)continue;if(ENGINE_EXIT_BANNER.test(line))return line;last??=line}return last}function exitReport(record){let match=KEY_RE.exec(record.key);return{...match?.[1]?{taskId:match[1]}:{},detail:{key:record.key,...match?.[2]?{tabId:match[2]}:{},pid:record.pid,code:record.code,signal:record.signal,exitedAt:record.at,tail:record.tail}}}function createActivityObserverIo(homeDir,runtime,activity){let peek=async(key)=>{let client=new RoveDaemonClient(defaultPtyHostSocketPath(homeDir));try{await client.connect();let result=await client.request("pty.peek",{key});return Buffer.from(result.data??"","base64").toString("utf8")}catch{return""}finally{client.close()}};return{onEngineExit({taskId,tabId,vendor,pid}){let key=`${taskId}::${tabId}`,pending=peek(key).then((tail)=>recordEngineExit({key,vendor,pid,at:new Date().toISOString(),tail},defaultPtyExitsPath(homeDir))).catch((err)=>logDaemonInfo("engine-exit",`record failed for ${key}: ${String(err)}`));return logDaemonInfo("engine-exit",`${vendor} (pid ${pid??"?"}) gone from live session ${key}`),pending},onEngineAbsentAtStart({taskId,tabId}){let key=`${taskId}::${tabId}`,path=defaultPtyExitsPath(homeDir),existing=readPtyExitRecords(path)[`${key}#engine`];if(existing){let death=engineDeathOf(existing);if(death)activity?.recordEngineDeath(death.taskId,death.tabId,death.exit,death.at);return}return peek(key).then((raw)=>{if(engineExitCodeFromTail(plainTail(raw))===null)return;recordEngineExit({key,pid:null,at:new Date().toISOString(),tail:raw,atApproximate:!0},path),logDaemonInfo("engine-exit",`recorded an unwatched death in ${key} (exit time unknown)`)}).catch((err)=>logDaemonInfo("engine-exit",`boot record failed for ${key}: ${String(err)}`))},async listSessions(){let client=new RoveDaemonClient(defaultPtyHostSocketPath(homeDir));try{return await client.connect(),((await client.request("pty.list")).sessions??[]).map((s)=>({key:s.key??"",programStatusEvent:s.programStatusEvent,alive:s.alive===!0,pid:typeof s.pid==="number"?s.pid:null,title:typeof s.title==="string"?s.title:"",totalBytes:typeof s.totalBytes==="number"?s.totalBytes:0}))}catch{return null}finally{client.close()}},foregroundEngines:(pids)=>runtime.foregroundEngines(pids),titleTurnHint:(vendor,title)=>runtime.titleTurnHint(vendor,title)}}var DEFAULT_OBSERVER_POLL_MS=1e4,DEFAULT_SILENCE_MS=30000,DEFAULT_WALK_EVERY_TICKS=6,DEFAULT_UNSUBSCRIBED_EVERY_TICKS=6,DEFAULT_CORRECT_AFTER_MS=20000;function startActivityObserver(activity,io,hasSubscribers,options={}){let pollMs=options.pollMs??DEFAULT_OBSERVER_POLL_MS,silenceMs=options.silenceMs??DEFAULT_SILENCE_MS,walkEvery=Math.max(1,options.walkEveryTicks??DEFAULT_WALK_EVERY_TICKS),unsubscribedEvery=Math.max(1,options.unsubscribedEveryTicks??DEFAULT_UNSUBSCRIBED_EVERY_TICKS),correctAfterMs=options.correctAfterMs??DEFAULT_CORRECT_AFTER_MS,log=options.log??logDaemonInfo,tracks=new Map,tickCount=0,unsubscribedTicks=0,inFlight,stopped=!1,bootWalkDone=!1,applyRest=(track,why)=>{if(activity.observeTab(track.taskId,track.tabId,"rest",{...track.vendor?{vendor:track.vendor}:{},correctHookRunningAfterMs:correctAfterMs})==="corrected-hook-running")log("activity-observe",`idled hook-claimed running for ${track.taskId}/${track.tabId} (${why})`)},tick=async()=>{let effects=[];try{let subscribed=hasSubscribers();if(!subscribed&&unsubscribedTicks++%unsubscribedEvery!==0)return;let walkTick=!subscribed||tickCount%walkEvery===0;tickCount++;let listed=await io.listSessions();if(stopped)return;if(listed===null){for(let track of tracks.values())activity.observeTab(track.taskId,track.tabId,"rest",{});return}let sessions=listed,seen=new Set,now=Date.now(),live=[],newborn=new Set;for(let s of sessions){let parts=s.key.split("::");if(parts.length!==2||!parts[0]||!parts[1])continue;if(seen.add(s.key),!s.alive){let track2=tracks.get(s.key);applyRest(track2??{taskId:parts[0],tabId:parts[1],vendor:void 0},"session exited"),tracks.delete(s.key);continue}let track=tracks.get(s.key);if(!track)track={taskId:parts[0],tabId:parts[1],firstSeenAt:now,lastTotalBytes:s.totalBytes,lastTitle:s.title,lastActivityAt:null,vendor:void 0,enginePid:null},tracks.set(s.key,track),newborn.add(s.key);else if(s.totalBytes!==track.lastTotalBytes||s.title!==track.lastTitle)track.lastTotalBytes=s.totalBytes,track.lastTitle=s.title,track.lastActivityAt=now;live.push(track)}for(let[key,track]of tracks){if(seen.has(key)&&sessions.some((s)=>s.key===key&&s.alive))continue;applyRest(track,"session gone"),tracks.delete(key)}let toWalk=live.filter((t)=>walkTick||newborn.has(`${t.taskId}::${t.tabId}`)||t.vendor===void 0);if(toWalk.length>0){let pidByKey=new Map;for(let s of sessions)if(s.alive&&s.pid!==null)pidByKey.set(s.key,s.pid);try{let pids=toWalk.map((t)=>pidByKey.get(`${t.taskId}::${t.tabId}`)).filter((pid)=>pid!==void 0),verdicts=await io.foregroundEngines(pids);if(stopped)return;let bootWalk=!bootWalkDone;bootWalkDone=!0;for(let track of toWalk){let pid=pidByKey.get(`${track.taskId}::${track.tabId}`);if(pid===void 0||!verdicts.has(pid))continue;let found=verdicts.get(pid)??null;if(found===null&&typeof track.vendor==="string")effects.push(io.onEngineExit?.({taskId:track.taskId,tabId:track.tabId,vendor:track.vendor,pid:track.enginePid}));else if(found===null&&track.vendor===void 0&&bootWalk)effects.push(io.onEngineAbsentAtStart?.({taskId:track.taskId,tabId:track.tabId}));track.vendor=found?.vendor??null,track.enginePid=found?.pid??null}}catch{}}if(stopped)return;for(let track of live){let key=`${track.taskId}::${track.tabId}`,session=sessions.find((s)=>s.key===key);if(!session||track.vendor===void 0)continue;if(effects.push(io.onEngineEvidence?.(track.taskId,track.tabId,{walkVendor:track.vendor,title:session.title})),session.programStatusEvent&&io.onProgramStatusEvent){if(effects.push(io.onProgramStatusEvent(session.programStatusEvent)),session.programStatusEvent.status!==null)continue}if(track.vendor===null){applyRest(track,"no engine in foreground");continue}let silentForMs=now-(track.lastActivityAt??track.firstSeenAt),hint=io.titleTurnHint(track.vendor,session.title),claimWorking=(why)=>{if(activity.observeTab(track.taskId,track.tabId,"working",{vendor:track.vendor??void 0})==="observed-running")log("activity-observe",`seeded running for ${track.taskId}/${track.tabId} (${why})`)};if(hint==="rest")applyRest(track,"engine title at rest");else if(track.lastActivityAt!==null&&now-track.lastActivityAt<silenceMs)claimWorking("live output");else if(hint==="working"&&silentForMs<silenceMs)claimWorking("working title frame");else if(silentForMs>=silenceMs)applyRest(track,`no output for ${Math.round(silentForMs/1000)}s`)}}catch{}finally{await Promise.allSettled(effects)}},schedule=()=>{if(stopped||inFlight)return;inFlight=tick().finally(()=>{inFlight=void 0})};schedule();let timer=setInterval(schedule,pollMs);return timer.unref?.(),async()=>{stopped=!0,clearInterval(timer),await inFlight}}function isThenable(value){return typeof value?.then==="function"}function startTicker(opts){if(opts.tickMs<=0)return async()=>{};let running=null,stopped=!1,tick=()=>{if(stopped||opts.gate&&!opts.gate())return;if(running)return;let result;try{result=opts.run()}catch(err){logDaemonError(opts.name,err);return}if(!isThenable(result))return;running=Promise.resolve(result).then(()=>{return}).catch((err)=>logDaemonError(opts.name,err)).finally(()=>{running=null})};if(opts.immediate)tick();let timer=setInterval(tick,opts.tickMs);return timer.unref?.(),async()=>{try{if(!stopped)stopped=!0,clearInterval(timer),opts.onStop?.()}finally{await running}}}var DEFAULT_AUTO_TITLE_POLL_MS=4000;async function runAutoTitlePass(orch,derive,placeholderTitle,defaultVendor){let renamed=[],snapshot=orch.listTasks();for(let task of snapshot){if(task.title!==placeholderTitle||!task.worktreePath)continue;try{let derived=await derive(task.worktreePath,task.vendor??defaultVendor);if(!derived)continue;let title=withGroupOrdinal(derived,task.id,task.groupId,snapshot),current=orch.getTask(task.id);if(!current||current.title!==placeholderTitle)continue;await orch.setTitle(task.id,title),renamed.push({id:task.id,title})}catch(err){logDaemonError("auto-title-poller",err)}}return renamed}function withGroupOrdinal(title,taskId,groupId,snapshot){if(!groupId)return title;let siblings=snapshot.filter((t)=>t.groupId===groupId);if(siblings.length<2)return title;let ordinal=siblings.findIndex((t)=>t.id===taskId);if(ordinal<0)return title;return`${title} #${ordinal+1}/${siblings.length}`}function startAutoTitlePoller(orch,runtime,intervalMs=DEFAULT_AUTO_TITLE_POLL_MS,hasSubscribers){return startTicker({name:"auto-title-poller",tickMs:intervalMs,...hasSubscribers?{gate:hasSubscribers}:{},run:()=>runAutoTitlePass(orch,runtime.deriveTitleFromSession,runtime.placeholderTaskTitle,runtime.defaultTaskVendor)})}import{realpath}from"fs/promises";function automationTarget(automation){if(automation.target)return automation.target;return automation.persistentSession?{kind:"standing",taskId:automation.sessionTaskId}:{kind:"fresh"}}function readAutomationTarget(value){if(value===null)return null;if(typeof value!=="object"||!value||!("kind"in value)||value.kind!=="existing-tab"||!("taskId"in value)||typeof value.taskId!=="string"||!value.taskId.trim()||!("tabId"in value)||typeof value.tabId!=="string"||!/^tab-[\w-]+$/.test(value.tabId))throw Error("target must be { kind: 'existing-tab', taskId, tabId } or null");return{kind:"existing-tab",taskId:value.taskId.trim(),tabId:value.tabId}}function assertAutomationTargetOptions(value){if(!value.target){if((value.model||value.modelEffort)&&!value.vendor)throw Error("a routine that pins model or effort must also store the vendor they were validated against");return}if(value.vendor||value.model||value.modelEffort||value.baseRef||value.persistentSession)throw Error("an existing-tab target cannot set vendor, model, effort, baseRef or persistentSession; clear them when binding")}function mergeAutomationTargetOptions(automation,patch){return{target:patch.target===null?void 0:patch.target??automation.target,vendor:patch.vendor===null?void 0:patch.vendor??automation.vendor,model:patch.model===null?void 0:patch.model??automation.model,modelEffort:patch.modelEffort===null?void 0:patch.modelEffort??automation.modelEffort,baseRef:patch.baseRef===null?void 0:patch.baseRef??automation.baseRef,persistentSession:patch.persistentSession??automation.persistentSession,sessionTaskId:patch.target||patch.sessionTaskId===null?void 0:patch.sessionTaskId??automation.sessionTaskId}}async function assertAutomationTargetTask(value,orch){if(!value.target)return;let task=orch.getTask(value.target.taskId);if(!task||task.deletion||!task.worktreePath)throw Error(`target task unavailable: ${value.target.taskId}`);let[repo,taskRepo]=await Promise.all([realpath(value.repo),realpath(task.repo)]);if(repo!==taskRepo)throw Error(`routine repo must match target task repo: ${task.repo}`)}function resolveStandingTask(orch,automation){let id=automation.sessionTaskId;if(!id)return{task:null,hadStaleLink:!1};let task=orch.getTask(id);if(!task||task.deletion||!task.worktreePath)return{task:null,hadStaleLink:!0};return{task}}async function createRunTask(deps,automation){return await deps.orch.createTask({repo:automation.repo,title:automation.name,...automation.vendor?{vendor:automation.vendor}:{},...automation.model?{model:automation.model}:{},...automation.modelEffort?{modelEffort:automation.modelEffort}:{},...automation.baseRef?{baseRef:automation.baseRef}:{},...automation.persistentSession?{routine:{automationId:automation.id}}:{}})}async function spawnWithPrompt(deps,prompt,taskId,status){if(deps.canDeliver?.()===!1)return{status:"skipped_cancelled",taskId};let outcome=await deps.runtime.startTaskSessionWithPrompt(deps.link(),taskId,prompt);if(!outcome.started)return{status:"dispatch_failed",taskId,error:outcome.error??"engine session did not start"};return{status,taskId}}async function dispatchAutomation(deps,automation,prompt=automation.prompt){if(deps.canDeliver?.()===!1)return{status:"skipped_cancelled"};let target=automationTarget(automation);if(target.kind==="existing-tab"){try{await assertAutomationTargetTask(automation,deps.orch)}catch(error){return{status:"skipped_unavailable",taskId:target.taskId,tabId:target.tabId,error:String(error)}}let task2=deps.orch.getTask(target.taskId);if(!task2||task2.deletion||!task2.worktreePath)return{status:"skipped_unavailable",taskId:target.taskId,tabId:target.tabId,error:"target task unavailable"};if(deps.canDeliver?.()===!1)return{status:"skipped_cancelled",taskId:task2.id,tabId:target.tabId};let currentTask=deps.orch.getTask(task2.id);if(!currentTask||currentTask.deletion||!currentTask.worktreePath)return{status:"skipped_unavailable",taskId:task2.id,tabId:target.tabId,error:"target task unavailable"};let result2=await deps.runtime.deliverPromptToLiveEngineTabDetailed({id:task2.id,tabId:target.tabId,vendor:task2.vendor,command:task2.command,worktreePath:task2.worktreePath},prompt);return await liveDeliveryOutcome(deps,automation,task2.id,result2)}if(target.kind==="fresh"){let task2=await createRunTask(deps,automation);return await spawnWithPrompt(deps,prompt,task2.id,"dispatched")}let standing=resolveStandingTask(deps.orch,automation);if(standing.task===null){let task2=await createRunTask(deps,automation);return{...await spawnWithPrompt(deps,prompt,task2.id,"dispatched"),sessionTaskIdToSet:task2.id,...standing.hadStaleLink?{sessionTaskIdToClear:!0}:{}}}let task=standing.task,result=await deps.runtime.deliverPromptToLiveEngineDetailed({id:task.id,vendor:task.vendor,command:task.command,worktreePath:task.worktreePath},prompt);if(result.outcome==="delivered")return await liveDeliveryOutcome(deps,automation,task.id,result);return await spawnWithPrompt(deps,prompt,task.id,"revived")}async function liveDeliveryOutcome(deps,automation,taskId,result){switch(result.outcome){case"delivered":return logDaemonInfo("automation",`delivered ${automation.name} task=${taskId} tab=${result.tabId}`),{status:"dispatched",taskId,tabId:result.tabId};case"no-engine":case"no-session":return{status:"dispatch_failed",taskId,tabId:automation.target?.tabId,error:result.outcome==="no-engine"?"target engine exited; restart it explicitly":"target tab has no live session"}}}import{spawn as spawn2}from"child_process";import{existsSync}from"fs";var MAX_OUTPUT_CHARS=4000,MAX_TIMEOUT_SECONDS=600;function killGroup(child){let pid=child.pid;if(pid===void 0)return;try{process.kill(-pid,"SIGKILL")}catch{try{child.kill("SIGKILL")}catch{}}}function withWatchdog(command,timeoutSeconds){return["set +m 2>/dev/null",`{ sleep ${timeoutSeconds} && { kill -9 -$$ 2>/dev/null || kill -9 $$ ; } ; } >/dev/null 2>&1 </dev/null &`,"__rove_watchdog=$!",`trap 'kill "$__rove_watchdog" 2>/dev/null' EXIT`,command].join(`
|
|
4
4
|
`)}function tail(chunks){let text=Buffer.concat(chunks.map((c)=>typeof c==="string"?Buffer.from(c):c)).toString("utf8");if(text.length<=MAX_OUTPUT_CHARS)return text;let points=Array.from(text);return points.length<=MAX_OUTPUT_CHARS?text:points.slice(-MAX_OUTPUT_CHARS).join("")}function runAutomationPrecheck(precheck,cwd,shell=resolveLoginShell({fallback:"/bin/sh"})){let startedAt=Date.now(),timeoutMs=Math.min(Math.max(precheck.timeoutSeconds,1),MAX_TIMEOUT_SECONDS)*1000;if(!existsSync(cwd))return Promise.resolve({exitCode:null,timedOut:!1,stdout:"",stderr:`working directory does not exist: ${cwd}`,durationMs:0});return new Promise((resolve)=>{let out=[],err=[],settled=!1,timedOut=!1,finish=(exitCode,timedOut2)=>{if(settled)return;settled=!0,clearTimeout(timer),resolve({exitCode,timedOut:timedOut2,stdout:tail(out),stderr:tail(err),durationMs:Date.now()-startedAt})},timer=setTimeout(()=>{if(timedOut=!0,child)killGroup(child);finish(null,!0)},timeoutMs);timer.unref?.();let child;try{child=spawn2(shell,["-ilc",withWatchdog(precheck.command,timeoutMs/1000+1)],{cwd,stdio:["ignore","pipe","pipe"],detached:process.platform!=="win32"})}catch(spawnError){err.push(spawnError instanceof Error?spawnError.message:String(spawnError)),finish(null,!1);return}child.stdout?.on("data",(chunk)=>out.push(chunk)),child.stderr?.on("data",(chunk)=>err.push(chunk)),child.on("error",(spawnError)=>{if(timedOut){finish(null,!0);return}err.push(spawnError.message),finish(null,!1)}),child.on("close",(code)=>finish(code,timedOut))})}function precheckPassed(result){return result.exitCode===0&&!result.timedOut}function formatPrecheckSkip(result){if(result.timedOut)return`precheck timed out after ${result.durationMs}ms`;if(result.exitCode===null)return`precheck could not run: ${result.stderr.trim()||"unknown error"}`;return`precheck exited ${result.exitCode}`}var DEFAULT_AUTOMATION_TICK_MS=60000;function dueAutomations(automations,nowMs){return automations.filter((a)=>{if(!a.enabled)return!1;let at=Date.parse(a.nextRunAt);return Number.isFinite(at)&&at<=nowMs})}function resolveDueOccurrence(automation,nowMs,tickMs=DEFAULT_AUTOMATION_TICK_MS){let notBefore=Date.parse(automation.createdAt),scheduledFor=latestCronAtOrBefore(automation.schedule,nowMs,Number.isFinite(notBefore)?notBefore:0);if(scheduledFor===null)return null;let graceMs=automation.missedRunGraceMinutes*60000+Math.max(tickMs,0);return{scheduledFor,missed:nowMs-scheduledFor>graceMs}}function runEventFor(status){if(status==="dispatched"||status==="revived")return"automation.dispatched";if(status==="dispatch_failed")return"automation.failed";return"automation.skipped"}function resolveLink(link){return typeof link==="function"?link():link}function emitRunEvent(deps,automation,status,args,extra){deps.plugins?.()?.handleUiReport({kind:runEventFor(status),...extra.taskId?{taskId:extra.taskId}:{},detail:{automationId:automation.id,name:automation.name,repo:automation.repo,status,trigger:args.trigger,scheduledFor:new Date(args.scheduledFor).toISOString(),...extra.tabId?{tabId:extra.tabId}:{},...extra.error?{error:extra.error}:{}}})}async function raiseOrClearInboxEpisode(deps,automation,status,extra){let inbox=deps.inbox;if(!inbox)return;let now=deps.now??Date.now;await(automationRunNeedsAttention(status)?inbox.recordRoutineFailure({automationId:automation.id,name:automation.name,status,...extra.error?{error:extra.error}:{}},extra.taskId??null,now()):inbox.deleteRoutineEpisode?.(automation.id,"routine_failed"))?.catch((err)=>logDaemonError("automation-inbox",err))}async function recordSkip(deps,automation,status,scheduledFor,error){let now=deps.now??Date.now;await deps.store.recordRun({automationId:automation.id,scheduledFor:new Date(scheduledFor).toISOString(),status,trigger:"scheduled",at:new Date(now()).toISOString(),error}),emitRunEvent(deps,automation,status,{scheduledFor,trigger:"scheduled"},{error})}function droppedOccurrences(automation,scheduledFor){let armedAt=Date.parse(automation.nextRunAt);if(!Number.isFinite(armedAt)||armedAt>=scheduledFor)return null;let count=countCronBetween(automation.schedule,armedAt,scheduledFor);return count>0?{count,firstMs:armedAt}:null}function withRoutineRunHeader(automation,run,api){return`[ROVE ROUTINE] "${automation.name}" run #${run.runNumber} \u2014 when done, report with: ${api} routine-respond --run ${run.id} --prompt-file -
|
|
5
5
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{writeOutdatedCache}from"./chunk-atmaakwp.js";import{PluginCliError,installPlugin}from"./chunk-
|
|
2
|
+
import{writeOutdatedCache}from"./chunk-atmaakwp.js";import{PluginCliError,installPlugin}from"./chunk-4a2veqfk.js";import{loadPluginRegistry,pluginCheckoutDir,pluginConfigDir,pluginDataDir,pluginStateDir,removePluginEntry,savePluginRegistry}from"./chunk-rqyaf0dw.js";import"./chunk-w7zv47mp.js";import"./chunk-8p579jct.js";import"./chunk-prqeddy7.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-0422g8ac.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-wqfp8d9w.js";import{execFileSync}from"child_process";import{existsSync,mkdirSync,readdirSync,renameSync}from"fs";import{join}from"path";function gitOut(args,cwd){try{return execFileSync("git",args,{cwd,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return null}}function checkEntry(entry){let repoSpec=entry.source.spec.split("/").slice(0,2).join("/"),localSha=gitOut(["rev-parse","HEAD"],pluginCheckoutDir(entry.id)),remote=gitOut(["ls-remote",`https://github.com/${repoSpec}.git`,"HEAD"]),remoteSha=remote?remote.split(/\s+/)[0]??null:null;return{id:entry.id,spec:entry.source.spec,version:entry.version,localSha,remoteSha,behind:Boolean(localSha&&remoteSha&&localSha!==remoteSha)}}function listOutdated(){let rows=loadPluginRegistry().plugins.filter((p)=>p.source.kind==="github").map(checkEntry);return writeOutdatedCache(rows.filter((r)=>r.behind).map((r)=>r.id)),rows}function printOutdated(){let rows=listOutdated();if(rows.length===0){console.log("no GitHub-installed plugins.");return}for(let r of rows){let status=r.behind?"update available":r.remoteSha===null?"remote unreachable":r.localSha===null?"local sha unreadable":"up to date";console.log(`${r.id} v${r.version} ${status}`)}}function migrateRenamedPlugin(oldId,newId){for(let dirOf of[pluginConfigDir,pluginStateDir]){let from=dirOf(oldId),to=dirOf(newId);if(!existsSync(from))continue;mkdirSync(to,{recursive:!0});for(let entry of readdirSync(from)){if(existsSync(join(to,entry)))continue;renameSync(join(from,entry),join(to,entry))}}savePluginRegistry(removePluginEntry(loadPluginRegistry(),oldId)),console.log(`renamed ${oldId} \u2192 ${newId}: settings and state carried over, old entry unregistered`),console.log(` leftover checkout (safe to remove): ${pluginDataDir(oldId)}`)}async function updatePlugins(ids,opts){let rows=listOutdated(),targets;if(opts.all){if(targets=rows.filter((r)=>r.behind),targets.length===0){console.log("all plugins up to date.");return}}else{if(ids.length===0)throw new PluginCliError("update takes plugin ids or --all");targets=ids.map((id)=>{let row=rows.find((r)=>r.id===id);if(!row)throw new PluginCliError(`\`${id}\` is not a GitHub-installed plugin; see \`${ROVE_PRODUCT_NAME} plugin list\``);return row})}for(let target of targets){if(!target.behind&&!ids.includes(target.id))continue;console.log(`updating ${target.id} (${target.spec})\u2026`);let installedId=await installPlugin(target.spec,{yes:opts.yes});if(installedId!==target.id)migrateRenamedPlugin(target.id,installedId)}listOutdated()}export{updatePlugins,printOutdated};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{JsonHookAdapter,editJsonSettings,isObject,removeRoveHooks,vendorConfigHome}from"./chunk-znjcesdr.js";import{ROVE_PRODUCT_NAME}from"./chunk-zt7wfnva.js";import{__require}from"./chunk-wqfp8d9w.js";import{join}from"path";var CLAUDE_HOOK_EVENT_MAP=[{event:"SessionStart",verb:"session-start"},{event:"UserPromptSubmit",verb:"turn-start"},{event:"Stop",verb:"turn-complete"},{event:"StopFailure",verb:"turn-failed"},{event:"Notification",matcher:"permission_prompt",verb:"awaiting-input"},{event:"Notification",matcher:"elicitation_dialog",verb:"awaiting-input"},{event:"SessionEnd",verb:"session-end"},{event:"PreCompact",verb:"pre-compact"},{event:"PostCompact",verb:"post-compact"},{event:"SubagentStart",verb:"subagent-start"},{event:"SubagentStop",verb:"subagent-stop"},{event:"PreToolUse",verb:"tool-pre"},{event:"PostToolUse",verb:"tool-post"},{event:"PostToolUseFailure",verb:"tool-failed"}],ROVE_HOOK_EVENTS=[...new Set(CLAUDE_HOOK_EVENT_MAP.map((e)=>e.event))];function failureFromErrorType(errorType){if(typeof errorType!=="string")return"other";if(errorType==="rate_limit"||errorType==="overloaded")return"rate_limit";if(errorType==="billing_error")return"billing";return"other"}function claudeSettingsPath(){return join(vendorConfigHome("claude"),"settings.json")}var WORKTREE_SYNC_VERB="worktree-created";function mergeWorktreeSyncHook(current,command){let{hooks:rawHooks,...restSettings}=current,{WorktreeCreate,...otherHooks}=isObject(rawHooks)?rawHooks:{},prior=Array.isArray(WorktreeCreate)?WorktreeCreate:[],kept=removeRoveHooks(prior,[WORKTREE_SYNC_VERB]);if(command!==null)kept.push({hooks:[{type:"command",command}]});let nextHooks={...otherHooks};if(kept.length>0)nextHooks.WorktreeCreate=kept;return Object.keys(nextHooks).length>0?{...restSettings,hooks:nextHooks}:{...restSettings}}class ClaudeHookAdapter extends JsonHookAdapter{vendor="claude";eventMap=CLAUDE_HOOK_EVENT_MAP;globalSettingsPath(){return claudeSettingsPath()}activityDetailFromPayload(kind,payload){if(kind==="turn-failed")return{failure:failureFromErrorType(payload.error_type)};if(kind==="awaiting-input")return{waiting:payload.notification_type==="elicitation_dialog"?"input":"permission"};if(kind==="tool-pre"||kind==="tool-post"||kind==="tool-failed")return{tool:{...typeof payload.tool_name==="string"?{name:payload.tool_name}:{},...typeof payload.tool_use_id==="string"?{id:payload.tool_use_id}:{}}};if(kind==="pre-compact"||kind==="post-compact")return{compact:{trigger:payload.trigger==="manual"?"manual":"auto"}};if(kind==="subagent-start"||kind==="subagent-stop")return{subagent:{...typeof payload.agent_type==="string"?{type:payload.agent_type}:{},...typeof payload.agent_id==="string"?{id:payload.agent_id}:{}}};return}sessionFromPayload(payload){if(typeof payload.session_id!=="string"||!payload.session_id)return;return{sessionId:payload.session_id,...typeof payload.transcript_path==="string"&&payload.transcript_path?{transcriptPath:payload.transcript_path}:{}}}isUnattendedSession(env){return env.CLAUDE_CODE_SESSION_ATTENDED==="0"}async externallyManagedHooks(){let{isRovePluginEnabled,detectLegacyInstalls,migrationHint}=await import("./chunk-4qytyfmt.js");if(!isRovePluginEnabled())return;let notice=migrationHint(detectLegacyInstalls(),ROVE_PRODUCT_NAME);return notice?{notice}:{}}supportsWorktreeSync(){return!0}async removeWorktreeSyncHook(settingsFilePath){await editJsonSettings(settingsFilePath,(cur)=>mergeWorktreeSyncHook(cur,null))}}
|
|
3
|
+
export{CLAUDE_HOOK_EVENT_MAP,claudeSettingsPath,ClaudeHookAdapter};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{API_VERBS,VERBS,VERB_ALIASES,VERB_GROUPS,findVerb,unknownVerbError}from"./chunk-
|
|
2
|
+
import{API_VERBS,VERBS,VERB_ALIASES,VERB_GROUPS,findVerb,unknownVerbError}from"./chunk-ctkf2m9h.js";import"./chunk-466djpa8.js";import"./chunk-83e13qdq.js";import"./chunk-hr2xky15.js";import"./chunk-pa6teq2c.js";import"./chunk-vrzb7s42.js";import"./chunk-17e2tgyg.js";import"./chunk-cbc1h345.js";import"./chunk-4xns5j33.js";import"./chunk-4hestsjp.js";import"./chunk-2bgmby1d.js";import"./chunk-rqyaf0dw.js";import"./chunk-41x1hrqe.js";import"./chunk-5mhvjytn.js";import"./chunk-atn06ncf.js";import"./chunk-qkehg2c1.js";import"./chunk-m9q1whep.js";import"./chunk-t64hwtzt.js";import"./chunk-e5k2j2x8.js";import"./chunk-cbjh43yc.js";import"./chunk-2apszxn2.js";import"./chunk-sak1tphp.js";import"./chunk-4r3s1z14.js";import"./chunk-rxqdw6s5.js";import"./chunk-4250pw6r.js";import"./chunk-h29wy8y3.js";import"./chunk-vjvkkrzc.js";import"./chunk-pdvyfz3n.js";import"./chunk-gcxcq22q.js";import"./chunk-hpay0ax8.js";import"./chunk-catrr0z3.js";import"./chunk-wam8sr6a.js";import"./chunk-ctmbj2y3.js";import"./chunk-k4374n9t.js";import"./chunk-w7zv47mp.js";import"./chunk-2tfnscxk.js";import"./chunk-etfh8f4z.js";import"./chunk-6xppe9bj.js";import"./chunk-f7zjggfv.js";import"./chunk-zsfyj36g.js";import"./chunk-96cjpssp.js";import"./chunk-9w5g7frx.js";import"./chunk-gvrtrvnz.js";import"./chunk-ag3txfg2.js";import"./chunk-2brn8e1y.js";import"./chunk-60fy3ckp.js";import"./chunk-znjcesdr.js";import"./chunk-7kysxgbq.js";import"./chunk-qzsahxd9.js";import"./chunk-xy8be792.js";import"./chunk-h2m7em1e.js";import"./chunk-tdhk4dz8.js";import"./chunk-8p579jct.js";import"./chunk-h9cg0j3a.js";import"./chunk-40dgv828.js";import"./chunk-3342qzve.js";import"./chunk-7q43tysm.js";import"./chunk-mw0ysrpd.js";import"./chunk-a7kq09ke.js";import"./chunk-prqeddy7.js";import"./chunk-zt7wfnva.js";import"./chunk-yt15y085.js";import"./chunk-wvwkmj3t.js";import"./chunk-jxyvk9c0.js";import"./chunk-nhakrm1f.js";import"./chunk-pxk2c2vj.js";import"./chunk-adkva3ep.js";import"./chunk-0422g8ac.js";import"./chunk-hq9tbzqa.js";import"./chunk-pn5ygqn6.js";import"./chunk-npwzmmv9.js";import"./chunk-b39sdtt0.js";import"./chunk-nc46gddg.js";import"./chunk-wqfp8d9w.js";export{unknownVerbError,findVerb,VERB_GROUPS,VERB_ALIASES,VERBS,API_VERBS};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{__require}from"./chunk-wqfp8d9w.js";var CHANNEL_LOADERS={weixin:async()=>(await import("./chunk-
|
|
2
|
+
import{__require}from"./chunk-wqfp8d9w.js";var CHANNEL_LOADERS={weixin:async()=>(await import("./chunk-7axwr3a5.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};
|