diff --git a/src/cli.ts b/src/cli.ts index 67dc353..b982344 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -16,6 +16,58 @@ const program = new Command() program.name("sandlot").description("Branch-based development with git worktrees and Apple Container").version(pkg.version) +// ── save helper ───────────────────────────────────────────────────── + +/** Stage all changes, generate a commit message, and commit. Returns true on success. */ +async function saveChanges(worktree: string, message?: string): Promise { + const spin = spinner("Staging changes") + + await $`git -C ${worktree} add .`.nothrow().quiet() + + const check = await $`git -C ${worktree} diff --staged --quiet`.nothrow().quiet() + if (check.exitCode === 0) { + spin.fail("No changes to commit") + return false + } + + let msg: string + if (message) { + msg = message + } else { + spin.text = "Starting container" + await vm.ensure((m) => { spin.text = m }) + + spin.text = "Generating commit message" + const diff = await $`git -C ${worktree} diff --staged`.nothrow().quiet().text() + const tmpPath = join(homedir(), '.sandlot', '.sandlot-diff-tmp') + await Bun.write(tmpPath, diff) + + const gen = await vm.exec( + join(homedir(), '.sandlot'), + 'cat /sandlot/.sandlot-diff-tmp | claude -p "write a short commit message summarizing these changes. output only the message, no quotes or extra text"', + ) + await Bun.file(tmpPath).unlink().catch(() => {}) + + if (gen.exitCode !== 0) { + spin.fail("Failed to generate commit message") + if (gen.stderr) console.error(gen.stderr) + return false + } + msg = gen.stdout + } + + spin.text = "Committing" + const commit = await $`git -C ${worktree} commit -m ${msg}`.nothrow().quiet() + if (commit.exitCode !== 0) { + spin.fail("Commit failed") + if (commit.stderr) console.error(commit.stderr.toString().trim()) + return false + } + + spin.succeed(`Saved: ${msg}`) + return true +} + // ── sandlot new ────────────────────────────────────────────── program @@ -70,6 +122,8 @@ program if (opts.print) console.log(`Running prompt…`) await vm.claude(worktreeAbs, { prompt, print: opts.print }) + + await saveChanges(worktreeAbs) }) // ── sandlot list ────────────────────────────────────────────────────── @@ -229,54 +283,8 @@ program process.exit(1) } - const wt = session.worktree - const spin = spinner("Staging changes") - - // Run git on the host — the worktree's .git references host paths and - // ~/dev is mounted read-only in the container, so git must run here. - await $`git -C ${wt} add .`.nothrow().quiet() - - const check = await $`git -C ${wt} diff --staged --quiet`.nothrow().quiet() - if (check.exitCode === 0) { - spin.fail("No changes to commit") - process.exit(1) - } - - let msg: string - if (message) { - msg = message - } else { - spin.text = "Starting container" - await vm.ensure((m) => { spin.text = m }) - - spin.text = "Generating commit message" - const diff = await $`git -C ${wt} diff --staged`.nothrow().quiet().text() - const tmpPath = join(homedir(), '.sandlot', '.sandlot-diff-tmp') - await Bun.write(tmpPath, diff) - - const gen = await vm.exec( - join(homedir(), '.sandlot'), - 'cat /sandlot/.sandlot-diff-tmp | claude -p "write a short commit message summarizing these changes. output only the message, no quotes or extra text"', - ) - await Bun.file(tmpPath).unlink().catch(() => {}) - - if (gen.exitCode !== 0) { - spin.fail("Failed to generate commit message") - if (gen.stderr) console.error(gen.stderr) - process.exit(1) - } - msg = gen.stdout - } - - spin.text = "Committing" - const commit = await $`git -C ${wt} commit -m ${msg}`.nothrow().quiet() - if (commit.exitCode !== 0) { - spin.fail("Commit failed") - if (commit.stderr) console.error(commit.stderr.toString().trim()) - process.exit(1) - } - - spin.succeed(`Saved: ${msg}`) + const ok = await saveChanges(session.worktree, message) + if (!ok) process.exit(1) }) // ── sandlot diff ───────────────────────────────────────────