@nolimitcli/cli 2.0.1 → 2.0.2
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/dist/index.js +120 -132
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import ora from 'ora';
|
|
|
5
5
|
import open from 'open';
|
|
6
6
|
import * as readline from 'readline';
|
|
7
7
|
const API_BASE = 'https://nolimit-production-2589.up.railway.app';
|
|
8
|
-
const VERSION = '2.0.
|
|
8
|
+
const VERSION = '2.0.2';
|
|
9
9
|
// Persistent config storage
|
|
10
10
|
const config = new Conf({
|
|
11
11
|
projectName: 'nolimit',
|
|
@@ -58,20 +58,16 @@ async function authenticate() {
|
|
|
58
58
|
}
|
|
59
59
|
async function watchAd(apiKey) {
|
|
60
60
|
try {
|
|
61
|
-
// Get starting balance
|
|
62
61
|
const startData = await getBalance(apiKey);
|
|
63
62
|
const startBalance = startData?.balance || 0;
|
|
64
|
-
// Request ad
|
|
65
63
|
const adResponse = await fetch(`${API_BASE}/api/ads/request`, {
|
|
66
64
|
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
67
65
|
});
|
|
68
66
|
if (!adResponse.ok)
|
|
69
67
|
return false;
|
|
70
68
|
const adData = await adResponse.json();
|
|
71
|
-
// Open ad viewer
|
|
72
69
|
const adUrl = `${API_BASE}/ad-viewer.html?adId=${adData.adId}&apiKey=${apiKey}`;
|
|
73
70
|
await open(adUrl);
|
|
74
|
-
// Poll for completion
|
|
75
71
|
const spinner = ora('Watching...').start();
|
|
76
72
|
let attempts = 0;
|
|
77
73
|
const maxAttempts = 60;
|
|
@@ -93,7 +89,7 @@ async function watchAd(apiKey) {
|
|
|
93
89
|
return false;
|
|
94
90
|
}
|
|
95
91
|
}
|
|
96
|
-
async function generate(apiKey,
|
|
92
|
+
async function generate(apiKey, userPrompt) {
|
|
97
93
|
try {
|
|
98
94
|
const response = await fetch(`${API_BASE}/api/ai/generate`, {
|
|
99
95
|
method: 'POST',
|
|
@@ -101,7 +97,7 @@ async function generate(apiKey, prompt) {
|
|
|
101
97
|
'Authorization': `Bearer ${apiKey}`,
|
|
102
98
|
'Content-Type': 'application/json',
|
|
103
99
|
},
|
|
104
|
-
body: JSON.stringify({ prompt }),
|
|
100
|
+
body: JSON.stringify({ prompt: userPrompt }),
|
|
105
101
|
});
|
|
106
102
|
const data = await response.json();
|
|
107
103
|
if (!response.ok) {
|
|
@@ -115,11 +111,27 @@ async function generate(apiKey, prompt) {
|
|
|
115
111
|
tokensUsed: data.usage?.totalTokens || 0,
|
|
116
112
|
};
|
|
117
113
|
}
|
|
118
|
-
catch
|
|
114
|
+
catch {
|
|
119
115
|
return null;
|
|
120
116
|
}
|
|
121
117
|
}
|
|
122
118
|
// ============================================================================
|
|
119
|
+
// READLINE HELPERS
|
|
120
|
+
// ============================================================================
|
|
121
|
+
function createReadline() {
|
|
122
|
+
return readline.createInterface({
|
|
123
|
+
input: process.stdin,
|
|
124
|
+
output: process.stdout,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function question(rl, query) {
|
|
128
|
+
return new Promise((resolve) => {
|
|
129
|
+
rl.question(query, (answer) => {
|
|
130
|
+
resolve(answer);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// ============================================================================
|
|
123
135
|
// WELCOME SCREEN
|
|
124
136
|
// ============================================================================
|
|
125
137
|
function showWelcome(balance) {
|
|
@@ -158,144 +170,120 @@ async function main() {
|
|
|
158
170
|
// Show welcome
|
|
159
171
|
showWelcome(balance);
|
|
160
172
|
// Create readline interface
|
|
161
|
-
const rl =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
const rl = createReadline();
|
|
174
|
+
// Main loop
|
|
175
|
+
let running = true;
|
|
176
|
+
while (running) {
|
|
177
|
+
try {
|
|
178
|
+
const input = await question(rl, chalk.green('› '));
|
|
179
|
+
const trimmed = input.trim();
|
|
180
|
+
if (!trimmed)
|
|
181
|
+
continue;
|
|
182
|
+
// Handle commands
|
|
183
|
+
if (trimmed.startsWith('/')) {
|
|
184
|
+
const cmd = trimmed.toLowerCase();
|
|
185
|
+
if (cmd === '/quit' || cmd === '/exit' || cmd === '/q') {
|
|
186
|
+
console.log(chalk.dim('\n Goodbye.\n'));
|
|
187
|
+
running = false;
|
|
188
|
+
break;
|
|
172
189
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
prompt();
|
|
190
|
-
return;
|
|
190
|
+
if (cmd === '/help' || cmd === '/h') {
|
|
191
|
+
console.log();
|
|
192
|
+
console.log(chalk.dim(' Commands:'));
|
|
193
|
+
console.log(chalk.cyan(' /earn') + chalk.dim(' Watch an ad to earn tokens'));
|
|
194
|
+
console.log(chalk.cyan(' /balance') + chalk.dim(' Check your token balance'));
|
|
195
|
+
console.log(chalk.cyan(' /clear') + chalk.dim(' Clear the screen'));
|
|
196
|
+
console.log(chalk.cyan(' /quit') + chalk.dim(' Exit NoLimit'));
|
|
197
|
+
console.log();
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (cmd === '/earn' || cmd === '/e') {
|
|
201
|
+
console.log();
|
|
202
|
+
const success = await watchAd(apiKey);
|
|
203
|
+
if (success) {
|
|
204
|
+
const newData = await getBalance(apiKey);
|
|
205
|
+
balance = newData?.balance || balance;
|
|
191
206
|
}
|
|
192
|
-
|
|
207
|
+
console.log();
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (cmd === '/balance' || cmd === '/b') {
|
|
211
|
+
const data = await getBalance(apiKey);
|
|
212
|
+
if (data) {
|
|
213
|
+
balance = data.balance;
|
|
193
214
|
console.log();
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
balance = newData?.balance || balance;
|
|
198
|
-
}
|
|
215
|
+
console.log(chalk.dim(' Balance: ') + chalk.bold.white(formatTokens(data.balance)) + chalk.dim(' tokens'));
|
|
216
|
+
console.log(chalk.dim(' Earned: ') + formatTokens(data.totalEarned));
|
|
217
|
+
console.log(chalk.dim(' Spent: ') + formatTokens(data.totalSpent));
|
|
199
218
|
console.log();
|
|
200
|
-
prompt();
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
if (cmd === '/balance' || cmd === '/b') {
|
|
204
|
-
const data = await getBalance(apiKey);
|
|
205
|
-
if (data) {
|
|
206
|
-
balance = data.balance;
|
|
207
|
-
console.log();
|
|
208
|
-
console.log(chalk.dim(' Balance: ') + chalk.bold.white(formatTokens(data.balance)) + chalk.dim(' tokens'));
|
|
209
|
-
console.log(chalk.dim(' Earned: ') + formatTokens(data.totalEarned));
|
|
210
|
-
console.log(chalk.dim(' Spent: ') + formatTokens(data.totalSpent));
|
|
211
|
-
console.log();
|
|
212
|
-
}
|
|
213
|
-
prompt();
|
|
214
|
-
return;
|
|
215
219
|
}
|
|
216
|
-
|
|
217
|
-
showWelcome(balance);
|
|
218
|
-
prompt();
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
console.log(chalk.dim(`\n Unknown command: ${trimmed}\n`));
|
|
222
|
-
prompt();
|
|
223
|
-
return;
|
|
220
|
+
continue;
|
|
224
221
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
console.log(chalk.yellow(' Low tokens.') + chalk.dim(' Watch an ad to continue.'));
|
|
229
|
-
console.log();
|
|
230
|
-
const watch = await new Promise((resolve) => {
|
|
231
|
-
rl.question(chalk.dim(' Watch now? ') + chalk.cyan('[Y/n] '), (answer) => {
|
|
232
|
-
resolve(answer.toLowerCase() !== 'n');
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
if (watch) {
|
|
236
|
-
const success = await watchAd(apiKey);
|
|
237
|
-
if (success) {
|
|
238
|
-
const newData = await getBalance(apiKey);
|
|
239
|
-
balance = newData?.balance || balance;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
console.log();
|
|
243
|
-
prompt();
|
|
244
|
-
return;
|
|
222
|
+
if (cmd === '/clear' || cmd === '/c') {
|
|
223
|
+
showWelcome(balance);
|
|
224
|
+
continue;
|
|
245
225
|
}
|
|
246
|
-
|
|
226
|
+
console.log(chalk.dim(`\n Unknown command: ${trimmed}\n`));
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
// Check if we have enough tokens
|
|
230
|
+
if (balance < 100) {
|
|
247
231
|
console.log();
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (result.text === '__INSUFFICIENT_TOKENS__') {
|
|
257
|
-
spinner.stop();
|
|
258
|
-
console.log(chalk.yellow(' Insufficient tokens.') + chalk.dim(' Watch an ad to continue.'));
|
|
259
|
-
console.log();
|
|
260
|
-
const watch = await new Promise((resolve) => {
|
|
261
|
-
rl.question(chalk.dim(' Watch now? ') + chalk.cyan('[Y/n] '), (answer) => {
|
|
262
|
-
resolve(answer.toLowerCase() !== 'n');
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
if (watch) {
|
|
266
|
-
const success = await watchAd(apiKey);
|
|
267
|
-
if (success) {
|
|
268
|
-
const newData = await getBalance(apiKey);
|
|
269
|
-
balance = newData?.balance || balance;
|
|
270
|
-
}
|
|
232
|
+
console.log(chalk.yellow(' Low tokens.') + chalk.dim(' Watch an ad to continue.'));
|
|
233
|
+
console.log();
|
|
234
|
+
const answer = await question(rl, chalk.dim(' Watch now? ') + chalk.cyan('[Y/n] '));
|
|
235
|
+
if (answer.toLowerCase() !== 'n') {
|
|
236
|
+
const success = await watchAd(apiKey);
|
|
237
|
+
if (success) {
|
|
238
|
+
const newData = await getBalance(apiKey);
|
|
239
|
+
balance = newData?.balance || balance;
|
|
271
240
|
}
|
|
272
|
-
console.log();
|
|
273
|
-
prompt();
|
|
274
|
-
return;
|
|
275
241
|
}
|
|
276
|
-
spinner.stop();
|
|
277
|
-
// Show response
|
|
278
|
-
console.log(chalk.white(result.text));
|
|
279
242
|
console.log();
|
|
280
|
-
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
// Generate response
|
|
246
|
+
console.log();
|
|
247
|
+
const spinner = ora({ text: chalk.dim('Thinking...'), spinner: 'dots' }).start();
|
|
248
|
+
const result = await generate(apiKey, trimmed);
|
|
249
|
+
if (!result) {
|
|
250
|
+
spinner.fail(chalk.red('Failed to generate response'));
|
|
281
251
|
console.log();
|
|
282
|
-
|
|
283
|
-
balance = Math.max(0, balance - result.tokensUsed);
|
|
284
|
-
prompt();
|
|
252
|
+
continue;
|
|
285
253
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
254
|
+
if (result.text === '__INSUFFICIENT_TOKENS__') {
|
|
255
|
+
spinner.stop();
|
|
256
|
+
console.log(chalk.yellow(' Insufficient tokens.') + chalk.dim(' Watch an ad to continue.'));
|
|
257
|
+
console.log();
|
|
258
|
+
const answer = await question(rl, chalk.dim(' Watch now? ') + chalk.cyan('[Y/n] '));
|
|
259
|
+
if (answer.toLowerCase() !== 'n') {
|
|
260
|
+
const success = await watchAd(apiKey);
|
|
261
|
+
if (success) {
|
|
262
|
+
const newData = await getBalance(apiKey);
|
|
263
|
+
balance = newData?.balance || balance;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
console.log();
|
|
267
|
+
continue;
|
|
289
268
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
269
|
+
spinner.stop();
|
|
270
|
+
// Show response
|
|
271
|
+
console.log(chalk.white(result.text));
|
|
272
|
+
console.log();
|
|
273
|
+
console.log(chalk.dim(` ─ ${formatTokens(result.tokensUsed)} tokens used`));
|
|
274
|
+
console.log();
|
|
275
|
+
// Update balance
|
|
276
|
+
balance = Math.max(0, balance - result.tokensUsed);
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
// Handle Ctrl+C or EOF
|
|
280
|
+
console.log(chalk.dim('\n Goodbye.\n'));
|
|
281
|
+
running = false;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
rl.close();
|
|
286
|
+
process.exit(0);
|
|
299
287
|
}
|
|
300
288
|
// Run
|
|
301
289
|
main().catch((error) => {
|