@trading-boy/cli 1.2.15 → 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.
- package/dist/cli.bundle.js +229 -150
- package/dist/commands/config-cmd.js +50 -30
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +64 -8
- package/dist/commands/trader.d.ts +1 -0
- package/dist/commands/trader.js +69 -0
- package/dist/credentials.d.ts +3 -1
- package/dist/credentials.js +2 -1
- package/package.json +1 -1
package/dist/cli.bundle.js
CHANGED
|
@@ -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 =
|
|
3715
|
-
STYLER =
|
|
3716
|
-
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 =
|
|
4314
|
-
var rawSymbol =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5090
|
-
var getLevelSym =
|
|
5091
|
-
var levelValSym =
|
|
5092
|
-
var levelCompSym =
|
|
5093
|
-
var useLevelLabelsSym =
|
|
5094
|
-
var useOnlyCustomLevelsSym =
|
|
5095
|
-
var mixinSym =
|
|
5096
|
-
var lsCacheSym =
|
|
5097
|
-
var chindingsSym =
|
|
5098
|
-
var asJsonSym =
|
|
5099
|
-
var writeSym =
|
|
5100
|
-
var redactFmtSym =
|
|
5101
|
-
var timeSym =
|
|
5102
|
-
var timeSliceIndexSym =
|
|
5103
|
-
var streamSym =
|
|
5104
|
-
var stringifySym =
|
|
5105
|
-
var stringifySafeSym =
|
|
5106
|
-
var stringifiersSym =
|
|
5107
|
-
var endSym =
|
|
5108
|
-
var formatOptsSym =
|
|
5109
|
-
var messageKeySym =
|
|
5110
|
-
var errorKeySym =
|
|
5111
|
-
var nestedKeySym =
|
|
5112
|
-
var nestedKeyStrSym =
|
|
5113
|
-
var mixinMergeStrategySym =
|
|
5114
|
-
var msgPrefixSym =
|
|
5115
|
-
var wildcardFirstSym =
|
|
5116
|
-
var serializersSym =
|
|
5117
|
-
var formattersSym =
|
|
5118
|
-
var hooksSym =
|
|
5119
|
-
var needsMetadataGsym =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 ?
|
|
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
|
-
}
|
|
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 ?
|
|
19936
|
+
});
|
|
19937
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
|
|
19938
19938
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19939
|
-
}
|
|
19939
|
+
} : function(o, v) {
|
|
19940
19940
|
o["default"] = v;
|
|
19941
19941
|
});
|
|
19942
|
-
var __importStar = exports && exports.__importStar || /* @__PURE__ */
|
|
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 =
|
|
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 =
|
|
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 =
|
|
35754
|
-
var $input =
|
|
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: (
|
|
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: (
|
|
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 = (
|
|
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 });
|
|
@@ -39723,21 +39734,6 @@ function date4(params) {
|
|
|
39723
39734
|
// ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
39724
39735
|
config(en_default());
|
|
39725
39736
|
|
|
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
39737
|
// ../core/dist/config/env.js
|
|
39742
39738
|
import_dotenv.default.config({ quiet: true });
|
|
39743
39739
|
var PRODUCTION_REQUIRED_PASSWORDS = [
|
|
@@ -39786,6 +39782,9 @@ var envSchema = external_exports.object({
|
|
|
39786
39782
|
LLM_ENCRYPTION_KEY: external_exports.string().default(""),
|
|
39787
39783
|
// Learning system
|
|
39788
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),
|
|
39789
39788
|
// Feature flags
|
|
39790
39789
|
ENABLE_LLM: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
|
|
39791
39790
|
ENABLE_LEARNING: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
|
|
@@ -39853,19 +39852,6 @@ var envSchema = external_exports.object({
|
|
|
39853
39852
|
}
|
|
39854
39853
|
}
|
|
39855
39854
|
});
|
|
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
39855
|
|
|
39870
39856
|
// ../core/dist/logging/logger.js
|
|
39871
39857
|
var import_pino = __toESM(require_pino(), 1);
|
|
@@ -47059,8 +47045,9 @@ async function loadCredentials() {
|
|
|
47059
47045
|
};
|
|
47060
47046
|
}
|
|
47061
47047
|
async function clearCredentials() {
|
|
47062
|
-
await deleteFromKeychain();
|
|
47048
|
+
const keychainCleared = await deleteFromKeychain();
|
|
47063
47049
|
deleteCredentialsFile();
|
|
47050
|
+
return { keychainCleared };
|
|
47064
47051
|
}
|
|
47065
47052
|
function redactApiKey(key) {
|
|
47066
47053
|
if (key.length <= 12)
|
|
@@ -48233,6 +48220,9 @@ function registerTraderCommand(program2) {
|
|
|
48233
48220
|
} else {
|
|
48234
48221
|
console.log(formatTraderOutput(result));
|
|
48235
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
|
+
}
|
|
48236
48226
|
console.log("");
|
|
48237
48227
|
console.log(source_default.bold(" Next: Set up your trading identity"));
|
|
48238
48228
|
console.log(source_default.dim(" SOUL and PURPOSE documents personalize your context \u2014 bias warnings,"));
|
|
@@ -48317,6 +48307,57 @@ function registerTraderCommand(program2) {
|
|
|
48317
48307
|
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
48318
48308
|
}
|
|
48319
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
|
+
});
|
|
48320
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) => {
|
|
48321
48362
|
if (options.summaryTime === void 0) {
|
|
48322
48363
|
console.error(source_default.yellow("No updates provided. Use --summary-time <hour>."));
|
|
@@ -49808,37 +49849,6 @@ function redactValue(key, value) {
|
|
|
49808
49849
|
}
|
|
49809
49850
|
return strValue.slice(0, 3) + "****";
|
|
49810
49851
|
}
|
|
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
49852
|
function resolveEnvPath() {
|
|
49843
49853
|
return resolve(process.cwd(), ".env");
|
|
49844
49854
|
}
|
|
@@ -49897,31 +49907,32 @@ function writeEnvValue(filePath, key, value) {
|
|
|
49897
49907
|
}
|
|
49898
49908
|
function registerConfigCommand(program2) {
|
|
49899
49909
|
const configCmd = program2.command("config").description("Configuration management commands");
|
|
49900
|
-
configCmd.command("show").description("Display current configuration
|
|
49901
|
-
|
|
49902
|
-
|
|
49903
|
-
|
|
49904
|
-
|
|
49905
|
-
|
|
49906
|
-
|
|
49907
|
-
|
|
49908
|
-
|
|
49909
|
-
|
|
49910
|
-
|
|
49911
|
-
|
|
49912
|
-
|
|
49913
|
-
|
|
49914
|
-
|
|
49915
|
-
|
|
49916
|
-
|
|
49917
|
-
|
|
49918
|
-
|
|
49919
|
-
|
|
49920
|
-
|
|
49910
|
+
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) => {
|
|
49911
|
+
const USER_CONFIG = [
|
|
49912
|
+
{ section: "Connection", keys: [
|
|
49913
|
+
{ key: "TRADING_BOY_API_URL", label: "API URL" }
|
|
49914
|
+
] },
|
|
49915
|
+
{ section: "LLM (Coaching)", keys: [
|
|
49916
|
+
{ key: "LLM_PROVIDER", label: "Provider" },
|
|
49917
|
+
{ key: "LLM_MODEL", label: "Model" },
|
|
49918
|
+
{ key: "LLM_API_KEY", label: "API Key" },
|
|
49919
|
+
{ key: "LLM_BASE_URL", label: "Base URL" }
|
|
49920
|
+
] },
|
|
49921
|
+
{ section: "Notifications", keys: [
|
|
49922
|
+
{ key: "TELEGRAM_BOT_TOKEN", label: "Telegram Bot" },
|
|
49923
|
+
{ key: "TELEGRAM_ALLOWED_CHAT_IDS", label: "Telegram Chat IDs" }
|
|
49924
|
+
] }
|
|
49925
|
+
];
|
|
49926
|
+
const getEnv = (key) => {
|
|
49927
|
+
const value = process.env[key];
|
|
49928
|
+
if (!value)
|
|
49929
|
+
return source_default.dim("not set");
|
|
49930
|
+
return SENSITIVE_KEYS.has(key) ? redactValue(key, value) : value;
|
|
49931
|
+
};
|
|
49932
|
+
if (options.all) {
|
|
49921
49933
|
const redacted = {};
|
|
49922
49934
|
for (const key of VALID_KEYS) {
|
|
49923
|
-
|
|
49924
|
-
redacted[key] = value !== void 0 ? redactValue(key, value) : source_default.dim("(not set)");
|
|
49935
|
+
redacted[key] = getEnv(key);
|
|
49925
49936
|
}
|
|
49926
49937
|
if (options.format === "json") {
|
|
49927
49938
|
console.log(JSON.stringify(redacted, null, 2));
|
|
@@ -49930,7 +49941,29 @@ function registerConfigCommand(program2) {
|
|
|
49930
49941
|
console.log(` ${source_default.cyan(key.padEnd(30))} ${value}`);
|
|
49931
49942
|
}
|
|
49932
49943
|
}
|
|
49944
|
+
return;
|
|
49945
|
+
}
|
|
49946
|
+
if (options.format === "json") {
|
|
49947
|
+
const result = {};
|
|
49948
|
+
for (const section of USER_CONFIG) {
|
|
49949
|
+
for (const { key } of section.keys) {
|
|
49950
|
+
result[key] = process.env[key] ?? "";
|
|
49951
|
+
}
|
|
49952
|
+
}
|
|
49953
|
+
console.log(JSON.stringify(result, null, 2));
|
|
49954
|
+
return;
|
|
49955
|
+
}
|
|
49956
|
+
console.log("");
|
|
49957
|
+
for (const section of USER_CONFIG) {
|
|
49958
|
+
console.log(source_default.bold(` ${section.section}`));
|
|
49959
|
+
console.log(source_default.gray(" " + "\u2500".repeat(40)));
|
|
49960
|
+
for (const { key, label } of section.keys) {
|
|
49961
|
+
console.log(` ${source_default.cyan(label.padEnd(22))} ${getEnv(key)}`);
|
|
49962
|
+
}
|
|
49963
|
+
console.log("");
|
|
49933
49964
|
}
|
|
49965
|
+
console.log(source_default.dim(" Use --all to show all config variables."));
|
|
49966
|
+
console.log("");
|
|
49934
49967
|
});
|
|
49935
49968
|
configCmd.command("set <key> <value>").description("Set a config value in the .env file").action((key, value) => {
|
|
49936
49969
|
try {
|
|
@@ -50258,17 +50291,44 @@ async function executeLogout() {
|
|
|
50258
50291
|
const existing = await loadCredentials();
|
|
50259
50292
|
const wasAuthenticated = existing !== null;
|
|
50260
50293
|
const redactedKey = existing ? redactApiKey(existing.apiKey) : void 0;
|
|
50261
|
-
await clearCredentials();
|
|
50262
|
-
return { wasAuthenticated, redactedKey };
|
|
50294
|
+
const { keychainCleared } = await clearCredentials();
|
|
50295
|
+
return { wasAuthenticated, redactedKey, keychainCleared };
|
|
50263
50296
|
}
|
|
50264
50297
|
function registerLogoutCommand(program2) {
|
|
50265
|
-
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) => {
|
|
50266
50299
|
try {
|
|
50300
|
+
const jsonMode = options.format === "json";
|
|
50267
50301
|
const existing = await loadCredentials();
|
|
50268
50302
|
if (!existing) {
|
|
50269
|
-
|
|
50270
|
-
|
|
50271
|
-
|
|
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));
|
|
50272
50332
|
return;
|
|
50273
50333
|
}
|
|
50274
50334
|
console.log("");
|
|
@@ -50276,20 +50336,39 @@ function registerLogoutCommand(program2) {
|
|
|
50276
50336
|
console.log(source_default.yellow(" You will need your API key to log back in."));
|
|
50277
50337
|
console.log(source_default.yellow(" There is no way to recover a lost key \u2014 a new one must be provisioned."));
|
|
50278
50338
|
console.log("");
|
|
50279
|
-
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?" });
|
|
50280
50340
|
if (!proceed) {
|
|
50281
50341
|
console.log(source_default.dim(" Logout cancelled."));
|
|
50282
50342
|
return;
|
|
50283
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;
|
|
50284
50354
|
const result = await executeLogout();
|
|
50285
50355
|
console.log("");
|
|
50286
50356
|
console.log(source_default.green(` Logged out successfully.`));
|
|
50287
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
|
+
}
|
|
50288
50363
|
console.log("");
|
|
50289
50364
|
} catch (error49) {
|
|
50290
50365
|
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
50291
50366
|
logger20.error({ error: message }, "Logout failed");
|
|
50292
|
-
|
|
50367
|
+
if (options.format === "json") {
|
|
50368
|
+
console.error(JSON.stringify({ error: message }));
|
|
50369
|
+
} else {
|
|
50370
|
+
console.error(source_default.red(` Error: ${message}`));
|
|
50371
|
+
}
|
|
50293
50372
|
process.exitCode = 1;
|
|
50294
50373
|
}
|
|
50295
50374
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Option } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import {
|
|
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
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
|
|
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
|
|
@@ -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
|
package/dist/commands/logout.js
CHANGED
|
@@ -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
|
-
.
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
});
|
package/dist/commands/trader.js
CHANGED
|
@@ -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')
|
package/dist/credentials.d.ts
CHANGED
|
@@ -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<
|
|
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
|
package/dist/credentials.js
CHANGED
|
@@ -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.
|
|
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": {
|