sandlot save <branch>

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Wanstrath 2026-02-17 19:15:24 -08:00
parent 19a1d0c563
commit 967b3f4512
2 changed files with 62 additions and 0 deletions

View File

@ -126,6 +126,58 @@ program
.argument("<branch>", "branch name")
.action(closeAction)
// ── sandlot save <branch> ───────────────────────────────────────────
program
.command("save")
.argument("<branch>", "branch name")
.description("Stage all changes and commit with an AI-generated message")
.action(async (branch: string) => {
const root = await git.repoRoot()
const session = await state.getSession(root, branch)
if (!session) {
console.error(`No session found for branch "${branch}".`)
process.exit(1)
}
const worktreeAbs = join(root, session.worktree)
const spin = spinner("Starting VM")
await vm.ensure()
spin.text = "Staging changes"
await vm.exec(worktreeAbs, "git add .")
const check = await vm.exec(worktreeAbs, "git diff --staged --quiet")
if (check.exitCode === 0) {
spin.fail("No changes to commit")
process.exit(1)
}
spin.text = "Generating commit message"
const gen = await vm.exec(
worktreeAbs,
'set -a; source ~/.env 2>/dev/null; set +a; git diff --staged | claude -p "write a short commit message summarizing these changes. output only the message, no quotes or extra text" > /tmp/sandlot_commit_msg',
)
if (gen.exitCode !== 0) {
spin.fail("Failed to generate commit message")
if (gen.stderr) console.error(gen.stderr)
process.exit(1)
}
spin.text = "Committing"
const commit = await vm.exec(worktreeAbs, "git commit -F /tmp/sandlot_commit_msg")
if (commit.exitCode !== 0) {
spin.fail("Commit failed")
if (commit.stderr) console.error(commit.stderr)
process.exit(1)
}
const { stdout: msg } = await vm.exec(worktreeAbs, "cat /tmp/sandlot_commit_msg")
await vm.exec(worktreeAbs, "rm -f /tmp/sandlot_commit_msg")
spin.succeed(`Saved: ${msg}`)
})
// ── sandlot vm ───────────────────────────────────────────────────────
const vmCmd = program.command("vm").description("Manage the sandlot VM")

View File

@ -89,6 +89,16 @@ export async function info(): Promise<void> {
await proc.exited
}
/** Run a bash command in the VM at the given workdir, capturing output. */
export async function exec(workdir: string, command: string): Promise<{ exitCode: number; stdout: string; stderr: string }> {
const result = await $`limactl shell --workdir=${workdir} ${VM_NAME} -- bash -c ${command}`.nothrow().quiet()
return {
exitCode: result.exitCode,
stdout: result.stdout.toString().trim(),
stderr: result.stderr.toString().trim(),
}
}
/** Stop the VM. */
export async function stop(): Promise<void> {
await $`limactl stop ${VM_NAME}`.nothrow().quiet()