/**
* Cross-runtime exec helpers.
*
* bare-subprocess 6.0.0 exports `spawn` + `spawnSync` but NOT `execSync`
* or `execFileSync` (Bare keeps the subprocess API minimal). Node's
* child_process has all four. This module provides execSync/execFileSync
* with drop-in semantics, implemented on top of spawnSync — which exists
* in both runtimes.
*
* Drop-in semantics:
* - Throws on non-zero exit (status + signal preserved on err)
* - Returns stdout Buffer/string when stdio:'pipe' (default)
* - Returns null when stdio:'inherit'
* - Honours { cwd, env, encoding, maxBuffer } as spawnSync does
*
* Use these instead of child_process.execSync / execFileSync so the
* call sites work on both Bare and Node without per-site branching.
*/
import { spawnSync } from '#node:child_process'
function _check (cmd, result) {
if (result.error) throw result.error
if (result.status !== 0) {
const err = new Error('Command failed: ' + cmd)
err.status = result.status
err.signal = result.signal
err.stderr = result.stderr
err.stdout = result.stdout
throw err
}
}
export function execSync (cmd, opts = {}) {
const result = spawnSync('sh', ['-c', cmd], { stdio: 'pipe', ...opts })
_check(cmd, result)
return opts.stdio === 'inherit' ? null : result.stdout
}
export function execFileSync (file, args = [], opts = {}) {
// execFileSync's signature is (file, args?, opts?). If `args` is
// omitted and opts is passed positionally, the caller's array form
// shifts. Match Node's behaviour: detect when args is the opts object.
if (args && !Array.isArray(args) && typeof args === 'object') {
opts = args
args = []
}
const result = spawnSync(file, args, { stdio: 'pipe', ...opts })
_check(file + ' ' + args.join(' '), result)
return opts.stdio === 'inherit' ? null : result.stdout
}