@nolimitcli/cli 2.1.0 → 2.1.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.
Files changed (2) hide show
  1. package/dist/index.js +111 -136
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,9 +3,9 @@ import Conf from 'conf';
3
3
  import chalk from 'chalk';
4
4
  import ora from 'ora';
5
5
  import open from 'open';
6
- import * as readline from 'readline/promises';
6
+ import repl from 'repl';
7
7
  const API_BASE = 'https://nolimit-production-2589.up.railway.app';
8
- const VERSION = '2.1.0';
8
+ const VERSION = '2.1.2';
9
9
  // Persistent config storage
10
10
  const config = new Conf({
11
11
  projectName: 'nolimit',
@@ -14,6 +14,9 @@ const config = new Conf({
14
14
  apiKey: { type: 'string' },
15
15
  },
16
16
  });
17
+ // State
18
+ let apiKey;
19
+ let balance = 0;
17
20
  // ============================================================================
18
21
  // HELPERS
19
22
  // ============================================================================
@@ -22,7 +25,9 @@ function formatTokens(tokens) {
22
25
  return (tokens / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
23
26
  return tokens.toString();
24
27
  }
25
- async function getBalance(apiKey) {
28
+ async function getBalance() {
29
+ if (!apiKey)
30
+ return null;
26
31
  try {
27
32
  const response = await fetch(`${API_BASE}/api/credits/balance`, {
28
33
  headers: { 'Authorization': `Bearer ${apiKey}` },
@@ -56,9 +61,11 @@ async function authenticate() {
56
61
  return null;
57
62
  }
58
63
  }
59
- async function watchAd(apiKey) {
64
+ async function watchAd() {
65
+ if (!apiKey)
66
+ return false;
60
67
  try {
61
- const startData = await getBalance(apiKey);
68
+ const startData = await getBalance();
62
69
  const startBalance = startData?.balance || 0;
63
70
  const adResponse = await fetch(`${API_BASE}/api/ads/request`, {
64
71
  headers: { 'Authorization': `Bearer ${apiKey}` },
@@ -76,9 +83,10 @@ async function watchAd(apiKey) {
76
83
  attempts++;
77
84
  const remaining = adData.duration - Math.min(attempts, adData.duration);
78
85
  spinner.text = remaining > 0 ? `${remaining}s` : 'Verifying...';
79
- const newData = await getBalance(apiKey);
86
+ const newData = await getBalance();
80
87
  if (newData && newData.balance > startBalance) {
81
88
  spinner.succeed(chalk.green(`+${formatTokens(newData.balance - startBalance)} tokens`));
89
+ balance = newData.balance;
82
90
  return true;
83
91
  }
84
92
  }
@@ -89,7 +97,9 @@ async function watchAd(apiKey) {
89
97
  return false;
90
98
  }
91
99
  }
92
- async function generate(apiKey, userPrompt) {
100
+ async function generate(userPrompt) {
101
+ if (!apiKey)
102
+ return null;
93
103
  try {
94
104
  const response = await fetch(`${API_BASE}/api/ai/generate`, {
95
105
  method: 'POST',
@@ -116,9 +126,9 @@ async function generate(apiKey, userPrompt) {
116
126
  }
117
127
  }
118
128
  // ============================================================================
119
- // WELCOME SCREEN
129
+ // WELCOME
120
130
  // ============================================================================
121
- function showWelcome(balance) {
131
+ function showWelcome() {
122
132
  console.clear();
123
133
  console.log();
124
134
  console.log(chalk.bold.white(' ┌───────────────────────────────┐'));
@@ -133,11 +143,11 @@ function showWelcome(balance) {
133
143
  console.log();
134
144
  }
135
145
  // ============================================================================
136
- // MAIN LOOP
146
+ // MAIN
137
147
  // ============================================================================
138
148
  async function main() {
139
149
  // Get or create API key
140
- let apiKey = config.get('apiKey');
150
+ apiKey = config.get('apiKey');
141
151
  if (!apiKey) {
142
152
  const spinner = ora('Initializing...').start();
143
153
  const newKey = await authenticate();
@@ -149,146 +159,111 @@ async function main() {
149
159
  spinner.succeed('Ready');
150
160
  }
151
161
  // Get balance
152
- const balanceData = await getBalance(apiKey);
153
- let balance = balanceData?.balance || 0;
162
+ const balanceData = await getBalance();
163
+ balance = balanceData?.balance || 0;
154
164
  // Show welcome
155
- showWelcome(balance);
156
- // Create readline interface using promises API
157
- const rl = readline.createInterface({
158
- input: process.stdin,
159
- output: process.stdout,
160
- });
161
- // Handle Ctrl+C
162
- process.on('SIGINT', () => {
163
- console.log(chalk.dim('\n\n Goodbye.\n'));
164
- rl.close();
165
- process.exit(0);
166
- });
167
- // Main loop
168
- while (true) {
169
- let input;
170
- try {
171
- input = await rl.question(chalk.green('› '));
172
- }
173
- catch {
174
- // EOF or stream closed
175
- break;
176
- }
177
- const trimmed = input.trim();
178
- if (!trimmed)
179
- continue;
180
- // Handle commands
181
- if (trimmed.startsWith('/')) {
182
- const cmd = trimmed.toLowerCase();
183
- if (cmd === '/quit' || cmd === '/exit' || cmd === '/q') {
184
- console.log(chalk.dim('\n Goodbye.\n'));
185
- break;
186
- }
187
- if (cmd === '/help' || cmd === '/h') {
188
- console.log();
189
- console.log(chalk.dim(' Commands:'));
190
- console.log(chalk.cyan(' /earn') + chalk.dim(' Watch ad for 8K tokens'));
191
- console.log(chalk.cyan(' /balance') + chalk.dim(' Check token balance'));
192
- console.log(chalk.cyan(' /clear') + chalk.dim(' Clear screen'));
193
- console.log(chalk.cyan(' /quit') + chalk.dim(' Exit'));
194
- console.log();
195
- continue;
165
+ showWelcome();
166
+ // Start REPL
167
+ const r = repl.start({
168
+ prompt: chalk.green('› '),
169
+ eval: async (input, _context, _filename, callback) => {
170
+ const trimmed = input.trim();
171
+ if (!trimmed) {
172
+ callback(null, undefined);
173
+ return;
196
174
  }
197
- if (cmd === '/earn' || cmd === '/e') {
198
- console.log();
199
- const success = await watchAd(apiKey);
200
- if (success) {
201
- const newData = await getBalance(apiKey);
202
- balance = newData?.balance || balance;
175
+ // Handle commands
176
+ if (trimmed.startsWith('/')) {
177
+ const cmd = trimmed.toLowerCase();
178
+ if (cmd === '/quit' || cmd === '/exit' || cmd === '/q') {
179
+ console.log(chalk.dim('\n Goodbye.\n'));
180
+ process.exit(0);
203
181
  }
204
- console.log();
205
- continue;
206
- }
207
- if (cmd === '/balance' || cmd === '/b') {
208
- const data = await getBalance(apiKey);
209
- if (data) {
210
- balance = data.balance;
182
+ if (cmd === '/help' || cmd === '/h') {
183
+ console.log();
184
+ console.log(chalk.dim(' Commands:'));
185
+ console.log(chalk.cyan(' /earn') + chalk.dim(' Watch ad for 8K tokens'));
186
+ console.log(chalk.cyan(' /balance') + chalk.dim(' Check token balance'));
187
+ console.log(chalk.cyan(' /clear') + chalk.dim(' Clear screen'));
188
+ console.log(chalk.cyan(' /quit') + chalk.dim(' Exit'));
211
189
  console.log();
212
- console.log(chalk.dim(' Balance: ') + chalk.bold.white(formatTokens(data.balance)));
213
- console.log(chalk.dim(' Earned: ') + formatTokens(data.totalEarned));
214
- console.log(chalk.dim(' Spent: ') + formatTokens(data.totalSpent));
190
+ callback(null, undefined);
191
+ return;
192
+ }
193
+ if (cmd === '/earn' || cmd === '/e') {
194
+ console.log();
195
+ await watchAd();
215
196
  console.log();
197
+ callback(null, undefined);
198
+ return;
199
+ }
200
+ if (cmd === '/balance' || cmd === '/b') {
201
+ const data = await getBalance();
202
+ if (data) {
203
+ balance = data.balance;
204
+ console.log();
205
+ console.log(chalk.dim(' Balance: ') + chalk.bold.white(formatTokens(data.balance)));
206
+ console.log(chalk.dim(' Earned: ') + formatTokens(data.totalEarned));
207
+ console.log(chalk.dim(' Spent: ') + formatTokens(data.totalSpent));
208
+ console.log();
209
+ }
210
+ callback(null, undefined);
211
+ return;
216
212
  }
217
- continue;
213
+ if (cmd === '/clear' || cmd === '/c') {
214
+ showWelcome();
215
+ callback(null, undefined);
216
+ return;
217
+ }
218
+ console.log(chalk.dim(`\n Unknown: ${trimmed}\n`));
219
+ callback(null, undefined);
220
+ return;
218
221
  }
219
- if (cmd === '/clear' || cmd === '/c') {
220
- showWelcome(balance);
221
- continue;
222
+ // Check tokens
223
+ if (balance < 100) {
224
+ console.log();
225
+ console.log(chalk.yellow(' Low tokens. Run /earn'));
226
+ console.log();
227
+ callback(null, undefined);
228
+ return;
222
229
  }
223
- console.log(chalk.dim(`\n Unknown: ${trimmed}\n`));
224
- continue;
225
- }
226
- // Check if we have enough tokens
227
- if (balance < 100) {
230
+ // Generate
228
231
  console.log();
229
- console.log(chalk.yellow(' Low tokens.'));
230
- let answer;
231
- try {
232
- answer = await rl.question(chalk.dim(' Watch ad? ') + chalk.cyan('[Y/n] '));
233
- }
234
- catch {
235
- break;
232
+ const spinner = ora({ text: chalk.dim('Thinking...'), spinner: 'dots' }).start();
233
+ const result = await generate(trimmed);
234
+ if (!result) {
235
+ spinner.fail(chalk.red('Failed'));
236
+ console.log();
237
+ callback(null, undefined);
238
+ return;
236
239
  }
237
- if (answer.toLowerCase() !== 'n') {
238
- const success = await watchAd(apiKey);
239
- if (success) {
240
- const newData = await getBalance(apiKey);
241
- balance = newData?.balance || balance;
242
- }
240
+ if (result.text === '__INSUFFICIENT_TOKENS__') {
241
+ spinner.stop();
242
+ console.log(chalk.yellow(' Insufficient tokens. Run /earn'));
243
+ console.log();
244
+ callback(null, undefined);
245
+ return;
243
246
  }
244
- console.log();
245
- continue;
246
- }
247
- // Generate response
248
- console.log();
249
- const spinner = ora({ text: chalk.dim('Thinking...'), spinner: 'dots' }).start();
250
- const result = await generate(apiKey, trimmed);
251
- if (!result) {
252
- spinner.fail(chalk.red('Failed'));
253
- console.log();
254
- continue;
255
- }
256
- if (result.text === '__INSUFFICIENT_TOKENS__') {
257
247
  spinner.stop();
258
- console.log(chalk.yellow(' Insufficient tokens.'));
259
- let answer;
260
- try {
261
- answer = await rl.question(chalk.dim(' Watch ad? ') + chalk.cyan('[Y/n] '));
262
- }
263
- catch {
264
- break;
265
- }
266
- if (answer.toLowerCase() !== 'n') {
267
- const success = await watchAd(apiKey);
268
- if (success) {
269
- const newData = await getBalance(apiKey);
270
- balance = newData?.balance || balance;
271
- }
248
+ // Show response
249
+ const lines = result.text.split('\n');
250
+ for (const line of lines) {
251
+ console.log(chalk.white(' ' + line));
272
252
  }
273
253
  console.log();
274
- continue;
275
- }
276
- spinner.stop();
277
- // Show response (indented for visual hierarchy)
278
- const lines = result.text.split('\n');
279
- for (const line of lines) {
280
- console.log(chalk.white(' ' + line));
281
- }
282
- console.log();
283
- // Update and show balance
284
- balance = Math.max(0, balance - result.tokensUsed);
285
- console.log(chalk.dim(` ─ ${formatTokens(result.tokensUsed)} tokens · ${formatTokens(balance)} remaining`));
286
- console.log();
287
- }
288
- rl.close();
289
- process.exit(0);
254
+ balance = Math.max(0, balance - result.tokensUsed);
255
+ console.log(chalk.dim(` ─ ${formatTokens(result.tokensUsed)} tokens · ${formatTokens(balance)} remaining`));
256
+ console.log();
257
+ callback(null, undefined);
258
+ },
259
+ writer: () => '', // Suppress default output
260
+ ignoreUndefined: true,
261
+ });
262
+ r.on('exit', () => {
263
+ console.log(chalk.dim('\n Goodbye.\n'));
264
+ process.exit(0);
265
+ });
290
266
  }
291
- // Run
292
267
  main().catch((error) => {
293
268
  console.error(chalk.red('Error:'), error.message);
294
269
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nolimitcli/cli",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "type": "module",
5
5
  "description": "No subscription. Just code. AI chat powered by watching ads.",
6
6
  "main": "dist/index.js",