Add git status utility for TUI.

Provides GitStatus interface and refreshGitStatus function for displaying
repository branch, dirty state, untracked files, and commit counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ace-pm 2026-04-15 16:16:47 +02:00
parent e501ffeefd
commit 7e03021b25

View file

@ -0,0 +1,70 @@
import { execFileSync } from "node:child_process";
export interface GitStatus {
branch: string | null;
dirty: boolean;
untracked: boolean;
ahead: number;
behind: number;
}
let cache: GitStatus | null = null;
let lastFetch = 0;
export function refreshGitStatus(cwd: string): GitStatus {
const now = Date.now();
if (now - lastFetch < 400 && cache) return cache;
lastFetch = now;
let branch: string | null = null;
try {
branch = execFileSync("git", ["branch", "--show-current"], {
cwd,
encoding: "utf-8",
stdio: ["pipe", "pipe", "ignore"],
timeout: 1500,
}).trim() || null;
} catch {
cache = { branch: null, dirty: false, untracked: false, ahead: 0, behind: 0 };
return cache;
}
try {
const status = execFileSync("git", ["status", "--porcelain"], {
cwd,
encoding: "utf-8",
stdio: ["pipe", "pipe", "ignore"],
timeout: 1500,
});
const lines = status.split("\n").filter((l) => l.length > 2);
const dirty = lines.some((l) => {
const x = l[0] ?? " ";
const y = l[1] ?? " ";
return x !== "?" && x !== " " && x !== "!" || y !== " " && y !== "?";
});
const untracked = lines.some((l) => l.startsWith("??"));
let ahead = 0;
let behind = 0;
try {
const ab = execFileSync("git", ["rev-list", "--left-right", "--count", "HEAD...@{u}"], {
cwd,
encoding: "utf-8",
stdio: ["pipe", "pipe", "ignore"],
timeout: 1500,
}).trim();
const [a, b] = ab.split("\t").map((n) => parseInt(n, 10));
ahead = Number.isNaN(a) ? 0 : a;
behind = Number.isNaN(b) ? 0 : b;
} catch { /* no upstream */ }
cache = { branch, dirty, untracked, ahead, behind };
} catch {
cache = { branch, dirty: false, untracked: false, ahead: 0, behind: 0 };
}
return cache;
}
export function invalidateGitStatus(): void {
lastFetch = 0;
}