void-cmd
Version:
AI-powered CLI tool that converts natural language to shell commands using Cerebras API
228 lines ⢠9.12 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConvertCommand = void 0;
const cerebras_1 = require("../services/cerebras");
const utils_1 = require("../utils");
const config_1 = require("../config");
const inquirer_1 = __importDefault(require("inquirer"));
const child_process_1 = require("child_process");
class ConvertCommand {
constructor() {
this.name = 'convert';
this.description = 'Convert natural language to shell command';
}
getCerebrasService() {
if (!this.cerebrasService) {
this.cerebrasService = new cerebras_1.CerebrasService();
}
return this.cerebrasService;
}
async execute(options) {
const query = options.query || options._?.[0];
if (!query) {
(0, utils_1.log)('Usage: convert "your natural language description"');
return;
}
try {
(0, utils_1.log)('Converting natural language to shell command...');
const startTime = performance.now();
const result = await this.getCerebrasService().convertToShellCommand(query);
const endTime = performance.now();
const responseTime = (endTime - startTime) / 1000; // Convert to seconds
process.stdout.write('\x1b[1A\x1b[2K');
await this.showCommandPrompt(result, responseTime);
}
catch (error) {
process.stdout.write('\x1b[1A\x1b[2K');
if (error instanceof Error && error.message.includes('API key not configured')) {
(0, utils_1.log)('ā CEREBRAS_API_KEY not configured!');
(0, utils_1.log)('\nPlease run: vcmd -settings');
(0, utils_1.log)('This will help you set up your API key interactively.');
}
else {
(0, utils_1.errorHandler)(error);
}
}
}
async showCommandPrompt(result, responseTime) {
const safetyEmoji = this.getSafetyEmoji(result.safety);
const safetyColor = this.getSafetyColor(result.safety);
const responseTimeText = responseTime ? ` | Response Time: ${responseTime.toFixed(2)}s` : '';
console.log(`\n${safetyColor}${safetyEmoji} Safety Level: ${result.safety.toUpperCase()}${responseTimeText}\x1b[0m`);
console.log('\x1b[1m' + result.command + '\x1b[0m');
console.log(`\n\x1b[90m${result.explanation}\x1b[0m\n`);
const choices = [
{
name: `ā¶ļø Execute: ${result.command}`,
value: 'execute'
},
{
name: 'š Explain command in detail',
value: 'explain'
},
{
name: 'ā Exit',
value: 'exit'
}
];
try {
const answer = await inquirer_1.default.prompt([
{
type: 'list',
name: 'action',
message: 'What would you like to do?',
choices: choices,
pageSize: 3
}
]);
if (answer.action === 'execute') {
await this.executeCommand(result.command, result.safety);
}
else if (answer.action === 'explain') {
await this.explainCommand(result.command);
}
else {
(0, utils_1.log)('Command execution cancelled.');
}
}
catch (error) {
if (error && typeof error === 'object' && 'isTtyError' in error) {
(0, utils_1.log)('\nš¤ Generated Command:');
(0, utils_1.log)(`Command: ${result.command}`);
(0, utils_1.log)(`Safety: ${safetyEmoji} ${result.safety.toUpperCase()}`);
(0, utils_1.log)(`Explanation: ${result.explanation}`);
}
else {
throw error;
}
}
}
async explainCommand(command) {
try {
(0, utils_1.log)('\nš Getting detailed explanation...');
const startTime = performance.now();
const explanation = await this.getCerebrasService().explainCommand(command);
const endTime = performance.now();
const responseTime = (endTime - startTime) / 1000;
process.stdout.write('\x1b[1A\x1b[2K');
console.log('\nš Command Explanation:');
console.log('========================\n');
console.log('\x1b[36m' + command + '\x1b[0m\n');
console.log(`\x1b[90mResponse Time: ${responseTime.toFixed(2)}s\x1b[0m\n`);
console.log(explanation);
console.log('\n');
}
catch (error) {
process.stdout.write('\x1b[1A\x1b[2K');
(0, utils_1.log)('ā Failed to get detailed explanation');
(0, utils_1.errorHandler)(error);
}
}
async executeCommand(command, safety) {
try {
if (safety === 'dangerous') {
console.log('\nšØ WARNING: This is a dangerous command!');
const confirm = await inquirer_1.default.prompt([
{
type: 'confirm',
name: 'proceed',
message: 'Are you absolutely sure you want to execute this?',
default: false
}
]);
if (!confirm.proceed) {
(0, utils_1.log)('Command execution cancelled for safety.');
return;
}
}
console.log('\nā” Executing command...\n');
console.log('\x1b[36m' + command + '\x1b[0m\n');
(0, config_1.saveCommandHistory)({
command,
timestamp: new Date().toISOString(),
safety
});
const childProcess = (0, child_process_1.spawn)(command, [], {
stdio: ['pipe', 'pipe', 'pipe'],
shell: true
});
let hasOutput = false;
let exitCode = 0;
childProcess.stdout.on('data', (data) => {
hasOutput = true;
process.stdout.write(data.toString());
});
childProcess.stderr.on('data', (data) => {
hasOutput = true;
process.stderr.write('\x1b[31m' + data.toString() + '\x1b[0m');
});
childProcess.on('close', (code) => {
exitCode = code || 0;
(0, config_1.saveCommandHistory)({
command,
timestamp: new Date().toISOString(),
safety,
exitCode,
success: code === 0
});
if (code === 0) {
console.log('\nā
Command executed successfully!');
}
else {
console.log(`\nā Command exited with code ${code}`);
console.log('\nš” Tip: Run "vcmd -e" to analyze what went wrong');
}
});
childProcess.on('error', (error) => {
console.error('\nā Command execution failed:');
console.error(error.message);
});
console.log('\n\x1b[90m(Press Ctrl+C to stop the command)\x1b[0m');
const signalHandler = () => {
console.log('\n\nā¹ļø Command interrupted by user');
childProcess.kill('SIGTERM');
process.exit(0);
};
process.on('SIGINT', signalHandler);
await new Promise((resolve) => {
childProcess.on('close', () => {
process.removeListener('SIGINT', signalHandler);
resolve();
});
});
}
catch (error) {
console.error('\nā Command execution failed:');
console.error(error.message);
console.log('\nš” Tip: Run "vcmd -e" to analyze what went wrong');
(0, config_1.saveCommandHistory)({
command,
timestamp: new Date().toISOString(),
safety,
success: false,
error: error.message
});
}
}
getSafetyEmoji(safety) {
switch (safety) {
case 'safe': return 'ā
';
case 'caution': return 'ā ļø';
case 'dangerous': return 'šØ';
default: return 'ā';
}
}
getSafetyColor(safety) {
switch (safety) {
case 'safe': return '\x1b[32m';
case 'caution': return '\x1b[33m';
case 'dangerous': return '\x1b[31m';
default: return '\x1b[37m';
}
}
}
exports.ConvertCommand = ConvertCommand;
//# sourceMappingURL=convert.js.map