npm-noxyai 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index-noxyai.js +154 -30
- package/package.json +1 -1
package/index-noxyai.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const { exec } = require('child_process');
|
|
7
|
+
const readline = require('readline');
|
|
6
8
|
|
|
7
9
|
const BASE_URL = 'https://www.noxyai.com';
|
|
8
10
|
const CONFIG_FILE = path.join(os.homedir(), '.noxyai.json');
|
|
@@ -10,6 +12,19 @@ const CONFIG_FILE = path.join(os.homedir(), '.noxyai.json');
|
|
|
10
12
|
const args = process.argv.slice(2);
|
|
11
13
|
const command = args[0];
|
|
12
14
|
|
|
15
|
+
// --- HELPER: ASCII ART ---
|
|
16
|
+
function printLogo() {
|
|
17
|
+
console.log('\x1b[36m' + `
|
|
18
|
+
███╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗ █████╗ ██╗
|
|
19
|
+
████╗ ██║██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝██╔══██╗██║
|
|
20
|
+
██╔██╗ ██║██║ ██║ ╚███╔╝ ╚████╔╝ ███████║██║
|
|
21
|
+
██║╚██╗██║██║ ██║ ██╔██╗ ╚██╔╝ ██╔══██║██║
|
|
22
|
+
██║ ╚████║╚██████╔╝██╔╝ ██╗ ██║ ██║ ██║██║
|
|
23
|
+
╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝
|
|
24
|
+
` + '\x1b[0m');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// --- HELPER: AUTHENTICATION ---
|
|
13
28
|
function saveToken(token) {
|
|
14
29
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify({ token }));
|
|
15
30
|
}
|
|
@@ -22,17 +37,48 @@ function getToken() {
|
|
|
22
37
|
return null;
|
|
23
38
|
}
|
|
24
39
|
|
|
40
|
+
function logout() {
|
|
41
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
42
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
43
|
+
console.log('✅ Successfully logged out.');
|
|
44
|
+
} else {
|
|
45
|
+
console.log('You are already logged out.');
|
|
46
|
+
}
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// --- HELPER: AUTO-OPEN URL ---
|
|
51
|
+
function openBrowser(url) {
|
|
52
|
+
const platform = os.platform();
|
|
53
|
+
if (platform === 'android') {
|
|
54
|
+
exec(`termux-open-url "${url}"`);
|
|
55
|
+
} else if (platform === 'darwin') {
|
|
56
|
+
exec(`open "${url}"`);
|
|
57
|
+
} else if (platform === 'win32') {
|
|
58
|
+
exec(`start "" "${url}"`);
|
|
59
|
+
} else {
|
|
60
|
+
exec(`xdg-open "${url}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- COMMAND: LOGIN ---
|
|
25
65
|
async function login() {
|
|
26
|
-
|
|
66
|
+
printLogo();
|
|
67
|
+
console.log('Initializing secure login...\n');
|
|
27
68
|
try {
|
|
28
69
|
const initRes = await fetch(BASE_URL + '/api/cli/init', { method: 'POST' });
|
|
29
70
|
const { deviceCode, verificationUrl, interval } = await initRes.json();
|
|
30
71
|
|
|
31
|
-
console.log('
|
|
32
|
-
console.log(
|
|
33
|
-
console.log('Open this URL in your browser:\n\n -> ' + verificationUrl + ' <-');
|
|
72
|
+
console.log('=============================================');
|
|
73
|
+
console.log(`URL: ${verificationUrl}`);
|
|
34
74
|
console.log('=============================================\n');
|
|
35
|
-
|
|
75
|
+
|
|
76
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
77
|
+
rl.question('Press ENTER to automatically open the browser...', () => {
|
|
78
|
+
openBrowser(verificationUrl);
|
|
79
|
+
rl.close();
|
|
80
|
+
console.log('\n⏳ Waiting for authentication...');
|
|
81
|
+
});
|
|
36
82
|
|
|
37
83
|
const pollInterval = setInterval(async () => {
|
|
38
84
|
try {
|
|
@@ -49,20 +95,9 @@ async function login() {
|
|
|
49
95
|
saveToken(data.token);
|
|
50
96
|
|
|
51
97
|
console.clear();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
/::| | /::\\ \\ |:| | |:| | /::\\ \\ /\\ \\
|
|
56
|
-
/:|:| | /:/\\:\\ \\ |:| | |:| | /:/\\:\\ \\ \\:\\ \\
|
|
57
|
-
/:/|:| |__ /:/ \\:\\ \\ |:|__|__ |:|__|__ /::\\~\\:\\ \\ /::\\__\\
|
|
58
|
-
/:/ |:| /\\__\\ /:/__/ \\:\\__\\ ____/::::\\__\\ /::::\\__\\ /:/\\:\\ \\:\\__\\ __/:/\\/__/
|
|
59
|
-
\\/__|:|/:/ / \\:\\ \\ /:/ / \\::::/~~/~ /:/~~/~ \\/__\\:\\/:/ / /\\/:/ /
|
|
60
|
-
|:/:/ / \\:\\ /:/ / ~~|:|~~| /:/ / \\::/ / \\::/__/
|
|
61
|
-
|::/ / \\:\\/:/ / |:| | \\/__/ /:/ / \\:\\__\\
|
|
62
|
-
/:/ / \\::/ / |:| | /:/ / \\/__/
|
|
63
|
-
\\/__/ \\/__/ \\|__| \\/__/` + '\x1b[0m');
|
|
64
|
-
console.log('\n✅ Login successful! Terminal connected.');
|
|
65
|
-
console.log('Try running: noxyai chat "Hello, world!"\n');
|
|
98
|
+
printLogo();
|
|
99
|
+
console.log('✅ Login successful! Terminal connected.');
|
|
100
|
+
console.log('Type "noxyai help" for commands.\n');
|
|
66
101
|
process.exit(0);
|
|
67
102
|
} else if (data.error) {
|
|
68
103
|
clearInterval(pollInterval);
|
|
@@ -77,22 +112,41 @@ async function login() {
|
|
|
77
112
|
}
|
|
78
113
|
}
|
|
79
114
|
|
|
80
|
-
|
|
115
|
+
// --- HELPER: EXECUTE COMMANDS & ERROR HANDLING ---
|
|
116
|
+
function runTerminalCommand(cmd) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
console.log(`\n\x1b[33m⚡ Running:\x1b[0m ${cmd}`);
|
|
119
|
+
const child = exec(cmd, (error, stdout, stderr) => {
|
|
120
|
+
if (error) {
|
|
121
|
+
reject(stderr || error.message);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
resolve(stdout);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Pipe output live to the terminal so user can see servers/logs
|
|
128
|
+
child.stdout.pipe(process.stdout);
|
|
129
|
+
child.stderr.pipe(process.stderr);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// --- COMMAND: CHAT & AGENT EXECUTION ---
|
|
134
|
+
async function chat(prompt, depth = 0) {
|
|
81
135
|
const token = getToken();
|
|
82
136
|
if (!token) {
|
|
83
|
-
console.error('❌ You
|
|
137
|
+
console.error('❌ Unauthorized: You must log in first. Run "noxyai login"');
|
|
84
138
|
process.exit(1);
|
|
85
139
|
}
|
|
86
140
|
|
|
87
|
-
if (
|
|
88
|
-
console.error('❌ Please
|
|
141
|
+
if (depth > 3) {
|
|
142
|
+
console.error('\n❌ Agent reached maximum retry depth. Please fix the error manually.');
|
|
89
143
|
process.exit(1);
|
|
90
144
|
}
|
|
91
145
|
|
|
92
146
|
const model = 'auto';
|
|
93
147
|
|
|
94
148
|
try {
|
|
95
|
-
const res = await fetch(BASE_URL + '/api/
|
|
149
|
+
const res = await fetch(BASE_URL + '/api/io', {
|
|
96
150
|
method: 'POST',
|
|
97
151
|
headers: {
|
|
98
152
|
'Content-Type': 'application/json',
|
|
@@ -107,10 +161,12 @@ async function chat(prompt) {
|
|
|
107
161
|
process.exit(1);
|
|
108
162
|
}
|
|
109
163
|
|
|
110
|
-
console.log('\n🤖
|
|
164
|
+
if (depth === 0) console.log('\n🤖 \x1b[36mNoxyAI\x1b[0m is thinking...\n');
|
|
165
|
+
else console.log('\n🤖 \x1b[36mNoxyAI\x1b[0m is analyzing the error and rewriting...\n');
|
|
111
166
|
|
|
112
167
|
const reader = res.body.getReader();
|
|
113
168
|
const decoder = new TextDecoder('utf-8');
|
|
169
|
+
let fullResponse = "";
|
|
114
170
|
|
|
115
171
|
while (true) {
|
|
116
172
|
const { done, value } = await reader.read();
|
|
@@ -122,29 +178,97 @@ async function chat(prompt) {
|
|
|
122
178
|
for (const line of lines) {
|
|
123
179
|
if (line.startsWith('data: ')) {
|
|
124
180
|
const data = line.slice(6).trim();
|
|
125
|
-
if (data === '[DONE]')
|
|
126
|
-
console.log('\n');
|
|
127
|
-
process.exit(0);
|
|
128
|
-
}
|
|
181
|
+
if (data === '[DONE]') break;
|
|
129
182
|
try {
|
|
130
183
|
const parsed = JSON.parse(data);
|
|
131
184
|
if (parsed.text) {
|
|
185
|
+
fullResponse += parsed.text;
|
|
132
186
|
process.stdout.write(parsed.text);
|
|
133
187
|
}
|
|
134
188
|
} catch (e) {}
|
|
135
189
|
}
|
|
136
190
|
}
|
|
137
191
|
}
|
|
192
|
+
|
|
193
|
+
console.log('\n\n\x1b[32m[Agent] Response complete. Processing actions...\x1b[0m');
|
|
194
|
+
|
|
195
|
+
// 1. EXTRACT AND CREATE FILES
|
|
196
|
+
const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/g;
|
|
197
|
+
let match;
|
|
198
|
+
while ((match = fileRegex.exec(fullResponse)) !== null) {
|
|
199
|
+
const filePath = match[1];
|
|
200
|
+
const content = match[2];
|
|
201
|
+
|
|
202
|
+
const dir = path.dirname(filePath);
|
|
203
|
+
if (!fs.existsSync(dir)) {
|
|
204
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
205
|
+
}
|
|
206
|
+
fs.writeFileSync(filePath, content.trim());
|
|
207
|
+
console.log(`\x1b[32m✔ Created file:\x1b[0m ${filePath}`);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 2. EXTRACT AND RUN COMMANDS
|
|
211
|
+
const execRegex = /<execute>([\s\S]*?)<\/execute>/g;
|
|
212
|
+
const commands = [];
|
|
213
|
+
while ((match = execRegex.exec(fullResponse)) !== null) {
|
|
214
|
+
commands.push(match[1].trim());
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (const cmd of commands) {
|
|
218
|
+
try {
|
|
219
|
+
await runTerminalCommand(cmd);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
console.error(`\n\x1b[31m❌ Command Failed:\x1b[0m ${err.trim()}`);
|
|
222
|
+
console.log(`\x1b[33m🔄 Triggering Auto-Heal Loop...\x1b[0m`);
|
|
223
|
+
|
|
224
|
+
const errorPrompt = `I ran the command "${cmd}" and got this error:\n\n${err}\n\nPlease fix the issue. If you need to rewrite a file, use the <file> tags. If you need to install a missing library, use the <execute> tag.`;
|
|
225
|
+
|
|
226
|
+
await chat(errorPrompt, depth + 1);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
process.exit(0);
|
|
232
|
+
|
|
138
233
|
} catch (error) {
|
|
139
234
|
console.error('\n❌ Connection error: ' + error.message);
|
|
235
|
+
process.exit(1);
|
|
140
236
|
}
|
|
141
237
|
}
|
|
142
238
|
|
|
239
|
+
// --- COMMAND: HELP ---
|
|
240
|
+
function showHelp() {
|
|
241
|
+
printLogo();
|
|
242
|
+
console.log(`
|
|
243
|
+
\x1b[33mNoxyAI Agent CLI - Available Commands\x1b[0m
|
|
244
|
+
|
|
245
|
+
\x1b[32mnoxyai login\x1b[0m Authenticate your terminal
|
|
246
|
+
\x1b[32mnoxyai logout\x1b[0m Remove authentication from this device
|
|
247
|
+
\x1b[32mnoxyai chat "<prompt>"\x1b[0m Chat with the AI. It can build apps, create files, and fix errors.
|
|
248
|
+
\x1b[32mnoxyai help\x1b[0m Show this menu
|
|
249
|
+
|
|
250
|
+
\x1b[33mExamples:\x1b[0m
|
|
251
|
+
noxyai chat "Create a snake game in python and run it"
|
|
252
|
+
noxyai chat "Initialize a react app called my-app"
|
|
253
|
+
noxyai chat "Create an express server that returns hello world on port 3000"
|
|
254
|
+
`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// --- ROUTER ---
|
|
143
258
|
if (command === 'login') {
|
|
144
259
|
login();
|
|
260
|
+
} else if (command === 'logout') {
|
|
261
|
+
logout();
|
|
262
|
+
} else if (command === 'help' || command === '--help' || !command) {
|
|
263
|
+
showHelp();
|
|
145
264
|
} else if (command === 'chat') {
|
|
146
265
|
const prompt = args.slice(1).join(' ');
|
|
266
|
+
if (!prompt) {
|
|
267
|
+
console.error('❌ Please provide a prompt. Example: noxyai chat "Create a python script"');
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
147
270
|
chat(prompt);
|
|
148
271
|
} else {
|
|
149
|
-
console.
|
|
272
|
+
console.error(`❌ Unknown command: ${command}`);
|
|
273
|
+
console.log('Run "noxyai help" for a list of commands.');
|
|
150
274
|
}
|