@trading-boy/cli 1.2.16 → 1.2.17

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.
@@ -3711,9 +3711,9 @@ var init_source = __esm({
3711
3711
  init_supports_color();
3712
3712
  init_utilities();
3713
3713
  ({ stdout: stdoutColor, stderr: stderrColor } = supports_color_default);
3714
- GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
3715
- STYLER = /* @__PURE__ */ Symbol("STYLER");
3716
- IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
3714
+ GENERATOR = Symbol("GENERATOR");
3715
+ STYLER = Symbol("STYLER");
3716
+ IS_EMPTY = Symbol("IS_EMPTY");
3717
3717
  levelMapping = [
3718
3718
  "ansi",
3719
3719
  "ansi",
@@ -4310,8 +4310,8 @@ var require_err_helpers = __commonJS({
4310
4310
  var require_err_proto = __commonJS({
4311
4311
  "../../node_modules/.pnpm/pino-std-serializers@7.1.0/node_modules/pino-std-serializers/lib/err-proto.js"(exports, module) {
4312
4312
  "use strict";
4313
- var seen = /* @__PURE__ */ Symbol("circular-ref-tag");
4314
- var rawSymbol = /* @__PURE__ */ Symbol("pino-raw-err-ref");
4313
+ var seen = Symbol("circular-ref-tag");
4314
+ var rawSymbol = Symbol("pino-raw-err-ref");
4315
4315
  var pinoErrProto = Object.create({}, {
4316
4316
  type: {
4317
4317
  enumerable: true,
@@ -4448,7 +4448,7 @@ var require_req = __commonJS({
4448
4448
  mapHttpRequest,
4449
4449
  reqSerializer
4450
4450
  };
4451
- var rawSymbol = /* @__PURE__ */ Symbol("pino-raw-req-ref");
4451
+ var rawSymbol = Symbol("pino-raw-req-ref");
4452
4452
  var pinoReqProto = Object.create({}, {
4453
4453
  id: {
4454
4454
  enumerable: true,
@@ -4543,7 +4543,7 @@ var require_res = __commonJS({
4543
4543
  mapHttpResponse,
4544
4544
  resSerializer
4545
4545
  };
4546
- var rawSymbol = /* @__PURE__ */ Symbol("pino-raw-res-ref");
4546
+ var rawSymbol = Symbol("pino-raw-res-ref");
4547
4547
  var pinoResProto = Object.create({}, {
4548
4548
  statusCode: {
4549
4549
  enumerable: true,
@@ -4785,7 +4785,7 @@ var require_redact = __commonJS({
4785
4785
  }
4786
4786
  return true;
4787
4787
  }
4788
- var PATH_NOT_FOUND = /* @__PURE__ */ Symbol("PATH_NOT_FOUND");
4788
+ var PATH_NOT_FOUND = Symbol("PATH_NOT_FOUND");
4789
4789
  function getValueIfExists(obj, parts) {
4790
4790
  let current = obj;
4791
4791
  for (const part of parts) {
@@ -5086,37 +5086,37 @@ var require_redact = __commonJS({
5086
5086
  var require_symbols = __commonJS({
5087
5087
  "../../node_modules/.pnpm/pino@10.3.1/node_modules/pino/lib/symbols.js"(exports, module) {
5088
5088
  "use strict";
5089
- var setLevelSym = /* @__PURE__ */ Symbol("pino.setLevel");
5090
- var getLevelSym = /* @__PURE__ */ Symbol("pino.getLevel");
5091
- var levelValSym = /* @__PURE__ */ Symbol("pino.levelVal");
5092
- var levelCompSym = /* @__PURE__ */ Symbol("pino.levelComp");
5093
- var useLevelLabelsSym = /* @__PURE__ */ Symbol("pino.useLevelLabels");
5094
- var useOnlyCustomLevelsSym = /* @__PURE__ */ Symbol("pino.useOnlyCustomLevels");
5095
- var mixinSym = /* @__PURE__ */ Symbol("pino.mixin");
5096
- var lsCacheSym = /* @__PURE__ */ Symbol("pino.lsCache");
5097
- var chindingsSym = /* @__PURE__ */ Symbol("pino.chindings");
5098
- var asJsonSym = /* @__PURE__ */ Symbol("pino.asJson");
5099
- var writeSym = /* @__PURE__ */ Symbol("pino.write");
5100
- var redactFmtSym = /* @__PURE__ */ Symbol("pino.redactFmt");
5101
- var timeSym = /* @__PURE__ */ Symbol("pino.time");
5102
- var timeSliceIndexSym = /* @__PURE__ */ Symbol("pino.timeSliceIndex");
5103
- var streamSym = /* @__PURE__ */ Symbol("pino.stream");
5104
- var stringifySym = /* @__PURE__ */ Symbol("pino.stringify");
5105
- var stringifySafeSym = /* @__PURE__ */ Symbol("pino.stringifySafe");
5106
- var stringifiersSym = /* @__PURE__ */ Symbol("pino.stringifiers");
5107
- var endSym = /* @__PURE__ */ Symbol("pino.end");
5108
- var formatOptsSym = /* @__PURE__ */ Symbol("pino.formatOpts");
5109
- var messageKeySym = /* @__PURE__ */ Symbol("pino.messageKey");
5110
- var errorKeySym = /* @__PURE__ */ Symbol("pino.errorKey");
5111
- var nestedKeySym = /* @__PURE__ */ Symbol("pino.nestedKey");
5112
- var nestedKeyStrSym = /* @__PURE__ */ Symbol("pino.nestedKeyStr");
5113
- var mixinMergeStrategySym = /* @__PURE__ */ Symbol("pino.mixinMergeStrategy");
5114
- var msgPrefixSym = /* @__PURE__ */ Symbol("pino.msgPrefix");
5115
- var wildcardFirstSym = /* @__PURE__ */ Symbol("pino.wildcardFirst");
5116
- var serializersSym = /* @__PURE__ */ Symbol.for("pino.serializers");
5117
- var formattersSym = /* @__PURE__ */ Symbol.for("pino.formatters");
5118
- var hooksSym = /* @__PURE__ */ Symbol.for("pino.hooks");
5119
- var needsMetadataGsym = /* @__PURE__ */ Symbol.for("pino.metadata");
5089
+ var setLevelSym = Symbol("pino.setLevel");
5090
+ var getLevelSym = Symbol("pino.getLevel");
5091
+ var levelValSym = Symbol("pino.levelVal");
5092
+ var levelCompSym = Symbol("pino.levelComp");
5093
+ var useLevelLabelsSym = Symbol("pino.useLevelLabels");
5094
+ var useOnlyCustomLevelsSym = Symbol("pino.useOnlyCustomLevels");
5095
+ var mixinSym = Symbol("pino.mixin");
5096
+ var lsCacheSym = Symbol("pino.lsCache");
5097
+ var chindingsSym = Symbol("pino.chindings");
5098
+ var asJsonSym = Symbol("pino.asJson");
5099
+ var writeSym = Symbol("pino.write");
5100
+ var redactFmtSym = Symbol("pino.redactFmt");
5101
+ var timeSym = Symbol("pino.time");
5102
+ var timeSliceIndexSym = Symbol("pino.timeSliceIndex");
5103
+ var streamSym = Symbol("pino.stream");
5104
+ var stringifySym = Symbol("pino.stringify");
5105
+ var stringifySafeSym = Symbol("pino.stringifySafe");
5106
+ var stringifiersSym = Symbol("pino.stringifiers");
5107
+ var endSym = Symbol("pino.end");
5108
+ var formatOptsSym = Symbol("pino.formatOpts");
5109
+ var messageKeySym = Symbol("pino.messageKey");
5110
+ var errorKeySym = Symbol("pino.errorKey");
5111
+ var nestedKeySym = Symbol("pino.nestedKey");
5112
+ var nestedKeyStrSym = Symbol("pino.nestedKeyStr");
5113
+ var mixinMergeStrategySym = Symbol("pino.mixinMergeStrategy");
5114
+ var msgPrefixSym = Symbol("pino.msgPrefix");
5115
+ var wildcardFirstSym = Symbol("pino.wildcardFirst");
5116
+ var serializersSym = Symbol.for("pino.serializers");
5117
+ var formattersSym = Symbol.for("pino.formatters");
5118
+ var hooksSym = Symbol.for("pino.hooks");
5119
+ var needsMetadataGsym = Symbol.for("pino.metadata");
5120
5120
  module.exports = {
5121
5121
  setLevelSym,
5122
5122
  getLevelSym,
@@ -6241,7 +6241,7 @@ var require_thread_stream = __commonJS({
6241
6241
  } = require_indexes();
6242
6242
  var buffer = __require("buffer");
6243
6243
  var assert2 = __require("assert");
6244
- var kImpl = /* @__PURE__ */ Symbol("kImpl");
6244
+ var kImpl = Symbol("kImpl");
6245
6245
  var MAX_STRING = buffer.constants.MAX_STRING_LENGTH;
6246
6246
  var FakeWeakRef = class {
6247
6247
  constructor(value) {
@@ -8257,7 +8257,7 @@ ${originalIndentation}`;
8257
8257
  var require_multistream = __commonJS({
8258
8258
  "../../node_modules/.pnpm/pino@10.3.1/node_modules/pino/lib/multistream.js"(exports, module) {
8259
8259
  "use strict";
8260
- var metadata = /* @__PURE__ */ Symbol.for("pino.metadata");
8260
+ var metadata = Symbol.for("pino.metadata");
8261
8261
  var { DEFAULT_LEVELS } = require_constants();
8262
8262
  var DEFAULT_INFO_LEVEL = DEFAULT_LEVELS.info;
8263
8263
  function multistream(streamsArray, opts) {
@@ -8754,7 +8754,7 @@ var init_mjs = __esm({
8754
8754
  "../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js"() {
8755
8755
  init_signals();
8756
8756
  processOk = (process17) => !!process17 && typeof process17 === "object" && typeof process17.removeListener === "function" && typeof process17.emit === "function" && typeof process17.reallyExit === "function" && typeof process17.listeners === "function" && typeof process17.kill === "function" && typeof process17.pid === "number" && typeof process17.on === "function";
8757
- kExitEmitter = /* @__PURE__ */ Symbol.for("signal-exit emitter");
8757
+ kExitEmitter = Symbol.for("signal-exit emitter");
8758
8758
  global2 = globalThis;
8759
8759
  ObjectDefineProperty = Object.defineProperty.bind(Object);
8760
8760
  Emitter = class {
@@ -19921,7 +19921,7 @@ var require_utils = __commonJS({
19921
19921
  var require_lib2 = __commonJS({
19922
19922
  "../../node_modules/.pnpm/chardet@2.1.1/node_modules/chardet/lib/index.js"(exports) {
19923
19923
  "use strict";
19924
- var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
19924
+ var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
19925
19925
  if (k2 === void 0) k2 = k;
19926
19926
  var desc = Object.getOwnPropertyDescriptor(m, k);
19927
19927
  if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
@@ -19930,16 +19930,16 @@ var require_lib2 = __commonJS({
19930
19930
  } };
19931
19931
  }
19932
19932
  Object.defineProperty(o, k2, desc);
19933
- }) : (function(o, m, k, k2) {
19933
+ } : function(o, m, k, k2) {
19934
19934
  if (k2 === void 0) k2 = k;
19935
19935
  o[k2] = m[k];
19936
- }));
19937
- var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
19936
+ });
19937
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
19938
19938
  Object.defineProperty(o, "default", { enumerable: true, value: v });
19939
- }) : function(o, v) {
19939
+ } : function(o, v) {
19940
19940
  o["default"] = v;
19941
19941
  });
19942
- var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
19942
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
19943
19943
  var ownKeys = function(o) {
19944
19944
  ownKeys = Object.getOwnPropertyNames || function(o2) {
19945
19945
  var ar = [];
@@ -19957,7 +19957,7 @@ var require_lib2 = __commonJS({
19957
19957
  __setModuleDefault(result, mod);
19958
19958
  return result;
19959
19959
  };
19960
- })();
19960
+ }();
19961
19961
  var __importDefault = exports && exports.__importDefault || function(mod) {
19962
19962
  return mod && mod.__esModule ? mod : { "default": mod };
19963
19963
  };
@@ -25905,6 +25905,17 @@ var PlanStatus;
25905
25905
  PlanStatus2["EXPIRED"] = "EXPIRED";
25906
25906
  PlanStatus2["CANCELLED"] = "CANCELLED";
25907
25907
  })(PlanStatus || (PlanStatus = {}));
25908
+ var Chamber;
25909
+ (function(Chamber2) {
25910
+ Chamber2["HOUSE"] = "HOUSE";
25911
+ Chamber2["SENATE"] = "SENATE";
25912
+ })(Chamber || (Chamber = {}));
25913
+ var PoliticianTransactionType;
25914
+ (function(PoliticianTransactionType2) {
25915
+ PoliticianTransactionType2["BUY"] = "BUY";
25916
+ PoliticianTransactionType2["SELL"] = "SELL";
25917
+ PoliticianTransactionType2["EXERCISE"] = "EXERCISE";
25918
+ })(PoliticianTransactionType || (PoliticianTransactionType = {}));
25908
25919
  var NotificationChannel;
25909
25920
  (function(NotificationChannel2) {
25910
25921
  NotificationChannel2["TELEGRAM"] = "TELEGRAM";
@@ -26530,7 +26541,7 @@ function $constructor(name, initializer3, params) {
26530
26541
  Object.defineProperty(_, "name", { value: name });
26531
26542
  return _;
26532
26543
  }
26533
- var $brand = /* @__PURE__ */ Symbol("zod_brand");
26544
+ var $brand = Symbol("zod_brand");
26534
26545
  var $ZodAsyncError = class extends Error {
26535
26546
  constructor() {
26536
26547
  super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
@@ -26677,7 +26688,7 @@ function floatSafeRemainder(val, step) {
26677
26688
  const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", ""));
26678
26689
  return valInt % stepInt / 10 ** decCount;
26679
26690
  }
26680
- var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
26691
+ var EVALUATING = Symbol("evaluating");
26681
26692
  function defineLazy(object2, key, getter) {
26682
26693
  let value = void 0;
26683
26694
  Object.defineProperty(object2, key, {
@@ -35750,8 +35761,8 @@ function yo_default() {
35750
35761
 
35751
35762
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/registries.js
35752
35763
  var _a;
35753
- var $output = /* @__PURE__ */ Symbol("ZodOutput");
35754
- var $input = /* @__PURE__ */ Symbol("ZodInput");
35764
+ var $output = Symbol("ZodOutput");
35765
+ var $input = Symbol("ZodInput");
35755
35766
  var $ZodRegistry = class {
35756
35767
  constructor() {
35757
35768
  this._map = /* @__PURE__ */ new WeakMap();
@@ -36788,7 +36799,7 @@ function _stringbool(Classes, _params) {
36788
36799
  type: "pipe",
36789
36800
  in: stringSchema,
36790
36801
  out: booleanSchema,
36791
- transform: ((input, payload) => {
36802
+ transform: (input, payload) => {
36792
36803
  let data = input;
36793
36804
  if (params.case !== "sensitive")
36794
36805
  data = data.toLowerCase();
@@ -36807,14 +36818,14 @@ function _stringbool(Classes, _params) {
36807
36818
  });
36808
36819
  return {};
36809
36820
  }
36810
- }),
36811
- reverseTransform: ((input, _payload) => {
36821
+ },
36822
+ reverseTransform: (input, _payload) => {
36812
36823
  if (input === true) {
36813
36824
  return truthyArray[0] || "true";
36814
36825
  } else {
36815
36826
  return falsyArray[0] || "false";
36816
36827
  }
36817
- }),
36828
+ },
36818
36829
  error: params.error
36819
36830
  });
36820
36831
  return codec2;
@@ -38142,10 +38153,10 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
38142
38153
  inst.with = inst.check;
38143
38154
  inst.clone = (def2, params) => clone(inst, def2, params);
38144
38155
  inst.brand = () => inst;
38145
- inst.register = ((reg, meta3) => {
38156
+ inst.register = (reg, meta3) => {
38146
38157
  reg.add(inst, meta3);
38147
38158
  return inst;
38148
- });
38159
+ };
38149
38160
  inst.parse = (data, params) => parse2(inst, data, params, { callee: inst.parse });
38150
38161
  inst.safeParse = (data, params) => safeParse2(inst, data, params);
38151
38162
  inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
@@ -39771,6 +39782,9 @@ var envSchema = external_exports.object({
39771
39782
  LLM_ENCRYPTION_KEY: external_exports.string().default(""),
39772
39783
  // Learning system
39773
39784
  BELIEF_HMAC_KEY: external_exports.string().default(""),
39785
+ BELIEF_DISCOUNT_FACTOR: external_exports.coerce.number().min(0).max(1).default(0.995),
39786
+ // Cold-start maturity threshold (number of trades before a trader is "established")
39787
+ COLD_START_MATURITY_THRESHOLD: external_exports.coerce.number().int().nonnegative().default(50),
39774
39788
  // Feature flags
39775
39789
  ENABLE_LLM: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
39776
39790
  ENABLE_LEARNING: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
@@ -47031,8 +47045,9 @@ async function loadCredentials() {
47031
47045
  };
47032
47046
  }
47033
47047
  async function clearCredentials() {
47034
- await deleteFromKeychain();
47048
+ const keychainCleared = await deleteFromKeychain();
47035
47049
  deleteCredentialsFile();
47050
+ return { keychainCleared };
47036
47051
  }
47037
47052
  function redactApiKey(key) {
47038
47053
  if (key.length <= 12)
@@ -48205,6 +48220,9 @@ function registerTraderCommand(program2) {
48205
48220
  } else {
48206
48221
  console.log(formatTraderOutput(result));
48207
48222
  console.log(source_default.green(" Trader registered successfully."));
48223
+ if (result.alias) {
48224
+ console.log(` ${source_default.gray("Leaderboard alias:")} ${source_default.white(result.alias)} ${source_default.dim("(change with: trading-boy trader set-alias <name> <alias>)")}`);
48225
+ }
48208
48226
  console.log("");
48209
48227
  console.log(source_default.bold(" Next: Set up your trading identity"));
48210
48228
  console.log(source_default.dim(" SOUL and PURPOSE documents personalize your context \u2014 bias warnings,"));
@@ -48289,6 +48307,57 @@ function registerTraderCommand(program2) {
48289
48307
  process.exitCode = error49 instanceof ApiError ? 2 : 1;
48290
48308
  }
48291
48309
  });
48310
+ const ALIAS_PATTERN = /^[a-zA-Z0-9_-]{3,30}$/;
48311
+ 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) => {
48312
+ const jsonMode = options.format === "json";
48313
+ if (!ALIAS_PATTERN.test(alias)) {
48314
+ const msg = "Invalid alias. Must be 3-30 characters, alphanumeric with underscores and hyphens.";
48315
+ if (jsonMode) {
48316
+ console.error(JSON.stringify({ error: msg }));
48317
+ } else {
48318
+ console.error(source_default.red(` ${msg}`));
48319
+ }
48320
+ process.exitCode = 1;
48321
+ return;
48322
+ }
48323
+ try {
48324
+ await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/alias`, { method: "PUT", body: { alias } });
48325
+ if (jsonMode) {
48326
+ console.log(JSON.stringify({ alias, updated: true }));
48327
+ } else {
48328
+ console.log("");
48329
+ console.log(source_default.green(` Alias updated to: ${source_default.white(alias)}`));
48330
+ console.log("");
48331
+ }
48332
+ } catch (error49) {
48333
+ if (error49 instanceof ApiError && error49.status === 409) {
48334
+ const msg = "Alias already taken. Try a different name.";
48335
+ if (jsonMode) {
48336
+ console.error(JSON.stringify({ error: msg }));
48337
+ } else {
48338
+ console.error(source_default.yellow(` ${msg}`));
48339
+ }
48340
+ process.exitCode = 2;
48341
+ } else if (error49 instanceof ApiError && error49.status === 404) {
48342
+ const msg = `Trader not found: "${nameOrId}"`;
48343
+ if (jsonMode) {
48344
+ console.error(JSON.stringify({ error: msg }));
48345
+ } else {
48346
+ console.error(source_default.yellow(msg));
48347
+ }
48348
+ process.exitCode = 2;
48349
+ } else {
48350
+ const message = error49 instanceof Error ? error49.message : String(error49);
48351
+ logger12.error({ error: message }, "Failed to set alias");
48352
+ if (jsonMode) {
48353
+ console.error(JSON.stringify({ error: message }));
48354
+ } else {
48355
+ console.error(source_default.red(`Error: ${message}`));
48356
+ }
48357
+ process.exitCode = error49 instanceof ApiError ? 2 : 1;
48358
+ }
48359
+ }
48360
+ });
48292
48361
  trader.command("preferences").description("Update notification preferences").option("--summary-time <hour>", "Hour (0-23 UTC) to receive daily email summary", parseInt).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
48293
48362
  if (options.summaryTime === void 0) {
48294
48363
  console.error(source_default.yellow("No updates provided. Use --summary-time <hour>."));
@@ -50222,17 +50291,44 @@ async function executeLogout() {
50222
50291
  const existing = await loadCredentials();
50223
50292
  const wasAuthenticated = existing !== null;
50224
50293
  const redactedKey = existing ? redactApiKey(existing.apiKey) : void 0;
50225
- await clearCredentials();
50226
- return { wasAuthenticated, redactedKey };
50294
+ const { keychainCleared } = await clearCredentials();
50295
+ return { wasAuthenticated, redactedKey, keychainCleared };
50227
50296
  }
50228
50297
  function registerLogoutCommand(program2) {
50229
- program2.command("logout").description("Clear stored API key and credentials").action(async () => {
50298
+ program2.command("logout").description("Clear stored API key and credentials").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).addOption(new Option("--force", "Skip confirmation prompt")).addOption(new Option("--reveal-key", "Include full API key in JSON output (requires --force --format json)")).action(async (options) => {
50230
50299
  try {
50300
+ const jsonMode = options.format === "json";
50231
50301
  const existing = await loadCredentials();
50232
50302
  if (!existing) {
50233
- console.log("");
50234
- console.log(source_default.dim(" No credentials found \u2014 already logged out."));
50235
- console.log("");
50303
+ if (jsonMode) {
50304
+ console.log(JSON.stringify({ loggedOut: false, reason: "no credentials" }));
50305
+ } else {
50306
+ console.log("");
50307
+ console.log(source_default.dim(" No credentials found \u2014 already logged out."));
50308
+ console.log("");
50309
+ }
50310
+ return;
50311
+ }
50312
+ if (jsonMode && !options.force) {
50313
+ console.error(JSON.stringify({ error: "--force is required with --format json" }));
50314
+ process.exitCode = 1;
50315
+ return;
50316
+ }
50317
+ if (jsonMode) {
50318
+ const fullKey = existing.apiKey;
50319
+ const storageMethod2 = existing.storageMethod;
50320
+ const result2 = await executeLogout();
50321
+ const output = {
50322
+ loggedOut: true,
50323
+ redactedKey: result2.redactedKey
50324
+ };
50325
+ if (options.revealKey) {
50326
+ output.apiKey = fullKey;
50327
+ }
50328
+ if (!result2.keychainCleared && storageMethod2 === "keychain") {
50329
+ output.keychainWarning = "Could not remove key from OS keychain. You may need to manually remove the 'trading-boy' entry from your keychain.";
50330
+ }
50331
+ console.log(JSON.stringify(output));
50236
50332
  return;
50237
50333
  }
50238
50334
  console.log("");
@@ -50240,20 +50336,39 @@ function registerLogoutCommand(program2) {
50240
50336
  console.log(source_default.yellow(" You will need your API key to log back in."));
50241
50337
  console.log(source_default.yellow(" There is no way to recover a lost key \u2014 a new one must be provisioned."));
50242
50338
  console.log("");
50243
- const proceed = await esm_default4({ message: "Are you sure you want to logout?" });
50339
+ const proceed = options.force || await esm_default4({ message: "Are you sure you want to logout?" });
50244
50340
  if (!proceed) {
50245
50341
  console.log(source_default.dim(" Logout cancelled."));
50246
50342
  return;
50247
50343
  }
50344
+ const revealKey = await esm_default4({
50345
+ message: "Would you like to see your full API key before it's deleted? (This is your last chance to copy it)"
50346
+ });
50347
+ if (revealKey) {
50348
+ console.log("");
50349
+ console.log(source_default.cyan(" Your API key:"));
50350
+ console.log(` ${source_default.bold(existing.apiKey)}`);
50351
+ console.log("");
50352
+ }
50353
+ const storageMethod = existing.storageMethod;
50248
50354
  const result = await executeLogout();
50249
50355
  console.log("");
50250
50356
  console.log(source_default.green(` Logged out successfully.`));
50251
50357
  console.log(` ${source_default.gray("Cleared key:")} ${result.redactedKey}`);
50358
+ if (!result.keychainCleared && storageMethod === "keychain") {
50359
+ console.log("");
50360
+ console.log(source_default.yellow(" Warning: Could not remove key from OS keychain."));
50361
+ console.log(source_default.yellow(" You may need to manually remove the 'trading-boy' entry from your keychain."));
50362
+ }
50252
50363
  console.log("");
50253
50364
  } catch (error49) {
50254
50365
  const message = error49 instanceof Error ? error49.message : String(error49);
50255
50366
  logger20.error({ error: message }, "Logout failed");
50256
- console.error(source_default.red(` Error: ${message}`));
50367
+ if (options.format === "json") {
50368
+ console.error(JSON.stringify({ error: message }));
50369
+ } else {
50370
+ console.error(source_default.red(` Error: ${message}`));
50371
+ }
50257
50372
  process.exitCode = 1;
50258
50373
  }
50259
50374
  });
@@ -2,6 +2,7 @@ import { Command } from 'commander';
2
2
  export declare function executeLogout(): Promise<{
3
3
  wasAuthenticated: boolean;
4
4
  redactedKey?: string;
5
+ keychainCleared: boolean;
5
6
  }>;
6
7
  export declare function registerLogoutCommand(program: Command): void;
7
8
  //# sourceMappingURL=logout.d.ts.map
@@ -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 { clearCredentials, loadCredentials, redactApiKey } from '../credentials.js';
@@ -8,43 +9,98 @@ export async function executeLogout() {
8
9
  const existing = await loadCredentials();
9
10
  const wasAuthenticated = existing !== null;
10
11
  const redactedKey = existing ? redactApiKey(existing.apiKey) : undefined;
11
- await clearCredentials();
12
- return { wasAuthenticated, redactedKey };
12
+ const { keychainCleared } = await clearCredentials();
13
+ return { wasAuthenticated, redactedKey, keychainCleared };
13
14
  }
14
15
  // ─── Command Registration ───
15
16
  export function registerLogoutCommand(program) {
16
17
  program
17
18
  .command('logout')
18
19
  .description('Clear stored API key and credentials')
19
- .action(async () => {
20
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
21
+ .addOption(new Option('--force', 'Skip confirmation prompt'))
22
+ .addOption(new Option('--reveal-key', 'Include full API key in JSON output (requires --force --format json)'))
23
+ .action(async (options) => {
20
24
  try {
25
+ const jsonMode = options.format === 'json';
21
26
  const existing = await loadCredentials();
22
27
  if (!existing) {
23
- console.log('');
24
- console.log(chalk.dim(' No credentials found already logged out.'));
25
- console.log('');
28
+ if (jsonMode) {
29
+ console.log(JSON.stringify({ loggedOut: false, reason: 'no credentials' }));
30
+ }
31
+ else {
32
+ console.log('');
33
+ console.log(chalk.dim(' No credentials found — already logged out.'));
34
+ console.log('');
35
+ }
36
+ return;
37
+ }
38
+ // JSON mode requires --force to skip interactive prompts
39
+ if (jsonMode && !options.force) {
40
+ console.error(JSON.stringify({ error: '--force is required with --format json' }));
41
+ process.exitCode = 1;
26
42
  return;
27
43
  }
44
+ if (jsonMode) {
45
+ // Non-interactive JSON path
46
+ const fullKey = existing.apiKey;
47
+ const storageMethod = existing.storageMethod;
48
+ const result = await executeLogout();
49
+ const output = {
50
+ loggedOut: true,
51
+ redactedKey: result.redactedKey,
52
+ };
53
+ if (options.revealKey) {
54
+ output.apiKey = fullKey;
55
+ }
56
+ if (!result.keychainCleared && storageMethod === 'keychain') {
57
+ output.keychainWarning = 'Could not remove key from OS keychain. You may need to manually remove the \'trading-boy\' entry from your keychain.';
58
+ }
59
+ console.log(JSON.stringify(output));
60
+ return;
61
+ }
62
+ // Interactive text path
28
63
  console.log('');
29
64
  console.log(chalk.yellow(' Warning: Your API key will be cleared from this machine.'));
30
65
  console.log(chalk.yellow(' You will need your API key to log back in.'));
31
66
  console.log(chalk.yellow(' There is no way to recover a lost key — a new one must be provisioned.'));
32
67
  console.log('');
33
- const proceed = await confirm({ message: 'Are you sure you want to logout?' });
68
+ const proceed = options.force || await confirm({ message: 'Are you sure you want to logout?' });
34
69
  if (!proceed) {
35
70
  console.log(chalk.dim(' Logout cancelled.'));
36
71
  return;
37
72
  }
73
+ // Offer to reveal the full key before deletion
74
+ const revealKey = await confirm({
75
+ message: 'Would you like to see your full API key before it\'s deleted? (This is your last chance to copy it)',
76
+ });
77
+ if (revealKey) {
78
+ console.log('');
79
+ console.log(chalk.cyan(' Your API key:'));
80
+ console.log(` ${chalk.bold(existing.apiKey)}`);
81
+ console.log('');
82
+ }
83
+ const storageMethod = existing.storageMethod;
38
84
  const result = await executeLogout();
39
85
  console.log('');
40
86
  console.log(chalk.green(` Logged out successfully.`));
41
87
  console.log(` ${chalk.gray('Cleared key:')} ${result.redactedKey}`);
88
+ if (!result.keychainCleared && storageMethod === 'keychain') {
89
+ console.log('');
90
+ console.log(chalk.yellow(' Warning: Could not remove key from OS keychain.'));
91
+ console.log(chalk.yellow(' You may need to manually remove the \'trading-boy\' entry from your keychain.'));
92
+ }
42
93
  console.log('');
43
94
  }
44
95
  catch (error) {
45
96
  const message = error instanceof Error ? error.message : String(error);
46
97
  logger.error({ error: message }, 'Logout failed');
47
- console.error(chalk.red(` Error: ${message}`));
98
+ if (options.format === 'json') {
99
+ console.error(JSON.stringify({ error: message }));
100
+ }
101
+ else {
102
+ console.error(chalk.red(` Error: ${message}`));
103
+ }
48
104
  process.exitCode = 1;
49
105
  }
50
106
  });
@@ -2,6 +2,7 @@ import { Command } from 'commander';
2
2
  interface TraderRecord {
3
3
  id: string;
4
4
  name: string;
5
+ alias?: string;
5
6
  maxDrawdownPct?: number;
6
7
  riskToleranceMax?: number;
7
8
  walletAddresses?: string[];
@@ -111,6 +111,9 @@ export function registerTraderCommand(program) {
111
111
  else {
112
112
  console.log(formatTraderOutput(result));
113
113
  console.log(chalk.green(' Trader registered successfully.'));
114
+ if (result.alias) {
115
+ console.log(` ${chalk.gray('Leaderboard alias:')} ${chalk.white(result.alias)} ${chalk.dim('(change with: trading-boy trader set-alias <name> <alias>)')}`);
116
+ }
114
117
  console.log('');
115
118
  console.log(chalk.bold(' Next: Set up your trading identity'));
116
119
  console.log(chalk.dim(' SOUL and PURPOSE documents personalize your context — bias warnings,'));
@@ -223,6 +226,72 @@ export function registerTraderCommand(program) {
223
226
  process.exitCode = error instanceof ApiError ? 2 : 1;
224
227
  }
225
228
  });
229
+ // ─── set-alias ───
230
+ const ALIAS_PATTERN = /^[a-zA-Z0-9_-]{3,30}$/;
231
+ trader
232
+ .command('set-alias')
233
+ .description('Set a public leaderboard alias')
234
+ .argument('<name-or-id>', 'Trader name or ID')
235
+ .argument('<alias>', 'Leaderboard alias (3-30 chars, alphanumeric/underscores/hyphens)')
236
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
237
+ .action(async (nameOrId, alias, options) => {
238
+ const jsonMode = options.format === 'json';
239
+ if (!ALIAS_PATTERN.test(alias)) {
240
+ const msg = 'Invalid alias. Must be 3-30 characters, alphanumeric with underscores and hyphens.';
241
+ if (jsonMode) {
242
+ console.error(JSON.stringify({ error: msg }));
243
+ }
244
+ else {
245
+ console.error(chalk.red(` ${msg}`));
246
+ }
247
+ process.exitCode = 1;
248
+ return;
249
+ }
250
+ try {
251
+ await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/alias`, { method: 'PUT', body: { alias } });
252
+ if (jsonMode) {
253
+ console.log(JSON.stringify({ alias, updated: true }));
254
+ }
255
+ else {
256
+ console.log('');
257
+ console.log(chalk.green(` Alias updated to: ${chalk.white(alias)}`));
258
+ console.log('');
259
+ }
260
+ }
261
+ catch (error) {
262
+ if (error instanceof ApiError && error.status === 409) {
263
+ const msg = 'Alias already taken. Try a different name.';
264
+ if (jsonMode) {
265
+ console.error(JSON.stringify({ error: msg }));
266
+ }
267
+ else {
268
+ console.error(chalk.yellow(` ${msg}`));
269
+ }
270
+ process.exitCode = 2;
271
+ }
272
+ else if (error instanceof ApiError && error.status === 404) {
273
+ const msg = `Trader not found: "${nameOrId}"`;
274
+ if (jsonMode) {
275
+ console.error(JSON.stringify({ error: msg }));
276
+ }
277
+ else {
278
+ console.error(chalk.yellow(msg));
279
+ }
280
+ process.exitCode = 2;
281
+ }
282
+ else {
283
+ const message = error instanceof Error ? error.message : String(error);
284
+ logger.error({ error: message }, 'Failed to set alias');
285
+ if (jsonMode) {
286
+ console.error(JSON.stringify({ error: message }));
287
+ }
288
+ else {
289
+ console.error(chalk.red(`Error: ${message}`));
290
+ }
291
+ process.exitCode = error instanceof ApiError ? 2 : 1;
292
+ }
293
+ }
294
+ });
226
295
  // ─── preferences ───
227
296
  trader
228
297
  .command('preferences')
@@ -12,7 +12,9 @@ export declare function storeCredentials(apiKey: string, metadata?: {
12
12
  plan?: string;
13
13
  }): Promise<void>;
14
14
  export declare function loadCredentials(): Promise<StoredCredentials | null>;
15
- export declare function clearCredentials(): Promise<void>;
15
+ export declare function clearCredentials(): Promise<{
16
+ keychainCleared: boolean;
17
+ }>;
16
18
  export declare function redactApiKey(key: string): string;
17
19
  export declare function getCredentialsFilePath(): string;
18
20
  //# sourceMappingURL=credentials.d.ts.map
@@ -151,8 +151,9 @@ export async function loadCredentials() {
151
151
  };
152
152
  }
153
153
  export async function clearCredentials() {
154
- await deleteFromKeychain();
154
+ const keychainCleared = await deleteFromKeychain();
155
155
  deleteCredentialsFile();
156
+ return { keychainCleared };
156
157
  }
157
158
  export function redactApiKey(key) {
158
159
  if (key.length <= 12)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trading-boy/cli",
3
- "version": "1.2.16",
3
+ "version": "1.2.17",
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": {