@trading-boy/cli 1.2.19 → 1.2.20

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.
@@ -39787,6 +39787,12 @@ var envSchema = external_exports.object({
39787
39787
  COLD_START_MATURITY_THRESHOLD: external_exports.coerce.number().int().nonnegative().default(50),
39788
39788
  // Politician trading data
39789
39789
  FINNHUB_API_KEY: external_exports.string().default(""),
39790
+ // Macro data sources
39791
+ FRED_API_KEY: external_exports.string().default(""),
39792
+ NEWSDATA_API_KEY: external_exports.string().default(""),
39793
+ KALSHI_API_KEY: external_exports.string().default(""),
39794
+ OILPRICE_API_KEY: external_exports.string().default(""),
39795
+ EXCHANGERATE_API_KEY: external_exports.string().default(""),
39790
39796
  // Feature flags
39791
39797
  ENABLE_LLM: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
39792
39798
  ENABLE_LEARNING: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
@@ -47664,7 +47670,7 @@ function stopWatchLoop(state) {
47664
47670
  }
47665
47671
  }
47666
47672
  function registerWatchCommand(program2) {
47667
- program2.command("watch <symbol>").description("Watch token data with periodic refresh").option("-i, --interval <seconds>", "Refresh interval in seconds", (v) => parseInt(v, 10)).option("-c, --context", "Watch full ContextPackage (default interval: 60s)").action(async (symbol2, options) => {
47673
+ program2.command("watch <symbol>").description("Watch token data with periodic refresh").option("-i, --interval <seconds>", "Refresh interval in seconds", (v) => parseInt(v, 10)).option("-c, --context", "Watch full ContextPackage (default interval: 60s)").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (symbol2, options) => {
47668
47674
  const useContext = options.context === true;
47669
47675
  const defaultInterval = useContext ? DEFAULT_CONTEXT_INTERVAL_SECONDS : DEFAULT_INTERVAL_SECONDS;
47670
47676
  const intervalSeconds = options.interval ?? defaultInterval;
@@ -47674,8 +47680,19 @@ function registerWatchCommand(program2) {
47674
47680
  return;
47675
47681
  }
47676
47682
  const mode = useContext ? "context" : "query";
47683
+ const isJson = options.format === "json";
47677
47684
  logger8.info({ symbol: symbol2, intervalSeconds, mode }, "Starting watch mode");
47678
- const state = startWatchLoop(symbol2, intervalSeconds, renderCycleRemote);
47685
+ const renderFn = isJson ? async (sym) => {
47686
+ try {
47687
+ const pkg = await apiRequest(`/api/v1/tokens/${encodeURIComponent(sym.toUpperCase())}/context`);
47688
+ console.log(JSON.stringify({ watchedAt: (/* @__PURE__ */ new Date()).toISOString(), symbol: sym.toUpperCase(), ...pkg }, null, 2));
47689
+ return pkg;
47690
+ } catch (error49) {
47691
+ console.log(JSON.stringify({ error: error49 instanceof Error ? error49.message : String(error49), timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
47692
+ return null;
47693
+ }
47694
+ } : renderCycleRemote;
47695
+ const state = startWatchLoop(symbol2, intervalSeconds, renderFn);
47679
47696
  const cleanup = () => {
47680
47697
  logger8.info("Watch mode stopped by user");
47681
47698
  stopWatchLoop(state);
@@ -48462,10 +48479,18 @@ function registerTraderCommand(program2) {
48462
48479
  }
48463
48480
  } catch (error49) {
48464
48481
  if (error49 instanceof ApiError && error49.status === 404) {
48465
- console.error(source_default.yellow(options.file ? `Trader not found: "${nameOrId}"` : "No SOUL document found."));
48482
+ if (options.format === "json") {
48483
+ console.log(JSON.stringify({ soul: null, message: options.file ? `Trader not found: "${nameOrId}"` : "No SOUL document found" }));
48484
+ } else {
48485
+ console.error(source_default.yellow(options.file ? `Trader not found: "${nameOrId}"` : "No SOUL document found."));
48486
+ }
48466
48487
  } else {
48467
48488
  const message = error49 instanceof Error ? error49.message : String(error49);
48468
- console.error(source_default.red(`Error: ${message}`));
48489
+ if (options.format === "json") {
48490
+ console.log(JSON.stringify({ error: message }));
48491
+ } else {
48492
+ console.error(source_default.red(`Error: ${message}`));
48493
+ }
48469
48494
  }
48470
48495
  process.exitCode = error49 instanceof ApiError ? 2 : 1;
48471
48496
  }
@@ -48510,10 +48535,18 @@ function registerTraderCommand(program2) {
48510
48535
  }
48511
48536
  } catch (error49) {
48512
48537
  if (error49 instanceof ApiError && error49.status === 404) {
48513
- console.error(source_default.yellow(options.file ? `Trader not found: "${nameOrId}"` : "No PURPOSE document found."));
48538
+ if (options.format === "json") {
48539
+ console.log(JSON.stringify({ purpose: null, message: options.file ? `Trader not found: "${nameOrId}"` : "No PURPOSE document found" }));
48540
+ } else {
48541
+ console.error(source_default.yellow(options.file ? `Trader not found: "${nameOrId}"` : "No PURPOSE document found."));
48542
+ }
48514
48543
  } else {
48515
48544
  const message = error49 instanceof Error ? error49.message : String(error49);
48516
- console.error(source_default.red(`Error: ${message}`));
48545
+ if (options.format === "json") {
48546
+ console.log(JSON.stringify({ error: message }));
48547
+ } else {
48548
+ console.error(source_default.red(`Error: ${message}`));
48549
+ }
48517
48550
  }
48518
48551
  process.exitCode = error49 instanceof ApiError ? 2 : 1;
48519
48552
  }
@@ -424,11 +424,21 @@ export function registerTraderCommand(program) {
424
424
  }
425
425
  catch (error) {
426
426
  if (error instanceof ApiError && error.status === 404) {
427
- console.error(chalk.yellow(options.file ? `Trader not found: "${nameOrId}"` : 'No SOUL document found.'));
427
+ if (options.format === 'json') {
428
+ console.log(JSON.stringify({ soul: null, message: options.file ? `Trader not found: "${nameOrId}"` : 'No SOUL document found' }));
429
+ }
430
+ else {
431
+ console.error(chalk.yellow(options.file ? `Trader not found: "${nameOrId}"` : 'No SOUL document found.'));
432
+ }
428
433
  }
429
434
  else {
430
435
  const message = error instanceof Error ? error.message : String(error);
431
- console.error(chalk.red(`Error: ${message}`));
436
+ if (options.format === 'json') {
437
+ console.log(JSON.stringify({ error: message }));
438
+ }
439
+ else {
440
+ console.error(chalk.red(`Error: ${message}`));
441
+ }
432
442
  }
433
443
  process.exitCode = error instanceof ApiError ? 2 : 1;
434
444
  }
@@ -484,11 +494,21 @@ export function registerTraderCommand(program) {
484
494
  }
485
495
  catch (error) {
486
496
  if (error instanceof ApiError && error.status === 404) {
487
- console.error(chalk.yellow(options.file ? `Trader not found: "${nameOrId}"` : 'No PURPOSE document found.'));
497
+ if (options.format === 'json') {
498
+ console.log(JSON.stringify({ purpose: null, message: options.file ? `Trader not found: "${nameOrId}"` : 'No PURPOSE document found' }));
499
+ }
500
+ else {
501
+ console.error(chalk.yellow(options.file ? `Trader not found: "${nameOrId}"` : 'No PURPOSE document found.'));
502
+ }
488
503
  }
489
504
  else {
490
505
  const message = error instanceof Error ? error.message : String(error);
491
- console.error(chalk.red(`Error: ${message}`));
506
+ if (options.format === 'json') {
507
+ console.log(JSON.stringify({ error: message }));
508
+ }
509
+ else {
510
+ console.error(chalk.red(`Error: ${message}`));
511
+ }
492
512
  }
493
513
  process.exitCode = error instanceof ApiError ? 2 : 1;
494
514
  }
@@ -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 { formatContextOutput } from './context.js';
@@ -61,6 +62,7 @@ export function registerWatchCommand(program) {
61
62
  .description('Watch token data with periodic refresh')
62
63
  .option('-i, --interval <seconds>', 'Refresh interval in seconds', (v) => parseInt(v, 10))
63
64
  .option('-c, --context', 'Watch full ContextPackage (default interval: 60s)')
65
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
64
66
  .action(async (symbol, options) => {
65
67
  const useContext = options.context === true;
66
68
  const defaultInterval = useContext ? DEFAULT_CONTEXT_INTERVAL_SECONDS : DEFAULT_INTERVAL_SECONDS;
@@ -71,8 +73,22 @@ export function registerWatchCommand(program) {
71
73
  return;
72
74
  }
73
75
  const mode = useContext ? 'context' : 'query';
76
+ const isJson = options.format === 'json';
74
77
  logger.info({ symbol, intervalSeconds, mode }, 'Starting watch mode');
75
- const state = startWatchLoop(symbol, intervalSeconds, renderCycleRemote);
78
+ const renderFn = isJson
79
+ ? async (sym) => {
80
+ try {
81
+ const pkg = await apiRequest(`/api/v1/tokens/${encodeURIComponent(sym.toUpperCase())}/context`);
82
+ console.log(JSON.stringify({ watchedAt: new Date().toISOString(), symbol: sym.toUpperCase(), ...pkg }, null, 2));
83
+ return pkg;
84
+ }
85
+ catch (error) {
86
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }));
87
+ return null;
88
+ }
89
+ }
90
+ : renderCycleRemote;
91
+ const state = startWatchLoop(symbol, intervalSeconds, renderFn);
76
92
  // Clean exit on SIGINT (Ctrl+C)
77
93
  const cleanup = () => {
78
94
  logger.info('Watch mode stopped by user');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trading-boy/cli",
3
- "version": "1.2.19",
3
+ "version": "1.2.20",
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": {