-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
executable file
·132 lines (113 loc) · 3.35 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#! /usr/bin/env node
import fs from 'fs';
import os from 'os';
import ora from 'ora';
import path from 'path';
import request from 'request-promise';
import chalk from 'chalk';
import readline from 'readline';
import ShellJS from 'shelljs';
const PATH_TO_API_KEY_FILE = path.join(os.homedir(), '.x');
const args = process.argv.slice(2);
const query = args.join(' ');
function getApiKey() {
if (!!process.env.OPENAI_TOKEN) {
return process.env.OPENAI_TOKEN;
}
if (fs.existsSync(PATH_TO_API_KEY_FILE)) {
return fs.readFileSync(PATH_TO_API_KEY_FILE, 'utf8');
}
return undefined;
}
async function fetchAndStoreApiKey() {
const spinner = ora('Initializing...').start();
const apiKey = await request('https://fant.io/x');
fs.writeFileSync(PATH_TO_API_KEY_FILE, apiKey, 'utf8');
spinner.succeed('Initialized');
}
async function getSuggestion(prompt) {
const response = await request({
url: 'https://api.openai.com/v1/engines/davinci-codex/completions',
method: 'POST',
json: true,
headers: {
'Authorization': `Bearer ${getApiKey()}`,
},
body: {
prompt,
temperature: 0,
max_tokens: 300,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
stop: ['#']
},
});
if (!response || !response.choices || !response.choices.length) {
throw new Error('No suggestion found');
}
const suggestion = response.choices[0].text.trim().replace(/^!/, '');
if (!suggestion) {
throw new Error('No suggestion found');
}
return suggestion;
}
async function suggest() {
readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);
process.stdin.on('keypress', (_chunk, key) => {
if (key.ctrl && key.name === 'c') {
process.exit();
}
});
let prompt = `# Bash\n# ${query}\n`;
let attempt = 0;
const spinner = ora(query).start();
try {
while (true) {
const suggestion = await getSuggestion(prompt);
spinner.color = 'green';
spinner.text = `${chalk.bold(suggestion)}\n\nenter → run command\nspace → new suggestion`;
spinner.spinner = { frames: ['$'] };
const shouldExecuteCommand = await new Promise((resolve) => {
function listener(_chunk, key) {
switch (key.name) {
case 'return':
process.stdin.removeListener('keypress', listener);
resolve(true);
break;
case 'space':
process.stdin.removeListener('keypress', listener);
resolve(false);
break;
}
}
process.stdin.on('keypress', listener);
});
if (shouldExecuteCommand) {
spinner.stop();
console.log(chalk.green('$ ') + chalk.bold(suggestion));
ShellJS.exec(suggestion, {async: true});
} else {
attempt++;
if (attempt === 3) break;
spinner.color = 'cyan';
spinner.text = query;
spinner.spinner = 'dots';
prompt += `${suggestion}\n\n# Same command, but differently formatted\n`;
}
}
throw new Error('No suggestion found');
} catch (error) {
spinner.fail(error.toString());
}
}
if (!query) {
console.log('Use like:');
console.log(chalk.green('$ ') + chalk.bold('x list s3 buckets'));
} else if (query === 'init') {
await fetchAndStoreApiKey();
} else {
if (!getApiKey()) await fetchAndStoreApiKey();
await suggest();
}