@trading-boy/cli 1.3.0 → 1.4.1

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.
@@ -39795,6 +39795,7 @@ var envSchema = external_exports.object({
39795
39795
  FINNHUB_API_KEY: external_exports.string().default(""),
39796
39796
  // Macro data sources
39797
39797
  FRED_API_KEY: external_exports.string().default(""),
39798
+ EIA_API_KEY: external_exports.string().default(""),
39798
39799
  NEWSDATA_API_KEY: external_exports.string().default(""),
39799
39800
  KALSHI_API_KEY: external_exports.string().default(""),
39800
39801
  OILPRICE_API_KEY: external_exports.string().default(""),
@@ -54632,9 +54633,21 @@ function formatWhoamiOutput(result) {
54632
54633
  return lines.join("\n");
54633
54634
  }
54634
54635
  function registerWhoamiCommand(program2) {
54635
- program2.command("whoami").description("Show current authentication status").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
54636
+ program2.command("whoami").description("Show current authentication status").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).addOption(new Option("--show-key", "Show full API key (for Telegram setup)")).action(async (options) => {
54636
54637
  try {
54637
54638
  const result = await executeWhoami();
54639
+ if (options.showKey && result.authenticated) {
54640
+ const envKey = process.env.TRADING_BOY_API_KEY;
54641
+ if (envKey) {
54642
+ console.log(envKey);
54643
+ return;
54644
+ }
54645
+ const creds = await loadCredentials();
54646
+ if (creds) {
54647
+ console.log(creds.apiKey);
54648
+ return;
54649
+ }
54650
+ }
54638
54651
  if (options.format === "json") {
54639
54652
  console.log(JSON.stringify(result, null, 2));
54640
54653
  } else {
@@ -55045,12 +55058,18 @@ function formatSubscribeSuccess(result) {
55045
55058
  if (result.plan) {
55046
55059
  lines.push(` ${source_default.bold("Plan:")} ${result.plan}`);
55047
55060
  }
55048
- if (result.keyPrefix) {
55061
+ if (result.apiKey) {
55062
+ lines.push(` ${source_default.bold("API Key:")} ${source_default.yellow(result.apiKey)}`);
55063
+ lines.push("");
55064
+ lines.push(source_default.dim(" \u26A0\uFE0F Copy this key now \u2014 it will not be shown again."));
55065
+ lines.push(source_default.dim(" Use it to connect Telegram: send /start to @TradingBoyBot"));
55066
+ lines.push(source_default.dim(" and paste the key when prompted."));
55067
+ } else if (result.keyPrefix) {
55049
55068
  lines.push(` ${source_default.bold("Key ID:")} ${result.keyPrefix}`);
55050
55069
  }
55051
55070
  lines.push("");
55052
- lines.push(source_default.dim(" Your API key has been stored securely."));
55053
- lines.push(source_default.dim(" You can now use all Trading Boy commands."));
55071
+ lines.push(source_default.dim(" Your API key has been stored locally."));
55072
+ lines.push(source_default.dim(" You can also view it anytime: trading-boy whoami --show-key"));
55054
55073
  lines.push("");
55055
55074
  lines.push(source_default.cyan(" Try it: trading-boy context SOL"));
55056
55075
  lines.push("");
@@ -57256,6 +57275,35 @@ function registerAgentCommand(program2) {
57256
57275
  handleApiError4(error49, "Agent delete failed");
57257
57276
  }
57258
57277
  });
57278
+ agent.command("exit <agentId>").description("Exit/close an open position for an agent").requiredOption("--symbol <symbol>", "Token symbol to exit (e.g. xyz:NATGAS)").option("--reason <text>", "Reason for exit").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, options) => {
57279
+ if (!await ensureRemote2())
57280
+ return;
57281
+ try {
57282
+ const body = {};
57283
+ if (options.reason)
57284
+ body.reason = options.reason;
57285
+ const result = await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/positions/${encodeURIComponent(options.symbol)}/exit`, { method: "POST", body });
57286
+ if (options.format === "json") {
57287
+ console.log(JSON.stringify(result, null, 2));
57288
+ } else {
57289
+ const pnlColor = result.pnl >= 0 ? source_default.green : source_default.red;
57290
+ const pnlSign = result.pnl >= 0 ? "+" : "";
57291
+ console.log("");
57292
+ console.log(source_default.green(" Position closed"));
57293
+ console.log(` ${source_default.gray("Symbol:")} ${result.symbol}`);
57294
+ console.log(` ${source_default.gray("Side:")} ${result.side}`);
57295
+ console.log(` ${source_default.gray("Exit price:")} $${result.exitPrice.toLocaleString()}`);
57296
+ console.log(` ${source_default.gray("PnL:")} ${pnlColor(`${pnlSign}$${result.pnl.toFixed(2)} (${pnlSign}${result.pnlPct.toFixed(2)}%)`)}`);
57297
+ console.log(` ${source_default.gray("Closed at:")} ${formatShortDate5(result.closedAt)}`);
57298
+ if (options.reason) {
57299
+ console.log(` ${source_default.gray("Reason:")} ${options.reason}`);
57300
+ }
57301
+ console.log("");
57302
+ }
57303
+ } catch (error49) {
57304
+ handleApiError4(error49, "Position exit failed");
57305
+ }
57306
+ });
57259
57307
  agent.command("update <agentId>").description("Update agent config").option("--name <name>", "Agent name").option("--autonomy <level>", "Autonomy level").option("--scan-interval <ms>", "Scan interval in ms").option("--scan-interval-human <duration>", "Scan interval in human-readable format (e.g. 1m, 5m, 15m, 30m, 1h)").option("--watchlist <symbols>", "Comma-separated token symbols").option("--max-daily-trades <n>", "Max daily trades").option("--max-daily-loss <usd>", "Max daily loss in USD").option("--max-position-size <pct>", "Max position size as decimal").option("--min-confidence <n>", "Min confidence threshold").option("--scan-model <model>", "LLM model for market scanning").option("--analyze-model <model>", "LLM model for deep analysis").option("--decide-model <model>", "LLM model for trade decisions").addOption(new Option("--asset-class <class>", "Asset class for this agent").choices(["crypto", "commodities", "mixed"])).option("--soul-override <text>", "Custom soul/personality for this agent").option("--purpose-override <text>", "Custom purpose/mission for this agent").option("--soul-file <path>", "Load soul from a file").option("--purpose-file <path>", "Load purpose from a file").action(async (agentId, options) => {
57260
57308
  if (!await ensureRemote2())
57261
57309
  return;
@@ -411,6 +411,44 @@ export function registerAgentCommand(program) {
411
411
  handleApiError(error, 'Agent delete failed');
412
412
  }
413
413
  });
414
+ // ── exit ───────────────────────────────────────────────────────────────────
415
+ agent
416
+ .command('exit <agentId>')
417
+ .description('Exit/close an open position for an agent')
418
+ .requiredOption('--symbol <symbol>', 'Token symbol to exit (e.g. xyz:NATGAS)')
419
+ .option('--reason <text>', 'Reason for exit')
420
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
421
+ .action(async (agentId, options) => {
422
+ if (!(await ensureRemote()))
423
+ return;
424
+ try {
425
+ const body = {};
426
+ if (options.reason)
427
+ body.reason = options.reason;
428
+ const result = await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/positions/${encodeURIComponent(options.symbol)}/exit`, { method: 'POST', body });
429
+ if (options.format === 'json') {
430
+ console.log(JSON.stringify(result, null, 2));
431
+ }
432
+ else {
433
+ const pnlColor = result.pnl >= 0 ? chalk.green : chalk.red;
434
+ const pnlSign = result.pnl >= 0 ? '+' : '';
435
+ console.log('');
436
+ console.log(chalk.green(' Position closed'));
437
+ console.log(` ${chalk.gray('Symbol:')} ${result.symbol}`);
438
+ console.log(` ${chalk.gray('Side:')} ${result.side}`);
439
+ console.log(` ${chalk.gray('Exit price:')} $${result.exitPrice.toLocaleString()}`);
440
+ console.log(` ${chalk.gray('PnL:')} ${pnlColor(`${pnlSign}$${result.pnl.toFixed(2)} (${pnlSign}${result.pnlPct.toFixed(2)}%)`)}`);
441
+ console.log(` ${chalk.gray('Closed at:')} ${formatShortDate(result.closedAt)}`);
442
+ if (options.reason) {
443
+ console.log(` ${chalk.gray('Reason:')} ${options.reason}`);
444
+ }
445
+ console.log('');
446
+ }
447
+ }
448
+ catch (error) {
449
+ handleApiError(error, 'Position exit failed');
450
+ }
451
+ });
414
452
  // ── update ──────────────────────────────────────────────────────────────────
415
453
  agent
416
454
  .command('update <agentId>')
@@ -213,12 +213,19 @@ export function formatSubscribeSuccess(result) {
213
213
  if (result.plan) {
214
214
  lines.push(` ${chalk.bold('Plan:')} ${result.plan}`);
215
215
  }
216
- if (result.keyPrefix) {
216
+ if (result.apiKey) {
217
+ lines.push(` ${chalk.bold('API Key:')} ${chalk.yellow(result.apiKey)}`);
218
+ lines.push('');
219
+ lines.push(chalk.dim(' ⚠️ Copy this key now — it will not be shown again.'));
220
+ lines.push(chalk.dim(' Use it to connect Telegram: send /start to @TradingBoyBot'));
221
+ lines.push(chalk.dim(' and paste the key when prompted.'));
222
+ }
223
+ else if (result.keyPrefix) {
217
224
  lines.push(` ${chalk.bold('Key ID:')} ${result.keyPrefix}`);
218
225
  }
219
226
  lines.push('');
220
- lines.push(chalk.dim(' Your API key has been stored securely.'));
221
- lines.push(chalk.dim(' You can now use all Trading Boy commands.'));
227
+ lines.push(chalk.dim(' Your API key has been stored locally.'));
228
+ lines.push(chalk.dim(' You can also view it anytime: trading-boy whoami --show-key'));
222
229
  lines.push('');
223
230
  lines.push(chalk.cyan(' Try it: trading-boy context SOL'));
224
231
  lines.push('');
@@ -68,9 +68,23 @@ export function registerWhoamiCommand(program) {
68
68
  .command('whoami')
69
69
  .description('Show current authentication status')
70
70
  .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
71
+ .addOption(new Option('--show-key', 'Show full API key (for Telegram setup)'))
71
72
  .action(async (options) => {
72
73
  try {
73
74
  const result = await executeWhoami();
75
+ // Show full key if requested
76
+ if (options.showKey && result.authenticated) {
77
+ const envKey = process.env.TRADING_BOY_API_KEY;
78
+ if (envKey) {
79
+ console.log(envKey);
80
+ return;
81
+ }
82
+ const creds = await loadCredentials();
83
+ if (creds) {
84
+ console.log(creds.apiKey);
85
+ return;
86
+ }
87
+ }
74
88
  if (options.format === 'json') {
75
89
  console.log(JSON.stringify(result, null, 2));
76
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trading-boy/cli",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
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": {