From ec1f6796b8fa2362fdc23c9ff3df05dfdd72b795 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Mon, 23 Feb 2026 19:14:58 -0800 Subject: [PATCH] Add `edit` command to open session files in $EDITOR --- src/cli.ts | 8 ++++++++ src/commands/edit.ts | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/commands/edit.ts diff --git a/src/cli.ts b/src/cli.ts index 5a0c3eb..45e0ccb 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -18,6 +18,7 @@ import { action as diffAction } from "./commands/diff.ts" import { action as showAction } from "./commands/show.ts" import { action as logAction } from "./commands/log.ts" import { action as dirAction } from "./commands/dir.ts" +import { action as editAction } from "./commands/edit.ts" import { action as cleanupAction } from "./commands/cleanup.ts" import { register as registerVmCommands } from "./commands/vm.ts" import { action as completionsAction } from "./commands/completions.ts" @@ -139,6 +140,13 @@ program .description("Open a shell in the VM") .action(shellAction) +program + .command("edit") + .argument("", "branch name") + .argument("", "file path relative to worktree root") + .description("Open a file from a session in $EDITOR") + .action(editAction) + program .command("dir") .argument("", "branch name") diff --git a/src/commands/edit.ts b/src/commands/edit.ts new file mode 100644 index 0000000..f7fbd6e --- /dev/null +++ b/src/commands/edit.ts @@ -0,0 +1,35 @@ +import { resolve } from "path" +import { existsSync } from "fs" +import { die } from "../fmt.ts" +import { requireSession } from "./helpers.ts" + +export async function action(branch: string, file: string) { + const editor = process.env.EDITOR + if (!editor) { + die("$EDITOR is not set.") + } + + const { session } = await requireSession(branch) + const worktree = resolve(session.worktree) + const path = resolve(worktree, file) + + if (!path.startsWith(worktree + "/") && path !== worktree) { + die("File path escapes the worktree.") + } + + if (!existsSync(path)) { + die(`File not found: ${file}`) + } + + const [cmd, ...args] = editor.split(/\s+/) + const proc = Bun.spawn([cmd, ...args, path], { + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }) + + const exitCode = await proc.exited + if (exitCode !== 0) { + die(`Editor exited with code ${exitCode}.`) + } +}