@commit451/salamander
Version:
Never be AFK
79 lines ⢠3.25 kB
JavaScript
import { execSync } from 'child_process';
import chalk from 'chalk';
import { RunnerType } from '../types/runner.js';
export class CommandExecutor {
static async executeCommand(runner, command) {
console.log(chalk.blue(`\nš§ Executing command for runner "${runner.name}"`));
console.log(chalk.gray(`Directory: ${runner.directory}`));
console.log(chalk.gray(`Command: ${command}`));
console.log(chalk.gray(`Type: ${runner.runnerType}\n`));
const startTime = Date.now();
try {
const output = this.executeRunnerCommand(runner, command);
const executionTime = Date.now() - startTime;
console.log(chalk.green('ā
Command completed successfully'));
console.log(chalk.grey(output));
return {
output: output || 'Command executed successfully (no output)',
success: true,
executionTime
};
}
catch (error) {
const executionTime = Date.now() - startTime;
console.error(chalk.red('ā Error executing command:'), error.message);
return {
output: `Failed to execute command: ${error.message}`,
success: false,
executionTime
};
}
}
static executeRunnerCommand(runner, userInput) {
const commandLine = this.buildCommandLine(runner, userInput);
try {
const output = execSync(commandLine, {
cwd: runner.directory,
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe']
});
return output.trim();
}
catch (error) {
// Check for common error patterns
if (error.message.includes('command not found') || error.message.includes('No such file')) {
const toolName = this.getToolName(runner.runnerType);
throw new Error(`${toolName} CLI not found. Please ensure ${toolName} is installed and accessible.`);
}
else {
throw new Error(error.stderr?.trim() || error.stdout?.trim() || error.message);
}
}
}
static buildCommandLine(runner, userInput) {
// Escape quotes in user input to prevent command injection
const escapedInput = userInput.replace(/"/g, '\\"');
switch (runner.runnerType) {
case RunnerType.CLAUDE:
const continuationFlag = runner.lastMessage ? '-c ' : '';
return `claude ${continuationFlag}-p --dangerously-skip-permissions "${escapedInput}"`;
case RunnerType.GEMINI:
return `gemini -p "${escapedInput}" --yolo`;
case RunnerType.CODEX:
return `codex exec "${escapedInput}" --full-auto --skip-git-repo-check`;
}
}
static getToolName(runnerType) {
switch (runnerType) {
case RunnerType.CLAUDE:
return 'Claude';
case RunnerType.GEMINI:
return 'Gemini';
case RunnerType.CODEX:
return 'Codex';
default:
return 'Claude';
}
}
}
//# sourceMappingURL=executor.js.map