@trading-boy/cli 1.2.14 → 1.2.16

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.
@@ -39723,21 +39723,6 @@ function date4(params) {
39723
39723
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
39724
39724
  config(en_default());
39725
39725
 
39726
- // ../core/dist/errors/index.js
39727
- var TradingBoyError = class extends Error {
39728
- code;
39729
- constructor(message, code) {
39730
- super(message);
39731
- this.name = this.constructor.name;
39732
- this.code = code;
39733
- }
39734
- };
39735
- var ConfigError = class extends TradingBoyError {
39736
- constructor(message) {
39737
- super(message, "CONFIG_ERROR");
39738
- }
39739
- };
39740
-
39741
39726
  // ../core/dist/config/env.js
39742
39727
  import_dotenv.default.config({ quiet: true });
39743
39728
  var PRODUCTION_REQUIRED_PASSWORDS = [
@@ -39853,19 +39838,6 @@ var envSchema = external_exports.object({
39853
39838
  }
39854
39839
  }
39855
39840
  });
39856
- var _config = null;
39857
- function getConfig() {
39858
- if (!_config) {
39859
- const result = envSchema.safeParse(process.env);
39860
- if (!result.success) {
39861
- const messages = result.error.issues.map((issue2) => ` - ${issue2.path.join(".")}: ${issue2.message}`).join("\n");
39862
- throw new ConfigError(`Environment validation failed:
39863
- ${messages}`);
39864
- }
39865
- _config = result.data;
39866
- }
39867
- return _config;
39868
- }
39869
39841
 
39870
39842
  // ../core/dist/logging/logger.js
39871
39843
  var import_pino = __toESM(require_pino(), 1);
@@ -49808,37 +49780,6 @@ function redactValue(key, value) {
49808
49780
  }
49809
49781
  return strValue.slice(0, 3) + "****";
49810
49782
  }
49811
- function formatConfigOutput(config2) {
49812
- const lines = [];
49813
- lines.push("");
49814
- lines.push(source_default.bold.cyan(" Configuration"));
49815
- lines.push(source_default.gray(" " + "\u2500".repeat(60)));
49816
- lines.push("");
49817
- const groups = [
49818
- { name: "Runtime", keys: ["NODE_ENV", "LOG_LEVEL"] },
49819
- { name: "Neo4j", keys: ["NEO4J_URI", "NEO4J_USER", "NEO4J_PASSWORD"] },
49820
- { name: "TimescaleDB", keys: ["TIMESCALE_HOST", "TIMESCALE_PORT", "TIMESCALE_USER", "TIMESCALE_PASSWORD", "TIMESCALE_DB"] },
49821
- { name: "Redis", keys: ["REDIS_URL", "REDIS_PASSWORD"] },
49822
- { name: "Data Sources", keys: ["HELIUS_API_KEY", "COINGECKO_API_KEY", "ALCHEMY_API_KEY", "GLASSNODE_API_KEY", "TWITTER_BEARER_TOKEN"] },
49823
- { name: "AI / LLM", keys: ["ANTHROPIC_API_KEY", "LLM_PROVIDER", "LLM_API_KEY", "LLM_BASE_URL", "LLM_MODEL", "LLM_FALLBACK_PROVIDER", "LLM_FALLBACK_MODEL", "LLM_FALLBACK_API_KEY", "LLM_MAX_RETRIES", "LLM_TIMEOUT_MS", "LLM_ENCRYPTION_KEY", "ENABLE_LLM"] },
49824
- { name: "Learning", keys: ["BELIEF_HMAC_KEY", "ENABLE_LEARNING", "ENABLE_SOCIAL"] },
49825
- { name: "API", keys: ["API_PORT", "API_KEY_HASHES", "API_KEY_AUTH_ENABLED"] },
49826
- { name: "Billing", keys: ["STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET", "STRIPE_PRICE_ID_STARTER", "STRIPE_PRICE_ID_PRO", "STRIPE_PRICE_ID_EDGE", "APP_URL"] },
49827
- { name: "Telegram", keys: ["TELEGRAM_BOT_TOKEN", "TELEGRAM_ALLOWED_CHAT_IDS"] },
49828
- { name: "Email", keys: ["RESEND_API_KEY", "EMAIL_FROM_ADDRESS", "EMAIL_FROM_NAME", "SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASS", "NOTIFICATION_FROM_EMAIL"] }
49829
- ];
49830
- const configRecord = config2;
49831
- for (const group of groups) {
49832
- lines.push(source_default.bold(` ${group.name}`));
49833
- for (const key of group.keys) {
49834
- const value = configRecord[key];
49835
- const displayValue = value !== void 0 ? redactValue(key, value) : source_default.dim("(not set)");
49836
- lines.push(` ${source_default.gray(padRight(key, 26))} ${displayValue}`);
49837
- }
49838
- lines.push("");
49839
- }
49840
- return lines.join("\n");
49841
- }
49842
49783
  function resolveEnvPath() {
49843
49784
  return resolve(process.cwd(), ".env");
49844
49785
  }
@@ -49897,31 +49838,32 @@ function writeEnvValue(filePath, key, value) {
49897
49838
  }
49898
49839
  function registerConfigCommand(program2) {
49899
49840
  const configCmd = program2.command("config").description("Configuration management commands");
49900
- configCmd.command("show").description("Display current configuration (sensitive values redacted)").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action((options) => {
49901
- let config2 = null;
49902
- try {
49903
- config2 = getConfig();
49904
- } catch {
49905
- config2 = null;
49906
- }
49907
- if (config2) {
49908
- if (options.format === "json") {
49909
- const configRecord = config2;
49910
- const redacted = {};
49911
- for (const key of VALID_KEYS) {
49912
- const value = configRecord[key];
49913
- redacted[key] = value !== void 0 ? redactValue(key, value) : "";
49914
- }
49915
- console.log(JSON.stringify(redacted, null, 2));
49916
- } else {
49917
- console.log(formatConfigOutput(config2));
49918
- }
49919
- } else {
49920
- console.log(source_default.yellow(" Note: Full config validation unavailable (server env vars not set)\n"));
49841
+ configCmd.command("show").description("Display current configuration").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).addOption(new Option("--all", "Show all config variables (including server/infrastructure)")).action((options) => {
49842
+ const USER_CONFIG = [
49843
+ { section: "Connection", keys: [
49844
+ { key: "TRADING_BOY_API_URL", label: "API URL" }
49845
+ ] },
49846
+ { section: "LLM (Coaching)", keys: [
49847
+ { key: "LLM_PROVIDER", label: "Provider" },
49848
+ { key: "LLM_MODEL", label: "Model" },
49849
+ { key: "LLM_API_KEY", label: "API Key" },
49850
+ { key: "LLM_BASE_URL", label: "Base URL" }
49851
+ ] },
49852
+ { section: "Notifications", keys: [
49853
+ { key: "TELEGRAM_BOT_TOKEN", label: "Telegram Bot" },
49854
+ { key: "TELEGRAM_ALLOWED_CHAT_IDS", label: "Telegram Chat IDs" }
49855
+ ] }
49856
+ ];
49857
+ const getEnv = (key) => {
49858
+ const value = process.env[key];
49859
+ if (!value)
49860
+ return source_default.dim("not set");
49861
+ return SENSITIVE_KEYS.has(key) ? redactValue(key, value) : value;
49862
+ };
49863
+ if (options.all) {
49921
49864
  const redacted = {};
49922
49865
  for (const key of VALID_KEYS) {
49923
- const value = process.env[key];
49924
- redacted[key] = value !== void 0 ? redactValue(key, value) : source_default.dim("(not set)");
49866
+ redacted[key] = getEnv(key);
49925
49867
  }
49926
49868
  if (options.format === "json") {
49927
49869
  console.log(JSON.stringify(redacted, null, 2));
@@ -49930,7 +49872,29 @@ function registerConfigCommand(program2) {
49930
49872
  console.log(` ${source_default.cyan(key.padEnd(30))} ${value}`);
49931
49873
  }
49932
49874
  }
49875
+ return;
49876
+ }
49877
+ if (options.format === "json") {
49878
+ const result = {};
49879
+ for (const section of USER_CONFIG) {
49880
+ for (const { key } of section.keys) {
49881
+ result[key] = process.env[key] ?? "";
49882
+ }
49883
+ }
49884
+ console.log(JSON.stringify(result, null, 2));
49885
+ return;
49886
+ }
49887
+ console.log("");
49888
+ for (const section of USER_CONFIG) {
49889
+ console.log(source_default.bold(` ${section.section}`));
49890
+ console.log(source_default.gray(" " + "\u2500".repeat(40)));
49891
+ for (const { key, label } of section.keys) {
49892
+ console.log(` ${source_default.cyan(label.padEnd(22))} ${getEnv(key)}`);
49893
+ }
49894
+ console.log("");
49933
49895
  }
49896
+ console.log(source_default.dim(" Use --all to show all config variables."));
49897
+ console.log("");
49934
49898
  });
49935
49899
  configCmd.command("set <key> <value>").description("Set a config value in the .env file").action((key, value) => {
49936
49900
  try {
@@ -50252,6 +50216,7 @@ function registerLoginCommand(program2) {
50252
50216
 
50253
50217
  // dist/commands/logout.js
50254
50218
  init_source();
50219
+ init_esm15();
50255
50220
  var logger20 = createLogger("cli-logout");
50256
50221
  async function executeLogout() {
50257
50222
  const existing = await loadCredentials();
@@ -50263,15 +50228,28 @@ async function executeLogout() {
50263
50228
  function registerLogoutCommand(program2) {
50264
50229
  program2.command("logout").description("Clear stored API key and credentials").action(async () => {
50265
50230
  try {
50266
- const result = await executeLogout();
50267
- console.log("");
50268
- if (result.wasAuthenticated) {
50269
- console.log(source_default.green(` Logged out successfully.`));
50270
- console.log(` ${source_default.gray("Cleared key:")} ${result.redactedKey}`);
50271
- } else {
50231
+ const existing = await loadCredentials();
50232
+ if (!existing) {
50233
+ console.log("");
50272
50234
  console.log(source_default.dim(" No credentials found \u2014 already logged out."));
50235
+ console.log("");
50236
+ return;
50273
50237
  }
50274
50238
  console.log("");
50239
+ console.log(source_default.yellow(" Warning: Your API key will be cleared from this machine."));
50240
+ console.log(source_default.yellow(" You will need your API key to log back in."));
50241
+ console.log(source_default.yellow(" There is no way to recover a lost key \u2014 a new one must be provisioned."));
50242
+ console.log("");
50243
+ const proceed = await esm_default4({ message: "Are you sure you want to logout?" });
50244
+ if (!proceed) {
50245
+ console.log(source_default.dim(" Logout cancelled."));
50246
+ return;
50247
+ }
50248
+ const result = await executeLogout();
50249
+ console.log("");
50250
+ console.log(source_default.green(` Logged out successfully.`));
50251
+ console.log(` ${source_default.gray("Cleared key:")} ${result.redactedKey}`);
50252
+ console.log("");
50275
50253
  } catch (error49) {
50276
50254
  const message = error49 instanceof Error ? error49.message : String(error49);
50277
50255
  logger20.error({ error: message }, "Logout failed");
@@ -1,6 +1,6 @@
1
1
  import { Option } from 'commander';
2
2
  import chalk from 'chalk';
3
- import { getConfig, createLogger } from '@trading-boy/core';
3
+ import { createLogger } from '@trading-boy/core';
4
4
  import { readFileSync, writeFileSync, existsSync } from 'node:fs';
5
5
  import { resolve } from 'node:path';
6
6
  import { apiRequest, ApiError } from '../api-client.js';
@@ -219,39 +219,37 @@ export function registerConfigCommand(program) {
219
219
  // ─── config show ───
220
220
  configCmd
221
221
  .command('show')
222
- .description('Display current configuration (sensitive values redacted)')
222
+ .description('Display current configuration')
223
223
  .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
224
+ .addOption(new Option('--all', 'Show all config variables (including server/infrastructure)'))
224
225
  .action((options) => {
225
- let config = null;
226
- try {
227
- config = getConfig();
228
- }
229
- catch {
230
- // Config validation failed (e.g. missing DB passwords in CLI-only mode)
231
- // Fall back to showing raw env vars
232
- config = null;
233
- }
234
- if (config) {
235
- if (options.format === 'json') {
236
- const configRecord = config;
237
- const redacted = {};
238
- for (const key of VALID_KEYS) {
239
- const value = configRecord[key];
240
- redacted[key] = value !== undefined ? redactValue(key, value) : '';
241
- }
242
- console.log(JSON.stringify(redacted, null, 2));
243
- }
244
- else {
245
- console.log(formatConfigOutput(config));
246
- }
247
- }
248
- else {
249
- // Graceful fallback: show available env vars without full validation
250
- console.log(chalk.yellow(' Note: Full config validation unavailable (server env vars not set)\n'));
226
+ // User-facing config: only what a CLI user cares about
227
+ const USER_CONFIG = [
228
+ { section: 'Connection', keys: [
229
+ { key: 'TRADING_BOY_API_URL', label: 'API URL' },
230
+ ] },
231
+ { section: 'LLM (Coaching)', keys: [
232
+ { key: 'LLM_PROVIDER', label: 'Provider' },
233
+ { key: 'LLM_MODEL', label: 'Model' },
234
+ { key: 'LLM_API_KEY', label: 'API Key' },
235
+ { key: 'LLM_BASE_URL', label: 'Base URL' },
236
+ ] },
237
+ { section: 'Notifications', keys: [
238
+ { key: 'TELEGRAM_BOT_TOKEN', label: 'Telegram Bot' },
239
+ { key: 'TELEGRAM_ALLOWED_CHAT_IDS', label: 'Telegram Chat IDs' },
240
+ ] },
241
+ ];
242
+ const getEnv = (key) => {
243
+ const value = process.env[key];
244
+ if (!value)
245
+ return chalk.dim('not set');
246
+ return SENSITIVE_KEYS.has(key) ? redactValue(key, value) : value;
247
+ };
248
+ if (options.all) {
249
+ // Full dump for developers
251
250
  const redacted = {};
252
251
  for (const key of VALID_KEYS) {
253
- const value = process.env[key];
254
- redacted[key] = value !== undefined ? redactValue(key, value) : chalk.dim('(not set)');
252
+ redacted[key] = getEnv(key);
255
253
  }
256
254
  if (options.format === 'json') {
257
255
  console.log(JSON.stringify(redacted, null, 2));
@@ -261,7 +259,29 @@ export function registerConfigCommand(program) {
261
259
  console.log(` ${chalk.cyan(key.padEnd(30))} ${value}`);
262
260
  }
263
261
  }
262
+ return;
263
+ }
264
+ if (options.format === 'json') {
265
+ const result = {};
266
+ for (const section of USER_CONFIG) {
267
+ for (const { key } of section.keys) {
268
+ result[key] = process.env[key] ?? '';
269
+ }
270
+ }
271
+ console.log(JSON.stringify(result, null, 2));
272
+ return;
273
+ }
274
+ console.log('');
275
+ for (const section of USER_CONFIG) {
276
+ console.log(chalk.bold(` ${section.section}`));
277
+ console.log(chalk.gray(' ' + '─'.repeat(40)));
278
+ for (const { key, label } of section.keys) {
279
+ console.log(` ${chalk.cyan(label.padEnd(22))} ${getEnv(key)}`);
280
+ }
281
+ console.log('');
264
282
  }
283
+ console.log(chalk.dim(' Use --all to show all config variables.'));
284
+ console.log('');
265
285
  });
266
286
  // ─── config set ───
267
287
  configCmd
@@ -1,6 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import { createLogger } from '@trading-boy/core';
3
3
  import { clearCredentials, loadCredentials, redactApiKey } from '../credentials.js';
4
+ import { confirm } from '@inquirer/prompts';
4
5
  const logger = createLogger('cli-logout');
5
6
  // ─── Logout Logic ───
6
7
  export async function executeLogout() {
@@ -17,15 +18,27 @@ export function registerLogoutCommand(program) {
17
18
  .description('Clear stored API key and credentials')
18
19
  .action(async () => {
19
20
  try {
20
- const result = await executeLogout();
21
- console.log('');
22
- if (result.wasAuthenticated) {
23
- console.log(chalk.green(` Logged out successfully.`));
24
- console.log(` ${chalk.gray('Cleared key:')} ${result.redactedKey}`);
25
- }
26
- else {
21
+ const existing = await loadCredentials();
22
+ if (!existing) {
23
+ console.log('');
27
24
  console.log(chalk.dim(' No credentials found — already logged out.'));
25
+ console.log('');
26
+ return;
27
+ }
28
+ console.log('');
29
+ console.log(chalk.yellow(' Warning: Your API key will be cleared from this machine.'));
30
+ console.log(chalk.yellow(' You will need your API key to log back in.'));
31
+ console.log(chalk.yellow(' There is no way to recover a lost key — a new one must be provisioned.'));
32
+ console.log('');
33
+ const proceed = await confirm({ message: 'Are you sure you want to logout?' });
34
+ if (!proceed) {
35
+ console.log(chalk.dim(' Logout cancelled.'));
36
+ return;
28
37
  }
38
+ const result = await executeLogout();
39
+ console.log('');
40
+ console.log(chalk.green(` Logged out successfully.`));
41
+ console.log(` ${chalk.gray('Cleared key:')} ${result.redactedKey}`);
29
42
  console.log('');
30
43
  }
31
44
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trading-boy/cli",
3
- "version": "1.2.14",
3
+ "version": "1.2.16",
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": {