/ src / utils / binaryCheck.ts
binaryCheck.ts
 1  import { logForDebugging } from './debug.js'
 2  import { which } from './which.js'
 3  
 4  // Session cache to avoid repeated checks
 5  const binaryCache = new Map<string, boolean>()
 6  
 7  /**
 8   * Check if a binary/command is installed and available on the system.
 9   * Uses 'which' on Unix systems (macOS, Linux, WSL) and 'where' on Windows.
10   *
11   * @param command - The command name to check (e.g., 'gopls', 'rust-analyzer')
12   * @returns Promise<boolean> - true if the command exists, false otherwise
13   */
14  export async function isBinaryInstalled(command: string): Promise<boolean> {
15    // Edge case: empty or whitespace-only command
16    if (!command || !command.trim()) {
17      logForDebugging('[binaryCheck] Empty command provided, returning false')
18      return false
19    }
20  
21    // Trim the command to handle whitespace
22    const trimmedCommand = command.trim()
23  
24    // Check cache first
25    const cached = binaryCache.get(trimmedCommand)
26    if (cached !== undefined) {
27      logForDebugging(
28        `[binaryCheck] Cache hit for '${trimmedCommand}': ${cached}`,
29      )
30      return cached
31    }
32  
33    let exists = false
34    if (await which(trimmedCommand).catch(() => null)) {
35      exists = true
36    }
37  
38    // Cache the result
39    binaryCache.set(trimmedCommand, exists)
40  
41    logForDebugging(
42      `[binaryCheck] Binary '${trimmedCommand}' ${exists ? 'found' : 'not found'}`,
43    )
44  
45    return exists
46  }
47  
48  /**
49   * Clear the binary check cache (useful for testing)
50   */
51  export function clearBinaryCache(): void {
52    binaryCache.clear()
53  }