@trading-boy/cli 2.0.1 → 2.1.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/dist/cli.bundle.js +104 -6
- package/package.json +12 -11
- package/LICENSE +0 -22
package/dist/cli.bundle.js
CHANGED
|
@@ -22472,6 +22472,7 @@ init_utils();
|
|
|
22472
22472
|
init_api_client();
|
|
22473
22473
|
init_esm15();
|
|
22474
22474
|
var logger9 = createLogger("cli-trader");
|
|
22475
|
+
var ALIAS_PATTERN = /^[a-zA-Z0-9_-]{3,30}$/;
|
|
22475
22476
|
function formatTraderOutput(trader, wallets) {
|
|
22476
22477
|
const lines = [];
|
|
22477
22478
|
lines.push("");
|
|
@@ -22495,6 +22496,10 @@ function formatTraderOutput(trader, wallets) {
|
|
|
22495
22496
|
lines.push(` ${source_default.dim("\u2022")} ${source_default.white(w.address)} ${source_default.dim(`(${w.chain})`)} ${source_default.dim(`since ${w.since}`)}`);
|
|
22496
22497
|
}
|
|
22497
22498
|
}
|
|
22499
|
+
lines.push(` ${source_default.gray("Public Board:")} ${trader.benchmarkOptIn ? source_default.green("visible") : source_default.dim("private")}`);
|
|
22500
|
+
if (trader.publicAlias) {
|
|
22501
|
+
lines.push(` ${source_default.gray("Public Alias:")} ${source_default.white(trader.publicAlias)}`);
|
|
22502
|
+
}
|
|
22498
22503
|
lines.push("");
|
|
22499
22504
|
lines.push(` ${source_default.gray("Created:")} ${source_default.dim(trader.createdAt)}`);
|
|
22500
22505
|
lines.push(` ${source_default.gray("Updated:")} ${source_default.dim(trader.updatedAt)}`);
|
|
@@ -22526,14 +22531,26 @@ function formatTraderListOutput(traders) {
|
|
|
22526
22531
|
}
|
|
22527
22532
|
function registerTraderCommand(program2) {
|
|
22528
22533
|
const trader = program2.command("trader").description("Manage trader profiles");
|
|
22529
|
-
trader.command("register").description("Register a new trader profile").requiredOption("--name <name>", "Trader display name").option("--wallet <address>", "Initial Solana wallet address").option("--max-drawdown <pct>", "Max acceptable drawdown percentage", parseFloatOption).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
22534
|
+
trader.command("register").description("Register a new trader profile").requiredOption("--name <name>", "Trader display name").option("--wallet <address>", "Initial Solana wallet address").option("--max-drawdown <pct>", "Max acceptable drawdown percentage", parseFloatOption).option("--public-leaderboard", "Opt this trader into the public leaderboard").option("--alias <alias>", "Public leaderboard alias for --public-leaderboard").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
22535
|
+
if (options.publicLeaderboard && !options.alias) {
|
|
22536
|
+
console.error(source_default.red("Error: --alias is required with --public-leaderboard."));
|
|
22537
|
+
process.exitCode = 1;
|
|
22538
|
+
return;
|
|
22539
|
+
}
|
|
22540
|
+
if (options.alias && !ALIAS_PATTERN.test(options.alias)) {
|
|
22541
|
+
console.error(source_default.red("Error: Invalid alias. Must be 3-30 characters, alphanumeric with underscores and hyphens."));
|
|
22542
|
+
process.exitCode = 1;
|
|
22543
|
+
return;
|
|
22544
|
+
}
|
|
22530
22545
|
try {
|
|
22531
22546
|
const result = await apiRequest("/api/v1/traders", {
|
|
22532
22547
|
method: "POST",
|
|
22533
22548
|
body: {
|
|
22534
22549
|
name: options.name,
|
|
22535
22550
|
wallet: options.wallet,
|
|
22536
|
-
maxDrawdown: options.maxDrawdown
|
|
22551
|
+
maxDrawdown: options.maxDrawdown,
|
|
22552
|
+
benchmarkOptIn: options.publicLeaderboard === true,
|
|
22553
|
+
publicAlias: options.alias
|
|
22537
22554
|
}
|
|
22538
22555
|
});
|
|
22539
22556
|
const traderId = result.name ?? result.id;
|
|
@@ -22549,8 +22566,11 @@ function registerTraderCommand(program2) {
|
|
|
22549
22566
|
} else {
|
|
22550
22567
|
console.log(formatTraderOutput(result));
|
|
22551
22568
|
console.log(source_default.green(" Trader registered successfully."));
|
|
22552
|
-
if (result.
|
|
22553
|
-
console.log(` ${source_default.gray("Leaderboard alias:")} ${source_default.white(result.
|
|
22569
|
+
if (result.publicAlias) {
|
|
22570
|
+
console.log(` ${source_default.gray("Leaderboard alias:")} ${source_default.white(result.publicAlias)} ${source_default.dim("(change with: trading-boy trader set-alias <name> <alias>)")}`);
|
|
22571
|
+
} else {
|
|
22572
|
+
console.log(` ${source_default.gray("Public leaderboard:")} ${source_default.dim("private by default")}`);
|
|
22573
|
+
console.log(` ${source_default.dim("Opt in later:")} ${source_default.white("trading-boy trader leaderboard opt-in <name> <alias>")}`);
|
|
22554
22574
|
}
|
|
22555
22575
|
console.log("");
|
|
22556
22576
|
console.log(source_default.bold(" Next: Set up your trading identity"));
|
|
@@ -22636,7 +22656,46 @@ function registerTraderCommand(program2) {
|
|
|
22636
22656
|
process.exitCode = error2 instanceof ApiError ? 2 : 1;
|
|
22637
22657
|
}
|
|
22638
22658
|
});
|
|
22639
|
-
const
|
|
22659
|
+
const leaderboard = trader.command("leaderboard").description("Manage public leaderboard visibility");
|
|
22660
|
+
leaderboard.command("opt-in").description("Show a trader on the public leaderboard").argument("<name-or-id>", "Trader name or ID").argument("<alias>", "Public alias (3-30 chars, alphanumeric/underscores/hyphens)").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (nameOrId, alias, options) => {
|
|
22661
|
+
const jsonMode = options.format === "json";
|
|
22662
|
+
if (!ALIAS_PATTERN.test(alias)) {
|
|
22663
|
+
const msg = "Invalid alias. Must be 3-30 characters, alphanumeric with underscores and hyphens.";
|
|
22664
|
+
if (jsonMode)
|
|
22665
|
+
console.error(JSON.stringify({ error: msg }));
|
|
22666
|
+
else
|
|
22667
|
+
console.error(source_default.red(` ${msg}`));
|
|
22668
|
+
process.exitCode = 1;
|
|
22669
|
+
return;
|
|
22670
|
+
}
|
|
22671
|
+
try {
|
|
22672
|
+
const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/public-profile`, { method: "PATCH", body: { benchmarkOptIn: true, publicAlias: alias } });
|
|
22673
|
+
if (jsonMode) {
|
|
22674
|
+
console.log(JSON.stringify(result));
|
|
22675
|
+
} else {
|
|
22676
|
+
console.log("");
|
|
22677
|
+
console.log(source_default.green(` Public leaderboard enabled as: ${source_default.white(result.publicAlias)}`));
|
|
22678
|
+
console.log("");
|
|
22679
|
+
}
|
|
22680
|
+
} catch (error2) {
|
|
22681
|
+
handlePublicProfileError(error2, jsonMode, "enable public leaderboard");
|
|
22682
|
+
}
|
|
22683
|
+
});
|
|
22684
|
+
leaderboard.command("opt-out").description("Hide a trader from the public leaderboard").argument("<name-or-id>", "Trader name or ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (nameOrId, options) => {
|
|
22685
|
+
const jsonMode = options.format === "json";
|
|
22686
|
+
try {
|
|
22687
|
+
const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/public-profile`, { method: "PATCH", body: { benchmarkOptIn: false } });
|
|
22688
|
+
if (jsonMode) {
|
|
22689
|
+
console.log(JSON.stringify(result));
|
|
22690
|
+
} else {
|
|
22691
|
+
console.log("");
|
|
22692
|
+
console.log(source_default.green(" Public leaderboard disabled. This trader is private."));
|
|
22693
|
+
console.log("");
|
|
22694
|
+
}
|
|
22695
|
+
} catch (error2) {
|
|
22696
|
+
handlePublicProfileError(error2, jsonMode, "disable public leaderboard");
|
|
22697
|
+
}
|
|
22698
|
+
});
|
|
22640
22699
|
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) => {
|
|
22641
22700
|
const jsonMode = options.format === "json";
|
|
22642
22701
|
if (!ALIAS_PATTERN.test(alias)) {
|
|
@@ -23210,6 +23269,19 @@ function handleAgentError(error2, jsonMode, agentId, action) {
|
|
|
23210
23269
|
}
|
|
23211
23270
|
process.exitCode = error2 instanceof ApiError ? 2 : 1;
|
|
23212
23271
|
}
|
|
23272
|
+
function handlePublicProfileError(error2, jsonMode, action) {
|
|
23273
|
+
let message = error2 instanceof Error ? error2.message : String(error2);
|
|
23274
|
+
if (error2 instanceof ApiError && error2.status === 409) {
|
|
23275
|
+
message = "Alias already taken. Try a different name.";
|
|
23276
|
+
}
|
|
23277
|
+
logger9.error({ error: message }, `Failed to ${action}`);
|
|
23278
|
+
if (jsonMode) {
|
|
23279
|
+
console.error(JSON.stringify({ error: message }));
|
|
23280
|
+
} else {
|
|
23281
|
+
console.error(source_default.red(`Error: ${message}`));
|
|
23282
|
+
}
|
|
23283
|
+
process.exitCode = error2 instanceof ApiError ? 2 : 1;
|
|
23284
|
+
}
|
|
23213
23285
|
function parseFloatOption(value) {
|
|
23214
23286
|
return parseFloat(value);
|
|
23215
23287
|
}
|
|
@@ -25369,6 +25441,12 @@ async function openBrowser(url) {
|
|
|
25369
25441
|
// dist/commands/onboarding.js
|
|
25370
25442
|
var DEFAULT_FIRST_AGENT_AUTONOMY = "FULLY_AUTONOMOUS";
|
|
25371
25443
|
var MIN_SCAN_INTERVAL_MS = 6e4;
|
|
25444
|
+
var LEADERBOARD_ALIAS_PATTERN = /^[a-zA-Z0-9_-]{3,30}$/;
|
|
25445
|
+
function defaultLeaderboardAlias(name) {
|
|
25446
|
+
const normalized = name.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
25447
|
+
const alias = normalized || "trader";
|
|
25448
|
+
return alias.slice(0, 24);
|
|
25449
|
+
}
|
|
25372
25450
|
function trackOnboardingEvent(eventType, metadata = {}) {
|
|
25373
25451
|
try {
|
|
25374
25452
|
emitCliProductEvent(eventType, {
|
|
@@ -25442,17 +25520,37 @@ async function runOnboarding() {
|
|
|
25442
25520
|
return true;
|
|
25443
25521
|
}
|
|
25444
25522
|
});
|
|
25523
|
+
const benchmarkOptIn = await confirm({
|
|
25524
|
+
message: "Show this trader on the public leaderboard? You can opt in later from the CLI.",
|
|
25525
|
+
default: false
|
|
25526
|
+
});
|
|
25527
|
+
let publicAlias;
|
|
25528
|
+
if (benchmarkOptIn) {
|
|
25529
|
+
publicAlias = await input({
|
|
25530
|
+
message: "Public leaderboard alias (3-30 letters, numbers, underscores, or hyphens)",
|
|
25531
|
+
default: defaultLeaderboardAlias(name),
|
|
25532
|
+
validate: (v) => LEADERBOARD_ALIAS_PATTERN.test(v.trim()) ? true : "Alias must be 3-30 characters using letters, numbers, underscores, or hyphens."
|
|
25533
|
+
});
|
|
25534
|
+
}
|
|
25445
25535
|
try {
|
|
25446
25536
|
if (await isRemoteMode()) {
|
|
25447
25537
|
const result = await apiRequest("/api/v1/traders", {
|
|
25448
25538
|
method: "POST",
|
|
25449
|
-
body: {
|
|
25539
|
+
body: {
|
|
25540
|
+
name: name.trim(),
|
|
25541
|
+
maxDrawdown: parseFloat(maxDrawdown),
|
|
25542
|
+
benchmarkOptIn,
|
|
25543
|
+
publicAlias: publicAlias?.trim()
|
|
25544
|
+
}
|
|
25450
25545
|
});
|
|
25451
25546
|
console.log(source_default.green(` \u2713 Trader "${result.name}" registered (id: ${result.id})`));
|
|
25452
25547
|
if (result.publicAlias) {
|
|
25453
25548
|
console.log(source_default.dim(` Leaderboard alias: ${result.publicAlias}`));
|
|
25454
25549
|
console.log(source_default.dim(" This alias is public on the leaderboard. Change it anytime:"));
|
|
25455
25550
|
console.log(source_default.dim(" trading-boy trader set-alias <name> <new-alias>"));
|
|
25551
|
+
} else {
|
|
25552
|
+
console.log(source_default.dim(" Public leaderboard: private. Opt in later with:"));
|
|
25553
|
+
console.log(source_default.dim(" trading-boy trader leaderboard opt-in <name> <alias>"));
|
|
25456
25554
|
}
|
|
25457
25555
|
traderName = name.trim();
|
|
25458
25556
|
traderId = result.id;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Trading Boy CLI — remote trading intelligence for traders and AI agents.",
|
|
5
5
|
"homepage": "https://cabal.ventures",
|
|
6
6
|
"repository": {
|
|
@@ -50,6 +50,14 @@
|
|
|
50
50
|
"README.md",
|
|
51
51
|
"!dist/**/*.map"
|
|
52
52
|
],
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc && node esbuild.config.js",
|
|
55
|
+
"typecheck": "tsc -b --pretty false",
|
|
56
|
+
"test": "vitest run",
|
|
57
|
+
"lint": "eslint src/",
|
|
58
|
+
"clean": "rm -rf dist .turbo",
|
|
59
|
+
"prepublishOnly": "node prepublish-check.js"
|
|
60
|
+
},
|
|
53
61
|
"dependencies": {
|
|
54
62
|
"@inquirer/prompts": "~7.10.1",
|
|
55
63
|
"@napi-rs/keyring": "~1.1.3",
|
|
@@ -60,15 +68,8 @@
|
|
|
60
68
|
"qrcode-terminal": "~0.12.0"
|
|
61
69
|
},
|
|
62
70
|
"devDependencies": {
|
|
71
|
+
"@trading-boy/core": "workspace:*",
|
|
63
72
|
"esbuild": "~0.27.7",
|
|
64
|
-
"typescript": "^5.7.0"
|
|
65
|
-
"@trading-boy/core": "1.3.0"
|
|
66
|
-
},
|
|
67
|
-
"scripts": {
|
|
68
|
-
"build": "tsc && node esbuild.config.js",
|
|
69
|
-
"typecheck": "tsc -b --pretty false",
|
|
70
|
-
"test": "vitest run",
|
|
71
|
-
"lint": "eslint src/",
|
|
72
|
-
"clean": "rm -rf dist .turbo"
|
|
73
|
+
"typescript": "^5.7.0"
|
|
73
74
|
}
|
|
74
|
-
}
|
|
75
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2026 Cabal Ventures. All rights reserved.
|
|
2
|
-
|
|
3
|
-
This software and associated documentation files (the "Software") are the
|
|
4
|
-
proprietary property of Cabal Ventures. Unauthorized copying, modification,
|
|
5
|
-
distribution, or use of this Software, in whole or in part, is strictly
|
|
6
|
-
prohibited without the express written permission of Cabal Ventures.
|
|
7
|
-
|
|
8
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
9
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
10
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
11
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
12
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
13
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
14
|
-
SOFTWARE.
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
This project uses the following open-source software:
|
|
19
|
-
|
|
20
|
-
Hermes Agent Framework — MIT License
|
|
21
|
-
Copyright (c) Hermes Contributors
|
|
22
|
-
https://github.com/hermes-ai/hermes
|