import path from "node:path"; import { execFileSync } from "node:child_process"; export type GitWorkspaceInfo = { root: string; commonDir: string; gitDir: string; hooksPath: string; }; /** * Resolve the repository metadata Git exposes for both primary checkouts and * linked worktrees. Returns null outside a Git working tree. */ export function detectGitWorkspaceInfo(cwd: string): GitWorkspaceInfo | null { try { const root = execFileSync("git", ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], }).trim(); const commonDirRaw = execFileSync("git", ["rev-parse", "--git-common-dir"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], }).trim(); const gitDirRaw = execFileSync("git", ["rev-parse", "--git-dir"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], }).trim(); const hooksPathRaw = execFileSync("git", ["rev-parse", "--git-path", "hooks"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], }).trim(); return { root: path.resolve(root), commonDir: path.resolve(root, commonDirRaw), gitDir: path.resolve(root, gitDirRaw), hooksPath: path.resolve(root, hooksPathRaw), }; } catch { return null; } } export function isLinkedGitWorktree(cwd: string): boolean { const workspace = detectGitWorkspaceInfo(cwd); return Boolean(workspace && workspace.gitDir !== workspace.commonDir); }