/** Shared no-shell `execFile` runner for native host dialogs and openers. */ import { execFile } from 'node:child_process' /** Testable command boundary; native implementations never invoke a shell. */ export type NativeCommandRunner = ( command: string, args: readonly string[], signal: AbortSignal, ) => Promise<{ stdout: string; stderr: string }> /** * Run a host command with utf8 stdio, abort propagation, and Windows hide. * @param command - executable path or PATH name. * @param args - argv (never a shell string). * @param signal - caller/connection lifetime; abort terminates the child. * @returns captured stdout/stderr on exit 0. */ export const runNativeCommand: NativeCommandRunner = (command, args, signal) => new Promise((resolve, reject) => { execFile( command, [...args], { encoding: 'utf8', signal, windowsHide: true }, (error, stdout, stderr) => { if (error !== null) { const failure = Object.assign(new Error(error.message, { cause: error }), { code: error.code, stdout, stderr, }) reject(failure) return } resolve({ stdout, stderr }) }, ) })