/** * Git command runner * @module orch/git */ import { execFileSync } from "child_process"; // ── Branch Helpers ─────────────────────────────────────────────────── /** * Get the current branch name (the branch checked out in the given directory). * * Uses `git rev-parse --abbrev-ref HEAD`. Returns the branch name or null * if HEAD is detached or git fails. * * @param cwd - Working directory (defaults to process.cwd()) */ export function getCurrentBranch(cwd?: string): string | null { const result = runGit(["rev-parse", "--abbrev-ref", "HEAD"], cwd); if (!result.ok || !result.stdout.trim() || result.stdout.trim() === "HEAD") { return null; } return result.stdout.trim(); } // ── Git Command Runner ─────────────────────────────────────────────── /** * Run a git command synchronously with consistent error handling. * * @param args - Array of git subcommand arguments (e.g. ["worktree", "add", ...]) * @param cwd - Working directory to run the command in (defaults to process.cwd()) * @returns - { ok, stdout, stderr } */ export function runGit( args: string[], cwd?: string, ): { ok: boolean; stdout: string; stderr: string } { try { const stdout = execFileSync("git", args, { encoding: "utf-8", timeout: 30_000, cwd: cwd || process.cwd(), stdio: ["pipe", "pipe", "pipe"], }).trim(); return { ok: true, stdout, stderr: "" }; } catch (err: unknown) { const e = err as { stdout?: string; stderr?: string; message?: string }; return { ok: false, stdout: (e.stdout ?? "").toString().trim(), stderr: (e.stderr ?? e.message ?? "unknown error").toString().trim(), }; } } /** * Run a git command with custom environment variables. * * Used by TP-169 to create commits on the orch branch without * modifying HEAD, via GIT_INDEX_FILE for alternate index manipulation. * * @param args - Git command arguments * @param cwd - Working directory * @param env - Additional environment variables to set */ export function runGitWithEnv( args: string[], cwd: string, env: Record, ): { ok: boolean; stdout: string; stderr: string } { try { const stdout = execFileSync("git", args, { encoding: "utf-8", timeout: 30_000, cwd, stdio: ["pipe", "pipe", "pipe"], env: { ...process.env, ...env }, }).trim(); return { ok: true, stdout, stderr: "" }; } catch (err: unknown) { const e = err as { stdout?: string; stderr?: string; message?: string }; return { ok: false, stdout: (e.stdout ?? "").toString().trim(), stderr: (e.stderr ?? e.message ?? "unknown error").toString().trim(), }; } }