slek-ai-cli 1.0.0

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.
Files changed (5) hide show
  1. package/README.md +70 -0
  2. package/auth.js +225 -0
  3. package/cli.js +452 -0
  4. package/package.json +22 -0
  5. package/setup.js +78 -0
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # ๐Ÿš€ NVIDIA AI CLI
2
+
3
+ เฆเฆ•เฆŸเฆฟ เฆธเงเฆจเงเฆฆเฆฐ AI Command Line Interface เฆฏเฆพ NVIDIA API เฆฌเงเฆฏเฆฌเฆนเฆพเฆฐ เฆ•เฆฐเง‡เฅค
4
+
5
+ ## โœจ Features
6
+
7
+ - ๐Ÿค– NVIDIA API เฆฆเฆฟเฆฏเฆผเง‡ AI chat
8
+ - ๐ŸŒŠ Real-time streaming response
9
+ - ๐ŸŽจ Colorful terminal UI
10
+ - ๐Ÿ“œ Chat history
11
+ - ๐Ÿ’พ Chat save เฆ•เฆฐเฆพเฆฐ เฆธเงเฆฌเฆฟเฆงเฆพ
12
+ - ๐Ÿ”„ Multiple AI models
13
+ - โšก Fast & lightweight
14
+
15
+ ## ๐Ÿ“ฆ Installation
16
+
17
+ ```bash
18
+ # Dependencies install เฆ•เฆฐเงเฆจ
19
+ npm install
20
+
21
+ # Setup เฆ•เฆฐเงเฆจ (API key เฆฆเฆฟเฆจ)
22
+ npm run setup
23
+ ```
24
+
25
+ ## ๐Ÿ”‘ NVIDIA API Key เฆชเฆพเฆฌเง‡เฆจ เฆ•เง€เฆญเฆพเฆฌเง‡?
26
+
27
+ 1. [https://build.nvidia.com](https://build.nvidia.com) เฆ เฆฏเฆพเฆจ
28
+ 2. Sign up / Login เฆ•เฆฐเงเฆจ (Free!)
29
+ 3. เฆฏเง‡เฆ•เง‹เฆจเง‹ model เฆ click เฆ•เฆฐเงเฆจ
30
+ 4. "Get API Key" เฆฌเฆพเฆŸเฆจเง‡ click เฆ•เฆฐเงเฆจ
31
+ 5. Key copy เฆ•เฆฐเงเฆจ
32
+
33
+ ## ๐Ÿƒ Run เฆ•เฆฐเงเฆจ
34
+
35
+ ```bash
36
+ node cli.js
37
+ ```
38
+
39
+ ## ๐Ÿ’ฌ Commands
40
+
41
+ | Command | เฆ•เฆพเฆœ |
42
+ |-------------|----------------------------|
43
+ | `/help` | Help เฆฆเง‡เฆ–เฆพเฆจ |
44
+ | `/model` | AI model เฆฌเฆฆเฆฒเฆพเฆจ |
45
+ | `/models` | เฆธเฆฌ models เฆฆเง‡เฆ–เฆพเฆจ |
46
+ | `/clear` | Chat history เฆฎเงเฆ›เงเฆจ |
47
+ | `/history` | Chat history เฆฆเง‡เฆ–เฆพเฆจ |
48
+ | `/save` | Chat file เฆ save เฆ•เฆฐเงเฆจ |
49
+ | `/info` | Current settings เฆฆเง‡เฆ–เฆพเฆจ |
50
+ | `/exit` | เฆฌเฆจเงเฆง เฆ•เฆฐเงเฆจ |
51
+
52
+ ## ๐Ÿค– Available Models
53
+
54
+ - **Llama 3.1 70B** - เฆธเฆฌเฆšเง‡เฆฏเฆผเง‡ เฆถเฆ•เงเฆคเฆฟเฆถเฆพเฆฒเง€
55
+ - **Llama 3.1 8B** - เฆฆเงเฆฐเงเฆค response
56
+ - **Nemotron 70B** - NVIDIA เฆเฆฐ เฆจเฆฟเฆœเฆธเงเฆฌ model
57
+ - **Mixtral 8x7B** - Mistral AI
58
+ - **Phi-3 Medium** - Microsoft
59
+ - **Gemma 7B** - Google
60
+
61
+ ## ๐Ÿ“ File Structure
62
+
63
+ ```
64
+ AI CLI/
65
+ โ”œโ”€โ”€ cli.js # Main CLI file
66
+ โ”œโ”€โ”€ setup.js # Setup script
67
+ โ”œโ”€โ”€ package.json # Dependencies
68
+ โ”œโ”€โ”€ .env # API key (เฆเฆŸเฆฟ share เฆ•เฆฐเฆฌเง‡เฆจ เฆจเฆพ!)
69
+ โ””โ”€โ”€ README.md # Documentation
70
+ ```
package/auth.js ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ require('dotenv').config({ path: require('path').join(__dirname, '.env') });
5
+
6
+ const http = require('http');
7
+ const urlModule = require('url');
8
+ const path = require('path');
9
+ const fs = require('fs');
10
+ const { execSync } = require('child_process');
11
+ const axios = require('axios');
12
+ const chalk = require('chalk');
13
+ const boxen = require('boxen');
14
+ const gradient = require('gradient-string');
15
+
16
+ const nvidiaGradient = gradient(['#76b900', '#00c8ff']);
17
+
18
+ // โ”€โ”€โ”€ Firebase / Google config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
19
+ const FIREBASE_API_KEY = process.env.FIREBASE_API_KEY;
20
+ const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;
21
+ const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET;
22
+ const REDIRECT_URI = 'http://localhost:9876/callback';
23
+ const AUTH_PORT = 9876;
24
+
25
+ // โ”€โ”€โ”€ Token file path (saved in user home) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
26
+ const TOKEN_PATH = path.join(
27
+ process.env.APPDATA || process.env.HOME || __dirname,
28
+ '.slek-auth.json'
29
+ );
30
+
31
+ // โ”€โ”€โ”€ Token helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
32
+ function saveToken(data) {
33
+ fs.writeFileSync(TOKEN_PATH, JSON.stringify(data, null, 2), 'utf8');
34
+ }
35
+
36
+ function loadToken() {
37
+ try {
38
+ if (fs.existsSync(TOKEN_PATH)) {
39
+ return JSON.parse(fs.readFileSync(TOKEN_PATH, 'utf8'));
40
+ }
41
+ } catch { }
42
+ return null;
43
+ }
44
+
45
+ function clearToken() {
46
+ try { fs.unlinkSync(TOKEN_PATH); } catch { }
47
+ }
48
+
49
+ function isLoggedIn() {
50
+ const token = loadToken();
51
+ if (!token) return false;
52
+ if (token.expiresAt && Date.now() > token.expiresAt) return false;
53
+ return true;
54
+ }
55
+
56
+ function getUser() {
57
+ return loadToken();
58
+ }
59
+
60
+ // โ”€โ”€โ”€ Open browser (PowerShell safe) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
61
+ function openBrowser(targetUrl) {
62
+ try {
63
+ execSync(`powershell -Command "Start-Process '${targetUrl}'"`, { stdio: 'ignore' });
64
+ } catch {
65
+ console.log(chalk.yellow('\n Could not open browser automatically.'));
66
+ console.log(chalk.white(' Paste this URL in your browser:\n'));
67
+ console.log(chalk.cyan(' ' + targetUrl + '\n'));
68
+ }
69
+ }
70
+
71
+ // โ”€โ”€โ”€ Exchange Google code โ†’ Firebase token โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
72
+ async function exchangeCodeForToken(code) {
73
+ const tokenRes = await axios.post('https://oauth2.googleapis.com/token', {
74
+ code,
75
+ client_id: GOOGLE_CLIENT_ID,
76
+ client_secret: GOOGLE_CLIENT_SECRET,
77
+ redirect_uri: REDIRECT_URI,
78
+ grant_type: 'authorization_code',
79
+ });
80
+
81
+ const { id_token } = tokenRes.data;
82
+
83
+ const firebaseRes = await axios.post(
84
+ `https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key=${FIREBASE_API_KEY}`,
85
+ {
86
+ postBody: `id_token=${id_token}&providerId=google.com`,
87
+ requestUri: REDIRECT_URI,
88
+ returnIdpCredential: true,
89
+ returnSecureToken: true,
90
+ }
91
+ );
92
+
93
+ const { displayName, email, idToken, expiresIn, photoUrl } = firebaseRes.data;
94
+ return {
95
+ name: displayName,
96
+ email,
97
+ photo: photoUrl,
98
+ idToken,
99
+ expiresAt: Date.now() + parseInt(expiresIn) * 1000,
100
+ };
101
+ }
102
+
103
+ // โ”€โ”€โ”€ Login โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
104
+ async function login() {
105
+ if (!FIREBASE_API_KEY || !GOOGLE_CLIENT_ID || !GOOGLE_CLIENT_SECRET) {
106
+ console.log(
107
+ boxen(
108
+ chalk.red('โœ— Firebase config missing!\n\n') +
109
+ chalk.white('Add to your ') + chalk.yellow('.env') + chalk.white(':\n\n') +
110
+ chalk.cyan('FIREBASE_API_KEY=...\nGOOGLE_CLIENT_ID=...\nGOOGLE_CLIENT_SECRET=...'),
111
+ { padding: 1, margin: { left: 2 }, borderStyle: 'round', borderColor: 'red' }
112
+ )
113
+ );
114
+ process.exit(1);
115
+ }
116
+
117
+ // Build Google OAuth URL
118
+ const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
119
+ authUrl.searchParams.set('client_id', GOOGLE_CLIENT_ID);
120
+ authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
121
+ authUrl.searchParams.set('response_type', 'code');
122
+ authUrl.searchParams.set('scope', 'openid email profile');
123
+ authUrl.searchParams.set('access_type', 'offline');
124
+ authUrl.searchParams.set('prompt', 'select_account');
125
+
126
+ return new Promise((resolve, reject) => {
127
+ const server = http.createServer(async (req, res) => {
128
+ const parsed = urlModule.parse(req.url, true);
129
+ if (parsed.pathname !== '/callback') {
130
+ res.writeHead(404); res.end(); return;
131
+ }
132
+
133
+ const code = parsed.query.code;
134
+ const error = parsed.query.error;
135
+
136
+ res.writeHead(200, { 'Content-Type': 'text/html' });
137
+ res.end(`<html><body style="background:#0a0a0a;color:#fff;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;"><div style="text-align:center;"><h1 style="color:#76b900;">โœ“ Login Successful!</h1><p style="color:#aaa;">You can close this tab and return to the terminal.</p></div></body></html>`);
138
+
139
+ server.close();
140
+
141
+ if (error) {
142
+ console.log(chalk.red('\n โœ— Login cancelled.\n'));
143
+ reject(new Error(error));
144
+ return;
145
+ }
146
+
147
+ try {
148
+ process.stdout.write(chalk.cyan('\n โณ Verifying with Firebase...\n'));
149
+ const userData = await exchangeCodeForToken(code);
150
+ saveToken(userData);
151
+ console.log(
152
+ '\n' + boxen(
153
+ chalk.green('โœ“ Logged in successfully!\n\n') +
154
+ chalk.cyan('Name : ') + chalk.white(userData.name) + '\n' +
155
+ chalk.cyan('Email : ') + chalk.white(userData.email),
156
+ { padding: 1, margin: { left: 2 }, borderStyle: 'round', borderColor: 'green' }
157
+ )
158
+ );
159
+ console.log(chalk.gray('\n Now run ') + chalk.yellow('slek') + chalk.gray(' to start chatting!\n'));
160
+ resolve(userData);
161
+ } catch (err) {
162
+ console.log(chalk.red('\n โœ— Auth failed: ') + err.message + '\n');
163
+ reject(err);
164
+ }
165
+ });
166
+
167
+ server.on('error', (err) => {
168
+ console.log(chalk.red('\n โœ— Server error: ') + err.message);
169
+ reject(err);
170
+ });
171
+
172
+ server.listen(AUTH_PORT, '127.0.0.1', () => {
173
+ console.log(
174
+ boxen(
175
+ chalk.bold.white('๐Ÿ” SLEK AI โ€” Google Login\n') +
176
+ chalk.gray('โ”€'.repeat(38)) + '\n\n' +
177
+ chalk.cyan('Opening browser...\n') +
178
+ chalk.gray('Waiting for Google authentication...\n\n') +
179
+ chalk.gray('If browser does not open, paste this URL:\n') +
180
+ chalk.yellow(authUrl.toString()),
181
+ { padding: 1, margin: { left: 2 }, borderStyle: 'double', borderColor: 'green' }
182
+ )
183
+ );
184
+ // Small delay to ensure server is fully ready before browser opens
185
+ setTimeout(() => openBrowser(authUrl.toString()), 500);
186
+ });
187
+
188
+ setTimeout(() => {
189
+ server.close();
190
+ console.log(chalk.red('\n โœ— Login timed out (2 min). Try again.\n'));
191
+ reject(new Error('Login timeout'));
192
+ }, 120000);
193
+ });
194
+ }
195
+
196
+ // โ”€โ”€โ”€ Logout โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
197
+ function logout() {
198
+ clearToken();
199
+ console.log(
200
+ '\n' + boxen(
201
+ chalk.yellow('๐Ÿ‘‹ Logged out!\n\n') +
202
+ chalk.gray('Run ') + chalk.yellow('slek login') + chalk.gray(' to log in again.'),
203
+ { padding: 1, margin: { left: 2 }, borderStyle: 'round', borderColor: 'yellow' }
204
+ ) + '\n'
205
+ );
206
+ }
207
+
208
+ // โ”€โ”€โ”€ Status โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
209
+ function status() {
210
+ const user = getUser();
211
+ if (user) {
212
+ console.log(
213
+ '\n' + boxen(
214
+ chalk.green('โœ“ Logged in\n\n') +
215
+ chalk.cyan('Name : ') + chalk.white(user.name) + '\n' +
216
+ chalk.cyan('Email : ') + chalk.white(user.email),
217
+ { padding: 1, margin: { left: 2 }, borderStyle: 'round', borderColor: 'green' }
218
+ ) + '\n'
219
+ );
220
+ } else {
221
+ console.log(chalk.yellow('\n Not logged in. Run: ') + chalk.white('slek login\n'));
222
+ }
223
+ }
224
+
225
+ module.exports = { isLoggedIn, getUser, login, logout, status };
package/cli.js ADDED
@@ -0,0 +1,452 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ require('dotenv').config({
5
+ path: require('path').join(__dirname, '.env')
6
+ });
7
+
8
+ // โ”€โ”€โ”€ Auth check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
9
+ const auth = require('./auth');
10
+
11
+ const arg = process.argv[2];
12
+
13
+ // Handle: slek login / slek logout / slek status
14
+ if (arg === 'login') {
15
+ auth.login().catch(() => process.exit(1));
16
+ return;
17
+ }
18
+ if (arg === 'logout') {
19
+ auth.logout();
20
+ process.exit(0);
21
+ }
22
+ if (arg === 'status') {
23
+ auth.status();
24
+ process.exit(0);
25
+ }
26
+
27
+ // Block access if not logged in
28
+ if (!auth.isLoggedIn()) {
29
+ const chalk = require('chalk');
30
+ const boxen = require('boxen');
31
+ console.log(
32
+ '\n' + boxen(
33
+ chalk.yellow('โš  You are not logged in!\n\n') +
34
+ chalk.white('Run this command to login:\n\n') +
35
+ chalk.green(' slek login'),
36
+ { padding: 1, margin: { left: 2 }, borderStyle: 'double', borderColor: 'yellow' }
37
+ ) + '\n'
38
+ );
39
+ process.exit(1);
40
+ }
41
+
42
+ const readline = require('readline');
43
+ const axios = require('axios');
44
+ const chalk = require('chalk');
45
+ const boxen = require('boxen');
46
+ const gradient = require('gradient-string');
47
+ const figlet = require('figlet');
48
+
49
+ // โ”€โ”€โ”€ NOTE: ora v5 is required (CommonJS compatible) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
50
+ // If ora gives errors, run: npm install ora@5
51
+ let ora;
52
+ try {
53
+ ora = require('ora');
54
+ } catch {
55
+ // Fallback spinner if ora fails
56
+ ora = (opts) => ({
57
+ start: () => { process.stdout.write(chalk.cyan(' โณ ' + (opts.text || 'Loading...') + '\n')); return { stop: () => {}, fail: () => {} }; },
58
+ stop: () => {},
59
+ fail: () => {},
60
+ });
61
+ }
62
+
63
+ // โ”€โ”€โ”€ NVIDIA API Config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
64
+ const NVIDIA_API_BASE = 'https://slek-ai-portal.vercel.app/api';
65
+ const DEFAULT_MODEL = 'qwen/qwen3.5-122b-a10b';
66
+
67
+ // โ”€โ”€โ”€ User config path (stored in user's home, not in project) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
68
+ const CONFIG_PATH = require('path').join(
69
+ process.env.APPDATA || process.env.HOME || __dirname,
70
+ '.slek-config.json'
71
+ );
72
+
73
+ function loadConfig() {
74
+ try {
75
+ if (require('fs').existsSync(CONFIG_PATH)) {
76
+ return JSON.parse(require('fs').readFileSync(CONFIG_PATH, 'utf8'));
77
+ }
78
+ } catch { }
79
+ return {};
80
+ }
81
+
82
+ function saveConfig(data) {
83
+ const current = loadConfig();
84
+ require('fs').writeFileSync(CONFIG_PATH, JSON.stringify({ ...current, ...data }, null, 2), 'utf8');
85
+ }
86
+
87
+ // โ”€โ”€โ”€ Gradient Colors โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
88
+ const nvidiaGradient = gradient(['#76b900', '#00c8ff']);
89
+ const userGradient = gradient(['#ff6b6b', '#feca57']);
90
+ const aiGradient = gradient(['#48dbfb', '#ff9ff3']);
91
+ const thinkGradient = gradient(['#f7971e', '#ffd200']);
92
+
93
+ // โ”€โ”€โ”€ State โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
94
+ let chatHistory = [];
95
+ let apiKey = process.env.NVIDIA_API_KEY || '';
96
+ const currentUser = auth.getUser();
97
+
98
+ // โ”€โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
99
+ function clearLine() {
100
+ process.stdout.write('\r\x1b[K');
101
+ }
102
+
103
+ // โ”€โ”€โ”€ Banner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
104
+ async function showBanner() {
105
+ console.clear();
106
+ const banner = figlet.textSync('SLEK AI', {
107
+ font: 'ANSI Shadow',
108
+ horizontalLayout: 'default',
109
+ });
110
+ console.log(nvidiaGradient(banner));
111
+ console.log(
112
+ boxen(
113
+ chalk.bold.white('๐Ÿš€ SLEK AI CLI') + chalk.gray(' โ€” Powered by NVIDIA API\n') +
114
+ chalk.gray('โ”'.repeat(42)) + '\n' +
115
+ chalk.cyan(' User : ') + chalk.green(currentUser ? currentUser.name : 'Unknown') + '\n' +
116
+ chalk.gray('โ”'.repeat(42)) + '\n' +
117
+ chalk.white(' Type ') + chalk.yellow('/help') + chalk.white(' for available commands'),
118
+ {
119
+ padding: 1,
120
+ margin: { top: 0, bottom: 1, left: 2, right: 2 },
121
+ borderStyle: 'double',
122
+ borderColor: 'green',
123
+ backgroundColor: '#000',
124
+ }
125
+ )
126
+ );
127
+ }
128
+
129
+ // โ”€โ”€โ”€ Help โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
130
+ function showHelp() {
131
+ const helpBox = boxen(
132
+ chalk.bold.cyan('๐Ÿ“‹ Available Commands\n') +
133
+ chalk.gray('โ•'.repeat(42)) + '\n\n' +
134
+ chalk.yellow('/help ') + chalk.white('Show this help menu\n') +
135
+ chalk.yellow('/clear ') + chalk.white('Clear chat history\n') +
136
+ chalk.yellow('/history ') + chalk.white('Show chat history\n') +
137
+ chalk.yellow('/save ') + chalk.white('Save chat to file\n') +
138
+ chalk.yellow('/info ') + chalk.white('Show current settings\n') +
139
+ chalk.yellow('/exit ') + chalk.white('Exit the CLI\n\n') +
140
+ chalk.gray('Or just type anything to chat with AI!'),
141
+ {
142
+ padding: 1,
143
+ margin: { left: 2 },
144
+ borderStyle: 'round',
145
+ borderColor: 'cyan',
146
+ }
147
+ );
148
+ console.log(helpBox);
149
+ }
150
+
151
+ // โ”€โ”€โ”€ Show Models โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
152
+ function showModels() {
153
+ console.log('\n' + chalk.bold.cyan(' ๐Ÿค– Available Models:\n'));
154
+ Object.entries(MODELS).forEach(([key, model]) => {
155
+ const active = model.id === currentModel ? chalk.green(' โ—„ ACTIVE') : '';
156
+ const thinking = model.thinking ? chalk.yellow(' [๐Ÿง  Thinking]') : '';
157
+ console.log(` ${chalk.yellow(key + '.')} ${chalk.white(model.name)}${thinking}${active}`);
158
+ });
159
+ console.log();
160
+ }
161
+
162
+ // โ”€โ”€โ”€ Change Model โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
163
+ async function changeModel(rl) {
164
+ showModels();
165
+ return new Promise(resolve => {
166
+ rl.question(chalk.cyan(' Enter model number (1-7): '), answer => {
167
+ const chosen = MODELS[answer.trim()];
168
+ if (chosen) {
169
+ currentModel = chosen.id;
170
+ enableThinking = chosen.thinking || false;
171
+ const thinkNote = chosen.thinking ? chalk.yellow(' (Thinking mode ON)') : '';
172
+ console.log(chalk.green(`\n โœ“ Model: ${chalk.yellow(chosen.name.trim())}${thinkNote}\n`));
173
+ } else {
174
+ console.log(chalk.red('\n โœ— Invalid choice\n'));
175
+ }
176
+ resolve();
177
+ });
178
+ });
179
+ }
180
+
181
+ // โ”€โ”€โ”€ Toggle Thinking โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
182
+ function toggleThinking() {
183
+ enableThinking = !enableThinking;
184
+ if (enableThinking) {
185
+ console.log(chalk.green('\n ๐Ÿง  Thinking mode: ON\n'));
186
+ } else {
187
+ console.log(chalk.gray('\n ๐Ÿ’ค Thinking mode: OFF\n'));
188
+ }
189
+ }
190
+
191
+
192
+
193
+ // โ”€โ”€โ”€ Show Info โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
194
+ function showInfo() {
195
+ const infoBox = boxen(
196
+ chalk.bold.white('โš™ Current Settings\n') +
197
+ chalk.gray('โ”€'.repeat(40)) + '\n\n' +
198
+ chalk.cyan('User : ') + chalk.green(currentUser ? currentUser.name : 'Unknown') + '\n' +
199
+ chalk.cyan('Messages : ') + chalk.white(chatHistory.length + ' in history') + '\n' +
200
+ chalk.cyan('API URL : ') + chalk.gray(NVIDIA_API_BASE),
201
+ {
202
+ padding: 1,
203
+ margin: { left: 2 },
204
+ borderStyle: 'single',
205
+ borderColor: 'yellow',
206
+ }
207
+ );
208
+ console.log('\n' + infoBox);
209
+ }
210
+
211
+ // โ”€โ”€โ”€ Show History โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
212
+ function showHistory() {
213
+ if (chatHistory.length === 0) {
214
+ console.log(chalk.yellow('\n No chat history yet.\n'));
215
+ return;
216
+ }
217
+ console.log('\n' + chalk.bold.cyan(' ๐Ÿ“œ Chat History:\n'));
218
+ chatHistory.forEach((msg, i) => {
219
+ if (msg.role === 'user') {
220
+ console.log(chalk.gray(` [${i + 1}] `) + userGradient('You: ') + chalk.white(msg.content));
221
+ } else {
222
+ const preview = msg.content.substring(0, 80) + (msg.content.length > 80 ? '...' : '');
223
+ console.log(chalk.gray(` [${i + 1}] `) + aiGradient('AI: ') + chalk.gray(preview));
224
+ }
225
+ });
226
+ console.log();
227
+ }
228
+
229
+ // โ”€โ”€โ”€ Save Chat โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
230
+ async function saveChat() {
231
+ if (chatHistory.length === 0) {
232
+ console.log(chalk.yellow('\n No chat history to save.\n'));
233
+ return;
234
+ }
235
+ const fs = require('fs');
236
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
237
+ const filename = `chat-${timestamp}.txt`;
238
+ const filepath = require('path').join(process.cwd(), filename);
239
+
240
+ let content = `SLEK AI CLI - Chat Log\n`;
241
+ content += `Date: ${new Date().toLocaleString()}\n`;
242
+ content += `Model: ${currentModel}\n`;
243
+ content += `${'โ•'.repeat(50)}\n\n`;
244
+
245
+ chatHistory.forEach(msg => {
246
+ if (msg.role === 'user') {
247
+ content += `YOU:\n${msg.content}\n\n`;
248
+ } else {
249
+ content += `AI:\n${msg.content}\n\n`;
250
+ content += `${'โ”€'.repeat(40)}\n\n`;
251
+ }
252
+ });
253
+
254
+ fs.writeFileSync(filepath, content, 'utf8');
255
+ console.log(chalk.green(`\n โœ“ Chat saved to: ${chalk.yellow(filename)}\n`));
256
+ }
257
+
258
+ // โ”€โ”€โ”€ Stream API Call โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
259
+ async function callNvidiaAPIStream(userMessage) {
260
+ if (!apiKey) {
261
+ throw new Error('API key not configured. Please set NVIDIA_API_KEY in your .env file.');
262
+ }
263
+
264
+ chatHistory.push({ role: 'user', content: userMessage });
265
+
266
+ const messages = [
267
+ {
268
+ role: 'system',
269
+ content:
270
+ 'You are a helpful, smart, and friendly AI assistant. ' +
271
+ 'Provide clear, accurate, and well-structured responses.',
272
+ },
273
+ ...chatHistory,
274
+ ];
275
+
276
+ const payload = {
277
+ model: DEFAULT_MODEL,
278
+ messages,
279
+ max_tokens: 16384,
280
+ temperature: 0.60,
281
+ top_p: 0.95,
282
+ stream: true,
283
+ chat_template_kwargs: { enable_thinking: true },
284
+ };
285
+
286
+ const response = await axios.post(
287
+ `${NVIDIA_API_BASE}/chat-free`,
288
+ payload,
289
+ {
290
+ headers: {
291
+ Authorization: `Bearer ${apiKey}`,
292
+ 'Content-Type': 'application/json',
293
+ Accept: 'text/event-stream',
294
+ },
295
+ responseType: 'stream',
296
+ timeout: 120000,
297
+ }
298
+ );
299
+
300
+ return new Promise((resolve, reject) => {
301
+ let fullResponse = '';
302
+ let inThinkBlock = false;
303
+
304
+ process.stdout.write('\n ' + aiGradient('โœฆ SLEK AI: ') + '\n\n ');
305
+
306
+ response.data.on('data', chunk => {
307
+ const lines = chunk.toString().split('\n');
308
+ for (const line of lines) {
309
+ if (line.startsWith('data: ') && !line.includes('[DONE]')) {
310
+ try {
311
+ const data = JSON.parse(line.slice(6));
312
+ const token = data.choices?.[0]?.delta?.content || '';
313
+ if (!token) continue;
314
+
315
+ fullResponse += token;
316
+
317
+ if (token.includes('<think>')) {
318
+ inThinkBlock = true;
319
+ process.stdout.write('\n ' + thinkGradient('๐Ÿ’ญ Thinking...') + '\n ');
320
+ continue;
321
+ }
322
+ if (token.includes('</think>')) {
323
+ inThinkBlock = false;
324
+ process.stdout.write('\n\n ' + aiGradient('โœฆ Answer:') + '\n\n ');
325
+ continue;
326
+ }
327
+
328
+ if (inThinkBlock) {
329
+ process.stdout.write(chalk.dim.yellow(token));
330
+ } else {
331
+ process.stdout.write(chalk.white(token));
332
+ }
333
+ } catch { /* ignore malformed SSE lines */ }
334
+ }
335
+ }
336
+ });
337
+
338
+ response.data.on('end', () => {
339
+ const cleanResponse = fullResponse.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
340
+ chatHistory.push({ role: 'assistant', content: cleanResponse });
341
+ console.log('\n');
342
+ resolve(cleanResponse);
343
+ });
344
+
345
+ response.data.on('error', reject);
346
+ });
347
+ }
348
+
349
+ // โ”€โ”€โ”€ Process User Input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
350
+ async function processInput(input, rl) {
351
+ const trimmed = input.trim();
352
+ if (!trimmed) return;
353
+
354
+ if (trimmed.startsWith('/')) {
355
+ const cmd = trimmed.toLowerCase().split(' ')[0];
356
+ switch (cmd) {
357
+ case '/help': showHelp(); break;
358
+ case '/clear':
359
+ chatHistory = [];
360
+ console.log(chalk.green('\n โœ“ Chat history cleared!\n'));
361
+ break;
362
+ case '/history': showHistory(); break;
363
+ case '/save': await saveChat(); break;
364
+ case '/info': showInfo(); break;
365
+ case '/exit':
366
+ case '/quit':
367
+ console.log('\n' + nvidiaGradient(' ๐Ÿ‘‹ Goodbye! Thanks for using SLEK AI CLI\n'));
368
+ rl.close();
369
+ process.exit(0);
370
+ break;
371
+ default:
372
+ console.log(chalk.red(`\n โœ— Unknown command: ${cmd}. Type /help for help.\n`));
373
+ }
374
+ return;
375
+ }
376
+
377
+ const spinner = ora({
378
+ text: chalk.cyan(' Connecting to NVIDIA API...'),
379
+ spinner: 'dots',
380
+ color: 'cyan',
381
+ prefixText: ' ',
382
+ }).start();
383
+
384
+ try {
385
+ spinner.stop();
386
+ clearLine();
387
+ await callNvidiaAPIStream(trimmed);
388
+ } catch (err) {
389
+ spinner.stop();
390
+ const errMsg =
391
+ err.response?.data?.detail ||
392
+ err.response?.data?.message ||
393
+ err.message ||
394
+ 'Unknown error';
395
+ console.log(
396
+ '\n' +
397
+ boxen(chalk.red('โœ— Error: ') + chalk.white(errMsg), {
398
+ padding: 1,
399
+ margin: { left: 2 },
400
+ borderStyle: 'round',
401
+ borderColor: 'red',
402
+ }) + '\n'
403
+ );
404
+ }
405
+ }
406
+
407
+ // โ”€โ”€โ”€ Prompt โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
408
+ function showPrompt(rl) {
409
+ const prompt =
410
+ '\n' +
411
+ chalk.gray(' โ”Œโ”€') +
412
+ userGradient(' You ') +
413
+ chalk.gray('โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n') +
414
+ chalk.gray(' โ””โ–ถ ');
415
+ rl.setPrompt(prompt);
416
+ rl.prompt();
417
+ }
418
+
419
+ // โ”€โ”€โ”€ Main โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
420
+ async function main() {
421
+ await showBanner();
422
+
423
+
424
+
425
+ const rl = readline.createInterface({
426
+ input: process.stdin,
427
+ output: process.stdout,
428
+ terminal: true,
429
+ });
430
+
431
+ showPrompt(rl);
432
+
433
+ rl.on('line', async line => {
434
+ await processInput(line, rl);
435
+ showPrompt(rl);
436
+ });
437
+
438
+ rl.on('close', () => {
439
+ console.log('\n' + nvidiaGradient(' ๐Ÿ‘‹ Goodbye!\n'));
440
+ process.exit(0);
441
+ });
442
+
443
+ rl.on('SIGINT', () => {
444
+ console.log(chalk.yellow('\n\n Press Ctrl+C again or type /exit to quit.\n'));
445
+ showPrompt(rl);
446
+ });
447
+ }
448
+
449
+ main().catch(err => {
450
+ console.error(chalk.red('Fatal Error:'), err.message);
451
+ process.exit(1);
452
+ });
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "slek-ai-cli",
3
+ "version": "1.0.0",
4
+ "description": "SLEK AI CLI โ€” Powered by NVIDIA API",
5
+ "main": "cli.js",
6
+ "bin": {
7
+ "slek": "cli.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node cli.js"
11
+ },
12
+ "dependencies": {
13
+ "axios": "^1.6.0",
14
+ "boxen": "^5.1.2",
15
+ "chalk": "^4.1.2",
16
+ "dotenv": "^16.0.0",
17
+ "figlet": "^1.7.0",
18
+ "gradient-string": "^2.0.2",
19
+ "open": "^8.4.2",
20
+ "ora": "^5.4.1"
21
+ }
22
+ }
package/setup.js ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Quick Setup Script for NVIDIA AI CLI
6
+ * Run: node setup.js
7
+ */
8
+
9
+ const readline = require('readline');
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const chalk = require('chalk');
13
+ const gradient = require('gradient-string');
14
+ const boxen = require('boxen');
15
+ const figlet = require('figlet');
16
+
17
+ const nvidiaGradient = gradient(['#76b900', '#00c8ff']);
18
+
19
+ async function setup() {
20
+ console.clear();
21
+
22
+ const banner = figlet.textSync('Setup', { font: 'Big' });
23
+ console.log(nvidiaGradient(banner));
24
+
25
+ console.log(
26
+ boxen(
27
+ chalk.bold.white('๐Ÿ›  NVIDIA AI CLI Setup\n\n') +
28
+ chalk.cyan('Step 1: ') + chalk.white('Go to ') + chalk.cyan.underline('https://build.nvidia.com') + '\n' +
29
+ chalk.cyan('Step 2: ') + chalk.white('Sign up / Log in for free\n') +
30
+ chalk.cyan('Step 3: ') + chalk.white('Click on any model โ†’ Get API Key\n') +
31
+ chalk.cyan('Step 4: ') + chalk.white('Copy your API key & paste below'),
32
+ {
33
+ padding: 1,
34
+ margin: { left: 2, bottom: 1 },
35
+ borderStyle: 'double',
36
+ borderColor: 'green',
37
+ }
38
+ )
39
+ );
40
+
41
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
42
+
43
+ const question = (q) => new Promise(resolve => rl.question(q, resolve));
44
+
45
+ const apiKey = await question(chalk.cyan(' Enter your NVIDIA API Key: '));
46
+
47
+ if (!apiKey.trim()) {
48
+ console.log(chalk.red('\n โœ— No API key entered. Setup cancelled.\n'));
49
+ rl.close();
50
+ return;
51
+ }
52
+
53
+ // Save to .env file
54
+ const envPath = path.join(__dirname, '.env');
55
+ fs.writeFileSync(envPath, `NVIDIA_API_KEY=${apiKey.trim()}\n`);
56
+
57
+ console.log(
58
+ '\n' +
59
+ boxen(
60
+ chalk.green('โœ… Setup Complete!\n\n') +
61
+ chalk.white('API Key saved to .env file\n\n') +
62
+ chalk.gray('Now run: ') + chalk.yellow('node cli.js') + chalk.gray(' to start chatting!'),
63
+ {
64
+ padding: 1,
65
+ margin: { left: 2 },
66
+ borderStyle: 'round',
67
+ borderColor: 'green',
68
+ }
69
+ )
70
+ );
71
+
72
+ rl.close();
73
+ }
74
+
75
+ setup().catch(err => {
76
+ console.error(chalk.red('Setup error:'), err.message);
77
+ process.exit(1);
78
+ });