flash-tool-oss
Version:
Fast AI-powered code completion using OpenAI API - No API key setup required!
273 lines (225 loc) ⢠9.04 kB
JavaScript
const { Command } = require('commander');
const { spawn } = require('child_process');
const path = require('path');
const readline = require('readline');
const fs = require('fs');
const program = new Command();
function callPythonScript(scriptPath, args) {
return new Promise((resolve, reject) => {
const pythonProcess = spawn('python', [scriptPath, ...args]);
let output = '';
let errorOutput = '';
pythonProcess.stdout.on('data', (data) => {
output += data.toString();
});
pythonProcess.stderr.on('data', (data) => {
errorOutput += data.toString();
});
pythonProcess.on('close', (code) => {
if (code === 0) {
resolve(output.trim());
} else {
reject(new Error(`Python script failed: ${errorOutput}`));
}
});
});
}
function insertCodeIntoFile(filePath, insertAfter, codeToInsert) {
const fileContent = fs.readFileSync(filePath, 'utf8');
const lines = fileContent.split('\n');
const insertIndex = lines.findIndex(line => line.includes(insertAfter));
if (insertIndex === -1) {
throw new Error(`Could not find insertion point: "${insertAfter}"`);
}
lines.splice(insertIndex + 1, 0, codeToInsert);
fs.writeFileSync(filePath, lines.join('\n'), 'utf8');
console.log(`ā
Code inserted into ${filePath} after "${insertAfter}"`);
}
program
.name('flash-tool-oss')
.description('Fast AI-powered code completion using OpenAI API')
.version('1.0.0');
// Complete command
program
.command('complete')
.description('Complete code using AI')
.argument('[context]', 'Code context to complete')
.option('-l, --language <language>', 'Programming language', 'python')
.option('-f, --file <filePath>', 'Target file to insert completion into')
.action(async (context, options) => {
try {
if (!context) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
context = await new Promise((resolve) => {
rl.question('Enter the code context to complete: ', (answer) => {
rl.close();
resolve(answer.trim());
});
});
if (!context) {
console.error('ā Error: Context cannot be empty');
return;
}
}
let fileContent = '';
if (options.file) {
if (!fs.existsSync(options.file)) {
console.error(`ā File not found: ${options.file}`);
return;
}
fileContent = fs.readFileSync(options.file, 'utf8');
}
console.log('š¤ Generating code completion...');
const scriptPath = path.join(__dirname, 'extension.py');
const rawOutput = await callPythonScript(scriptPath, [
'complete',
context,
options.language,
fileContent
]);
let completionObject;
try {
completionObject = JSON.parse(rawOutput);
} catch {
console.error('ā Error: Could not parse response from Python script. Expected JSON.');
console.log('Raw output:', rawOutput);
return;
}
const { insert_after, code } = completionObject;
if (!code || !insert_after) {
console.error('ā Error: Incomplete response. Must include both "insert_after" and "code".');
return;
}
console.log('\n⨠Code to insert:\n' + code);
if (options.file) {
insertCodeIntoFile(options.file, insert_after, code);
} else {
console.log('\nš No file specified. Code not inserted.');
}
} catch (error) {
console.error('ā Error:', error.message);
}
});
// Chat command
program
.command('chat')
.description('Chat with AI assistant')
.argument('[message]', 'Message to send to AI')
.action(async (message) => {
try {
if (!message) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
message = await new Promise((resolve) => {
rl.question('What would you like to ask? ', (answer) => {
rl.close();
resolve(answer.trim());
});
});
if (!message) {
console.error('ā Error: Message cannot be empty');
return;
}
}
console.log('š¤ Thinking...');
const scriptPath = path.join(__dirname, 'extension.py');
const response = await callPythonScript(scriptPath, ['chat', message]);
console.log('\nš¬ AI Response:');
console.log(response);
} catch (error) {
console.error('ā Error:', error.message);
}
});
// Interactive mode
program
.command('interactive')
.alias('i')
.description('Start interactive mode')
.action(async () => {
console.log('š Flash Interactive Mode');
console.log('Type "exit" to quit\n');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const askQuestion = (question) => {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer.trim());
});
});
};
while (true) {
console.log('Options:');
console.log('1. š¬ Chat with AI');
console.log('2. ⨠Complete code');
console.log('3. šŖ Exit');
const choice = await askQuestion('\nWhat would you like to do? (1-3): ');
if (choice === '3' || choice.toLowerCase() === 'exit') {
console.log('š Goodbye!');
rl.close();
break;
}
if (choice === '1') {
const message = await askQuestion('What would you like to ask? ');
if (message) {
try {
console.log('š¤ Thinking...');
const scriptPath = path.join(__dirname, 'extension.py');
const response = await callPythonScript(scriptPath, ['chat', message]);
console.log('\nš¬ AI Response:');
console.log(response);
console.log(); // Empty line for spacing
} catch (error) {
console.error('ā Error:', error.message);
}
}
}
if (choice === '2') {
const context = await askQuestion('Enter the code context to complete: ');
const filePath = await askQuestion('Path to target file (optional): ');
const language = await askQuestion('Programming language (default: python): ') || 'python';
let fileContent = '';
if (filePath) {
try {
fileContent = fs.readFileSync(filePath, 'utf8');
} catch (err) {
console.error(`ā Failed to read file: ${err.message}`);
continue;
}
}
try {
console.log('š¤ Generating code completion...');
const scriptPath = path.join(__dirname, 'extension.py');
const rawOutput = await callPythonScript(scriptPath, [
'complete',
context,
language,
fileContent
]);
let completionObject = JSON.parse(rawOutput);
const { insert_after, code } = completionObject;
console.log('\n⨠Code to insert:\n' + code);
if (filePath) {
insertCodeIntoFile(filePath, insert_after, code);
} else {
console.log('\nš No file specified. Code not inserted.');
}
console.log(); // spacing
} catch (error) {
console.error('ā Error:', error.message);
}
}
}
});
// Default command (show help)
program.action(() => {
program.help();
});
program.parse();