// engine/sandbox/runner-detect.ts — Capability probe for sandbox runners (SPEC-742)
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileAsync = promisify(execFile);
/**
 * Cached runner detection result.
 * Null means "not yet detected", the string means "detected", false means "unavailable".
 */
let cachedRunner;
/**
 * Probe if a command is available on the system.
 * Returns true if the command exits without error, false otherwise.
 */
async function isAvailable(command, args) {
    try {
        await execFileAsync(command, args, { timeout: 3000 });
        return true;
    }
    catch {
        return false;
    }
}
/**
 * Detect the best available sandbox runner.
 * Priority: bwrap (Linux) > sandbox-exec (macOS) > docker (CI fallback).
 * Returns null if no runner is available.
 *
 * Result is cached after first call to avoid repeated probing.
 */
export async function detectRunner() {
    if (cachedRunner !== undefined) {
        return cachedRunner;
    }
    // bwrap — Linux only
    if (process.platform === 'linux') {
        const hasBwrap = await isAvailable('bwrap', ['--version']);
        if (hasBwrap) {
            cachedRunner = 'bwrap';
            return cachedRunner;
        }
    }
    // sandbox-exec — macOS only
    if (process.platform === 'darwin') {
        const hasSandboxExec = await isAvailable('sandbox-exec', ['-n', 'deny default', 'true']);
        if (hasSandboxExec) {
            cachedRunner = 'sandbox-exec';
            return cachedRunner;
        }
    }
    // Docker — CI fallback (any platform)
    const hasDocker = await isAvailable('docker', ['info']);
    if (hasDocker) {
        cachedRunner = 'docker';
        return cachedRunner;
    }
    cachedRunner = null;
    return null;
}
/**
 * Synchronous version that returns the cached detection result.
 * Returns undefined if detection has not been run yet.
 */
export function getCachedRunner() {
    return cachedRunner;
}
/**
 * Reset the cache (for testing only).
 */
export function resetRunnerCache() {
    cachedRunner = undefined;
}
//# sourceMappingURL=runner-detect.js.map