@nolimitcli/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.
- package/README.md +25 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +173 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @nolimit/cli
|
|
2
|
+
|
|
3
|
+
No subscription. Just code.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @nolimit/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
nolimit auth # Authenticate (get 2K welcome tokens)
|
|
15
|
+
nolimit earn # Watch ad to earn 8K tokens
|
|
16
|
+
nolimit balance # Check token balance
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## How it works
|
|
20
|
+
|
|
21
|
+
1. Watch a 30-second ad
|
|
22
|
+
2. Earn 8,000 tokens
|
|
23
|
+
3. Use tokens for AI prompts
|
|
24
|
+
|
|
25
|
+
No subscription. No credit card. Just code.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import Conf from 'conf';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import open from 'open';
|
|
7
|
+
const API_BASE = 'https://nolimit-production-2589.up.railway.app';
|
|
8
|
+
// Persistent config storage
|
|
9
|
+
const config = new Conf({
|
|
10
|
+
projectName: 'nolimit',
|
|
11
|
+
schema: {
|
|
12
|
+
sessionId: { type: 'string' },
|
|
13
|
+
apiKey: { type: 'string' },
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const program = new Command();
|
|
17
|
+
program
|
|
18
|
+
.name('nolimit')
|
|
19
|
+
.description('No subscription. Just code.')
|
|
20
|
+
.version('1.0.0');
|
|
21
|
+
// Auth command - register and get API key
|
|
22
|
+
program
|
|
23
|
+
.command('auth')
|
|
24
|
+
.description('Authenticate with NoLimit')
|
|
25
|
+
.action(async () => {
|
|
26
|
+
const spinner = ora('Registering...').start();
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetch(`${API_BASE}/api/auth/register`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'Content-Type': 'application/json' },
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
deviceId: `cli-${Date.now()}`,
|
|
33
|
+
userAgent: 'nolimit-cli/1.0.0',
|
|
34
|
+
consent: true,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
throw new Error(`Registration failed: ${response.status}`);
|
|
39
|
+
}
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
config.set('sessionId', data.sessionId);
|
|
42
|
+
config.set('apiKey', data.apiKey);
|
|
43
|
+
spinner.succeed(chalk.green('Authenticated'));
|
|
44
|
+
console.log();
|
|
45
|
+
console.log(chalk.dim('Session:'), data.sessionId.slice(0, 8) + '...');
|
|
46
|
+
if (data.welcomeBonus > 0) {
|
|
47
|
+
console.log(chalk.green(`+${data.welcomeBonus.toLocaleString()}`), 'welcome tokens');
|
|
48
|
+
}
|
|
49
|
+
console.log();
|
|
50
|
+
console.log(chalk.dim('Run'), chalk.cyan('nolimit earn'), chalk.dim('to get more tokens'));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
spinner.fail(chalk.red('Authentication failed'));
|
|
54
|
+
console.error(error instanceof Error ? error.message : error);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
// Earn command - watch ad to earn tokens
|
|
59
|
+
program
|
|
60
|
+
.command('earn')
|
|
61
|
+
.description('Watch an ad to earn tokens')
|
|
62
|
+
.action(async () => {
|
|
63
|
+
const apiKey = config.get('apiKey');
|
|
64
|
+
if (!apiKey) {
|
|
65
|
+
console.log(chalk.yellow('Not authenticated.'));
|
|
66
|
+
console.log(chalk.dim('Run'), chalk.cyan('nolimit auth'), chalk.dim('first'));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const spinner = ora('Requesting ad...').start();
|
|
70
|
+
try {
|
|
71
|
+
// Request ad
|
|
72
|
+
const adResponse = await fetch(`${API_BASE}/api/ads/request`, {
|
|
73
|
+
method: 'GET',
|
|
74
|
+
headers: {
|
|
75
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
if (!adResponse.ok) {
|
|
79
|
+
throw new Error(`Ad request failed: ${adResponse.status}`);
|
|
80
|
+
}
|
|
81
|
+
const adData = await adResponse.json();
|
|
82
|
+
spinner.succeed('Ad ready');
|
|
83
|
+
console.log();
|
|
84
|
+
console.log(chalk.dim('Reward:'), chalk.bold(adData.tokenReward.toLocaleString()), 'tokens');
|
|
85
|
+
console.log(chalk.dim('Duration:'), adData.duration, 'seconds');
|
|
86
|
+
console.log();
|
|
87
|
+
// Open ad viewer in browser
|
|
88
|
+
const adUrl = `${API_BASE}/ad-viewer.html?adId=${adData.adId}&apiKey=${apiKey}`;
|
|
89
|
+
console.log(chalk.dim('Opening ad in browser...'));
|
|
90
|
+
await open(adUrl);
|
|
91
|
+
// Wait for user to complete ad
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(chalk.yellow('Complete the ad in your browser.'));
|
|
94
|
+
console.log(chalk.dim('Press Enter when done...'));
|
|
95
|
+
await new Promise((resolve) => {
|
|
96
|
+
process.stdin.once('data', () => resolve());
|
|
97
|
+
});
|
|
98
|
+
// Verify completion
|
|
99
|
+
const verifySpinner = ora('Verifying...').start();
|
|
100
|
+
const verifyResponse = await fetch(`${API_BASE}/api/ads/verify-completion`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: {
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
105
|
+
},
|
|
106
|
+
body: JSON.stringify({
|
|
107
|
+
adId: adData.adId,
|
|
108
|
+
completedAt: Date.now(),
|
|
109
|
+
events: [
|
|
110
|
+
{ event: 'play', time: 0 },
|
|
111
|
+
{ event: 'midpoint', time: Math.floor(adData.duration / 2) },
|
|
112
|
+
{ event: 'complete', time: adData.duration },
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
if (!verifyResponse.ok) {
|
|
117
|
+
const errorData = await verifyResponse.json().catch(() => ({}));
|
|
118
|
+
throw new Error(errorData.error || `Verification failed: ${verifyResponse.status}`);
|
|
119
|
+
}
|
|
120
|
+
const verifyData = await verifyResponse.json();
|
|
121
|
+
verifySpinner.succeed(chalk.green('Tokens earned'));
|
|
122
|
+
console.log();
|
|
123
|
+
console.log(chalk.bold.green(`+${verifyData.tokensGranted.toLocaleString()}`), 'tokens');
|
|
124
|
+
console.log(chalk.dim('New balance:'), chalk.bold(verifyData.newBalance.toLocaleString()));
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
spinner.fail(chalk.red('Failed'));
|
|
128
|
+
console.error(error instanceof Error ? error.message : error);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// Balance command - check current balance
|
|
133
|
+
program
|
|
134
|
+
.command('balance')
|
|
135
|
+
.description('Check your token balance')
|
|
136
|
+
.action(async () => {
|
|
137
|
+
const apiKey = config.get('apiKey');
|
|
138
|
+
if (!apiKey) {
|
|
139
|
+
console.log(chalk.yellow('Not authenticated.'));
|
|
140
|
+
console.log(chalk.dim('Run'), chalk.cyan('nolimit auth'), chalk.dim('first'));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const spinner = ora('Fetching balance...').start();
|
|
144
|
+
try {
|
|
145
|
+
const response = await fetch(`${API_BASE}/api/credits/balance`, {
|
|
146
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
147
|
+
});
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw new Error(`Failed to fetch balance: ${response.status}`);
|
|
150
|
+
}
|
|
151
|
+
const data = await response.json();
|
|
152
|
+
spinner.succeed('Balance');
|
|
153
|
+
console.log();
|
|
154
|
+
console.log(chalk.bold.white(data.balance.toLocaleString()), 'tokens');
|
|
155
|
+
console.log();
|
|
156
|
+
console.log(chalk.dim('Total earned:'), data.totalEarned.toLocaleString());
|
|
157
|
+
console.log(chalk.dim('Total spent:'), data.totalSpent.toLocaleString());
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
spinner.fail(chalk.red('Failed'));
|
|
161
|
+
console.error(error instanceof Error ? error.message : error);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// Default action - show help
|
|
166
|
+
program.action(() => {
|
|
167
|
+
console.log();
|
|
168
|
+
console.log(chalk.bold('NoLimit'));
|
|
169
|
+
console.log(chalk.dim('No subscription. Just code.'));
|
|
170
|
+
console.log();
|
|
171
|
+
program.outputHelp();
|
|
172
|
+
});
|
|
173
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nolimitcli/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "No subscription. Just code. Watch an ad, build without limits.",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"nolimit": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc -w",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai",
|
|
17
|
+
"coding",
|
|
18
|
+
"free",
|
|
19
|
+
"tokens",
|
|
20
|
+
"cli",
|
|
21
|
+
"developer-tools"
|
|
22
|
+
],
|
|
23
|
+
"author": "Buzzer Network",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/anthropics/nolimit"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=16"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"chalk": "^5.3.0",
|
|
34
|
+
"commander": "^12.0.0",
|
|
35
|
+
"conf": "^12.0.0",
|
|
36
|
+
"open": "^10.0.0",
|
|
37
|
+
"ora": "^8.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^20.0.0",
|
|
41
|
+
"typescript": "^5.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|