@trading-boy/cli 1.2.17 → 1.2.19
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 +296 -71
- package/dist/commands/onboarding.js +6 -1
- package/dist/commands/trader.js +283 -0
- 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 = Symbol("GENERATOR");
|
|
3715
|
-
STYLER = Symbol("STYLER");
|
|
3716
|
-
IS_EMPTY = Symbol("IS_EMPTY");
|
|
3714
|
+
GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
3715
|
+
STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
3716
|
+
IS_EMPTY = /* @__PURE__ */ 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 = Symbol("circular-ref-tag");
|
|
4314
|
-
var rawSymbol = Symbol("pino-raw-err-ref");
|
|
4313
|
+
var seen = /* @__PURE__ */ Symbol("circular-ref-tag");
|
|
4314
|
+
var rawSymbol = /* @__PURE__ */ 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 = Symbol("pino-raw-req-ref");
|
|
4451
|
+
var rawSymbol = /* @__PURE__ */ 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 = Symbol("pino-raw-res-ref");
|
|
4546
|
+
var rawSymbol = /* @__PURE__ */ 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 = Symbol("PATH_NOT_FOUND");
|
|
4788
|
+
var PATH_NOT_FOUND = /* @__PURE__ */ 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 = 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");
|
|
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");
|
|
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 = Symbol("kImpl");
|
|
6244
|
+
var kImpl = /* @__PURE__ */ 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 = Symbol.for("pino.metadata");
|
|
8260
|
+
var metadata = /* @__PURE__ */ 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 = Symbol.for("signal-exit emitter");
|
|
8757
|
+
kExitEmitter = /* @__PURE__ */ 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
|
};
|
|
@@ -23934,7 +23934,7 @@ var init_RemoveFileError = __esm({
|
|
|
23934
23934
|
|
|
23935
23935
|
// ../../node_modules/.pnpm/@inquirer+external-editor@1.0.3_@types+node@25.2.3/node_modules/@inquirer/external-editor/dist/esm/index.js
|
|
23936
23936
|
import { spawn, spawnSync } from "child_process";
|
|
23937
|
-
import { readFileSync as
|
|
23937
|
+
import { readFileSync as readFileSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
23938
23938
|
import path2 from "node:path";
|
|
23939
23939
|
import os2 from "node:os";
|
|
23940
23940
|
import { randomUUID } from "node:crypto";
|
|
@@ -24051,14 +24051,14 @@ var init_esm5 = __esm({
|
|
|
24051
24051
|
if (Object.prototype.hasOwnProperty.call(this.fileOptions, "mode")) {
|
|
24052
24052
|
opt.mode = this.fileOptions.mode;
|
|
24053
24053
|
}
|
|
24054
|
-
|
|
24054
|
+
writeFileSync2(this.tempFile, this.text, opt);
|
|
24055
24055
|
} catch (createFileError) {
|
|
24056
24056
|
throw new CreateFileError(createFileError);
|
|
24057
24057
|
}
|
|
24058
24058
|
}
|
|
24059
24059
|
readTemporaryFile() {
|
|
24060
24060
|
try {
|
|
24061
|
-
const tempFileBuffer =
|
|
24061
|
+
const tempFileBuffer = readFileSync2(this.tempFile);
|
|
24062
24062
|
if (tempFileBuffer.length === 0) {
|
|
24063
24063
|
this.text = "";
|
|
24064
24064
|
} else {
|
|
@@ -26541,7 +26541,7 @@ function $constructor(name, initializer3, params) {
|
|
|
26541
26541
|
Object.defineProperty(_, "name", { value: name });
|
|
26542
26542
|
return _;
|
|
26543
26543
|
}
|
|
26544
|
-
var $brand = Symbol("zod_brand");
|
|
26544
|
+
var $brand = /* @__PURE__ */ Symbol("zod_brand");
|
|
26545
26545
|
var $ZodAsyncError = class extends Error {
|
|
26546
26546
|
constructor() {
|
|
26547
26547
|
super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
|
|
@@ -26688,7 +26688,7 @@ function floatSafeRemainder(val, step) {
|
|
|
26688
26688
|
const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", ""));
|
|
26689
26689
|
return valInt % stepInt / 10 ** decCount;
|
|
26690
26690
|
}
|
|
26691
|
-
var EVALUATING = Symbol("evaluating");
|
|
26691
|
+
var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
|
|
26692
26692
|
function defineLazy(object2, key, getter) {
|
|
26693
26693
|
let value = void 0;
|
|
26694
26694
|
Object.defineProperty(object2, key, {
|
|
@@ -35761,8 +35761,8 @@ function yo_default() {
|
|
|
35761
35761
|
|
|
35762
35762
|
// ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/registries.js
|
|
35763
35763
|
var _a;
|
|
35764
|
-
var $output = Symbol("ZodOutput");
|
|
35765
|
-
var $input = Symbol("ZodInput");
|
|
35764
|
+
var $output = /* @__PURE__ */ Symbol("ZodOutput");
|
|
35765
|
+
var $input = /* @__PURE__ */ Symbol("ZodInput");
|
|
35766
35766
|
var $ZodRegistry = class {
|
|
35767
35767
|
constructor() {
|
|
35768
35768
|
this._map = /* @__PURE__ */ new WeakMap();
|
|
@@ -36799,7 +36799,7 @@ function _stringbool(Classes, _params) {
|
|
|
36799
36799
|
type: "pipe",
|
|
36800
36800
|
in: stringSchema,
|
|
36801
36801
|
out: booleanSchema,
|
|
36802
|
-
transform: (input, payload) => {
|
|
36802
|
+
transform: ((input, payload) => {
|
|
36803
36803
|
let data = input;
|
|
36804
36804
|
if (params.case !== "sensitive")
|
|
36805
36805
|
data = data.toLowerCase();
|
|
@@ -36818,14 +36818,14 @@ function _stringbool(Classes, _params) {
|
|
|
36818
36818
|
});
|
|
36819
36819
|
return {};
|
|
36820
36820
|
}
|
|
36821
|
-
},
|
|
36822
|
-
reverseTransform: (input, _payload) => {
|
|
36821
|
+
}),
|
|
36822
|
+
reverseTransform: ((input, _payload) => {
|
|
36823
36823
|
if (input === true) {
|
|
36824
36824
|
return truthyArray[0] || "true";
|
|
36825
36825
|
} else {
|
|
36826
36826
|
return falsyArray[0] || "false";
|
|
36827
36827
|
}
|
|
36828
|
-
},
|
|
36828
|
+
}),
|
|
36829
36829
|
error: params.error
|
|
36830
36830
|
});
|
|
36831
36831
|
return codec2;
|
|
@@ -38153,10 +38153,10 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
38153
38153
|
inst.with = inst.check;
|
|
38154
38154
|
inst.clone = (def2, params) => clone(inst, def2, params);
|
|
38155
38155
|
inst.brand = () => inst;
|
|
38156
|
-
inst.register = (reg, meta3) => {
|
|
38156
|
+
inst.register = ((reg, meta3) => {
|
|
38157
38157
|
reg.add(inst, meta3);
|
|
38158
38158
|
return inst;
|
|
38159
|
-
};
|
|
38159
|
+
});
|
|
38160
38160
|
inst.parse = (data, params) => parse2(inst, data, params, { callee: inst.parse });
|
|
38161
38161
|
inst.safeParse = (data, params) => safeParse2(inst, data, params);
|
|
38162
38162
|
inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
|
|
@@ -39785,6 +39785,8 @@ var envSchema = external_exports.object({
|
|
|
39785
39785
|
BELIEF_DISCOUNT_FACTOR: external_exports.coerce.number().min(0).max(1).default(0.995),
|
|
39786
39786
|
// Cold-start maturity threshold (number of trades before a trader is "established")
|
|
39787
39787
|
COLD_START_MATURITY_THRESHOLD: external_exports.coerce.number().int().nonnegative().default(50),
|
|
39788
|
+
// Politician trading data
|
|
39789
|
+
FINNHUB_API_KEY: external_exports.string().default(""),
|
|
39788
39790
|
// Feature flags
|
|
39789
39791
|
ENABLE_LLM: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
|
|
39790
39792
|
ENABLE_LEARNING: external_exports.enum(["true", "false"]).default("false").transform((v) => v === "true"),
|
|
@@ -39806,6 +39808,8 @@ var envSchema = external_exports.object({
|
|
|
39806
39808
|
NOTIFICATION_FROM_EMAIL: external_exports.string().default("alerts@tradingboy.dev"),
|
|
39807
39809
|
// Solana (crypto payments)
|
|
39808
39810
|
SOLANA_MERCHANT_WALLET: external_exports.string().default(""),
|
|
39811
|
+
// Resend Email
|
|
39812
|
+
RESEND_WEBHOOK_SECRET: external_exports.string().default(""),
|
|
39809
39813
|
// Stripe Billing
|
|
39810
39814
|
STRIPE_SECRET_KEY: external_exports.string().default(""),
|
|
39811
39815
|
STRIPE_WEBHOOK_SECRET: external_exports.string().default(""),
|
|
@@ -48139,9 +48143,10 @@ function computeStats(decisions) {
|
|
|
48139
48143
|
}
|
|
48140
48144
|
|
|
48141
48145
|
// dist/commands/trader.js
|
|
48142
|
-
import { readFileSync as
|
|
48146
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
48143
48147
|
init_source();
|
|
48144
48148
|
init_utils();
|
|
48149
|
+
init_esm15();
|
|
48145
48150
|
var logger12 = createLogger("cli-trader");
|
|
48146
48151
|
function formatTraderOutput(trader, wallets) {
|
|
48147
48152
|
const lines = [];
|
|
@@ -48420,7 +48425,7 @@ function registerTraderCommand(program2) {
|
|
|
48420
48425
|
trader.command("soul").description("Show or upload a SOUL document").argument("<name-or-id>", "Trader name or ID").option("--file <path>", "Path to SOUL document file to upload").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (nameOrId, options) => {
|
|
48421
48426
|
try {
|
|
48422
48427
|
if (options.file) {
|
|
48423
|
-
const document =
|
|
48428
|
+
const document = readFileSync3(options.file, "utf-8");
|
|
48424
48429
|
const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/soul`, { method: "PUT", body: { document } });
|
|
48425
48430
|
if (options.format === "json") {
|
|
48426
48431
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -48468,7 +48473,7 @@ function registerTraderCommand(program2) {
|
|
|
48468
48473
|
trader.command("purpose").description("Show or upload a PURPOSE document").argument("<name-or-id>", "Trader name or ID").option("--file <path>", "Path to PURPOSE document file to upload").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (nameOrId, options) => {
|
|
48469
48474
|
try {
|
|
48470
48475
|
if (options.file) {
|
|
48471
|
-
const document =
|
|
48476
|
+
const document = readFileSync3(options.file, "utf-8");
|
|
48472
48477
|
const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/purpose`, { method: "PUT", body: { document } });
|
|
48473
48478
|
if (options.format === "json") {
|
|
48474
48479
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -48629,6 +48634,221 @@ function registerTraderCommand(program2) {
|
|
|
48629
48634
|
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
48630
48635
|
}
|
|
48631
48636
|
});
|
|
48637
|
+
const AUTONOMY_LEVELS = ["OBSERVE_ONLY", "SUGGEST", "AUTO_WITH_APPROVAL", "FULLY_AUTONOMOUS"];
|
|
48638
|
+
const agent = trader.command("agent").description("Manage autonomous trading agent");
|
|
48639
|
+
agent.command("status").description("Show agent runtime status").argument("<agent-id>", "Agent ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, options) => {
|
|
48640
|
+
const jsonMode = options.format === "json";
|
|
48641
|
+
try {
|
|
48642
|
+
const result = await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/status`);
|
|
48643
|
+
if (jsonMode) {
|
|
48644
|
+
const safeOutput = {
|
|
48645
|
+
agentId,
|
|
48646
|
+
state: result.state,
|
|
48647
|
+
autonomyLevel: result.autonomyLevel,
|
|
48648
|
+
paused: result.paused,
|
|
48649
|
+
killed: result.killed,
|
|
48650
|
+
override: result.humanOverride,
|
|
48651
|
+
openPositions: result.openPositions ?? 0,
|
|
48652
|
+
dailyTradeCount: result.dailyTradeCount ?? 0,
|
|
48653
|
+
dailyPnlUsd: result.dailyPnlUsd ?? null,
|
|
48654
|
+
lastTransitionAt: result.lastTransitionAt ?? null,
|
|
48655
|
+
healthTimestamp: result.healthTimestamp ?? null
|
|
48656
|
+
};
|
|
48657
|
+
console.log(JSON.stringify(safeOutput, null, 2));
|
|
48658
|
+
} else {
|
|
48659
|
+
console.log("");
|
|
48660
|
+
console.log(source_default.bold.cyan(" Agent Status"));
|
|
48661
|
+
console.log(source_default.gray(" " + "\u2500".repeat(50)));
|
|
48662
|
+
console.log("");
|
|
48663
|
+
console.log(` ${source_default.gray("Agent ID:")} ${source_default.white(agentId)}`);
|
|
48664
|
+
console.log(` ${source_default.gray("State:")} ${formatAgentState(result.state)}`);
|
|
48665
|
+
console.log(` ${source_default.gray("Autonomy:")} ${source_default.white(result.autonomyLevel)}`);
|
|
48666
|
+
console.log(` ${source_default.gray("Paused:")} ${result.paused ? source_default.yellow("yes") : source_default.green("no")}`);
|
|
48667
|
+
console.log(` ${source_default.gray("Killed:")} ${result.killed ? source_default.red("yes") : source_default.green("no")}`);
|
|
48668
|
+
console.log(` ${source_default.gray("Override:")} ${result.humanOverride ? source_default.yellow("active") : source_default.dim("none")}`);
|
|
48669
|
+
console.log(` ${source_default.gray("Open positions:")} ${source_default.white(String(result.openPositions ?? 0))}`);
|
|
48670
|
+
console.log(` ${source_default.gray("Trades today:")} ${source_default.white(String(result.dailyTradeCount ?? 0))}`);
|
|
48671
|
+
console.log(` ${source_default.gray("Daily PnL:")} ${formatPnl2(result.dailyPnlUsd)}`);
|
|
48672
|
+
console.log("");
|
|
48673
|
+
}
|
|
48674
|
+
} catch (error49) {
|
|
48675
|
+
handleAgentError(error49, jsonMode, agentId, "get agent status");
|
|
48676
|
+
}
|
|
48677
|
+
});
|
|
48678
|
+
agent.command("pause").description("Pause the agent (stops all trading)").argument("<agent-id>", "Agent ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, options) => {
|
|
48679
|
+
const jsonMode = options.format === "json";
|
|
48680
|
+
try {
|
|
48681
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/pause`, { method: "POST" });
|
|
48682
|
+
if (jsonMode) {
|
|
48683
|
+
console.log(JSON.stringify({ agentId, paused: true }));
|
|
48684
|
+
} else {
|
|
48685
|
+
console.log("");
|
|
48686
|
+
console.log(source_default.yellow(` Agent ${agentId} paused.`));
|
|
48687
|
+
console.log(source_default.dim(" Resume with: trading-boy trader agent resume " + agentId));
|
|
48688
|
+
console.log("");
|
|
48689
|
+
}
|
|
48690
|
+
} catch (error49) {
|
|
48691
|
+
handleAgentError(error49, jsonMode, agentId, "pause agent");
|
|
48692
|
+
}
|
|
48693
|
+
});
|
|
48694
|
+
agent.command("resume").description("Resume a paused agent").argument("<agent-id>", "Agent ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, options) => {
|
|
48695
|
+
const jsonMode = options.format === "json";
|
|
48696
|
+
try {
|
|
48697
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/resume`, { method: "POST" });
|
|
48698
|
+
if (jsonMode) {
|
|
48699
|
+
console.log(JSON.stringify({ agentId, resumed: true }));
|
|
48700
|
+
} else {
|
|
48701
|
+
console.log("");
|
|
48702
|
+
console.log(source_default.green(` Agent ${agentId} resumed.`));
|
|
48703
|
+
console.log("");
|
|
48704
|
+
}
|
|
48705
|
+
} catch (error49) {
|
|
48706
|
+
handleAgentError(error49, jsonMode, agentId, "resume agent");
|
|
48707
|
+
}
|
|
48708
|
+
});
|
|
48709
|
+
agent.command("kill").description("Kill the agent permanently (until revived)").argument("<agent-id>", "Agent ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).addOption(new Option("--force", "Skip confirmation prompt")).action(async (agentId, options) => {
|
|
48710
|
+
const jsonMode = options.format === "json";
|
|
48711
|
+
if (jsonMode && !options.force) {
|
|
48712
|
+
console.error(JSON.stringify({ error: "--force is required with --format json" }));
|
|
48713
|
+
process.exitCode = 1;
|
|
48714
|
+
return;
|
|
48715
|
+
}
|
|
48716
|
+
if (!options.force) {
|
|
48717
|
+
const proceed = await esm_default4({
|
|
48718
|
+
message: `Are you sure you want to kill agent ${agentId}? This is permanent until revived.`
|
|
48719
|
+
});
|
|
48720
|
+
if (!proceed) {
|
|
48721
|
+
console.log(source_default.dim(" Kill cancelled."));
|
|
48722
|
+
return;
|
|
48723
|
+
}
|
|
48724
|
+
}
|
|
48725
|
+
try {
|
|
48726
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/kill`, { method: "POST" });
|
|
48727
|
+
if (jsonMode) {
|
|
48728
|
+
console.log(JSON.stringify({ agentId, killed: true }));
|
|
48729
|
+
} else {
|
|
48730
|
+
console.log("");
|
|
48731
|
+
console.log(source_default.red(` Agent ${agentId} killed.`));
|
|
48732
|
+
console.log(source_default.dim(" The agent will not trade until manually revived."));
|
|
48733
|
+
console.log("");
|
|
48734
|
+
}
|
|
48735
|
+
} catch (error49) {
|
|
48736
|
+
handleAgentError(error49, jsonMode, agentId, "kill agent");
|
|
48737
|
+
}
|
|
48738
|
+
});
|
|
48739
|
+
agent.command("autonomy").description("Set agent autonomy level").argument("<agent-id>", "Agent ID").argument("<level>", `Autonomy level: ${AUTONOMY_LEVELS.join(" | ")}`).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, level, options) => {
|
|
48740
|
+
const jsonMode = options.format === "json";
|
|
48741
|
+
const upperLevel = level.toUpperCase();
|
|
48742
|
+
if (!AUTONOMY_LEVELS.includes(upperLevel)) {
|
|
48743
|
+
const msg = `Invalid autonomy level. Must be one of: ${AUTONOMY_LEVELS.join(", ")}`;
|
|
48744
|
+
if (jsonMode) {
|
|
48745
|
+
console.error(JSON.stringify({ error: msg }));
|
|
48746
|
+
} else {
|
|
48747
|
+
console.error(source_default.red(` ${msg}`));
|
|
48748
|
+
}
|
|
48749
|
+
process.exitCode = 1;
|
|
48750
|
+
return;
|
|
48751
|
+
}
|
|
48752
|
+
try {
|
|
48753
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/autonomy`, {
|
|
48754
|
+
method: "PUT",
|
|
48755
|
+
body: { level: upperLevel }
|
|
48756
|
+
});
|
|
48757
|
+
if (jsonMode) {
|
|
48758
|
+
console.log(JSON.stringify({ agentId, autonomyLevel: upperLevel }));
|
|
48759
|
+
} else {
|
|
48760
|
+
console.log("");
|
|
48761
|
+
console.log(source_default.green(` Autonomy level set to: ${source_default.white(upperLevel)}`));
|
|
48762
|
+
console.log("");
|
|
48763
|
+
}
|
|
48764
|
+
} catch (error49) {
|
|
48765
|
+
handleAgentError(error49, jsonMode, agentId, "set autonomy");
|
|
48766
|
+
}
|
|
48767
|
+
});
|
|
48768
|
+
agent.command("override").description("Set human override (agent defers all decisions to human)").argument("<agent-id>", "Agent ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).addOption(new Option("--force", "Skip confirmation prompt")).action(async (agentId, options) => {
|
|
48769
|
+
const jsonMode = options.format === "json";
|
|
48770
|
+
if (jsonMode && !options.force) {
|
|
48771
|
+
console.error(JSON.stringify({ error: "--force is required with --format json" }));
|
|
48772
|
+
process.exitCode = 1;
|
|
48773
|
+
return;
|
|
48774
|
+
}
|
|
48775
|
+
if (!options.force) {
|
|
48776
|
+
const proceed = await esm_default4({
|
|
48777
|
+
message: `Are you sure you want to set human override for agent ${agentId}?`
|
|
48778
|
+
});
|
|
48779
|
+
if (!proceed) {
|
|
48780
|
+
console.log(source_default.dim(" Override cancelled."));
|
|
48781
|
+
return;
|
|
48782
|
+
}
|
|
48783
|
+
}
|
|
48784
|
+
try {
|
|
48785
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/override`, { method: "POST" });
|
|
48786
|
+
if (jsonMode) {
|
|
48787
|
+
console.log(JSON.stringify({ agentId, humanOverride: true }));
|
|
48788
|
+
} else {
|
|
48789
|
+
console.log("");
|
|
48790
|
+
console.log(source_default.yellow(` Human override set for agent ${agentId}.`));
|
|
48791
|
+
console.log(source_default.dim(" The agent will defer all decisions to you."));
|
|
48792
|
+
console.log(source_default.dim(" Clear with: trading-boy trader agent clear-override " + agentId));
|
|
48793
|
+
console.log("");
|
|
48794
|
+
}
|
|
48795
|
+
} catch (error49) {
|
|
48796
|
+
handleAgentError(error49, jsonMode, agentId, "set override");
|
|
48797
|
+
}
|
|
48798
|
+
});
|
|
48799
|
+
agent.command("clear-override").description("Clear human override (return control to agent)").argument("<agent-id>", "Agent ID").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (agentId, options) => {
|
|
48800
|
+
const jsonMode = options.format === "json";
|
|
48801
|
+
try {
|
|
48802
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/clear-override`, { method: "POST" });
|
|
48803
|
+
if (jsonMode) {
|
|
48804
|
+
console.log(JSON.stringify({ agentId, humanOverride: false }));
|
|
48805
|
+
} else {
|
|
48806
|
+
console.log("");
|
|
48807
|
+
console.log(source_default.green(` Human override cleared for agent ${agentId}.`));
|
|
48808
|
+
console.log(source_default.dim(" The agent will resume autonomous decision-making."));
|
|
48809
|
+
console.log("");
|
|
48810
|
+
}
|
|
48811
|
+
} catch (error49) {
|
|
48812
|
+
handleAgentError(error49, jsonMode, agentId, "clear override");
|
|
48813
|
+
}
|
|
48814
|
+
});
|
|
48815
|
+
}
|
|
48816
|
+
function formatAgentState(state) {
|
|
48817
|
+
const colors8 = {
|
|
48818
|
+
"IDLE": source_default.dim,
|
|
48819
|
+
"SCANNING": source_default.cyan,
|
|
48820
|
+
"ANALYZING": source_default.blue,
|
|
48821
|
+
"EXECUTING": source_default.yellow,
|
|
48822
|
+
"PAUSED": source_default.yellow,
|
|
48823
|
+
"KILLED": source_default.red
|
|
48824
|
+
};
|
|
48825
|
+
return (colors8[state] ?? source_default.white)(state);
|
|
48826
|
+
}
|
|
48827
|
+
function formatPnl2(pnl) {
|
|
48828
|
+
if (pnl === void 0 || pnl === null)
|
|
48829
|
+
return source_default.dim("n/a");
|
|
48830
|
+
const sign = pnl >= 0 ? "+" : "";
|
|
48831
|
+
const color = pnl >= 0 ? source_default.green : source_default.red;
|
|
48832
|
+
return color(`${sign}$${pnl.toFixed(2)}`);
|
|
48833
|
+
}
|
|
48834
|
+
function handleAgentError(error49, jsonMode, agentId, action) {
|
|
48835
|
+
if (error49 instanceof ApiError && error49.status === 404) {
|
|
48836
|
+
const msg = `Agent not found: "${agentId}"`;
|
|
48837
|
+
if (jsonMode) {
|
|
48838
|
+
console.error(JSON.stringify({ error: msg }));
|
|
48839
|
+
} else {
|
|
48840
|
+
console.error(source_default.yellow(msg));
|
|
48841
|
+
}
|
|
48842
|
+
} else {
|
|
48843
|
+
const message = error49 instanceof Error ? error49.message : String(error49);
|
|
48844
|
+
logger12.error({ error: message }, `Failed to ${action}`);
|
|
48845
|
+
if (jsonMode) {
|
|
48846
|
+
console.error(JSON.stringify({ error: message }));
|
|
48847
|
+
} else {
|
|
48848
|
+
console.error(source_default.red(`Error: ${message}`));
|
|
48849
|
+
}
|
|
48850
|
+
}
|
|
48851
|
+
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
48632
48852
|
}
|
|
48633
48853
|
function parseFloatOption(value) {
|
|
48634
48854
|
return parseFloat(value);
|
|
@@ -49758,7 +49978,7 @@ function registerAuditCommand(program2) {
|
|
|
49758
49978
|
|
|
49759
49979
|
// dist/commands/config-cmd.js
|
|
49760
49980
|
init_source();
|
|
49761
|
-
import { readFileSync as
|
|
49981
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync2 } from "node:fs";
|
|
49762
49982
|
import { resolve } from "node:path";
|
|
49763
49983
|
init_utils();
|
|
49764
49984
|
var logger17 = createLogger("cli-config");
|
|
@@ -49858,7 +50078,7 @@ function parseEnvFile(filePath) {
|
|
|
49858
50078
|
if (!existsSync2(filePath)) {
|
|
49859
50079
|
return { entries, lines };
|
|
49860
50080
|
}
|
|
49861
|
-
const content =
|
|
50081
|
+
const content = readFileSync4(filePath, "utf-8");
|
|
49862
50082
|
const rawLines = content.split("\n");
|
|
49863
50083
|
for (const line of rawLines) {
|
|
49864
50084
|
lines.push(line);
|
|
@@ -49897,11 +50117,11 @@ function writeEnvValue(filePath, key, value) {
|
|
|
49897
50117
|
}
|
|
49898
50118
|
return line;
|
|
49899
50119
|
});
|
|
49900
|
-
|
|
50120
|
+
writeFileSync3(filePath, updatedLines.join("\n"));
|
|
49901
50121
|
} else {
|
|
49902
|
-
const existing = existsSync2(filePath) ?
|
|
50122
|
+
const existing = existsSync2(filePath) ? readFileSync4(filePath, "utf-8") : "";
|
|
49903
50123
|
const separator = existing.endsWith("\n") || existing === "" ? "" : "\n";
|
|
49904
|
-
|
|
50124
|
+
writeFileSync3(filePath, existing + separator + `${key}=${value}
|
|
49905
50125
|
`);
|
|
49906
50126
|
}
|
|
49907
50127
|
}
|
|
@@ -50571,7 +50791,7 @@ async function runOnboarding() {
|
|
|
50571
50791
|
});
|
|
50572
50792
|
if (wantsTrader) {
|
|
50573
50793
|
const name = await input({
|
|
50574
|
-
message: "Trader name (
|
|
50794
|
+
message: "Trader name (this will appear on the public leaderboard \u2014 use a pseudonym to stay anonymous)",
|
|
50575
50795
|
default: "default",
|
|
50576
50796
|
validate: (v) => v.trim().length > 0 ? true : "Name cannot be empty"
|
|
50577
50797
|
});
|
|
@@ -50592,6 +50812,11 @@ async function runOnboarding() {
|
|
|
50592
50812
|
body: { name: name.trim(), riskToleranceMax: parseFloat(maxDrawdown) }
|
|
50593
50813
|
});
|
|
50594
50814
|
console.log(source_default.green(` \u2713 Trader "${result.name}" registered (id: ${result.id})`));
|
|
50815
|
+
if (result.publicAlias) {
|
|
50816
|
+
console.log(source_default.dim(` Leaderboard alias: ${result.publicAlias}`));
|
|
50817
|
+
console.log(source_default.dim(" This alias is public on the leaderboard. Change it anytime:"));
|
|
50818
|
+
console.log(source_default.dim(" trading-boy trader set-alias <name> <new-alias>"));
|
|
50819
|
+
}
|
|
50595
50820
|
traderRegistered = true;
|
|
50596
50821
|
} else {
|
|
50597
50822
|
console.log(source_default.yellow(" Skipped \u2014 not connected to API. Run: trading-boy trader register"));
|
|
@@ -28,7 +28,7 @@ export async function runOnboarding() {
|
|
|
28
28
|
});
|
|
29
29
|
if (wantsTrader) {
|
|
30
30
|
const name = await input({
|
|
31
|
-
message: 'Trader name (
|
|
31
|
+
message: 'Trader name (this will appear on the public leaderboard — use a pseudonym to stay anonymous)',
|
|
32
32
|
default: 'default',
|
|
33
33
|
validate: (v) => (v.trim().length > 0 ? true : 'Name cannot be empty'),
|
|
34
34
|
});
|
|
@@ -49,6 +49,11 @@ export async function runOnboarding() {
|
|
|
49
49
|
body: { name: name.trim(), riskToleranceMax: parseFloat(maxDrawdown) },
|
|
50
50
|
});
|
|
51
51
|
console.log(chalk.green(` \u2713 Trader "${result.name}" registered (id: ${result.id})`));
|
|
52
|
+
if (result.publicAlias) {
|
|
53
|
+
console.log(chalk.dim(` Leaderboard alias: ${result.publicAlias}`));
|
|
54
|
+
console.log(chalk.dim(' This alias is public on the leaderboard. Change it anytime:'));
|
|
55
|
+
console.log(chalk.dim(' trading-boy trader set-alias <name> <new-alias>'));
|
|
56
|
+
}
|
|
52
57
|
traderRegistered = true;
|
|
53
58
|
}
|
|
54
59
|
else {
|
package/dist/commands/trader.js
CHANGED
|
@@ -4,6 +4,7 @@ import chalk from 'chalk';
|
|
|
4
4
|
import { createLogger } from '@trading-boy/core';
|
|
5
5
|
import { padRight } from '../utils.js';
|
|
6
6
|
import { apiRequest, ApiError } from '../api-client.js';
|
|
7
|
+
import { confirm } from '@inquirer/prompts';
|
|
7
8
|
// ─── Logger ───
|
|
8
9
|
const logger = createLogger('cli-trader');
|
|
9
10
|
// ─── Formatters ───
|
|
@@ -634,6 +635,288 @@ export function registerTraderCommand(program) {
|
|
|
634
635
|
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
635
636
|
}
|
|
636
637
|
});
|
|
638
|
+
// ─── agent (subcommand group) ───
|
|
639
|
+
const AUTONOMY_LEVELS = ['OBSERVE_ONLY', 'SUGGEST', 'AUTO_WITH_APPROVAL', 'FULLY_AUTONOMOUS'];
|
|
640
|
+
const agent = trader
|
|
641
|
+
.command('agent')
|
|
642
|
+
.description('Manage autonomous trading agent');
|
|
643
|
+
// ─── agent status ───
|
|
644
|
+
agent
|
|
645
|
+
.command('status')
|
|
646
|
+
.description('Show agent runtime status')
|
|
647
|
+
.argument('<agent-id>', 'Agent ID')
|
|
648
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
649
|
+
.action(async (agentId, options) => {
|
|
650
|
+
const jsonMode = options.format === 'json';
|
|
651
|
+
try {
|
|
652
|
+
const result = await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/status`);
|
|
653
|
+
if (jsonMode) {
|
|
654
|
+
const safeOutput = {
|
|
655
|
+
agentId,
|
|
656
|
+
state: result.state,
|
|
657
|
+
autonomyLevel: result.autonomyLevel,
|
|
658
|
+
paused: result.paused,
|
|
659
|
+
killed: result.killed,
|
|
660
|
+
override: result.humanOverride,
|
|
661
|
+
openPositions: result.openPositions ?? 0,
|
|
662
|
+
dailyTradeCount: result.dailyTradeCount ?? 0,
|
|
663
|
+
dailyPnlUsd: result.dailyPnlUsd ?? null,
|
|
664
|
+
lastTransitionAt: result.lastTransitionAt ?? null,
|
|
665
|
+
healthTimestamp: result.healthTimestamp ?? null,
|
|
666
|
+
};
|
|
667
|
+
console.log(JSON.stringify(safeOutput, null, 2));
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
console.log('');
|
|
671
|
+
console.log(chalk.bold.cyan(' Agent Status'));
|
|
672
|
+
console.log(chalk.gray(' ' + '\u2500'.repeat(50)));
|
|
673
|
+
console.log('');
|
|
674
|
+
console.log(` ${chalk.gray('Agent ID:')} ${chalk.white(agentId)}`);
|
|
675
|
+
console.log(` ${chalk.gray('State:')} ${formatAgentState(result.state)}`);
|
|
676
|
+
console.log(` ${chalk.gray('Autonomy:')} ${chalk.white(result.autonomyLevel)}`);
|
|
677
|
+
console.log(` ${chalk.gray('Paused:')} ${result.paused ? chalk.yellow('yes') : chalk.green('no')}`);
|
|
678
|
+
console.log(` ${chalk.gray('Killed:')} ${result.killed ? chalk.red('yes') : chalk.green('no')}`);
|
|
679
|
+
console.log(` ${chalk.gray('Override:')} ${result.humanOverride ? chalk.yellow('active') : chalk.dim('none')}`);
|
|
680
|
+
console.log(` ${chalk.gray('Open positions:')} ${chalk.white(String(result.openPositions ?? 0))}`);
|
|
681
|
+
console.log(` ${chalk.gray('Trades today:')} ${chalk.white(String(result.dailyTradeCount ?? 0))}`);
|
|
682
|
+
console.log(` ${chalk.gray('Daily PnL:')} ${formatPnl(result.dailyPnlUsd)}`);
|
|
683
|
+
console.log('');
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
catch (error) {
|
|
687
|
+
handleAgentError(error, jsonMode, agentId, 'get agent status');
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
// ─── agent pause ───
|
|
691
|
+
agent
|
|
692
|
+
.command('pause')
|
|
693
|
+
.description('Pause the agent (stops all trading)')
|
|
694
|
+
.argument('<agent-id>', 'Agent ID')
|
|
695
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
696
|
+
.action(async (agentId, options) => {
|
|
697
|
+
const jsonMode = options.format === 'json';
|
|
698
|
+
try {
|
|
699
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/pause`, { method: 'POST' });
|
|
700
|
+
if (jsonMode) {
|
|
701
|
+
console.log(JSON.stringify({ agentId, paused: true }));
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
console.log('');
|
|
705
|
+
console.log(chalk.yellow(` Agent ${agentId} paused.`));
|
|
706
|
+
console.log(chalk.dim(' Resume with: trading-boy trader agent resume ' + agentId));
|
|
707
|
+
console.log('');
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
catch (error) {
|
|
711
|
+
handleAgentError(error, jsonMode, agentId, 'pause agent');
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
// ─── agent resume ───
|
|
715
|
+
agent
|
|
716
|
+
.command('resume')
|
|
717
|
+
.description('Resume a paused agent')
|
|
718
|
+
.argument('<agent-id>', 'Agent ID')
|
|
719
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
720
|
+
.action(async (agentId, options) => {
|
|
721
|
+
const jsonMode = options.format === 'json';
|
|
722
|
+
try {
|
|
723
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/resume`, { method: 'POST' });
|
|
724
|
+
if (jsonMode) {
|
|
725
|
+
console.log(JSON.stringify({ agentId, resumed: true }));
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
console.log('');
|
|
729
|
+
console.log(chalk.green(` Agent ${agentId} resumed.`));
|
|
730
|
+
console.log('');
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
catch (error) {
|
|
734
|
+
handleAgentError(error, jsonMode, agentId, 'resume agent');
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
// ─── agent kill ───
|
|
738
|
+
agent
|
|
739
|
+
.command('kill')
|
|
740
|
+
.description('Kill the agent permanently (until revived)')
|
|
741
|
+
.argument('<agent-id>', 'Agent ID')
|
|
742
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
743
|
+
.addOption(new Option('--force', 'Skip confirmation prompt'))
|
|
744
|
+
.action(async (agentId, options) => {
|
|
745
|
+
const jsonMode = options.format === 'json';
|
|
746
|
+
if (jsonMode && !options.force) {
|
|
747
|
+
console.error(JSON.stringify({ error: '--force is required with --format json' }));
|
|
748
|
+
process.exitCode = 1;
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (!options.force) {
|
|
752
|
+
const proceed = await confirm({
|
|
753
|
+
message: `Are you sure you want to kill agent ${agentId}? This is permanent until revived.`,
|
|
754
|
+
});
|
|
755
|
+
if (!proceed) {
|
|
756
|
+
console.log(chalk.dim(' Kill cancelled.'));
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
try {
|
|
761
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/kill`, { method: 'POST' });
|
|
762
|
+
if (jsonMode) {
|
|
763
|
+
console.log(JSON.stringify({ agentId, killed: true }));
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
console.log('');
|
|
767
|
+
console.log(chalk.red(` Agent ${agentId} killed.`));
|
|
768
|
+
console.log(chalk.dim(' The agent will not trade until manually revived.'));
|
|
769
|
+
console.log('');
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
handleAgentError(error, jsonMode, agentId, 'kill agent');
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
// ─── agent autonomy ───
|
|
777
|
+
agent
|
|
778
|
+
.command('autonomy')
|
|
779
|
+
.description('Set agent autonomy level')
|
|
780
|
+
.argument('<agent-id>', 'Agent ID')
|
|
781
|
+
.argument('<level>', `Autonomy level: ${AUTONOMY_LEVELS.join(' | ')}`)
|
|
782
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
783
|
+
.action(async (agentId, level, options) => {
|
|
784
|
+
const jsonMode = options.format === 'json';
|
|
785
|
+
const upperLevel = level.toUpperCase();
|
|
786
|
+
if (!AUTONOMY_LEVELS.includes(upperLevel)) {
|
|
787
|
+
const msg = `Invalid autonomy level. Must be one of: ${AUTONOMY_LEVELS.join(', ')}`;
|
|
788
|
+
if (jsonMode) {
|
|
789
|
+
console.error(JSON.stringify({ error: msg }));
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
console.error(chalk.red(` ${msg}`));
|
|
793
|
+
}
|
|
794
|
+
process.exitCode = 1;
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
try {
|
|
798
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/autonomy`, {
|
|
799
|
+
method: 'PUT',
|
|
800
|
+
body: { level: upperLevel },
|
|
801
|
+
});
|
|
802
|
+
if (jsonMode) {
|
|
803
|
+
console.log(JSON.stringify({ agentId, autonomyLevel: upperLevel }));
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
console.log('');
|
|
807
|
+
console.log(chalk.green(` Autonomy level set to: ${chalk.white(upperLevel)}`));
|
|
808
|
+
console.log('');
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
catch (error) {
|
|
812
|
+
handleAgentError(error, jsonMode, agentId, 'set autonomy');
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
// ─── agent override ───
|
|
816
|
+
agent
|
|
817
|
+
.command('override')
|
|
818
|
+
.description('Set human override (agent defers all decisions to human)')
|
|
819
|
+
.argument('<agent-id>', 'Agent ID')
|
|
820
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
821
|
+
.addOption(new Option('--force', 'Skip confirmation prompt'))
|
|
822
|
+
.action(async (agentId, options) => {
|
|
823
|
+
const jsonMode = options.format === 'json';
|
|
824
|
+
if (jsonMode && !options.force) {
|
|
825
|
+
console.error(JSON.stringify({ error: '--force is required with --format json' }));
|
|
826
|
+
process.exitCode = 1;
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
if (!options.force) {
|
|
830
|
+
const proceed = await confirm({
|
|
831
|
+
message: `Are you sure you want to set human override for agent ${agentId}?`,
|
|
832
|
+
});
|
|
833
|
+
if (!proceed) {
|
|
834
|
+
console.log(chalk.dim(' Override cancelled.'));
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
try {
|
|
839
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/override`, { method: 'POST' });
|
|
840
|
+
if (jsonMode) {
|
|
841
|
+
console.log(JSON.stringify({ agentId, humanOverride: true }));
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
console.log('');
|
|
845
|
+
console.log(chalk.yellow(` Human override set for agent ${agentId}.`));
|
|
846
|
+
console.log(chalk.dim(' The agent will defer all decisions to you.'));
|
|
847
|
+
console.log(chalk.dim(' Clear with: trading-boy trader agent clear-override ' + agentId));
|
|
848
|
+
console.log('');
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
catch (error) {
|
|
852
|
+
handleAgentError(error, jsonMode, agentId, 'set override');
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
// ─── agent clear-override ───
|
|
856
|
+
agent
|
|
857
|
+
.command('clear-override')
|
|
858
|
+
.description('Clear human override (return control to agent)')
|
|
859
|
+
.argument('<agent-id>', 'Agent ID')
|
|
860
|
+
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
861
|
+
.action(async (agentId, options) => {
|
|
862
|
+
const jsonMode = options.format === 'json';
|
|
863
|
+
try {
|
|
864
|
+
await apiRequest(`/api/v1/agents/${encodeURIComponent(agentId)}/clear-override`, { method: 'POST' });
|
|
865
|
+
if (jsonMode) {
|
|
866
|
+
console.log(JSON.stringify({ agentId, humanOverride: false }));
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
869
|
+
console.log('');
|
|
870
|
+
console.log(chalk.green(` Human override cleared for agent ${agentId}.`));
|
|
871
|
+
console.log(chalk.dim(' The agent will resume autonomous decision-making.'));
|
|
872
|
+
console.log('');
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
catch (error) {
|
|
876
|
+
handleAgentError(error, jsonMode, agentId, 'clear override');
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
// ─── Agent Helpers ───
|
|
881
|
+
function formatAgentState(state) {
|
|
882
|
+
const colors = {
|
|
883
|
+
'IDLE': chalk.dim,
|
|
884
|
+
'SCANNING': chalk.cyan,
|
|
885
|
+
'ANALYZING': chalk.blue,
|
|
886
|
+
'EXECUTING': chalk.yellow,
|
|
887
|
+
'PAUSED': chalk.yellow,
|
|
888
|
+
'KILLED': chalk.red,
|
|
889
|
+
};
|
|
890
|
+
return (colors[state] ?? chalk.white)(state);
|
|
891
|
+
}
|
|
892
|
+
function formatPnl(pnl) {
|
|
893
|
+
if (pnl === undefined || pnl === null)
|
|
894
|
+
return chalk.dim('n/a');
|
|
895
|
+
const sign = pnl >= 0 ? '+' : '';
|
|
896
|
+
const color = pnl >= 0 ? chalk.green : chalk.red;
|
|
897
|
+
return color(`${sign}$${pnl.toFixed(2)}`);
|
|
898
|
+
}
|
|
899
|
+
function handleAgentError(error, jsonMode, agentId, action) {
|
|
900
|
+
if (error instanceof ApiError && error.status === 404) {
|
|
901
|
+
const msg = `Agent not found: "${agentId}"`;
|
|
902
|
+
if (jsonMode) {
|
|
903
|
+
console.error(JSON.stringify({ error: msg }));
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
console.error(chalk.yellow(msg));
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
else {
|
|
910
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
911
|
+
logger.error({ error: message }, `Failed to ${action}`);
|
|
912
|
+
if (jsonMode) {
|
|
913
|
+
console.error(JSON.stringify({ error: message }));
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
637
920
|
}
|
|
638
921
|
// ─── Helpers ───
|
|
639
922
|
function parseFloatOption(value) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.19",
|
|
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": {
|