@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.
Files changed (3) hide show
  1. package/dist/cli.bundle.js +104 -6
  2. package/package.json +12 -11
  3. package/LICENSE +0 -22
@@ -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.alias) {
22553
- console.log(` ${source_default.gray("Leaderboard alias:")} ${source_default.white(result.alias)} ${source_default.dim("(change with: trading-boy trader set-alias <name> <alias>)")}`);
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 ALIAS_PATTERN = /^[a-zA-Z0-9_-]{3,30}$/;
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: { name: name.trim(), riskToleranceMax: parseFloat(maxDrawdown) }
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.1",
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