sandlot save <branch>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
19a1d0c563
commit
967b3f4512
52
src/cli.ts
52
src/cli.ts
|
|
@ -126,6 +126,58 @@ program
|
||||||
.argument("<branch>", "branch name")
|
.argument("<branch>", "branch name")
|
||||||
.action(closeAction)
|
.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 ───────────────────────────────────────────────────────
|
// ── sandlot vm ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
const vmCmd = program.command("vm").description("Manage the sandlot VM")
|
const vmCmd = program.command("vm").description("Manage the sandlot VM")
|
||||||
|
|
|
||||||
10
src/vm.ts
10
src/vm.ts
|
|
@ -89,6 +89,16 @@ export async function info(): Promise<void> {
|
||||||
await proc.exited
|
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. */
|
/** Stop the VM. */
|
||||||
export async function stop(): Promise<void> {
|
export async function stop(): Promise<void> {
|
||||||
await $`limactl stop ${VM_NAME}`.nothrow().quiet()
|
await $`limactl stop ${VM_NAME}`.nothrow().quiet()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user