import { $ } from "bun" import * as git from "../git.ts" import * as vm from "../vm.ts" import { spinner } from "../spinner.ts" import { die } from "../fmt.ts" import { requireSession, resolveConflicts } from "./helpers.ts" const MAX_REBASE_ROUNDS = 10 export async function action(branch: string) { const { root, session } = await requireSession(branch) const worktree = session.worktree if (await git.isDirty(worktree)) { die(`Branch "${branch}" has unsaved changes. Run "sandlot save ${branch}" first.`) } const main = await git.mainBranch(root) const fetchSpin = spinner("Fetching origin", branch) await $`git -C ${root} fetch origin ${main}`.nothrow().quiet() fetchSpin.text = `Rebasing onto origin/${main}` let conflicts = await git.rebase(`origin/${main}`, worktree) if (conflicts.length === 0) { fetchSpin.succeed(`Rebased ${branch} onto ${main}`) return } fetchSpin.stop() console.log(`◆ Rebase conflicts in ${conflicts.length} file(s). Resolving with Claude...`) const resolveSpin = spinner("Starting container", branch) try { await vm.ensure((msg) => { resolveSpin.text = msg }) let round = 1 while (conflicts.length > 0) { if (round > MAX_REBASE_ROUNDS) { throw new Error(`Exceeded ${MAX_REBASE_ROUNDS} conflict resolution rounds — aborting rebase`) } await resolveConflicts(conflicts, worktree, (file) => { resolveSpin.text = `Resolving ${file} (round ${round})` }) conflicts = await git.rebaseContinue(worktree) round++ } resolveSpin.succeed(`Rebased ${branch} onto ${main} (resolved ${round - 1} conflict round(s))`) } catch (err) { resolveSpin.fail(String((err as Error).message ?? err)) await git.rebaseAbort(worktree) process.exit(1) } }