/** * v2.3 phase 2: tier-1 fast availability check — is a binary on PATH? * * Uses execFile (NO shell) because the binary name can come from the provider * config file (custom ACP entries) — mirrors the Phase 1 agent-probe hardening. * Note: agent-probe's `whichBinary` returns the resolved path (it needs it for * `install_path`); this returns a boolean. Kept separate rather than over- * refactored into one helper — different return contracts, two short call sites. */ import { execFile as execFileCb } from 'node:child_process'; import { promisify } from 'node:util'; const execFile = promisify(execFileCb); export async function isCommandAvailable(binary: string): Promise { try { const { stdout } = await execFile('which', [binary], { timeout: 10_000 }); return stdout.trim().length > 0; } catch { return false; } }