@sma1lboy/rove 0.9.236 → 0.9.238
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-4jf24zj7.js → chunk-0wgheepg.js} +2 -2
- package/dist/cli/{chunk-rv5726t0.js → chunk-1265fmzk.js} +1 -1
- package/dist/cli/{chunk-xd5v9zbs.js → chunk-1bm6sryf.js} +1 -1
- package/dist/cli/{chunk-swez6wr7.js → chunk-2yd128k1.js} +1 -1
- package/dist/cli/chunk-507zn8rs.js +3 -0
- package/dist/cli/{chunk-dnh40ghr.js → chunk-67ev8k22.js} +1 -1
- package/dist/cli/{chunk-m2m36wnt.js → chunk-6rvzzrd7.js} +1 -1
- package/dist/cli/{chunk-fvd4nc8w.js → chunk-77w83wgh.js} +1 -1
- package/dist/cli/{chunk-dh9dd83p.js → chunk-8h0khkap.js} +1 -1
- package/dist/cli/{chunk-xfbyzaa6.js → chunk-9ek7xm94.js} +2 -2
- package/dist/cli/{chunk-aaqvcmfz.js → chunk-a1k2z44b.js} +1 -1
- package/dist/cli/{chunk-7vfp9x2d.js → chunk-acw32w13.js} +2 -2
- package/dist/cli/{chunk-dmhk2t2h.js → chunk-aj7fkrha.js} +1 -1
- package/dist/cli/{chunk-37gjvf90.js → chunk-b503z32q.js} +1 -1
- package/dist/cli/{chunk-4gy259ab.js → chunk-bav389wj.js} +1 -1
- package/dist/cli/{chunk-dxxgcycm.js → chunk-be757xzj.js} +1 -1
- package/dist/cli/{chunk-wrphtkn7.js → chunk-bhqracn8.js} +1 -1
- package/dist/cli/{chunk-tq65mkr3.js → chunk-c2tevj9f.js} +1 -1
- package/dist/cli/{chunk-r2qe8zja.js → chunk-d1agt94n.js} +1 -1
- package/dist/cli/chunk-g56km26e.js +3 -0
- package/dist/cli/{chunk-6e6g1701.js → chunk-gqphk56d.js} +1 -1
- package/dist/cli/{chunk-wcg6gwfk.js → chunk-gqrh2gp1.js} +1 -1
- package/dist/cli/{chunk-qmyj3ret.js → chunk-grt1e2s8.js} +1 -1
- package/dist/cli/{chunk-799hfryr.js → chunk-hk8mc43r.js} +3 -3
- package/dist/cli/{chunk-0g6mnxhy.js → chunk-hp32tbes.js} +1 -1
- package/dist/cli/{chunk-p0v78qw0.js → chunk-j6kataan.js} +1 -1
- package/dist/cli/{chunk-jfsgt823.js → chunk-janvvpv5.js} +1 -1
- package/dist/cli/{chunk-ag06bry1.js → chunk-mb1e73jm.js} +2 -2
- package/dist/cli/{chunk-m987tpw1.js → chunk-n0mg67wn.js} +1 -1
- package/dist/cli/{chunk-63pxanxt.js → chunk-n24dmy2r.js} +2 -2
- package/dist/cli/chunk-nntg9d85.js +3 -0
- package/dist/cli/{chunk-xyj34nsw.js → chunk-pzbrj3gd.js} +1 -1
- package/dist/cli/{chunk-bdkv3557.js → chunk-r8xqvg26.js} +1 -1
- package/dist/cli/{chunk-jhq4bhc7.js → chunk-ssfj9td0.js} +1 -1
- package/dist/cli/{chunk-hc34weyf.js → chunk-tcj36cqg.js} +1 -1
- package/dist/cli/{chunk-9jphsv70.js → chunk-vejgnmcp.js} +1 -1
- package/dist/cli/{chunk-hpxx730k.js → chunk-wpsbyq4s.js} +1 -1
- package/dist/cli/{chunk-ze4a2d4m.js → chunk-y05d79az.js} +1 -1
- package/dist/cli/{chunk-hep47we2.js → chunk-y4048296.js} +1 -1
- package/dist/cli/{chunk-sg1pmcqf.js → chunk-ygd572ee.js} +1 -1
- package/dist/cli/{chunk-k23ny7k4.js → chunk-yj5pjxx2.js} +1 -1
- package/dist/cli/{chunk-x1r2bn3n.js → chunk-z5fnv7nk.js} +19 -19
- package/dist/cli/{chunk-bkpx0hr2.js → chunk-zwgns5ce.js} +1 -1
- package/dist/cli/index.js +3 -3
- package/dist/cli/kobe.js +1 -1
- package/dist/cli/pty-host-node.mjs +310 -9
- package/dist/cli/rove.js +1 -1
- package/dist/web-ui/assets/harness-CQ-1WI4q.js +87 -0
- package/dist/web-ui/assets/index-C4dLQEqf.css +1 -0
- package/dist/web-ui/assets/{index-D2wALq0b.js → index-_ttAn6pY.js} +2 -2
- package/dist/web-ui/index.html +2 -2
- package/dist/web-ui/pty-server.mjs +44 -0
- package/dist/web-ui/pty-session-lifecycle.mjs +41 -2
- package/package.json +1 -1
- package/dist/cli/chunk-1m7cp5ze.js +0 -3
- package/dist/cli/chunk-6nqcycx4.js +0 -3
- package/dist/cli/chunk-c2rtg3x8.js +0 -3
- package/dist/web-ui/assets/harness-CLsfHgXB.js +0 -86
- package/dist/web-ui/assets/index-B4knjCIs.css +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{submitFeedback}from"./chunk-
|
|
2
|
+
import{submitFeedback}from"./chunk-77w83wgh.js";import"./chunk-be757xzj.js";import{activeCliName}from"./chunk-ppwpjm39.js";import"./chunk-fxs82dsx.js";import"./chunk-zyd6k6ak.js";import"./chunk-8hbtca1g.js";import"./chunk-hq2n27y1.js";import"./chunk-sb0ns0c7.js";import"./chunk-vnpqemb0.js";import"./chunk-9prawccj.js";import"./chunk-y8fqdnh3.js";import"./chunk-hq4b3fca.js";import"./chunk-wqfp8d9w.js";import{readFileSync}from"fs";var CLI_NAME=activeCliName(),FEEDBACK_USAGE=[`Usage: ${CLI_NAME} feedback --title <text> (--body <text> | --body-file <path>) [--category <slug>]`,"","Create a GitHub Discussion in the Rove repository using the GitHub CLI.","","Requires:"," gh auth login","","Options:"," --title <text> Discussion title"," --body <text> Discussion body"," --body-file <path> Read the Discussion body from a file; use - for stdin"," --category <slug> Discussion category slug (default: feedback)"," -h, --help Print this help",""].join(`
|
|
3
3
|
`);function usageError(message){process.stderr.write(`${CLI_NAME} feedback: ${message}
|
|
4
4
|
|
|
5
5
|
${FEEDBACK_USAGE}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{matchPathGlob}from"./chunk-kg11c1py.js";import{argvHasFlag}from"./chunk-jvxh93nz.js";import{connectIfRunning}from"./chunk-wtqxv2rv.js";import"./chunk-pz907kve.js";import{expandTilde}from"./chunk-nvqdmx7q.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{BUILTIN_VENDORS,coerceVendorId,isBuiltinVendor}from"./chunk-05jej26n.js";import{CURRENT_VERSION}from"./chunk-
|
|
4
|
-
`),process.exit(1);let projectRoot=await projectRootFor(dir);await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-hgx20x94.js");writeLastActiveTaskId(String(task.id))}});let{publishKobeTerminalTitle}=await import("./chunk-1tx1s5v6.js");publishKobeTerminalTitle();let{startTui}=await import("./chunk-
|
|
3
|
+
import{matchPathGlob}from"./chunk-kg11c1py.js";import{argvHasFlag}from"./chunk-jvxh93nz.js";import{connectIfRunning}from"./chunk-wtqxv2rv.js";import"./chunk-pz907kve.js";import{expandTilde}from"./chunk-nvqdmx7q.js";import{errorMessage}from"./chunk-2brn8e1y.js";import{BUILTIN_VENDORS,coerceVendorId,isBuiltinVendor}from"./chunk-05jej26n.js";import{CURRENT_VERSION}from"./chunk-be757xzj.js";import{rejectionReason}from"./chunk-mkksdcsw.js";import{activeCliName,prepareCliEnvironment}from"./chunk-ppwpjm39.js";import"./chunk-fxs82dsx.js";import"./chunk-zyd6k6ak.js";import"./chunk-8hbtca1g.js";import"./chunk-hq2n27y1.js";import"./chunk-sb0ns0c7.js";import"./chunk-vnpqemb0.js";import"./chunk-9prawccj.js";import"./chunk-qagek3wg.js";import"./chunk-544bwsss.js";import"./chunk-hqbmzz4t.js";import"./chunk-3es6spp4.js";import"./chunk-pw6yfj10.js";import{pathSyntax}from"./chunk-f10n6063.js";import"./chunk-y8fqdnh3.js";import"./chunk-hq4b3fca.js";import{__require}from"./chunk-wqfp8d9w.js";import{resolve as resolve2}from"path";function debugEnabled(env){return env.KOBE_DEBUG==="1"||env.ROVE_DEBUG==="1"}function failureSubject(cliName,argv){let verb=argv[2];return verb&&!verb.startsWith("-")&&!verb.includes("/")?`${cliName} ${verb}`:cliName}function summarizeCliGitError(message,cwd){if(!/not a git repository/i.test(message))return null;return`${cwd} is not a git repository \u2014 run this inside one, or pass a repo path.`}function formatCliFailure(err,opts){let subject=failureSubject(opts.cliName,opts.argv);if(debugEnabled(opts.env))return`${subject}: ${String(err instanceof Error?err.stack??err:err)}`;let raw=errorMessage(err);return`${subject}: ${summarizeCliGitError(raw,opts.cwd)??raw}`}var DYNAMIC_COMMANDS=new Map([["completions",async(args)=>{let{runCompletionsSubcommand}=await import("./chunk-9ek7xm94.js");await runCompletionsSubcommand(args)}],["export",async(args)=>{let{runExportSubcommand}=await import("./chunk-s1e0e9hc.js");await runExportSubcommand(args)}],["repo",async(args)=>{let{runRepoSubcommand}=await import("./chunk-4d54zgc7.js");await runRepoSubcommand(args)}],["api",async(args)=>{let{runApiSubcommand}=await import("./chunk-8h0khkap.js");await runApiSubcommand(args)}],["update",async(args)=>{let{runUpdateSubcommand}=await import("./chunk-mb1e73jm.js");await runUpdateSubcommand(args)}],["theme",async(args)=>{let{runThemeSubcommand}=await import("./chunk-k7g060qr.js");await runThemeSubcommand(args)}],["feedback",async(args)=>{let{runFeedbackSubcommand}=await import("./chunk-zwgns5ce.js");await runFeedbackSubcommand(args)}],["daemon",async(args)=>{let{runDaemonSubcommand}=await import("./chunk-b503z32q.js");await runDaemonSubcommand(args)}],["machine",async(args)=>{let{runMachineSubcommand}=await import("./chunk-3sg5v7cg.js");await runMachineSubcommand(args)}],["doctor",async(args)=>{let{runDoctorSubcommand}=await import("./chunk-2yd128k1.js");await runDoctorSubcommand(args)}],["config",async(args)=>{let{runConfigSubcommand}=await import("./chunk-8pa1ph1s.js");await runConfigSubcommand(args)}],["reset",async(args)=>{let{runResetSubcommand}=await import("./chunk-grt1e2s8.js");await runResetSubcommand(args)}],["pty-host",async(args)=>{let{runPtyHostSubcommand}=await import("./chunk-507zn8rs.js");await runPtyHostSubcommand(args)}],["skill",async(args)=>{let{runSkillSubcommand}=await import("./chunk-cv1kaq8a.js");await runSkillSubcommand(args)}],["plugin",async(args)=>{let{runPluginSubcommand}=await import("./chunk-0wgheepg.js");await runPluginSubcommand(args)}],["hook",async(args)=>{let{runHookSubcommand}=await import("./chunk-wpsbyq4s.js");await runHookSubcommand(args)}]]);import{statSync}from"fs";import{resolve}from"path";async function openLocalOrchestrator(){let{TaskIndexStore}=await import("./chunk-vzqrj32e.js"),{GitWorktreeManager}=await import("./chunk-9k47xr7m.js"),{Orchestrator}=await import("./chunk-md8k7c5w.js"),store=new TaskIndexStore;return await store.load(),new Orchestrator({store,worktrees:new GitWorktreeManager})}async function withDaemonOrLocal(bridge){let client=await connectIfRunning();if(client)try{return await bridge.daemon(client)}finally{client.close()}let orch=await openLocalOrchestrator();return bridge.local(orch)}function isPathLikeArg(arg){return arg==="."||arg===".."||arg.startsWith("./")||arg.startsWith("../")||arg.startsWith(".\\")||arg.startsWith("..\\")||pathSyntax(arg).isAbsolute(arg)||arg.startsWith("/")||arg==="~"||arg.startsWith("~/")||arg.startsWith("~\\")}async function projectRootFor(dir){let{isGitRepo,resolveRepoRoot}=await import("./chunk-7s1kx9ez.js"),{projectRejection}=await import("./chunk-9mtxxsb3.js"),top=resolveRepoRoot(dir);if(top!==dir)return null;return projectRejection(top,isGitRepo,"explicit")?null:top}async function runOpenDirectory(arg){let dir=resolve(process.cwd(),expandTilde(arg)),isDir=!1;try{isDir=statSync(dir).isDirectory()}catch{isDir=!1}if(!isDir)process.stderr.write(`${activeCliName()}: "${arg}" is not a directory (resolved to ${dir}).
|
|
4
|
+
`),process.exit(1);let projectRoot=await projectRootFor(dir);await withDaemonOrLocal({daemon:async(client)=>{let taskId;if(projectRoot)taskId=(await client.request("task.ensureMain",{repo:projectRoot})).task.id;else taskId=(await client.request("task.openDir",{dir})).taskId;await client.request("task.setActive",{taskId})},local:async(orch)=>{let task=projectRoot?await orch.ensureMainTask(projectRoot):await orch.openDirectoryTask({dir}),{writeLastActiveTaskId}=await import("./chunk-hgx20x94.js");writeLastActiveTaskId(String(task.id))}});let{publishKobeTerminalTitle}=await import("./chunk-1tx1s5v6.js");publishKobeTerminalTitle();let{startTui}=await import("./chunk-tcj36cqg.js");await startTui()}function topLevelUsage(cliName=activeCliName()){return[`${cliName} ${CURRENT_VERSION}`,"",`Usage: ${cliName} [command] [options]`,"","Run with no command to launch PureTUI.",`Run \`${cliName} .\` (or \`${cliName} <path>\`) to open a directory as a standalone task.`,"","Commands:"," completions <shell> Generate shell completion script (bash/zsh/fish)"," add [path] Save a repo path for the new-task picker"," remove [path] Forget a saved project (inverse of add; non-destructive)"," adopt [glob] Import existing git worktrees as tasks"," export [--csv|--json] Print the task list (json/csv/table; daemon-free)"," repo <verb> Per-repo init script + first prompt (show|set|unset)",` api <verb> Scriptable RPC surface for agents (see \`${cliName} api --help\`)`," daemon <verb> Manage the daemon (start|stop|status|restart)"," machine <verb> Other computers running Rove (add|remove|list)"," doctor [--report|--fix] Diagnose daemon/PTY/engines/git; --fix walks the remedies",` config [--path] Open ${cliName}'s config file (state.json) in your editor`," reset [--hard] Stop runtimes; optionally wipe task/UI state"," theme <verb> Manage user themes (list|add|remove)",` skill <verb> Install the ${cliName} agent skill (install|status|command|print)`," plugin <verb> Install and run plugins (install|link|list|action|\u2026)"," feedback Send feedback to GitHub Discussions",` update [version|channel|list] Self-update ${cliName}, switch channel, or list versions`,"","Options:"," -v, --version Print version"," -h, --help Print this help"," --skill Print the agent skill file and exit"].join(`
|
|
5
5
|
`)}prepareCliEnvironment();var CLI_NAME=activeCliName(),ADD_USAGE=[`Usage: ${CLI_NAME} add [path]`,` ${CLI_NAME} add --remote --host <host> --user <user> --path <basePath> [--port N] [--key [path] | --password]`,"","Save a repo for the new-task picker. With --remote, register an SSH-backed","project whose worktrees live on <host>; engine launch over SSH is pending.",""].join(`
|
|
6
6
|
`);async function runAddSubcommand(rest){let arg=rest[0];if(arg==="--help"||arg==="-h"||arg==="help"){process.stdout.write(ADD_USAGE);return}if(arg==="--remote"){let{runAddRemote}=await import("./chunk-s1p650mm.js");await runAddRemote(rest.slice(1));return}if(arg?.startsWith("-"))process.stderr.write(`${CLI_NAME} add: unknown flag "${arg}"
|
|
7
7
|
|
|
@@ -22,4 +22,4 @@ ${ADOPT_USAGE}
|
|
|
22
22
|
pass a path glob to adopt, e.g. ${CLI_NAME} adopt '${repo}/*' --yes`);return}let matched=worktrees.filter(isMatch);if(matched.length===0){console.log(`
|
|
23
23
|
no worktrees match glob ${JSON.stringify(glob)}`);return}if(!yes){console.log(`
|
|
24
24
|
${matched.length} worktree(s) match \u2014 re-run with --yes to adopt them`);return}await adoptWorktreesInto(orch,repo,matched,vendor),console.log(`done \u2014 adopted ${matched.length} worktree(s)`)}function printTopLevelUsage(out){out.write(`${topLevelUsage()}
|
|
25
|
-
`)}var COMMANDS=new Map([["add",runAddSubcommand],["remove",runRemoveSubcommand],["adopt",runAdoptSubcommand],...DYNAMIC_COMMANDS]);async function main(){let[,,...rawArgs]=process.argv,[subcommand,...rest]=rawArgs;if(subcommand==="--version"||subcommand==="-v"||subcommand==="version"){let{CURRENT_VERSION:CURRENT_VERSION2}=await import("./chunk-
|
|
25
|
+
`)}var COMMANDS=new Map([["add",runAddSubcommand],["remove",runRemoveSubcommand],["adopt",runAdoptSubcommand],...DYNAMIC_COMMANDS]);async function main(){let[,,...rawArgs]=process.argv,[subcommand,...rest]=rawArgs;if(subcommand==="--version"||subcommand==="-v"||subcommand==="version"){let{CURRENT_VERSION:CURRENT_VERSION2}=await import("./chunk-a1k2z44b.js");console.log(`${CLI_NAME} ${CURRENT_VERSION2}`);return}if(subcommand==="--help"||subcommand==="-h"||subcommand==="help"){printTopLevelUsage(process.stdout);return}if(subcommand==="--skill"){let{runSkillSubcommand}=await import("./chunk-cv1kaq8a.js");await runSkillSubcommand(["print"]);return}let handler=subcommand!==void 0?COMMANDS.get(subcommand):void 0;if(handler){await handler(rest);return}if(subcommand!==void 0&&isPathLikeArg(subcommand)){await runOpenDirectory(subcommand);return}if(subcommand!==void 0)console.error(`${CLI_NAME}: unknown command '${subcommand}'`),printTopLevelUsage(process.stderr),process.exit(2);let{publishKobeTerminalTitle}=await import("./chunk-1tx1s5v6.js");publishKobeTerminalTitle();let{startTui}=await import("./chunk-tcj36cqg.js");await startTui();let{runPendingWelcomeInstalls}=await import("./chunk-67ev8k22.js");runPendingWelcomeInstalls()}main().catch((err)=>{console.error(formatCliFailure(err,{cliName:CLI_NAME,argv:process.argv,cwd:process.cwd(),env:process.env})),process.exit(1)});
|
package/dist/cli/kobe.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{join as G1}from"node:path";import{createInterface as K1}from"node:readline/promises";import{pathToFileURL as U1}from"node:url";import{spawnSync as V}from"node:child_process";import{constants as a,accessSync as e}from"node:fs";import{homedir as W1}from"node:os";import{basename as z1,delimiter as J1,dirname as Q1,join as G}from"node:path";import{fileURLToPath as N}from"node:url";var M={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.
|
|
2
|
+
import{join as G1}from"node:path";import{createInterface as K1}from"node:readline/promises";import{pathToFileURL as U1}from"node:url";import{spawnSync as V}from"node:child_process";import{constants as a,accessSync as e}from"node:fs";import{homedir as W1}from"node:os";import{basename as z1,delimiter as J1,dirname as Q1,join as G}from"node:path";import{fileURLToPath as N}from"node:url";var M={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.238",description:"Rove — the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",keywords:["terminal","tui","cli","multiplexer","ai-agents","coding-agent","ai-coding-assistant","agentic-ai","parallel-agents","git-worktree","claude-code","codex","llm","developer-tools"],type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/completions","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://rove.run",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:rubric":"bun run scripts/build-tier-rubric.ts",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun scripts/render-track.mjs",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build","plugin-sandbox":"bun run scripts/plugin-sandbox.ts"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8","smol-toml":"^1.7.1",ws:"^8.21.3"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.19","@tsconfig/bun":"1.0.11","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]};var O="rove",T="kobe";var I=T;var L=O;var t="ROVE_INVOKED_AS";function K(W=process.env){return W[t]===L?L:I}var U="ROVE_BUN",Z1="ROVE_NO_BUN_BOOTSTRAP",R="ROVE_SKIP_BUN_CHECK",x=M.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0",y=(W)=>{try{return e(W,a.X_OK),!0}catch{return!1}},$1=(W)=>W==="win32"?"bun.exe":"bun",X1=(W)=>{let z=V(W,["--version"],{encoding:"utf8",timeout:5000});if(z.error||z.status!==0)return null;return z.stdout?.split(`
|
|
3
3
|
`)[0]?.trim()??""};function F(W){return W.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function C(W,z=x){let J=F(W),$=F(z);if(!J||!$)return!0;let Z=J.split(".").map(Number),Q=$.split(".").map(Number);for(let X=0;X<3;X++){let Y=Z[X]??0,b=Q[X]??0;if(Y!==b)return Y>b}return!0}function j(W=process.env){return W[R]==="1"}function k(W={}){let z=W.env??process.env,J=W.platform??process.platform,$=W.home??z.HOME??z.USERPROFILE??W1(),Z=$1(J),Q=[],X=z[U]?.trim();if(X)Q.push(X);for(let w of(z.PATH??z.Path??"").split(J1))if(w)Q.push(G(w,Z));let Y=z.BUN_INSTALL?.trim();if(Y)Q.push(G(Y,"bin",Z));if($)Q.push(G($,".bun","bin",Z));let b=W.launcherDir;if(b)Q.push(G(b,"..","..","node_modules","bun","bin",Z)),Q.push(G(b,"..","..","..","bun","bin",Z));return Q}function q1(W={}){let z=W.isExecutable??y;return k(W).find((J)=>z(J))??null}function B(W={}){let z=W.isExecutable??y,J=W.bunVersionOf??X1;if(j(W.env??process.env))return{bun:q1(W),stale:null,unusable:null};let $=null,Z=null;for(let Q of k(W)){if(!z(Q))continue;let X=J(Q);if(X===null){Z??=Q;continue}if(C(X))return{bun:Q,stale:$,unusable:Z};$??={path:Q,version:F(X)??X}}return{bun:null,stale:$,unusable:Z}}function _(W){return Q1(N(W))}function P(W){return z1(N(W)).replace(/\.[cm]?[jt]s$/,"")}function b1(W=process.platform){return W==="win32"?["powershell","-NoProfile","-Command","irm bun.sh/install.ps1 | iex"]:["bash","-c","curl -fsSL https://bun.sh/install | bash"]}function D(W=K(),z=process.platform){let J=z==="win32"?'powershell -c "irm bun.sh/install.ps1 | iex"':"curl -fsSL https://bun.sh/install | bash";return[`${W}: Rove runs on the Bun runtime, and no Bun was found on this machine.`,"","Install Bun, then run this command again:",` ${J}`," npm install -g bun # any platform, if you already have npm","","Or install Bun and Rove together in one step:"," curl -fsSL https://rove.run/install.sh | sh","",`Already have Bun somewhere unusual? Point Rove at it: ${U}=/path/to/bun`,""].join(`
|
|
4
4
|
`)}function g(W,z,J=K()){return[`${J}: this machine's Bun is too old for Rove — found ${z} at ${W}, need ${x} or newer.`,"","Rove's terminals are built on Bun's PTY API. An older Bun ignores it silently,","so every terminal and engine tab would open empty and stay empty.","","Upgrade Bun, then run this command again:"," bun upgrade # Bun installed itself (~/.bun)"," brew upgrade bun # Homebrew"," npm install -g bun@latest # npm-managed Bun","",`Have a newer Bun elsewhere? Point Rove at it: ${U}=/path/to/bun`,`Run on this one anyway (unsupported, terminals will be blank): ${R}=1`,""].join(`
|
|
5
5
|
`)}function p(W,z=K()){return[`${z}: the Bun at ${W} could not be run — \`${W} --version\` failed or never returned.`,"","Rove skipped it rather than starting through it, which would hang or fail","with a message from that binary instead of this one.","","Reinstall Bun, then run this command again:"," curl -fsSL https://bun.sh/install | bash","",`Have a working Bun elsewhere? Point Rove at it: ${U}=/path/to/bun`,""].join(`
|
|
@@ -758,6 +758,278 @@ function foldDefaultColorQueries(previousCarry, chunkText) {
|
|
|
758
758
|
return { slots, carry: trailingQueryPrefix(text.slice(end)) };
|
|
759
759
|
}
|
|
760
760
|
|
|
761
|
+
// ../kobe-daemon/src/daemon/terminal-modes.ts
|
|
762
|
+
var DEFAULT_MODES = {
|
|
763
|
+
applicationCursorKeys: false,
|
|
764
|
+
applicationKeypad: false,
|
|
765
|
+
origin: false,
|
|
766
|
+
wraparound: true,
|
|
767
|
+
reverseWraparound: false,
|
|
768
|
+
cursorBlink: false,
|
|
769
|
+
cursorVisible: true,
|
|
770
|
+
insertMode: false,
|
|
771
|
+
sendFocus: false,
|
|
772
|
+
bracketedPaste: false,
|
|
773
|
+
synchronizedOutput: false,
|
|
774
|
+
altScreen: false,
|
|
775
|
+
mouseProtocol: "none",
|
|
776
|
+
mouseEncoding: "default"
|
|
777
|
+
};
|
|
778
|
+
var MOUSE_PROTOCOLS = { 9: "x10", 1000: "vt200", 1002: "drag", 1003: "any" };
|
|
779
|
+
var MOUSE_ENCODINGS = { 1006: "sgr", 1016: "sgr-pixels" };
|
|
780
|
+
var MAX_CARRY = 64;
|
|
781
|
+
var DA1_REPLY = "\x1B[?1;2c";
|
|
782
|
+
function freshModeTrack(modes = { ...DEFAULT_MODES }) {
|
|
783
|
+
return { modes, carry: "" };
|
|
784
|
+
}
|
|
785
|
+
function normalizeTerminalModes(raw) {
|
|
786
|
+
const modes = { ...DEFAULT_MODES };
|
|
787
|
+
if (typeof raw !== "object" || raw === null)
|
|
788
|
+
return modes;
|
|
789
|
+
const record = raw;
|
|
790
|
+
for (const key of Object.keys(DEFAULT_MODES)) {
|
|
791
|
+
if (typeof record[key] === "boolean" && typeof modes[key] === "boolean")
|
|
792
|
+
modes[key] = record[key];
|
|
793
|
+
}
|
|
794
|
+
if (Object.values(MOUSE_PROTOCOLS).includes(record.mouseProtocol))
|
|
795
|
+
modes.mouseProtocol = record.mouseProtocol;
|
|
796
|
+
if (Object.values(MOUSE_ENCODINGS).includes(record.mouseEncoding))
|
|
797
|
+
modes.mouseEncoding = record.mouseEncoding;
|
|
798
|
+
return modes;
|
|
799
|
+
}
|
|
800
|
+
function scanTerminalModes(track, chunk) {
|
|
801
|
+
const text = track.carry + chunk;
|
|
802
|
+
track.carry = "";
|
|
803
|
+
const replies = [];
|
|
804
|
+
let i = text.indexOf("\x1B");
|
|
805
|
+
while (i !== -1) {
|
|
806
|
+
if (i + 1 >= text.length) {
|
|
807
|
+
track.carry = "\x1B";
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
const next = text.charCodeAt(i + 1);
|
|
811
|
+
if (next === 91) {
|
|
812
|
+
const end = csiEnd(text, i + 2);
|
|
813
|
+
if (end === -1) {
|
|
814
|
+
if (text.length - i <= MAX_CARRY)
|
|
815
|
+
track.carry = text.slice(i);
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
if (end >= 0)
|
|
819
|
+
applyCsi(track.modes, text.slice(i + 2, end), text[end], replies);
|
|
820
|
+
i = text.indexOf("\x1B", end >= 0 ? end + 1 : i + 2);
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
if (next === 61)
|
|
824
|
+
track.modes.applicationKeypad = true;
|
|
825
|
+
else if (next === 62)
|
|
826
|
+
track.modes.applicationKeypad = false;
|
|
827
|
+
else if (next === 99)
|
|
828
|
+
track.modes = { ...DEFAULT_MODES };
|
|
829
|
+
i = text.indexOf("\x1B", i + 1);
|
|
830
|
+
}
|
|
831
|
+
return replies;
|
|
832
|
+
}
|
|
833
|
+
function terminalModePreamble(modes) {
|
|
834
|
+
const set = [];
|
|
835
|
+
const reset = [];
|
|
836
|
+
if (modes.applicationCursorKeys)
|
|
837
|
+
set.push(1);
|
|
838
|
+
if (modes.origin)
|
|
839
|
+
set.push(6);
|
|
840
|
+
if (!modes.wraparound)
|
|
841
|
+
reset.push(7);
|
|
842
|
+
if (modes.cursorBlink)
|
|
843
|
+
set.push(12);
|
|
844
|
+
if (!modes.cursorVisible)
|
|
845
|
+
reset.push(25);
|
|
846
|
+
if (modes.reverseWraparound)
|
|
847
|
+
set.push(45);
|
|
848
|
+
for (const [mode, protocol] of Object.entries(MOUSE_PROTOCOLS))
|
|
849
|
+
if (modes.mouseProtocol === protocol)
|
|
850
|
+
set.push(+mode);
|
|
851
|
+
for (const [mode, encoding] of Object.entries(MOUSE_ENCODINGS))
|
|
852
|
+
if (modes.mouseEncoding === encoding)
|
|
853
|
+
set.push(+mode);
|
|
854
|
+
if (modes.sendFocus)
|
|
855
|
+
set.push(1004);
|
|
856
|
+
if (modes.bracketedPaste)
|
|
857
|
+
set.push(2004);
|
|
858
|
+
let out = modes.altScreen ? "\x1B[?1049h" : "";
|
|
859
|
+
if (set.length > 0)
|
|
860
|
+
out += `\x1B[?${set.join(";")}h`;
|
|
861
|
+
if (reset.length > 0)
|
|
862
|
+
out += `\x1B[?${reset.join(";")}l`;
|
|
863
|
+
if (modes.applicationKeypad)
|
|
864
|
+
out += "\x1B=";
|
|
865
|
+
if (modes.insertMode)
|
|
866
|
+
out += "\x1B[4h";
|
|
867
|
+
return out;
|
|
868
|
+
}
|
|
869
|
+
function csiEnd(text, from) {
|
|
870
|
+
for (let j = from;j < text.length; j++) {
|
|
871
|
+
const c = text.charCodeAt(j);
|
|
872
|
+
if (c >= 64 && c <= 126)
|
|
873
|
+
return j;
|
|
874
|
+
if (c < 32 || c > 63)
|
|
875
|
+
return -2;
|
|
876
|
+
}
|
|
877
|
+
return -1;
|
|
878
|
+
}
|
|
879
|
+
function applyCsi(modes, body, final, replies) {
|
|
880
|
+
let start = 0;
|
|
881
|
+
let prefix = "";
|
|
882
|
+
const first = body.charCodeAt(0);
|
|
883
|
+
if (first >= 60 && first <= 63) {
|
|
884
|
+
prefix = body[0];
|
|
885
|
+
start = 1;
|
|
886
|
+
}
|
|
887
|
+
let end = body.length;
|
|
888
|
+
while (end > start && body.charCodeAt(end - 1) <= 47)
|
|
889
|
+
end--;
|
|
890
|
+
const intermediates = body.slice(end);
|
|
891
|
+
const params = body.slice(start, end).split(";").map((param) => Number.parseInt(param.split(":")[0] ?? "", 10) || 0);
|
|
892
|
+
if (intermediates === "" && (final === "h" || final === "l")) {
|
|
893
|
+
const on = final === "h";
|
|
894
|
+
if (prefix === "?")
|
|
895
|
+
for (const mode of params)
|
|
896
|
+
setPrivateMode(modes, mode, on);
|
|
897
|
+
else if (prefix === "" && params.includes(4))
|
|
898
|
+
modes.insertMode = on;
|
|
899
|
+
} else if (intermediates === "$" && final === "p" && (prefix === "?" || prefix === "")) {
|
|
900
|
+
const mode = params[0] ?? 0;
|
|
901
|
+
const value = prefix === "?" ? privateModeValue(modes, mode) : ansiModeValue(modes, mode);
|
|
902
|
+
replies.push(`\x1B[${prefix}${mode};${value}$y`);
|
|
903
|
+
} else if (intermediates === "!" && final === "p" && prefix === "") {
|
|
904
|
+
softReset(modes);
|
|
905
|
+
} else if (intermediates === "" && final === "c" && prefix === "" && (params[0] ?? 0) === 0) {
|
|
906
|
+
replies.push(DA1_REPLY);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
function setPrivateMode(modes, mode, on) {
|
|
910
|
+
if (mode in MOUSE_PROTOCOLS) {
|
|
911
|
+
modes.mouseProtocol = on ? MOUSE_PROTOCOLS[mode] : "none";
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
if (mode in MOUSE_ENCODINGS) {
|
|
915
|
+
modes.mouseEncoding = on ? MOUSE_ENCODINGS[mode] : "default";
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
switch (mode) {
|
|
919
|
+
case 1:
|
|
920
|
+
modes.applicationCursorKeys = on;
|
|
921
|
+
break;
|
|
922
|
+
case 6:
|
|
923
|
+
modes.origin = on;
|
|
924
|
+
break;
|
|
925
|
+
case 7:
|
|
926
|
+
modes.wraparound = on;
|
|
927
|
+
break;
|
|
928
|
+
case 12:
|
|
929
|
+
modes.cursorBlink = on;
|
|
930
|
+
break;
|
|
931
|
+
case 25:
|
|
932
|
+
modes.cursorVisible = on;
|
|
933
|
+
break;
|
|
934
|
+
case 45:
|
|
935
|
+
modes.reverseWraparound = on;
|
|
936
|
+
break;
|
|
937
|
+
case 66:
|
|
938
|
+
modes.applicationKeypad = on;
|
|
939
|
+
break;
|
|
940
|
+
case 1004:
|
|
941
|
+
modes.sendFocus = on;
|
|
942
|
+
break;
|
|
943
|
+
case 47:
|
|
944
|
+
case 1047:
|
|
945
|
+
case 1049:
|
|
946
|
+
modes.altScreen = on;
|
|
947
|
+
break;
|
|
948
|
+
case 2004:
|
|
949
|
+
modes.bracketedPaste = on;
|
|
950
|
+
break;
|
|
951
|
+
case 2026:
|
|
952
|
+
modes.synchronizedOutput = on;
|
|
953
|
+
break;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
function softReset(modes) {
|
|
957
|
+
Object.assign(modes, {
|
|
958
|
+
applicationCursorKeys: false,
|
|
959
|
+
applicationKeypad: false,
|
|
960
|
+
origin: false,
|
|
961
|
+
wraparound: true,
|
|
962
|
+
reverseWraparound: false,
|
|
963
|
+
cursorVisible: true,
|
|
964
|
+
insertMode: false,
|
|
965
|
+
sendFocus: false,
|
|
966
|
+
bracketedPaste: false,
|
|
967
|
+
synchronizedOutput: false
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
var NOT_RECOGNIZED = 0;
|
|
971
|
+
var SET = 1;
|
|
972
|
+
var RESET = 2;
|
|
973
|
+
var PERMANENTLY_SET = 3;
|
|
974
|
+
var PERMANENTLY_RESET = 4;
|
|
975
|
+
var flag = (on) => on ? SET : RESET;
|
|
976
|
+
function privateModeValue(modes, mode) {
|
|
977
|
+
if (mode in MOUSE_PROTOCOLS)
|
|
978
|
+
return flag(modes.mouseProtocol === MOUSE_PROTOCOLS[mode]);
|
|
979
|
+
if (mode in MOUSE_ENCODINGS)
|
|
980
|
+
return flag(modes.mouseEncoding === MOUSE_ENCODINGS[mode]);
|
|
981
|
+
switch (mode) {
|
|
982
|
+
case 1:
|
|
983
|
+
return flag(modes.applicationCursorKeys);
|
|
984
|
+
case 6:
|
|
985
|
+
return flag(modes.origin);
|
|
986
|
+
case 7:
|
|
987
|
+
return flag(modes.wraparound);
|
|
988
|
+
case 8:
|
|
989
|
+
return PERMANENTLY_SET;
|
|
990
|
+
case 12:
|
|
991
|
+
return flag(modes.cursorBlink);
|
|
992
|
+
case 25:
|
|
993
|
+
return flag(modes.cursorVisible);
|
|
994
|
+
case 45:
|
|
995
|
+
return flag(modes.reverseWraparound);
|
|
996
|
+
case 66:
|
|
997
|
+
return flag(modes.applicationKeypad);
|
|
998
|
+
case 67:
|
|
999
|
+
case 1005:
|
|
1000
|
+
case 1015:
|
|
1001
|
+
return PERMANENTLY_RESET;
|
|
1002
|
+
case 1004:
|
|
1003
|
+
return flag(modes.sendFocus);
|
|
1004
|
+
case 1048:
|
|
1005
|
+
return SET;
|
|
1006
|
+
case 47:
|
|
1007
|
+
case 1047:
|
|
1008
|
+
case 1049:
|
|
1009
|
+
return flag(modes.altScreen);
|
|
1010
|
+
case 2004:
|
|
1011
|
+
return flag(modes.bracketedPaste);
|
|
1012
|
+
case 2026:
|
|
1013
|
+
return flag(modes.synchronizedOutput);
|
|
1014
|
+
default:
|
|
1015
|
+
return NOT_RECOGNIZED;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
function ansiModeValue(modes, mode) {
|
|
1019
|
+
switch (mode) {
|
|
1020
|
+
case 2:
|
|
1021
|
+
return PERMANENTLY_RESET;
|
|
1022
|
+
case 4:
|
|
1023
|
+
return flag(modes.insertMode);
|
|
1024
|
+
case 12:
|
|
1025
|
+
return PERMANENTLY_SET;
|
|
1026
|
+
case 20:
|
|
1027
|
+
return RESET;
|
|
1028
|
+
default:
|
|
1029
|
+
return NOT_RECOGNIZED;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
761
1033
|
// ../kobe-daemon/src/daemon/pty-freeze-store.ts
|
|
762
1034
|
var FREEZE_VERSION = 1;
|
|
763
1035
|
function freezeSession(session, now = new Date) {
|
|
@@ -772,6 +1044,7 @@ function freezeSession(session, now = new Date) {
|
|
|
772
1044
|
totalBytes: session.totalBytes,
|
|
773
1045
|
exit: session.exit,
|
|
774
1046
|
ringB64: Buffer.concat(session.chunks).toString("base64"),
|
|
1047
|
+
...session.ringModes ? { ringModes: session.ringModes.modes } : {},
|
|
775
1048
|
updatedAt: now.toISOString()
|
|
776
1049
|
};
|
|
777
1050
|
}
|
|
@@ -782,13 +1055,20 @@ function thawRing(record, cap) {
|
|
|
782
1055
|
} catch {
|
|
783
1056
|
return null;
|
|
784
1057
|
}
|
|
785
|
-
const
|
|
786
|
-
|
|
1058
|
+
const cut = Math.max(0, ring.byteLength - cap);
|
|
1059
|
+
const trimmed = ring.subarray(cut);
|
|
1060
|
+
const ringModes = freshModeTrack(normalizeTerminalModes(record.ringModes));
|
|
1061
|
+
if (cut > 0)
|
|
1062
|
+
scanTerminalModes(ringModes, ring.subarray(0, cut).toString("latin1"));
|
|
1063
|
+
return { chunks: trimmed.byteLength > 0 ? [trimmed] : [], bytes: trimmed.byteLength, ringModes };
|
|
787
1064
|
}
|
|
788
1065
|
function thawSession(record, cap) {
|
|
789
1066
|
const ring = thawRing(record, cap);
|
|
790
1067
|
if (!ring)
|
|
791
1068
|
return null;
|
|
1069
|
+
const modes = freshModeTrack({ ...ring.ringModes.modes });
|
|
1070
|
+
for (const chunk of ring.chunks)
|
|
1071
|
+
scanTerminalModes(modes, chunk.toString("latin1"));
|
|
792
1072
|
return {
|
|
793
1073
|
key: record.key,
|
|
794
1074
|
generation: randomUUID3(),
|
|
@@ -806,7 +1086,10 @@ function thawSession(record, cap) {
|
|
|
806
1086
|
titleDecoder: new StringDecoder("utf8"),
|
|
807
1087
|
colorQueryCarry: "",
|
|
808
1088
|
defaultColors: DEFAULT_TERMINAL_COLORS,
|
|
1089
|
+
modes,
|
|
1090
|
+
ringModes: ring.ringModes,
|
|
809
1091
|
sinks: new Map,
|
|
1092
|
+
emulatorSinks: new Set,
|
|
810
1093
|
parked: false,
|
|
811
1094
|
parkedScreenBytes: 0,
|
|
812
1095
|
exit: record.exit,
|
|
@@ -1033,7 +1316,10 @@ function freshSessionState(key, spec, argv) {
|
|
|
1033
1316
|
titleDecoder: new StringDecoder2("utf8"),
|
|
1034
1317
|
colorQueryCarry: "",
|
|
1035
1318
|
defaultColors: parseTerminalDefaultColors(spec.defaultColors) ?? DEFAULT_TERMINAL_COLORS,
|
|
1319
|
+
modes: freshModeTrack(),
|
|
1320
|
+
ringModes: freshModeTrack(),
|
|
1036
1321
|
sinks: new Map,
|
|
1322
|
+
emulatorSinks: new Set,
|
|
1037
1323
|
parked: false,
|
|
1038
1324
|
parkedScreenBytes: 0,
|
|
1039
1325
|
exit: null,
|
|
@@ -1256,11 +1542,16 @@ class PtyChildController {
|
|
|
1256
1542
|
}
|
|
1257
1543
|
onData(session, data) {
|
|
1258
1544
|
const buf = typeof data === "string" ? Buffer.from(data, "utf8") : Buffer.from(data);
|
|
1259
|
-
const
|
|
1545
|
+
const text = buf.toString("latin1");
|
|
1546
|
+
const colorQueries = foldDefaultColorQueries(session.colorQueryCarry, text);
|
|
1260
1547
|
session.colorQueryCarry = colorQueries.carry;
|
|
1261
|
-
|
|
1548
|
+
const replies = colorQueries.slots.map((slot) => formatDefaultColorReply(slot, session.defaultColors));
|
|
1549
|
+
const modeReplies = scanTerminalModes(session.modes, text);
|
|
1550
|
+
if (session.emulatorSinks.size === 0)
|
|
1551
|
+
replies.push(...modeReplies);
|
|
1552
|
+
if (replies.length > 0) {
|
|
1262
1553
|
try {
|
|
1263
|
-
session.proc?.write(
|
|
1554
|
+
session.proc?.write(replies.join(""));
|
|
1264
1555
|
} catch {}
|
|
1265
1556
|
}
|
|
1266
1557
|
scanOscTitle(session, buf);
|
|
@@ -1269,8 +1560,10 @@ class PtyChildController {
|
|
|
1269
1560
|
session.totalBytes += buf.byteLength;
|
|
1270
1561
|
while (session.bytes > this.deps.scrollbackCap && session.chunks.length > 1) {
|
|
1271
1562
|
const dropped = session.chunks.shift();
|
|
1272
|
-
if (dropped)
|
|
1273
|
-
|
|
1563
|
+
if (!dropped)
|
|
1564
|
+
break;
|
|
1565
|
+
session.bytes -= dropped.byteLength;
|
|
1566
|
+
scanTerminalModes(session.ringModes, dropped.toString("latin1"));
|
|
1274
1567
|
}
|
|
1275
1568
|
this.deps.onOutput?.(session, buf);
|
|
1276
1569
|
}
|
|
@@ -1412,7 +1705,7 @@ class PtyHost {
|
|
|
1412
1705
|
onSessionStart: () => this.opts.onSessionStart?.()
|
|
1413
1706
|
});
|
|
1414
1707
|
}
|
|
1415
|
-
open(key, spec, token, sink, sinceOffset, sincePid) {
|
|
1708
|
+
open(key, spec, token, sink, sinceOffset, sincePid, answersQueries = false) {
|
|
1416
1709
|
let session = this.sessions.get(key);
|
|
1417
1710
|
let created = false;
|
|
1418
1711
|
let respawned = false;
|
|
@@ -1430,6 +1723,10 @@ class PtyHost {
|
|
|
1430
1723
|
if (defaultColors)
|
|
1431
1724
|
session.defaultColors = defaultColors;
|
|
1432
1725
|
session.sinks.set(token, sink);
|
|
1726
|
+
if (answersQueries)
|
|
1727
|
+
session.emulatorSinks.add(token);
|
|
1728
|
+
else
|
|
1729
|
+
session.emulatorSinks.delete(token);
|
|
1433
1730
|
session.parked = false;
|
|
1434
1731
|
session.parkedScreenBytes = 0;
|
|
1435
1732
|
const windowStart = session.totalBytes - session.bytes;
|
|
@@ -1445,6 +1742,8 @@ class PtyHost {
|
|
|
1445
1742
|
else
|
|
1446
1743
|
this.parkRestoreFallbacks++;
|
|
1447
1744
|
}
|
|
1745
|
+
if (!sinceValid)
|
|
1746
|
+
replay = Buffer.concat([Buffer.from(terminalModePreamble(session.ringModes.modes), "latin1"), replay]);
|
|
1448
1747
|
return {
|
|
1449
1748
|
replay: replay.toString("base64"),
|
|
1450
1749
|
alive: session.alive,
|
|
@@ -1516,10 +1815,12 @@ class PtyHost {
|
|
|
1516
1815
|
if (!session)
|
|
1517
1816
|
return;
|
|
1518
1817
|
session.sinks.delete(token);
|
|
1818
|
+
session.emulatorSinks.delete(token);
|
|
1519
1819
|
this.applyParkedOnDetach(session, parked, parkedScreenBytes);
|
|
1520
1820
|
}
|
|
1521
1821
|
detachClient(token) {
|
|
1522
1822
|
for (const session of this.sessions.values()) {
|
|
1823
|
+
session.emulatorSinks.delete(token);
|
|
1523
1824
|
if (!session.sinks.delete(token))
|
|
1524
1825
|
continue;
|
|
1525
1826
|
this.applyParkedOnDetach(session);
|
|
@@ -1642,7 +1943,7 @@ function dispatchPtyRequest(req, client, deps) {
|
|
|
1642
1943
|
cols: typeof payload.cols === "number" ? payload.cols : undefined,
|
|
1643
1944
|
rows: typeof payload.rows === "number" ? payload.rows : undefined,
|
|
1644
1945
|
defaultColors: parseTerminalDefaultColors(payload.defaultColors) ?? undefined
|
|
1645
|
-
}, client, (frame) => deps.writeFrame(client, frame), typeof payload.sinceOffset === "number" ? payload.sinceOffset : undefined, typeof payload.sincePid === "number" ? payload.sincePid : undefined);
|
|
1946
|
+
}, client, (frame) => deps.writeFrame(client, frame), typeof payload.sinceOffset === "number" ? payload.sinceOffset : undefined, typeof payload.sincePid === "number" ? payload.sincePid : undefined, payload.answersQueries === true);
|
|
1646
1947
|
}
|
|
1647
1948
|
case "pty.write": {
|
|
1648
1949
|
const payload = objectPayload(req.payload);
|
package/dist/cli/rove.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{join as G1}from"node:path";import{createInterface as K1}from"node:readline/promises";import{pathToFileURL as U1}from"node:url";import{spawnSync as V}from"node:child_process";import{constants as a,accessSync as e}from"node:fs";import{homedir as W1}from"node:os";import{basename as z1,delimiter as J1,dirname as Q1,join as G}from"node:path";import{fileURLToPath as N}from"node:url";var M={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.
|
|
2
|
+
import{join as G1}from"node:path";import{createInterface as K1}from"node:readline/promises";import{pathToFileURL as U1}from"node:url";import{spawnSync as V}from"node:child_process";import{constants as a,accessSync as e}from"node:fs";import{homedir as W1}from"node:os";import{basename as z1,delimiter as J1,dirname as Q1,join as G}from"node:path";import{fileURLToPath as N}from"node:url";var M={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/rove",version:"0.9.238",description:"Rove — the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",keywords:["terminal","tui","cli","multiplexer","ai-agents","coding-agent","ai-coding-assistant","agentic-ai","parallel-agents","git-worktree","claude-code","codex","llm","developer-tools"],type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/kobe.js",rove:"dist/cli/rove.js"},files:["dist/cli","dist/completions","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/rove.git"},homepage:"https://rove.run",bugs:{url:"https://github.com/Sma1lboy/rove/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"ROVE_DEV=1 bun --conditions=browser ./src/cli/rove.ts","dev:kobe":"KOBE_DEV=1 bun --conditions=browser ./src/cli/kobe.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:rubric":"bun run scripts/build-tier-rubric.ts",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun scripts/render-track.mjs",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build","plugin-sandbox":"bun run scripts/plugin-sandbox.ts"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8","smol-toml":"^1.7.1",ws:"^8.21.3"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.19","@tsconfig/bun":"1.0.11","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]};var O="rove",T="kobe";var I=T;var L=O;var t="ROVE_INVOKED_AS";function K(W=process.env){return W[t]===L?L:I}var U="ROVE_BUN",Z1="ROVE_NO_BUN_BOOTSTRAP",R="ROVE_SKIP_BUN_CHECK",x=M.engines.bun.match(/\d+\.\d+\.\d+/)?.[0]??"0.0.0",y=(W)=>{try{return e(W,a.X_OK),!0}catch{return!1}},$1=(W)=>W==="win32"?"bun.exe":"bun",X1=(W)=>{let z=V(W,["--version"],{encoding:"utf8",timeout:5000});if(z.error||z.status!==0)return null;return z.stdout?.split(`
|
|
3
3
|
`)[0]?.trim()??""};function F(W){return W.trim().match(/^v?(\d+\.\d+\.\d+)/)?.[1]??null}function C(W,z=x){let J=F(W),$=F(z);if(!J||!$)return!0;let Z=J.split(".").map(Number),Q=$.split(".").map(Number);for(let X=0;X<3;X++){let Y=Z[X]??0,b=Q[X]??0;if(Y!==b)return Y>b}return!0}function j(W=process.env){return W[R]==="1"}function k(W={}){let z=W.env??process.env,J=W.platform??process.platform,$=W.home??z.HOME??z.USERPROFILE??W1(),Z=$1(J),Q=[],X=z[U]?.trim();if(X)Q.push(X);for(let w of(z.PATH??z.Path??"").split(J1))if(w)Q.push(G(w,Z));let Y=z.BUN_INSTALL?.trim();if(Y)Q.push(G(Y,"bin",Z));if($)Q.push(G($,".bun","bin",Z));let b=W.launcherDir;if(b)Q.push(G(b,"..","..","node_modules","bun","bin",Z)),Q.push(G(b,"..","..","..","bun","bin",Z));return Q}function q1(W={}){let z=W.isExecutable??y;return k(W).find((J)=>z(J))??null}function B(W={}){let z=W.isExecutable??y,J=W.bunVersionOf??X1;if(j(W.env??process.env))return{bun:q1(W),stale:null,unusable:null};let $=null,Z=null;for(let Q of k(W)){if(!z(Q))continue;let X=J(Q);if(X===null){Z??=Q;continue}if(C(X))return{bun:Q,stale:$,unusable:Z};$??={path:Q,version:F(X)??X}}return{bun:null,stale:$,unusable:Z}}function _(W){return Q1(N(W))}function P(W){return z1(N(W)).replace(/\.[cm]?[jt]s$/,"")}function b1(W=process.platform){return W==="win32"?["powershell","-NoProfile","-Command","irm bun.sh/install.ps1 | iex"]:["bash","-c","curl -fsSL https://bun.sh/install | bash"]}function D(W=K(),z=process.platform){let J=z==="win32"?'powershell -c "irm bun.sh/install.ps1 | iex"':"curl -fsSL https://bun.sh/install | bash";return[`${W}: Rove runs on the Bun runtime, and no Bun was found on this machine.`,"","Install Bun, then run this command again:",` ${J}`," npm install -g bun # any platform, if you already have npm","","Or install Bun and Rove together in one step:"," curl -fsSL https://rove.run/install.sh | sh","",`Already have Bun somewhere unusual? Point Rove at it: ${U}=/path/to/bun`,""].join(`
|
|
4
4
|
`)}function g(W,z,J=K()){return[`${J}: this machine's Bun is too old for Rove — found ${z} at ${W}, need ${x} or newer.`,"","Rove's terminals are built on Bun's PTY API. An older Bun ignores it silently,","so every terminal and engine tab would open empty and stay empty.","","Upgrade Bun, then run this command again:"," bun upgrade # Bun installed itself (~/.bun)"," brew upgrade bun # Homebrew"," npm install -g bun@latest # npm-managed Bun","",`Have a newer Bun elsewhere? Point Rove at it: ${U}=/path/to/bun`,`Run on this one anyway (unsupported, terminals will be blank): ${R}=1`,""].join(`
|
|
5
5
|
`)}function p(W,z=K()){return[`${z}: the Bun at ${W} could not be run — \`${W} --version\` failed or never returned.`,"","Rove skipped it rather than starting through it, which would hang or fail","with a message from that binary instead of this one.","","Reinstall Bun, then run this command again:"," curl -fsSL https://bun.sh/install | bash","",`Have a working Bun elsewhere? Point Rove at it: ${U}=/path/to/bun`,""].join(`
|