@trading-boy/cli 1.2.7 → 1.2.9
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/cli.bundle.js +51 -10
- package/dist/commands/login.js +10 -6
- package/dist/commands/subscribe.d.ts +6 -0
- package/dist/commands/subscribe.js +45 -5
- package/package.json +10 -10
package/dist/cli.bundle.js
CHANGED
|
@@ -45742,7 +45742,7 @@ function registerInfraCommand(program2) {
|
|
|
45742
45742
|
// dist/commands/login.js
|
|
45743
45743
|
init_source();
|
|
45744
45744
|
var logger19 = createLogger("cli-login");
|
|
45745
|
-
var API_KEY_PATTERN = /^tb_(live|test)_[a-f0-9]{32}$/;
|
|
45745
|
+
var API_KEY_PATTERN = /^tb_(live|test|free)_[a-f0-9]{32}$/;
|
|
45746
45746
|
function validateApiKeyFormat(key) {
|
|
45747
45747
|
return API_KEY_PATTERN.test(key);
|
|
45748
45748
|
}
|
|
@@ -45750,8 +45750,11 @@ async function verifyApiKey(apiKey) {
|
|
|
45750
45750
|
const apiBase = getApiBase();
|
|
45751
45751
|
const response = await fetch(`${apiBase}/api/v1/auth/verify`, {
|
|
45752
45752
|
method: "POST",
|
|
45753
|
-
headers: {
|
|
45754
|
-
|
|
45753
|
+
headers: {
|
|
45754
|
+
"Content-Type": "application/json",
|
|
45755
|
+
"Authorization": `Bearer ${apiKey}`
|
|
45756
|
+
},
|
|
45757
|
+
body: "{}"
|
|
45755
45758
|
});
|
|
45756
45759
|
if (!response.ok) {
|
|
45757
45760
|
if (response.status === 401) {
|
|
@@ -45782,7 +45785,7 @@ async function executeLogin(apiKey) {
|
|
|
45782
45785
|
};
|
|
45783
45786
|
}
|
|
45784
45787
|
function registerLoginCommand(program2) {
|
|
45785
|
-
program2.command("login").description("Authenticate with your Trading Boy API key").
|
|
45788
|
+
program2.command("login").description("Authenticate with your Trading Boy API key").addOption(new Option("--api-key <key>", "API key (deprecated \u2014 use TRADING_BOY_API_KEY env var)").hideHelp()).action(async (opts) => {
|
|
45786
45789
|
try {
|
|
45787
45790
|
let apiKey;
|
|
45788
45791
|
if (opts.apiKey) {
|
|
@@ -45801,14 +45804,14 @@ function registerLoginCommand(program2) {
|
|
|
45801
45804
|
if (!input)
|
|
45802
45805
|
return "API key is required";
|
|
45803
45806
|
if (!validateApiKeyFormat(input)) {
|
|
45804
|
-
return "Invalid key format. Expected: tb_live_<32hex
|
|
45807
|
+
return "Invalid key format. Expected: tb_live_<32hex>, tb_test_<32hex>, or tb_free_<32hex>";
|
|
45805
45808
|
}
|
|
45806
45809
|
return true;
|
|
45807
45810
|
}
|
|
45808
45811
|
});
|
|
45809
45812
|
}
|
|
45810
45813
|
if (!validateApiKeyFormat(apiKey)) {
|
|
45811
|
-
console.error(source_default.red(" Invalid key format. Expected: tb_live_<32hex
|
|
45814
|
+
console.error(source_default.red(" Invalid key format. Expected: tb_live_<32hex>, tb_test_<32hex>, or tb_free_<32hex>"));
|
|
45812
45815
|
process.exitCode = 1;
|
|
45813
45816
|
return;
|
|
45814
45817
|
}
|
|
@@ -46371,9 +46374,9 @@ function registerSubscribeCommand(program2) {
|
|
|
46371
46374
|
plan = await select({
|
|
46372
46375
|
message: "Choose your plan",
|
|
46373
46376
|
choices: [
|
|
46374
|
-
{ name: "Starter \u2014
|
|
46375
|
-
{ name: "Pro \u2014 $
|
|
46376
|
-
{ name: "Edge \u2014 $
|
|
46377
|
+
{ name: "Starter \u2014 Free (core context + journal)", value: "starter" },
|
|
46378
|
+
{ name: "Pro \u2014 $29/mo (+ coaching + thesis extraction)", value: "pro" },
|
|
46379
|
+
{ name: "Edge \u2014 $99/mo (+ edge analysis + full analytics)", value: "edge" }
|
|
46377
46380
|
]
|
|
46378
46381
|
});
|
|
46379
46382
|
}
|
|
@@ -46383,6 +46386,14 @@ function registerSubscribeCommand(program2) {
|
|
|
46383
46386
|
process.exitCode = 1;
|
|
46384
46387
|
return;
|
|
46385
46388
|
}
|
|
46389
|
+
const planLabels = { starter: "Starter (Free)", pro: "Pro ($29/mo)", edge: "Edge ($99/mo)" };
|
|
46390
|
+
if (plan === "starter") {
|
|
46391
|
+
console.log("");
|
|
46392
|
+
console.log(` ${source_default.bold("Plan:")} ${planLabels[plan]}`);
|
|
46393
|
+
console.log("");
|
|
46394
|
+
await handleFreeRegistration(email3);
|
|
46395
|
+
return;
|
|
46396
|
+
}
|
|
46386
46397
|
if (!pay) {
|
|
46387
46398
|
pay = await select({
|
|
46388
46399
|
message: "How would you like to pay?",
|
|
@@ -46398,7 +46409,6 @@ function registerSubscribeCommand(program2) {
|
|
|
46398
46409
|
process.exitCode = 1;
|
|
46399
46410
|
return;
|
|
46400
46411
|
}
|
|
46401
|
-
const planLabels = { starter: "Starter ($20/mo)", pro: "Pro ($40/mo)", edge: "Edge ($75/mo)" };
|
|
46402
46412
|
console.log("");
|
|
46403
46413
|
console.log(` ${source_default.bold("Plan:")} ${planLabels[plan] ?? plan}`);
|
|
46404
46414
|
console.log(` ${source_default.bold("Pay:")} ${pay === "crypto" ? "USDC on Solana" : "Stripe"}`);
|
|
@@ -46420,6 +46430,37 @@ function registerSubscribeCommand(program2) {
|
|
|
46420
46430
|
}
|
|
46421
46431
|
});
|
|
46422
46432
|
}
|
|
46433
|
+
async function handleFreeRegistration(email3) {
|
|
46434
|
+
console.log(source_default.white(" Creating your free account..."));
|
|
46435
|
+
let result;
|
|
46436
|
+
try {
|
|
46437
|
+
const response = await fetch(`${getApiBase()}/api/v1/auth/register`, {
|
|
46438
|
+
method: "POST",
|
|
46439
|
+
headers: { "Content-Type": "application/json" },
|
|
46440
|
+
body: JSON.stringify({ email: email3 })
|
|
46441
|
+
});
|
|
46442
|
+
if (!response.ok) {
|
|
46443
|
+
const body = await response.text();
|
|
46444
|
+
throw new Error(`Registration failed (${response.status}): ${body}`);
|
|
46445
|
+
}
|
|
46446
|
+
result = await response.json();
|
|
46447
|
+
} catch (err) {
|
|
46448
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
46449
|
+
console.error(source_default.red(` Failed to register: ${message}`));
|
|
46450
|
+
const hint = formatConnectionError2(message);
|
|
46451
|
+
if (hint)
|
|
46452
|
+
console.error(hint);
|
|
46453
|
+
process.exitCode = 1;
|
|
46454
|
+
return;
|
|
46455
|
+
}
|
|
46456
|
+
await storeAndDisplayKey({
|
|
46457
|
+
success: true,
|
|
46458
|
+
apiKey: result.apiKey,
|
|
46459
|
+
keyPrefix: result.keyPrefix,
|
|
46460
|
+
email: result.email,
|
|
46461
|
+
plan: result.plan
|
|
46462
|
+
});
|
|
46463
|
+
}
|
|
46423
46464
|
async function handleStripeCheckout(email3, plan) {
|
|
46424
46465
|
let checkout;
|
|
46425
46466
|
try {
|
package/dist/commands/login.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { Option } from 'commander';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import { createLogger } from '@trading-boy/core';
|
|
3
4
|
import { storeCredentials, redactApiKey } from '../credentials.js';
|
|
4
5
|
import { getApiBase } from '../api-client.js';
|
|
5
6
|
const logger = createLogger('cli-login');
|
|
6
7
|
// ─── API Key Validation ───
|
|
7
|
-
const API_KEY_PATTERN = /^tb_(live|test)_[a-f0-9]{32}$/;
|
|
8
|
+
const API_KEY_PATTERN = /^tb_(live|test|free)_[a-f0-9]{32}$/;
|
|
8
9
|
export function validateApiKeyFormat(key) {
|
|
9
10
|
return API_KEY_PATTERN.test(key);
|
|
10
11
|
}
|
|
@@ -13,8 +14,11 @@ export async function verifyApiKey(apiKey) {
|
|
|
13
14
|
const apiBase = getApiBase();
|
|
14
15
|
const response = await fetch(`${apiBase}/api/v1/auth/verify`, {
|
|
15
16
|
method: 'POST',
|
|
16
|
-
headers: {
|
|
17
|
-
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
20
|
+
},
|
|
21
|
+
body: '{}',
|
|
18
22
|
});
|
|
19
23
|
if (!response.ok) {
|
|
20
24
|
if (response.status === 401) {
|
|
@@ -53,7 +57,7 @@ export function registerLoginCommand(program) {
|
|
|
53
57
|
program
|
|
54
58
|
.command('login')
|
|
55
59
|
.description('Authenticate with your Trading Boy API key')
|
|
56
|
-
.
|
|
60
|
+
.addOption(new Option('--api-key <key>', 'API key (deprecated — use TRADING_BOY_API_KEY env var)').hideHelp())
|
|
57
61
|
.action(async (opts) => {
|
|
58
62
|
try {
|
|
59
63
|
let apiKey;
|
|
@@ -76,7 +80,7 @@ export function registerLoginCommand(program) {
|
|
|
76
80
|
if (!input)
|
|
77
81
|
return 'API key is required';
|
|
78
82
|
if (!validateApiKeyFormat(input)) {
|
|
79
|
-
return 'Invalid key format. Expected: tb_live_<32hex
|
|
83
|
+
return 'Invalid key format. Expected: tb_live_<32hex>, tb_test_<32hex>, or tb_free_<32hex>';
|
|
80
84
|
}
|
|
81
85
|
return true;
|
|
82
86
|
},
|
|
@@ -84,7 +88,7 @@ export function registerLoginCommand(program) {
|
|
|
84
88
|
}
|
|
85
89
|
// Validate format before making network request
|
|
86
90
|
if (!validateApiKeyFormat(apiKey)) {
|
|
87
|
-
console.error(chalk.red(' Invalid key format. Expected: tb_live_<32hex
|
|
91
|
+
console.error(chalk.red(' Invalid key format. Expected: tb_live_<32hex>, tb_test_<32hex>, or tb_free_<32hex>'));
|
|
88
92
|
process.exitCode = 1;
|
|
89
93
|
return;
|
|
90
94
|
}
|
|
@@ -69,4 +69,10 @@ export declare function saveApiKey(apiKey: string, metadata: {
|
|
|
69
69
|
}): Promise<void>;
|
|
70
70
|
export declare function formatSubscribeSuccess(result: PollResult): string;
|
|
71
71
|
export declare function registerSubscribeCommand(program: Command): void;
|
|
72
|
+
export interface RegisterResponse {
|
|
73
|
+
apiKey: string;
|
|
74
|
+
keyPrefix: string;
|
|
75
|
+
email: string;
|
|
76
|
+
plan: string;
|
|
77
|
+
}
|
|
72
78
|
//# sourceMappingURL=subscribe.d.ts.map
|
|
@@ -251,9 +251,9 @@ export function registerSubscribeCommand(program) {
|
|
|
251
251
|
plan = await select({
|
|
252
252
|
message: 'Choose your plan',
|
|
253
253
|
choices: [
|
|
254
|
-
{ name: 'Starter —
|
|
255
|
-
{ name: 'Pro — $
|
|
256
|
-
{ name: 'Edge — $
|
|
254
|
+
{ name: 'Starter — Free (core context + journal)', value: 'starter' },
|
|
255
|
+
{ name: 'Pro — $29/mo (+ coaching + thesis extraction)', value: 'pro' },
|
|
256
|
+
{ name: 'Edge — $99/mo (+ edge analysis + full analytics)', value: 'edge' },
|
|
257
257
|
],
|
|
258
258
|
});
|
|
259
259
|
}
|
|
@@ -263,7 +263,16 @@ export function registerSubscribeCommand(program) {
|
|
|
263
263
|
process.exitCode = 1;
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
|
-
|
|
266
|
+
const planLabels = { starter: 'Starter (Free)', pro: 'Pro ($29/mo)', edge: 'Edge ($99/mo)' };
|
|
267
|
+
// Free tier — skip payment entirely
|
|
268
|
+
if (plan === 'starter') {
|
|
269
|
+
console.log('');
|
|
270
|
+
console.log(` ${chalk.bold('Plan:')} ${planLabels[plan]}`);
|
|
271
|
+
console.log('');
|
|
272
|
+
await handleFreeRegistration(email);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
// Paid plans — pick payment method
|
|
267
276
|
if (!pay) {
|
|
268
277
|
pay = await select({
|
|
269
278
|
message: 'How would you like to pay?',
|
|
@@ -279,7 +288,6 @@ export function registerSubscribeCommand(program) {
|
|
|
279
288
|
process.exitCode = 1;
|
|
280
289
|
return;
|
|
281
290
|
}
|
|
282
|
-
const planLabels = { starter: 'Starter ($20/mo)', pro: 'Pro ($40/mo)', edge: 'Edge ($75/mo)' };
|
|
283
291
|
console.log('');
|
|
284
292
|
console.log(` ${chalk.bold('Plan:')} ${planLabels[plan] ?? plan}`);
|
|
285
293
|
console.log(` ${chalk.bold('Pay:')} ${pay === 'crypto' ? 'USDC on Solana' : 'Stripe'}`);
|
|
@@ -304,6 +312,38 @@ export function registerSubscribeCommand(program) {
|
|
|
304
312
|
}
|
|
305
313
|
});
|
|
306
314
|
}
|
|
315
|
+
async function handleFreeRegistration(email) {
|
|
316
|
+
console.log(chalk.white(' Creating your free account...'));
|
|
317
|
+
let result;
|
|
318
|
+
try {
|
|
319
|
+
const response = await fetch(`${getApiBase()}/api/v1/auth/register`, {
|
|
320
|
+
method: 'POST',
|
|
321
|
+
headers: { 'Content-Type': 'application/json' },
|
|
322
|
+
body: JSON.stringify({ email }),
|
|
323
|
+
});
|
|
324
|
+
if (!response.ok) {
|
|
325
|
+
const body = await response.text();
|
|
326
|
+
throw new Error(`Registration failed (${response.status}): ${body}`);
|
|
327
|
+
}
|
|
328
|
+
result = await response.json();
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
332
|
+
console.error(chalk.red(` Failed to register: ${message}`));
|
|
333
|
+
const hint = formatConnectionError(message);
|
|
334
|
+
if (hint)
|
|
335
|
+
console.error(hint);
|
|
336
|
+
process.exitCode = 1;
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
await storeAndDisplayKey({
|
|
340
|
+
success: true,
|
|
341
|
+
apiKey: result.apiKey,
|
|
342
|
+
keyPrefix: result.keyPrefix,
|
|
343
|
+
email: result.email,
|
|
344
|
+
plan: result.plan,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
307
347
|
// ─── Checkout Flows ───
|
|
308
348
|
async function handleStripeCheckout(email, plan) {
|
|
309
349
|
// Step 1: Create checkout session
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"description": "Trading Boy CLI — crypto context intelligence for traders and AI agents",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -16,10 +16,17 @@
|
|
|
16
16
|
"!dist/**/*.test.*",
|
|
17
17
|
"!dist/**/*.map"
|
|
18
18
|
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc && node esbuild.config.js",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"lint": "eslint src/",
|
|
24
|
+
"clean": "rm -rf dist .turbo"
|
|
25
|
+
},
|
|
19
26
|
"dependencies": {
|
|
20
27
|
"@inquirer/prompts": "~7.10.1",
|
|
21
28
|
"@napi-rs/keyring": "~1.1.3",
|
|
22
|
-
"@trading-boy/core": "
|
|
29
|
+
"@trading-boy/core": "workspace:~1.2.0",
|
|
23
30
|
"chalk": "~5.6.2",
|
|
24
31
|
"commander": "~13.1.0",
|
|
25
32
|
"open": "~10.2.0",
|
|
@@ -29,12 +36,5 @@
|
|
|
29
36
|
"devDependencies": {
|
|
30
37
|
"esbuild": "~0.27.4",
|
|
31
38
|
"typescript": "^5.7.0"
|
|
32
|
-
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "tsc && node esbuild.config.js",
|
|
35
|
-
"typecheck": "tsc --noEmit",
|
|
36
|
-
"test": "vitest run",
|
|
37
|
-
"lint": "eslint src/",
|
|
38
|
-
"clean": "rm -rf dist .turbo"
|
|
39
39
|
}
|
|
40
|
-
}
|
|
40
|
+
}
|