import { existsSync } from "fs" import { rm } from "fs/promises" import { $ } from "bun" /** Get the repo root from a working directory. */ export async function repoRoot(cwd?: string): Promise { const result = await $`git rev-parse --show-toplevel`.cwd(cwd ?? ".").text() return result.trim() } /** Get the current branch name. */ export async function currentBranch(cwd?: string): Promise { const result = await $`git rev-parse --abbrev-ref HEAD`.cwd(cwd ?? ".").text() return result.trim() } /** Check if a branch exists locally or remotely. Returns "local", "remote", or null. */ export async function branchExists(branch: string, cwd?: string): Promise<"local" | "remote" | null> { const dir = cwd ?? "." const local = await $`git show-ref --verify --quiet refs/heads/${branch}`.cwd(dir).nothrow().quiet() if (local.exitCode === 0) return "local" await $`git fetch origin`.cwd(dir).nothrow().quiet() const remote = await $`git show-ref --verify --quiet refs/remotes/origin/${branch}`.cwd(dir).nothrow().quiet() if (remote.exitCode === 0) return "remote" return null } /** Create a worktree for the given branch. */ export async function createWorktree(branch: string, worktreePath: string, cwd: string): Promise { // Clean up stale worktree path if it exists if (existsSync(worktreePath)) { await $`git worktree remove ${worktreePath} --force`.cwd(cwd).nothrow().quiet() if (existsSync(worktreePath)) { await rm(worktreePath, { recursive: true }) } } await $`git worktree prune`.cwd(cwd).nothrow().quiet() const exists = await branchExists(branch, cwd) if (exists === "local") { await $`git worktree add ${worktreePath} ${branch}`.cwd(cwd).quiet() } else if (exists === "remote") { await $`git worktree add ${worktreePath} -b ${branch} origin/${branch}`.cwd(cwd).quiet() } else { // New branch from current HEAD await $`git worktree add -b ${branch} ${worktreePath}`.cwd(cwd).quiet() } } /** Remove a worktree. */ export async function removeWorktree(worktreePath: string, cwd: string): Promise { await $`git worktree remove ${worktreePath} --force`.cwd(cwd) } /** Delete a local branch. */ export async function deleteLocalBranch(branch: string, cwd: string): Promise { await $`git branch -D ${branch}`.cwd(cwd).nothrow() } /** Checkout a branch. */ export async function checkout(branch: string, cwd: string): Promise { await $`git checkout ${branch}`.cwd(cwd) }