git-metadata.ts
1 import { execFileSync } from 'node:child_process' 2 3 /** 4 * Pure helpers for reading git metadata at runtime, with graceful degradation 5 * when the working directory is not a git checkout (Docker production image, 6 * npm tarball install, etc.). 7 * 8 * Always uses `execFileSync` with an arg array (no shell) so user input cannot 9 * influence the command line. 10 */ 11 export function safeGit(args: string[], cwd: string = process.cwd()): string | null { 12 try { 13 const out = execFileSync('git', args, { 14 cwd, 15 encoding: 'utf-8', 16 timeout: 15_000, 17 stdio: ['ignore', 'pipe', 'ignore'], 18 }) 19 return typeof out === 'string' ? out.trim() : null 20 } catch { 21 return null 22 } 23 } 24 25 let cachedAvailable: boolean | null = null 26 27 /** 28 * Returns true when the current working directory looks like a git checkout 29 * (i.e. `git rev-parse --git-dir` succeeds). Cached for the lifetime of the 30 * process, since the answer does not change while a server is running. 31 * 32 * Exported `resetGitAvailableCache` is for unit tests only. 33 */ 34 export function gitAvailable(): boolean { 35 if (cachedAvailable !== null) return cachedAvailable 36 cachedAvailable = safeGit(['rev-parse', '--git-dir']) !== null 37 return cachedAvailable 38 } 39 40 export function resetGitAvailableCache(): void { 41 cachedAvailable = null 42 }