UNPKG

void-cmd

Version:

AI-powered CLI tool that converts natural language to shell commands using Cerebras API

228 lines • 9.12 kB
"use strict"; 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