@trading-boy/cli 1.2.16 → 1.2.18
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 +134 -10
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +64 -8
- package/dist/commands/onboarding.js +6 -1
- package/dist/commands/trader.d.ts +1 -0
- package/dist/commands/trader.js +69 -0
- package/dist/credentials.d.ts +3 -1
- package/dist/credentials.js +2 -1
- package/package.json +1 -1
package/dist/cli.bundle.js
CHANGED
|
@@ -25905,6 +25905,17 @@ var PlanStatus;
|
|
|
25905
25905
|
PlanStatus2["EXPIRED"] = "EXPIRED";
|
|
25906
25906
|
PlanStatus2["CANCELLED"] = "CANCELLED";
|
|
25907
25907
|
})(PlanStatus || (PlanStatus = {}));
|
|
25908
|
+
var Chamber;
|
|
25909
|
+
(function(Chamber2) {
|
|
25910
|
+
Chamber2["HOUSE"] = "HOUSE";
|
|
25911
|
+
Chamber2["SENATE"] = "SENATE";
|
|
25912
|
+
})(Chamber || (Chamber = {}));
|
|
25913
|
+
var PoliticianTransactionType;
|
|
25914
|
+
(function(PoliticianTransactionType2) {
|
|
25915
|
+
PoliticianTransactionType2["BUY"] = "BUY";
|
|
25916
|
+
PoliticianTransactionType2["SELL"] = "SELL";
|
|
25917
|
+
PoliticianTransactionType2["EXERCISE"] = "EXERCISE";
|
|
25918
|
+
})(PoliticianTransactionType || (PoliticianTransactionType = {}));
|
|
25908
25919
|
var NotificationChannel;
|
|
25909
25920
|
(function(NotificationChannel2) {
|
|
25910
25921
|
NotificationChannel2["TELEGRAM"] = "TELEGRAM";
|
|
@@ -39771,6 +39782,11 @@ var envSchema = external_exports.object({
|
|
|
39771
39782
|
LLM_ENCRYPTION_KEY: external_exports.string().default(""),
|
|
39772
39783
|
// Learning system
|
|
39773
39784
|
BELIEF_HMAC_KEY: external_exports.string().default(""),
|
|
39785
|
+
BELIEF_DISCOUNT_FACTOR: external_exports.coerce.number().min(0).max(1).default(0.995),
|
|
39786
|
+
// Cold-start maturity threshold (number of trades before a trader is "established")
|
|
39787
|
+
COLD_START_MATURITY_THRESHOLD: external_exports.coerce.number().int().nonnegative().default(50),
|
|
39788
|
+
// Politician trading data
|
|
39789
|
+
FINNHUB_API_KEY: external_exports.string().default(""),
|
|
39774
39790
|
// Feature flags
|
|
39775
39791
|
ENABLE_LLM: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
|
|
39776
39792
|
ENABLE_LEARNING: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
|
|
@@ -39792,6 +39808,8 @@ var envSchema = external_exports.object({
|
|
|
39792
39808
|
NOTIFICATION_FROM_EMAIL: external_exports.string().default("alerts@tradingboy.dev"),
|
|
39793
39809
|
// Solana (crypto payments)
|
|
39794
39810
|
SOLANA_MERCHANT_WALLET: external_exports.string().default(""),
|
|
39811
|
+
// Resend Email
|
|
39812
|
+
RESEND_WEBHOOK_SECRET: external_exports.string().default(""),
|
|
39795
39813
|
// Stripe Billing
|
|
39796
39814
|
STRIPE_SECRET_KEY: external_exports.string().default(""),
|
|
39797
39815
|
STRIPE_WEBHOOK_SECRET: external_exports.string().default(""),
|
|
@@ -47031,8 +47049,9 @@ async function loadCredentials() {
|
|
|
47031
47049
|
};
|
|
47032
47050
|
}
|
|
47033
47051
|
async function clearCredentials() {
|
|
47034
|
-
await deleteFromKeychain();
|
|
47052
|
+
const keychainCleared = await deleteFromKeychain();
|
|
47035
47053
|
deleteCredentialsFile();
|
|
47054
|
+
return { keychainCleared };
|
|
47036
47055
|
}
|
|
47037
47056
|
function redactApiKey(key) {
|
|
47038
47057
|
if (key.length <= 12)
|
|
@@ -48205,6 +48224,9 @@ function registerTraderCommand(program2) {
|
|
|
48205
48224
|
} else {
|
|
48206
48225
|
console.log(formatTraderOutput(result));
|
|
48207
48226
|
console.log(source_default.green(" Trader registered successfully."));
|
|
48227
|
+
if (result.alias) {
|
|
48228
|
+
console.log(` ${source_default.gray("Leaderboard alias:")} ${source_default.white(result.alias)} ${source_default.dim("(change with: trading-boy trader set-alias <name> <alias>)")}`);
|
|
48229
|
+
}
|
|
48208
48230
|
console.log("");
|
|
48209
48231
|
console.log(source_default.bold(" Next: Set up your trading identity"));
|
|
48210
48232
|
console.log(source_default.dim(" SOUL and PURPOSE documents personalize your context \u2014 bias warnings,"));
|
|
@@ -48289,6 +48311,57 @@ function registerTraderCommand(program2) {
|
|
|
48289
48311
|
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
48290
48312
|
}
|
|
48291
48313
|
});
|
|
48314
|
+
const ALIAS_PATTERN = /^[a-zA-Z0-9_-]{3,30}$/;
|
|
48315
|
+
trader.command("set-alias").description("Set a public leaderboard alias").argument("<name-or-id>", "Trader name or ID").argument("<alias>", "Leaderboard alias (3-30 chars, alphanumeric/underscores/hyphens)").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (nameOrId, alias, options) => {
|
|
48316
|
+
const jsonMode = options.format === "json";
|
|
48317
|
+
if (!ALIAS_PATTERN.test(alias)) {
|
|
48318
|
+
const msg = "Invalid alias. Must be 3-30 characters, alphanumeric with underscores and hyphens.";
|
|
48319
|
+
if (jsonMode) {
|
|
48320
|
+
console.error(JSON.stringify({ error: msg }));
|
|
48321
|
+
} else {
|
|
48322
|
+
console.error(source_default.red(` ${msg}`));
|
|
48323
|
+
}
|
|
48324
|
+
process.exitCode = 1;
|
|
48325
|
+
return;
|
|
48326
|
+
}
|
|
48327
|
+
try {
|
|
48328
|
+
await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/alias`, { method: "PUT", body: { alias } });
|
|
48329
|
+
if (jsonMode) {
|
|
48330
|
+
console.log(JSON.stringify({ alias, updated: true }));
|
|
48331
|
+
} else {
|
|
48332
|
+
console.log("");
|
|
48333
|
+
console.log(source_default.green(` Alias updated to: ${source_default.white(alias)}`));
|
|
48334
|
+
console.log("");
|
|
48335
|
+
}
|
|
48336
|
+
} catch (error49) {
|
|
48337
|
+
if (error49 instanceof ApiError && error49.status === 409) {
|
|
48338
|
+
const msg = "Alias already taken. Try a different name.";
|
|
48339
|
+
if (jsonMode) {
|
|
48340
|
+
console.error(JSON.stringify({ error: msg }));
|
|
48341
|
+
} else {
|
|
48342
|
+
console.error(source_default.yellow(` ${msg}`));
|
|
48343
|
+
}
|
|
48344
|
+
process.exitCode = 2;
|
|
48345
|
+
} else if (error49 instanceof ApiError && error49.status === 404) {
|
|
48346
|
+
const msg = `Trader not found: "${nameOrId}"`;
|
|
48347
|
+
if (jsonMode) {
|
|
48348
|
+
console.error(JSON.stringify({ error: msg }));
|
|
48349
|
+
} else {
|
|
48350
|
+
console.error(source_default.yellow(msg));
|
|
48351
|
+
}
|
|
48352
|
+
process.exitCode = 2;
|
|
48353
|
+
} else {
|
|
48354
|
+
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
48355
|
+
logger12.error({ error: message }, "Failed to set alias");
|
|
48356
|
+
if (jsonMode) {
|
|
48357
|
+
console.error(JSON.stringify({ error: message }));
|
|
48358
|
+
} else {
|
|
48359
|
+
console.error(source_default.red(`Error: ${message}`));
|
|
48360
|
+
}
|
|
48361
|
+
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
48362
|
+
}
|
|
48363
|
+
}
|
|
48364
|
+
});
|
|
48292
48365
|
trader.command("preferences").description("Update notification preferences").option("--summary-time <hour>", "Hour (0-23 UTC) to receive daily email summary", parseInt).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
48293
48366
|
if (options.summaryTime === void 0) {
|
|
48294
48367
|
console.error(source_default.yellow("No updates provided. Use --summary-time <hour>."));
|
|
@@ -50222,17 +50295,44 @@ async function executeLogout() {
|
|
|
50222
50295
|
const existing = await loadCredentials();
|
|
50223
50296
|
const wasAuthenticated = existing !== null;
|
|
50224
50297
|
const redactedKey = existing ? redactApiKey(existing.apiKey) : void 0;
|
|
50225
|
-
await clearCredentials();
|
|
50226
|
-
return { wasAuthenticated, redactedKey };
|
|
50298
|
+
const { keychainCleared } = await clearCredentials();
|
|
50299
|
+
return { wasAuthenticated, redactedKey, keychainCleared };
|
|
50227
50300
|
}
|
|
50228
50301
|
function registerLogoutCommand(program2) {
|
|
50229
|
-
program2.command("logout").description("Clear stored API key and credentials").action(async () => {
|
|
50302
|
+
program2.command("logout").description("Clear stored API key and credentials").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).addOption(new Option("--force", "Skip confirmation prompt")).addOption(new Option("--reveal-key", "Include full API key in JSON output (requires --force --format json)")).action(async (options) => {
|
|
50230
50303
|
try {
|
|
50304
|
+
const jsonMode = options.format === "json";
|
|
50231
50305
|
const existing = await loadCredentials();
|
|
50232
50306
|
if (!existing) {
|
|
50233
|
-
|
|
50234
|
-
|
|
50235
|
-
|
|
50307
|
+
if (jsonMode) {
|
|
50308
|
+
console.log(JSON.stringify({ loggedOut: false, reason: "no credentials" }));
|
|
50309
|
+
} else {
|
|
50310
|
+
console.log("");
|
|
50311
|
+
console.log(source_default.dim(" No credentials found \u2014 already logged out."));
|
|
50312
|
+
console.log("");
|
|
50313
|
+
}
|
|
50314
|
+
return;
|
|
50315
|
+
}
|
|
50316
|
+
if (jsonMode && !options.force) {
|
|
50317
|
+
console.error(JSON.stringify({ error: "--force is required with --format json" }));
|
|
50318
|
+
process.exitCode = 1;
|
|
50319
|
+
return;
|
|
50320
|
+
}
|
|
50321
|
+
if (jsonMode) {
|
|
50322
|
+
const fullKey = existing.apiKey;
|
|
50323
|
+
const storageMethod2 = existing.storageMethod;
|
|
50324
|
+
const result2 = await executeLogout();
|
|
50325
|
+
const output = {
|
|
50326
|
+
loggedOut: true,
|
|
50327
|
+
redactedKey: result2.redactedKey
|
|
50328
|
+
};
|
|
50329
|
+
if (options.revealKey) {
|
|
50330
|
+
output.apiKey = fullKey;
|
|
50331
|
+
}
|
|
50332
|
+
if (!result2.keychainCleared && storageMethod2 === "keychain") {
|
|
50333
|
+
output.keychainWarning = "Could not remove key from OS keychain. You may need to manually remove the 'trading-boy' entry from your keychain.";
|
|
50334
|
+
}
|
|
50335
|
+
console.log(JSON.stringify(output));
|
|
50236
50336
|
return;
|
|
50237
50337
|
}
|
|
50238
50338
|
console.log("");
|
|
@@ -50240,20 +50340,39 @@ function registerLogoutCommand(program2) {
|
|
|
50240
50340
|
console.log(source_default.yellow(" You will need your API key to log back in."));
|
|
50241
50341
|
console.log(source_default.yellow(" There is no way to recover a lost key \u2014 a new one must be provisioned."));
|
|
50242
50342
|
console.log("");
|
|
50243
|
-
const proceed = await esm_default4({ message: "Are you sure you want to logout?" });
|
|
50343
|
+
const proceed = options.force || await esm_default4({ message: "Are you sure you want to logout?" });
|
|
50244
50344
|
if (!proceed) {
|
|
50245
50345
|
console.log(source_default.dim(" Logout cancelled."));
|
|
50246
50346
|
return;
|
|
50247
50347
|
}
|
|
50348
|
+
const revealKey = await esm_default4({
|
|
50349
|
+
message: "Would you like to see your full API key before it's deleted? (This is your last chance to copy it)"
|
|
50350
|
+
});
|
|
50351
|
+
if (revealKey) {
|
|
50352
|
+
console.log("");
|
|
50353
|
+
console.log(source_default.cyan(" Your API key:"));
|
|
50354
|
+
console.log(` ${source_default.bold(existing.apiKey)}`);
|
|
50355
|
+
console.log("");
|
|
50356
|
+
}
|
|
50357
|
+
const storageMethod = existing.storageMethod;
|
|
50248
50358
|
const result = await executeLogout();
|
|
50249
50359
|
console.log("");
|
|
50250
50360
|
console.log(source_default.green(` Logged out successfully.`));
|
|
50251
50361
|
console.log(` ${source_default.gray("Cleared key:")} ${result.redactedKey}`);
|
|
50362
|
+
if (!result.keychainCleared && storageMethod === "keychain") {
|
|
50363
|
+
console.log("");
|
|
50364
|
+
console.log(source_default.yellow(" Warning: Could not remove key from OS keychain."));
|
|
50365
|
+
console.log(source_default.yellow(" You may need to manually remove the 'trading-boy' entry from your keychain."));
|
|
50366
|
+
}
|
|
50252
50367
|
console.log("");
|
|
50253
50368
|
} catch (error49) {
|
|
50254
50369
|
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
50255
50370
|
logger20.error({ error: message }, "Logout failed");
|
|
50256
|
-
|
|
50371
|
+
if (options.format === "json") {
|
|
50372
|
+
console.error(JSON.stringify({ error: message }));
|
|
50373
|
+
} else {
|
|
50374
|
+
console.error(source_default.red(` Error: ${message}`));
|
|
50375
|
+
}
|
|
50257
50376
|
process.exitCode = 1;
|
|
50258
50377
|
}
|
|
50259
50378
|
});
|
|
@@ -50456,7 +50575,7 @@ async function runOnboarding() {
|
|
|
50456
50575
|
});
|
|
50457
50576
|
if (wantsTrader) {
|
|
50458
50577
|
const name = await input({
|
|
50459
|
-
message: "Trader name (
|
|
50578
|
+
message: "Trader name (this will appear on the public leaderboard \u2014 use a pseudonym to stay anonymous)",
|
|
50460
50579
|
default: "default",
|
|
50461
50580
|
validate: (v) => v.trim().length > 0 ? true : "Name cannot be empty"
|
|
50462
50581
|
});
|
|
@@ -50477,6 +50596,11 @@ async function runOnboarding() {
|
|
|
50477
50596
|
body: { name: name.trim(), riskToleranceMax: parseFloat(maxDrawdown) }
|
|
50478
50597
|
});
|
|
50479
50598
|
console.log(source_default.green(` \u2713 Trader "${result.name}" registered (id: ${result.id})`));
|
|
50599
|
+
if (result.publicAlias) {
|
|
50600
|
+
console.log(source_default.dim(` Leaderboard alias: ${result.publicAlias}`));
|
|
50601
|
+
console.log(source_default.dim(" This alias is public on the leaderboard. Change it anytime:"));
|
|
50602
|
+
console.log(source_default.dim(" trading-boy trader set-alias <name> <new-alias>"));
|
|
50603
|
+
}
|
|
50480
50604
|
traderRegistered = true;
|
|
50481
50605
|
} else {
|
|
50482
50606
|
console.log(source_default.yellow(" Skipped \u2014 not connected to API. Run: trading-boy trader register"));
|
|
@@ -2,6 +2,7 @@ import { Command } from 'commander';
|
|
|
2
2
|
export declare function executeLogout(): Promise<{
|
|
3
3
|
wasAuthenticated: boolean;
|
|
4
4
|
redactedKey?: string;
|
|
5
|
+
keychainCleared: boolean;
|
|
5
6
|
}>;
|
|
6
7
|
export declare function registerLogoutCommand(program: Command): void;
|
|
7
8
|
//# sourceMappingURL=logout.d.ts.map
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Option } from 'commander';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import { createLogger } from '@trading-boy/core';
|
|
3
4
|
import { clearCredentials, loadCredentials, redactApiKey } from '../credentials.js';
|
|
@@ -8,43 +9,98 @@ export async function executeLogout() {
|
|
|
8
9
|
const existing = await loadCredentials();
|
|
9
10
|
const wasAuthenticated = existing !== null;
|
|
10
11
|
const redactedKey = existing ? redactApiKey(existing.apiKey) : undefined;
|
|
11
|
-
await clearCredentials();
|
|
12
|
-
return { wasAuthenticated, redactedKey };
|
|
12
|
+
const { keychainCleared } = await clearCredentials();
|
|
13
|
+
return { wasAuthenticated, redactedKey, keychainCleared };
|
|
13
14
|
}
|
|
14
15
|
// ─── Command Registration ───
|
|
15
16
|
export function registerLogoutCommand(program) {
|
|
16
17
|
program
|
|
17
18
|
.command('logout')
|
|
18
19
|
.description('Clear stored API key and credentials')
|
|
19
|
-
.
|
|
20
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
21
|
+
.addOption(new Option('--force', 'Skip confirmation prompt'))
|
|
22
|
+
.addOption(new Option('--reveal-key', 'Include full API key in JSON output (requires --force --format json)'))
|
|
23
|
+
.action(async (options) => {
|
|
20
24
|
try {
|
|
25
|
+
const jsonMode = options.format === 'json';
|
|
21
26
|
const existing = await loadCredentials();
|
|
22
27
|
if (!existing) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
if (jsonMode) {
|
|
29
|
+
console.log(JSON.stringify({ loggedOut: false, reason: 'no credentials' }));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(chalk.dim(' No credentials found — already logged out.'));
|
|
34
|
+
console.log('');
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// JSON mode requires --force to skip interactive prompts
|
|
39
|
+
if (jsonMode && !options.force) {
|
|
40
|
+
console.error(JSON.stringify({ error: '--force is required with --format json' }));
|
|
41
|
+
process.exitCode = 1;
|
|
26
42
|
return;
|
|
27
43
|
}
|
|
44
|
+
if (jsonMode) {
|
|
45
|
+
// Non-interactive JSON path
|
|
46
|
+
const fullKey = existing.apiKey;
|
|
47
|
+
const storageMethod = existing.storageMethod;
|
|
48
|
+
const result = await executeLogout();
|
|
49
|
+
const output = {
|
|
50
|
+
loggedOut: true,
|
|
51
|
+
redactedKey: result.redactedKey,
|
|
52
|
+
};
|
|
53
|
+
if (options.revealKey) {
|
|
54
|
+
output.apiKey = fullKey;
|
|
55
|
+
}
|
|
56
|
+
if (!result.keychainCleared && storageMethod === 'keychain') {
|
|
57
|
+
output.keychainWarning = 'Could not remove key from OS keychain. You may need to manually remove the \'trading-boy\' entry from your keychain.';
|
|
58
|
+
}
|
|
59
|
+
console.log(JSON.stringify(output));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Interactive text path
|
|
28
63
|
console.log('');
|
|
29
64
|
console.log(chalk.yellow(' Warning: Your API key will be cleared from this machine.'));
|
|
30
65
|
console.log(chalk.yellow(' You will need your API key to log back in.'));
|
|
31
66
|
console.log(chalk.yellow(' There is no way to recover a lost key — a new one must be provisioned.'));
|
|
32
67
|
console.log('');
|
|
33
|
-
const proceed = await confirm({ message: 'Are you sure you want to logout?' });
|
|
68
|
+
const proceed = options.force || await confirm({ message: 'Are you sure you want to logout?' });
|
|
34
69
|
if (!proceed) {
|
|
35
70
|
console.log(chalk.dim(' Logout cancelled.'));
|
|
36
71
|
return;
|
|
37
72
|
}
|
|
73
|
+
// Offer to reveal the full key before deletion
|
|
74
|
+
const revealKey = await confirm({
|
|
75
|
+
message: 'Would you like to see your full API key before it\'s deleted? (This is your last chance to copy it)',
|
|
76
|
+
});
|
|
77
|
+
if (revealKey) {
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(chalk.cyan(' Your API key:'));
|
|
80
|
+
console.log(` ${chalk.bold(existing.apiKey)}`);
|
|
81
|
+
console.log('');
|
|
82
|
+
}
|
|
83
|
+
const storageMethod = existing.storageMethod;
|
|
38
84
|
const result = await executeLogout();
|
|
39
85
|
console.log('');
|
|
40
86
|
console.log(chalk.green(` Logged out successfully.`));
|
|
41
87
|
console.log(` ${chalk.gray('Cleared key:')} ${result.redactedKey}`);
|
|
88
|
+
if (!result.keychainCleared && storageMethod === 'keychain') {
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(chalk.yellow(' Warning: Could not remove key from OS keychain.'));
|
|
91
|
+
console.log(chalk.yellow(' You may need to manually remove the \'trading-boy\' entry from your keychain.'));
|
|
92
|
+
}
|
|
42
93
|
console.log('');
|
|
43
94
|
}
|
|
44
95
|
catch (error) {
|
|
45
96
|
const message = error instanceof Error ? error.message : String(error);
|
|
46
97
|
logger.error({ error: message }, 'Logout failed');
|
|
47
|
-
|
|
98
|
+
if (options.format === 'json') {
|
|
99
|
+
console.error(JSON.stringify({ error: message }));
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.error(chalk.red(` Error: ${message}`));
|
|
103
|
+
}
|
|
48
104
|
process.exitCode = 1;
|
|
49
105
|
}
|
|
50
106
|
});
|
|
@@ -28,7 +28,7 @@ export async function runOnboarding() {
|
|
|
28
28
|
});
|
|
29
29
|
if (wantsTrader) {
|
|
30
30
|
const name = await input({
|
|
31
|
-
message: 'Trader name (
|
|
31
|
+
message: 'Trader name (this will appear on the public leaderboard — use a pseudonym to stay anonymous)',
|
|
32
32
|
default: 'default',
|
|
33
33
|
validate: (v) => (v.trim().length > 0 ? true : 'Name cannot be empty'),
|
|
34
34
|
});
|
|
@@ -49,6 +49,11 @@ export async function runOnboarding() {
|
|
|
49
49
|
body: { name: name.trim(), riskToleranceMax: parseFloat(maxDrawdown) },
|
|
50
50
|
});
|
|
51
51
|
console.log(chalk.green(` \u2713 Trader "${result.name}" registered (id: ${result.id})`));
|
|
52
|
+
if (result.publicAlias) {
|
|
53
|
+
console.log(chalk.dim(` Leaderboard alias: ${result.publicAlias}`));
|
|
54
|
+
console.log(chalk.dim(' This alias is public on the leaderboard. Change it anytime:'));
|
|
55
|
+
console.log(chalk.dim(' trading-boy trader set-alias <name> <new-alias>'));
|
|
56
|
+
}
|
|
52
57
|
traderRegistered = true;
|
|
53
58
|
}
|
|
54
59
|
else {
|
package/dist/commands/trader.js
CHANGED
|
@@ -111,6 +111,9 @@ export function registerTraderCommand(program) {
|
|
|
111
111
|
else {
|
|
112
112
|
console.log(formatTraderOutput(result));
|
|
113
113
|
console.log(chalk.green(' Trader registered successfully.'));
|
|
114
|
+
if (result.alias) {
|
|
115
|
+
console.log(` ${chalk.gray('Leaderboard alias:')} ${chalk.white(result.alias)} ${chalk.dim('(change with: trading-boy trader set-alias <name> <alias>)')}`);
|
|
116
|
+
}
|
|
114
117
|
console.log('');
|
|
115
118
|
console.log(chalk.bold(' Next: Set up your trading identity'));
|
|
116
119
|
console.log(chalk.dim(' SOUL and PURPOSE documents personalize your context — bias warnings,'));
|
|
@@ -223,6 +226,72 @@ export function registerTraderCommand(program) {
|
|
|
223
226
|
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
224
227
|
}
|
|
225
228
|
});
|
|
229
|
+
// ─── set-alias ───
|
|
230
|
+
const ALIAS_PATTERN = /^[a-zA-Z0-9_-]{3,30}$/;
|
|
231
|
+
trader
|
|
232
|
+
.command('set-alias')
|
|
233
|
+
.description('Set a public leaderboard alias')
|
|
234
|
+
.argument('<name-or-id>', 'Trader name or ID')
|
|
235
|
+
.argument('<alias>', 'Leaderboard alias (3-30 chars, alphanumeric/underscores/hyphens)')
|
|
236
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
237
|
+
.action(async (nameOrId, alias, options) => {
|
|
238
|
+
const jsonMode = options.format === 'json';
|
|
239
|
+
if (!ALIAS_PATTERN.test(alias)) {
|
|
240
|
+
const msg = 'Invalid alias. Must be 3-30 characters, alphanumeric with underscores and hyphens.';
|
|
241
|
+
if (jsonMode) {
|
|
242
|
+
console.error(JSON.stringify({ error: msg }));
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
console.error(chalk.red(` ${msg}`));
|
|
246
|
+
}
|
|
247
|
+
process.exitCode = 1;
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/alias`, { method: 'PUT', body: { alias } });
|
|
252
|
+
if (jsonMode) {
|
|
253
|
+
console.log(JSON.stringify({ alias, updated: true }));
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
console.log('');
|
|
257
|
+
console.log(chalk.green(` Alias updated to: ${chalk.white(alias)}`));
|
|
258
|
+
console.log('');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (error instanceof ApiError && error.status === 409) {
|
|
263
|
+
const msg = 'Alias already taken. Try a different name.';
|
|
264
|
+
if (jsonMode) {
|
|
265
|
+
console.error(JSON.stringify({ error: msg }));
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
console.error(chalk.yellow(` ${msg}`));
|
|
269
|
+
}
|
|
270
|
+
process.exitCode = 2;
|
|
271
|
+
}
|
|
272
|
+
else if (error instanceof ApiError && error.status === 404) {
|
|
273
|
+
const msg = `Trader not found: "${nameOrId}"`;
|
|
274
|
+
if (jsonMode) {
|
|
275
|
+
console.error(JSON.stringify({ error: msg }));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
console.error(chalk.yellow(msg));
|
|
279
|
+
}
|
|
280
|
+
process.exitCode = 2;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
284
|
+
logger.error({ error: message }, 'Failed to set alias');
|
|
285
|
+
if (jsonMode) {
|
|
286
|
+
console.error(JSON.stringify({ error: message }));
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
290
|
+
}
|
|
291
|
+
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
});
|
|
226
295
|
// ─── preferences ───
|
|
227
296
|
trader
|
|
228
297
|
.command('preferences')
|
package/dist/credentials.d.ts
CHANGED
|
@@ -12,7 +12,9 @@ export declare function storeCredentials(apiKey: string, metadata?: {
|
|
|
12
12
|
plan?: string;
|
|
13
13
|
}): Promise<void>;
|
|
14
14
|
export declare function loadCredentials(): Promise<StoredCredentials | null>;
|
|
15
|
-
export declare function clearCredentials(): Promise<
|
|
15
|
+
export declare function clearCredentials(): Promise<{
|
|
16
|
+
keychainCleared: boolean;
|
|
17
|
+
}>;
|
|
16
18
|
export declare function redactApiKey(key: string): string;
|
|
17
19
|
export declare function getCredentialsFilePath(): string;
|
|
18
20
|
//# sourceMappingURL=credentials.d.ts.map
|
package/dist/credentials.js
CHANGED
|
@@ -151,8 +151,9 @@ export async function loadCredentials() {
|
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
export async function clearCredentials() {
|
|
154
|
-
await deleteFromKeychain();
|
|
154
|
+
const keychainCleared = await deleteFromKeychain();
|
|
155
155
|
deleteCredentialsFile();
|
|
156
|
+
return { keychainCleared };
|
|
156
157
|
}
|
|
157
158
|
export function redactApiKey(key) {
|
|
158
159
|
if (key.length <= 12)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.18",
|
|
4
4
|
"description": "Trading Boy CLI — crypto context intelligence for traders and AI agents. Query real-time prices, funding rates, whale activity, and DeFi risk for 100+ Solana tokens and 229 Hyperliquid perpetuals.",
|
|
5
5
|
"homepage": "https://cabal.ventures",
|
|
6
6
|
"repository": {
|