import { spawn } from 'child_process';
import chalk from 'chalk';
import { CommandExecutionError } from '../errors.js';
import { type CommandResult } from '../types.js';
export async function executeCommand(
file: string,
args: string[] = [],
stdin?: string
): Promise<CommandResult> {
return new Promise((resolve, reject) => {
console.error(chalk.blue('Executing:'), file, args.join(' '));
const child = spawn(file, args, {
shell: true, // Required for Windows .cmd files
stdio: ['pipe', 'pipe', 'pipe'],
});
let stdout = '';
let stderr = '';
child.stdout.on('data', (data) => {
stdout += data.toString();
});
child.stderr.on('data', (data) => {
stderr += data.toString();
});
child.on('error', (error) => {
reject(new CommandExecutionError(
[file, ...args].join(' '),
'Command execution failed',
error
));
});
child.on('close', (code) => {
if (stderr) {
console.error(chalk.yellow('Command stderr:'), stderr);
}
// Accept exit code 0, or any exit code if we got stdout
if (code === 0 || stdout) {
resolve({ stdout, stderr });
} else {
reject(new CommandExecutionError(
[file, ...args].join(' '),
`Command failed with exit code ${code}: ${stderr}`,
new Error(stderr)
));
}
});
// Write stdin if provided, then close
if (stdin) {
child.stdin.write(stdin);
}
child.stdin.end();
});
}