npm-noxyai 1.0.6 → 1.0.8

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 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 { spawn } = require('child_process'); // 🚨 CHANGED from exec to spawn
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,17 @@ 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
+ function printLogo() {
16
+ console.log('\x1b[36m' + `
17
+ ███╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗ █████╗ ██╗
18
+ ████╗ ██║██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝██╔══██╗██║
19
+ ██╔██╗ ██║██║ ██║ ╚███╔╝ ╚████╔╝ ███████║██║
20
+ ██║╚██╗██║██║ ██║ ██╔██╗ ╚██╔╝ ██╔══██║██║
21
+ ██║ ╚████║╚██████╔╝██╔╝ ██╗ ██║ ██║ ██║██║
22
+ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝
23
+ ` + '\x1b[0m');
24
+ }
25
+
13
26
  function saveToken(token) {
14
27
  fs.writeFileSync(CONFIG_FILE, JSON.stringify({ token }));
15
28
  }
@@ -22,17 +35,46 @@ function getToken() {
22
35
  return null;
23
36
  }
24
37
 
38
+ function logout() {
39
+ if (fs.existsSync(CONFIG_FILE)) {
40
+ fs.unlinkSync(CONFIG_FILE);
41
+ console.log('✅ Successfully logged out.');
42
+ } else {
43
+ console.log('You are already logged out.');
44
+ }
45
+ process.exit(0);
46
+ }
47
+
48
+ function openBrowser(url) {
49
+ const platform = os.platform();
50
+ if (platform === 'android') {
51
+ spawn('termux-open-url', [url], { stdio: 'ignore' });
52
+ } else if (platform === 'darwin') {
53
+ spawn('open', [url], { stdio: 'ignore' });
54
+ } else if (platform === 'win32') {
55
+ spawn('cmd.exe', ['/c', 'start', '""', url], { stdio: 'ignore' });
56
+ } else {
57
+ spawn('xdg-open', [url], { stdio: 'ignore' });
58
+ }
59
+ }
60
+
25
61
  async function login() {
26
- console.log('Initializing login...');
62
+ printLogo();
63
+ console.log('Initializing secure login...\n');
27
64
  try {
28
65
  const initRes = await fetch(BASE_URL + '/api/cli/init', { method: 'POST' });
29
66
  const { deviceCode, verificationUrl, interval } = await initRes.json();
30
67
 
31
- console.log('\n=============================================');
32
- console.log('Action Required: Please authenticate your terminal');
33
- console.log('Open this URL in your browser:\n\n -> ' + verificationUrl + ' <-');
68
+ console.log('=============================================');
69
+ console.log(`URL: ${verificationUrl}`);
34
70
  console.log('=============================================\n');
35
- console.log('Waiting for confirmation...');
71
+
72
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
73
+ rl.question('Press ENTER to automatically open the browser...', () => {
74
+ openBrowser(verificationUrl);
75
+ rl.close();
76
+ console.log('\n⏳ Waiting for authentication...');
77
+ });
36
78
 
37
79
  const pollInterval = setInterval(async () => {
38
80
  try {
@@ -49,20 +91,9 @@ async function login() {
49
91
  saveToken(data.token);
50
92
 
51
93
  console.clear();
52
- console.log('\x1b[36m' +
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');
94
+ printLogo();
95
+ console.log('✅ Login successful! Terminal connected.');
96
+ console.log('Type "noxyai help" for commands.\n');
66
97
  process.exit(0);
67
98
  } else if (data.error) {
68
99
  clearInterval(pollInterval);
@@ -77,22 +108,41 @@ async function login() {
77
108
  }
78
109
  }
79
110
 
80
- async function chat(prompt) {
111
+ // 🚨 THE FIX: Upgraded to spawn with interactive stdio
112
+ function runTerminalCommand(cmd) {
113
+ return new Promise((resolve, reject) => {
114
+ console.log(`\n\x1b[33m⚡ Running:\x1b[0m ${cmd}\n`);
115
+
116
+ const child = spawn(cmd, {
117
+ shell: true,
118
+ stdio: 'inherit' // This connects your live keyboard to the Python script!
119
+ });
120
+
121
+ child.on('close', (code) => {
122
+ if (code !== 0) reject(`Command failed with exit code ${code}`);
123
+ else resolve();
124
+ });
125
+
126
+ child.on('error', (error) => reject(error.message));
127
+ });
128
+ }
129
+
130
+ async function chat(prompt, depth = 0) {
81
131
  const token = getToken();
82
132
  if (!token) {
83
- console.error('❌ You are not logged in. Please run: noxyai login');
133
+ console.error('❌ Unauthorized: You must log in first. Run "noxyai login"');
84
134
  process.exit(1);
85
135
  }
86
136
 
87
- if (!prompt) {
88
- console.error('❌ Please provide a prompt.');
137
+ if (depth > 3) {
138
+ console.error('\nAgent reached maximum retry depth. Please fix the error manually.');
89
139
  process.exit(1);
90
140
  }
91
141
 
92
142
  const model = 'auto';
93
143
 
94
144
  try {
95
- const res = await fetch(BASE_URL + '/api/cli/execute', {
145
+ const res = await fetch(BASE_URL + '/api/io', {
96
146
  method: 'POST',
97
147
  headers: {
98
148
  'Content-Type': 'application/json',
@@ -107,10 +157,12 @@ async function chat(prompt) {
107
157
  process.exit(1);
108
158
  }
109
159
 
110
- console.log('\n🤖 NoxyAI (' + model + '):\n');
160
+ if (depth === 0) console.log('\n🤖 \x1b[36mNoxyAI\x1b[0m is thinking...\n');
161
+ else console.log('\n🤖 \x1b[36mNoxyAI\x1b[0m is analyzing the error and rewriting...\n');
111
162
 
112
163
  const reader = res.body.getReader();
113
164
  const decoder = new TextDecoder('utf-8');
165
+ let fullResponse = "";
114
166
 
115
167
  while (true) {
116
168
  const { done, value } = await reader.read();
@@ -122,29 +174,85 @@ async function chat(prompt) {
122
174
  for (const line of lines) {
123
175
  if (line.startsWith('data: ')) {
124
176
  const data = line.slice(6).trim();
125
- if (data === '[DONE]') {
126
- console.log('\n');
127
- process.exit(0);
128
- }
177
+ if (data === '[DONE]') break;
129
178
  try {
130
179
  const parsed = JSON.parse(data);
131
180
  if (parsed.text) {
181
+ fullResponse += parsed.text;
132
182
  process.stdout.write(parsed.text);
133
183
  }
134
184
  } catch (e) {}
135
185
  }
136
186
  }
137
187
  }
188
+
189
+ console.log('\n\n\x1b[32m[Agent] Response complete. Processing actions...\x1b[0m');
190
+
191
+ const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/g;
192
+ let match;
193
+ while ((match = fileRegex.exec(fullResponse)) !== null) {
194
+ const filePath = match[1];
195
+ const content = match[2];
196
+
197
+ const dir = path.dirname(filePath);
198
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
199
+ fs.writeFileSync(filePath, content.trim());
200
+ console.log(`\x1b[32m✔ Created file:\x1b[0m ${filePath}`);
201
+ }
202
+
203
+ const execRegex = /<execute>([\s\S]*?)<\/execute>/g;
204
+ const commands = [];
205
+ while ((match = execRegex.exec(fullResponse)) !== null) {
206
+ commands.push(match[1].trim());
207
+ }
208
+
209
+ for (const cmd of commands) {
210
+ try {
211
+ await runTerminalCommand(cmd);
212
+ } catch (err) {
213
+ console.error(`\n\x1b[31m❌ Command Failed:\x1b[0m ${err}`);
214
+ console.log(`\x1b[33m🔄 Triggering Auto-Heal Loop...\x1b[0m`);
215
+ const errorPrompt = `I ran the command "${cmd}" and got this error:\n\n${err}\n\nPlease fix the issue. Use <file> tags to rewrite files or <execute> to run commands.`;
216
+ await chat(errorPrompt, depth + 1);
217
+ return;
218
+ }
219
+ }
220
+ process.exit(0);
221
+
138
222
  } catch (error) {
139
223
  console.error('\n❌ Connection error: ' + error.message);
224
+ process.exit(1);
140
225
  }
141
226
  }
142
227
 
143
- if (command === 'login') {
144
- login();
145
- } else if (command === 'chat') {
228
+ function showHelp() {
229
+ printLogo();
230
+ console.log(`
231
+ \x1b[33mNoxyAI Agent CLI - Available Commands\x1b[0m
232
+
233
+ \x1b[32mnoxyai login\x1b[0m Authenticate your terminal
234
+ \x1b[32mnoxyai logout\x1b[0m Remove authentication from this device
235
+ \x1b[32mnoxyai chat "<prompt>"\x1b[0m Chat with the AI. It can build apps, create files, and fix errors.
236
+ \x1b[32mnoxyai help\x1b[0m Show this menu
237
+
238
+ \x1b[33mExamples:\x1b[0m
239
+ noxyai chat "Create a snake game in python and run it"
240
+ noxyai chat "Initialize a react app called my-app"
241
+ noxyai chat "Create an express server that returns hello world on port 3000"
242
+ `);
243
+ }
244
+
245
+ if (command === 'login') login();
246
+ else if (command === 'logout') logout();
247
+ else if (command === 'help' || command === '--help' || !command) showHelp();
248
+ else if (command === 'chat') {
146
249
  const prompt = args.slice(1).join(' ');
250
+ if (!prompt) {
251
+ console.error('❌ Please provide a prompt. Example: noxyai chat "Create a python script"');
252
+ process.exit(1);
253
+ }
147
254
  chat(prompt);
148
255
  } else {
149
- console.log('\nUsage:\n noxyai login\n noxyai chat <prompt>\n');
256
+ console.error(`❌ Unknown command: ${command}`);
257
+ console.log('Run "noxyai help" for a list of commands.');
150
258
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "npm-noxyai",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "CLI for NoxyAI",
5
5
  "main": "index-noxyai.js",
6
6
  "bin": {
package/tic_tac_toe.py ADDED
@@ -0,0 +1,111 @@
1
+ import random
2
+
3
+ class TicTacToe:
4
+ def __init__(self):
5
+ self.board = [' ' for _ in range(9)]
6
+
7
+ def print_board(self):
8
+ row1 = '| {} | {} | {} |'.format(self.board[0], self.board[1], self.board[2])
9
+ row2 = '| {} | {} | {} |'.format(self.board[3], self.board[4], self.board[5])
10
+ row3 = '| {} | {} | {} |'.format(self.board[6], self.board[7], self.board[8])
11
+
12
+ print()
13
+ print(row1)
14
+ print(row2)
15
+ print(row3)
16
+ print()
17
+
18
+ def available_moves(self):
19
+ return [i for i, spot in enumerate(self.board) if spot == ' ']
20
+
21
+ def empty_cells(self):
22
+ return ' ' in self.board
23
+
24
+ def num_empty_cells(self):
25
+ return self.board.count(' ')
26
+
27
+ def make_move(self, letter, move):
28
+ self.board[move] = letter
29
+
30
+ def winner(self):
31
+ winning_combos = [(0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)]
32
+ for combo in winning_combos:
33
+ if self.board[combo[0]] == self.board[combo[1]] == self.board[combo[2]] != ' ':
34
+ return self.board[combo[0]]
35
+ if ' ' not in self.board:
36
+ return 'Tie'
37
+ return False
38
+
39
+ def minimax(board, depth, is_maximizing):
40
+ result = board.winner()
41
+ if result:
42
+ if result == 'X':
43
+ return -10 + depth
44
+ elif result == 'O':
45
+ return 10 - depth
46
+ elif result == 'Tie':
47
+ return 0
48
+
49
+ if is_maximizing:
50
+ best_score = float('-inf')
51
+ for move in board.available_moves():
52
+ board.make_move('O', move)
53
+ score = minimax(board, depth + 1, False)
54
+ board.board[move] = ' '
55
+ best_score = max(score, best_score)
56
+ return best_score
57
+ else:
58
+ best_score = float('inf')
59
+ for move in board.available_moves():
60
+ board.make_move('X', move)
61
+ score = minimax(board, depth + 1, True)
62
+ board.board[move] = ' '
63
+ best_score = min(score, best_score)
64
+ return best_score
65
+
66
+ def ai_move(board):
67
+ best_score = float('-inf')
68
+ best_move = 0
69
+ for move in board.available_moves():
70
+ board.make_move('O', move)
71
+ score = minimax(board, 0, False)
72
+ board.board[move] = ' '
73
+ if score > best_score:
74
+ best_score = score
75
+ best_move = move
76
+ return best_move
77
+
78
+ def main():
79
+ board = TicTacToe()
80
+ while True:
81
+ board.print_board()
82
+ move = input("Enter your move (1-9): ")
83
+ if board.board[int(move) - 1] != ' ':
84
+ print("Invalid move, try again.")
85
+ continue
86
+ board.make_move('X', int(move) - 1)
87
+ result = board.winner()
88
+ if result:
89
+ board.print_board()
90
+ if result == 'X':
91
+ print("You win!")
92
+ elif result == 'O':
93
+ print("AI wins!")
94
+ else:
95
+ print("It's a tie!")
96
+ break
97
+ move = ai_move(board)
98
+ board.make_move('O', move)
99
+ result = board.winner()
100
+ if result:
101
+ board.print_board()
102
+ if result == 'X':
103
+ print("You win!")
104
+ elif result == 'O':
105
+ print("AI wins!")
106
+ else:
107
+ print("It's a tie!")
108
+ break
109
+
110
+ if __name__ == '__main__':
111
+ main()