/** * Utility for checking git availability. * * Git is required for installing GitHub-based marketplaces. This module * provides a memoized check to determine if git is available on the system. */ import memoize from 'lodash-es/memoize.js' import { which } from '../which.js' /** * Check if a command is available in PATH. * * Uses which to find the actual executable without executing it. * This is a security best practice to avoid executing arbitrary code * in untrusted directories. * * @param command - The command to check for * @returns True if the command exists and is executable */ async function isCommandAvailable(command: string): Promise { try { return !!(await which(command)) } catch { return false } } /** * Check if git is available on the system. * * This is memoized so repeated calls within a session return the cached result. * Git availability is unlikely to change during a single CLI session. * * Only checks PATH — does not exec git. On macOS this means the /usr/bin/git * xcrun shim passes even without Xcode CLT installed; callers that hit * `xcrun: error:` at exec time should call markGitUnavailable() so the rest * of the session behaves as though git is absent. * * @returns True if git is installed and executable */ export const checkGitAvailable = memoize(async (): Promise => { return isCommandAvailable('git') }) /** * Force the memoized git-availability check to return false for the rest of * the session. * * Call this when a git invocation fails in a way that indicates the binary * exists on PATH but cannot actually run — the macOS xcrun shim being the * main case (`xcrun: error: invalid active developer path`). Subsequent * checkGitAvailable() calls then short-circuit to false, so downstream code * that guards on git availability skips cleanly instead of failing repeatedly * with the same exec error. * * lodash memoize uses a no-arg cache key of undefined. */ export function markGitUnavailable(): void { checkGitAvailable.cache?.set?.(undefined, Promise.resolve(false)) } /** * Clear the git availability cache. * Used for testing purposes. */ export function clearGitAvailabilityCache(): void { checkGitAvailable.cache?.clear?.() }