@trading-boy/cli 1.4.1 → 1.5.1
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 +121 -15
- package/dist/commands/agent-cmd.js +21 -3
- package/dist/commands/context.js +15 -1
- package/dist/commands/decisions.js +13 -1
- package/dist/commands/infra.d.ts +6 -2
- package/dist/commands/infra.js +18 -11
- package/dist/commands/journal.js +31 -1
- package/dist/commands/login.js +1 -0
- package/dist/commands/onboarding.js +4 -4
- package/dist/commands/query.js +8 -1
- package/dist/commands/risk.js +7 -1
- package/dist/commands/subscribe.js +1 -1
- package/dist/commands/suggestions-cmd.js +19 -1
- package/dist/commands/whoami.js +1 -1
- package/package.json +1 -1
package/dist/cli.bundle.js
CHANGED
|
@@ -51201,6 +51201,12 @@ function contextToQueryResult(pkg) {
|
|
|
51201
51201
|
function registerQueryCommand(program2) {
|
|
51202
51202
|
program2.command("query <symbol>").description("Query token info, price, funding rate, and whale activity").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (symbol2, options) => {
|
|
51203
51203
|
try {
|
|
51204
|
+
if (!await isRemoteMode()) {
|
|
51205
|
+
console.error(source_default.yellow("This command requires a remote API connection."));
|
|
51206
|
+
console.error(source_default.dim(" Run: trading-boy login"));
|
|
51207
|
+
process.exitCode = 1;
|
|
51208
|
+
return;
|
|
51209
|
+
}
|
|
51204
51210
|
const pkg = await apiRequest(`/api/v1/tokens/${encodeURIComponent(symbol2.toUpperCase())}/context`);
|
|
51205
51211
|
const result = contextToQueryResult(pkg);
|
|
51206
51212
|
if (result.token.name === null && result.token.chains.length === 0 && result.price.price === null) {
|
|
@@ -51497,6 +51503,12 @@ function buildHistoryQueryParams(options) {
|
|
|
51497
51503
|
function registerContextCommand(program2) {
|
|
51498
51504
|
program2.command("context <symbol>").description("Assemble and display a full ContextPackage for a token").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).option("--at <date>", "Fetch historical context at a specific date/time (e.g., 2026-01-15 or 2026-01-15T12:00:00Z)").option("--from <date>", "Start of time range for context history").option("--to <date>", "End of time range for context history").addOption(new Option("--interval <interval>", "Sampling interval for range queries").choices(["15m", "1h", "4h", "1d"])).option("--trader-id <id>", "Trader ID for personalized context").action(async (symbol2, options) => {
|
|
51499
51505
|
try {
|
|
51506
|
+
if (!await isRemoteMode()) {
|
|
51507
|
+
console.error(source_default.yellow("This command requires a remote API connection."));
|
|
51508
|
+
console.error(source_default.dim(" Run: trading-boy login"));
|
|
51509
|
+
process.exitCode = 1;
|
|
51510
|
+
return;
|
|
51511
|
+
}
|
|
51500
51512
|
if (options.from && !options.to || !options.from && options.to) {
|
|
51501
51513
|
console.error(source_default.red("Error: Both --from and --to must be provided for range queries."));
|
|
51502
51514
|
process.exitCode = 1;
|
|
@@ -51533,6 +51545,12 @@ function registerContextCommand(program2) {
|
|
|
51533
51545
|
} else {
|
|
51534
51546
|
const traderQs = options.traderId ? `?traderId=${encodeURIComponent(options.traderId)}` : "";
|
|
51535
51547
|
const pkg = await apiRequest(`/api/v1/tokens/${encodeURIComponent(symbol2.toUpperCase())}/context${traderQs}`);
|
|
51548
|
+
if (pkg.token.name == null && (!Array.isArray(pkg.token.chains) || pkg.token.chains.length === 0) && pkg.market?.price == null) {
|
|
51549
|
+
console.error(source_default.red(`Error: Token not found: ${symbol2.toUpperCase()}`));
|
|
51550
|
+
console.error(source_default.dim(" Check the symbol and try again. Use a symbol like SOL, JUP, or BONK."));
|
|
51551
|
+
process.exitCode = 1;
|
|
51552
|
+
return;
|
|
51553
|
+
}
|
|
51536
51554
|
if (options.format === "json") {
|
|
51537
51555
|
console.log(JSON.stringify(pkg, null, 2));
|
|
51538
51556
|
} else {
|
|
@@ -51805,6 +51823,12 @@ function registerRiskCommand(program2) {
|
|
|
51805
51823
|
process.exitCode = 1;
|
|
51806
51824
|
return;
|
|
51807
51825
|
}
|
|
51826
|
+
if (!await isRemoteMode()) {
|
|
51827
|
+
console.error(source_default.yellow("This command requires a remote API connection."));
|
|
51828
|
+
console.error(source_default.dim(" Run: trading-boy login or trading-boy subscribe"));
|
|
51829
|
+
process.exitCode = 1;
|
|
51830
|
+
return;
|
|
51831
|
+
}
|
|
51808
51832
|
try {
|
|
51809
51833
|
const apiResult = await apiRequest(`/api/v1/protocols/${encodeURIComponent(protocol.toLowerCase())}/risk`);
|
|
51810
51834
|
const result = {
|
|
@@ -51981,6 +52005,12 @@ function registerDecisionsCommand(program2) {
|
|
|
51981
52005
|
}
|
|
51982
52006
|
} catch (error49) {
|
|
51983
52007
|
const message = error49 instanceof ApiError ? error49.message : error49 instanceof Error ? error49.message : String(error49);
|
|
52008
|
+
const connErr = formatConnectionError(message);
|
|
52009
|
+
if (connErr) {
|
|
52010
|
+
console.error(connErr);
|
|
52011
|
+
process.exitCode = 1;
|
|
52012
|
+
return;
|
|
52013
|
+
}
|
|
51984
52014
|
logger11.error({ error: message }, "Failed to fetch decisions");
|
|
51985
52015
|
console.error(source_default.red(`Error: ${message}`));
|
|
51986
52016
|
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
@@ -52011,6 +52041,12 @@ function registerDecisionsCommand(program2) {
|
|
|
52011
52041
|
}
|
|
52012
52042
|
} catch (error49) {
|
|
52013
52043
|
const message = error49 instanceof ApiError ? error49.message : error49 instanceof Error ? error49.message : String(error49);
|
|
52044
|
+
const connErr = formatConnectionError(message);
|
|
52045
|
+
if (connErr) {
|
|
52046
|
+
console.error(connErr);
|
|
52047
|
+
process.exitCode = 1;
|
|
52048
|
+
return;
|
|
52049
|
+
}
|
|
52014
52050
|
logger11.error({ error: message }, "Failed to fetch stats");
|
|
52015
52051
|
console.error(source_default.red(`Error: ${message}`));
|
|
52016
52052
|
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
@@ -53741,6 +53777,12 @@ function registerJournalCommand(program2) {
|
|
|
53741
53777
|
console.log(`Entry logged: id=${result.id} hash=${result.hash}`);
|
|
53742
53778
|
} catch (error49) {
|
|
53743
53779
|
const message = error49 instanceof ApiError ? error49.message : error49 instanceof Error ? error49.message : String(error49);
|
|
53780
|
+
const connErr = formatConnectionError(message);
|
|
53781
|
+
if (connErr) {
|
|
53782
|
+
console.error(connErr);
|
|
53783
|
+
process.exitCode = 1;
|
|
53784
|
+
return;
|
|
53785
|
+
}
|
|
53744
53786
|
console.error(`Error: ${message}`);
|
|
53745
53787
|
if (error49 instanceof ApiError && error49.body && typeof error49.body === "object") {
|
|
53746
53788
|
const detail = error49.body.error ?? error49.body.code;
|
|
@@ -53773,6 +53815,12 @@ function registerJournalCommand(program2) {
|
|
|
53773
53815
|
console.log(`Exit logged: id=${result.id} hash=${result.hash}`);
|
|
53774
53816
|
} catch (error49) {
|
|
53775
53817
|
const message = error49 instanceof ApiError ? error49.message : error49 instanceof Error ? error49.message : String(error49);
|
|
53818
|
+
const connErr = formatConnectionError(message);
|
|
53819
|
+
if (connErr) {
|
|
53820
|
+
console.error(connErr);
|
|
53821
|
+
process.exitCode = 1;
|
|
53822
|
+
return;
|
|
53823
|
+
}
|
|
53776
53824
|
console.error(`Error: ${message}`);
|
|
53777
53825
|
if (error49 instanceof ApiError && error49.body && typeof error49.body === "object") {
|
|
53778
53826
|
const detail = error49.body.error ?? error49.body.code;
|
|
@@ -53817,6 +53865,12 @@ function registerJournalCommand(program2) {
|
|
|
53817
53865
|
console.log(`Total: ${decisions.length} decision(s)`);
|
|
53818
53866
|
} catch (error49) {
|
|
53819
53867
|
const message = error49 instanceof ApiError ? error49.message : error49 instanceof Error ? error49.message : String(error49);
|
|
53868
|
+
const connErr = formatConnectionError(message);
|
|
53869
|
+
if (connErr) {
|
|
53870
|
+
console.error(connErr);
|
|
53871
|
+
process.exitCode = 1;
|
|
53872
|
+
return;
|
|
53873
|
+
}
|
|
53820
53874
|
console.error(`Error: ${message}`);
|
|
53821
53875
|
if (error49 instanceof ApiError && error49.body && typeof error49.body === "object") {
|
|
53822
53876
|
const detail = error49.body.error ?? error49.body.code;
|
|
@@ -53853,6 +53907,12 @@ function registerJournalCommand(program2) {
|
|
|
53853
53907
|
}
|
|
53854
53908
|
} catch (error49) {
|
|
53855
53909
|
const message = error49 instanceof ApiError ? error49.message : error49 instanceof Error ? error49.message : String(error49);
|
|
53910
|
+
const connErr = formatConnectionError(message);
|
|
53911
|
+
if (connErr) {
|
|
53912
|
+
console.error(connErr);
|
|
53913
|
+
process.exitCode = 1;
|
|
53914
|
+
return;
|
|
53915
|
+
}
|
|
53856
53916
|
console.error(`Error: ${message}`);
|
|
53857
53917
|
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
53858
53918
|
}
|
|
@@ -53875,6 +53935,12 @@ function registerJournalCommand(program2) {
|
|
|
53875
53935
|
}
|
|
53876
53936
|
} catch (error49) {
|
|
53877
53937
|
const message = error49 instanceof ApiError ? error49.message : error49 instanceof Error ? error49.message : String(error49);
|
|
53938
|
+
const connErr = formatConnectionError(message);
|
|
53939
|
+
if (connErr) {
|
|
53940
|
+
console.error(connErr);
|
|
53941
|
+
process.exitCode = 1;
|
|
53942
|
+
return;
|
|
53943
|
+
}
|
|
53878
53944
|
console.error(`Error: ${message}`);
|
|
53879
53945
|
process.exitCode = error49 instanceof ApiError ? 2 : 1;
|
|
53880
53946
|
}
|
|
@@ -54273,7 +54339,7 @@ function registerConfigCommand(program2) {
|
|
|
54273
54339
|
init_source();
|
|
54274
54340
|
init_utils();
|
|
54275
54341
|
var logger18 = createLogger("cli-infra");
|
|
54276
|
-
async function checkInfraStatus() {
|
|
54342
|
+
async function checkInfraStatus(options) {
|
|
54277
54343
|
const apiBase = getApiBase();
|
|
54278
54344
|
try {
|
|
54279
54345
|
const response = await fetch(`${apiBase}/health`);
|
|
@@ -54286,7 +54352,7 @@ async function checkInfraStatus() {
|
|
|
54286
54352
|
details: apiBase
|
|
54287
54353
|
}
|
|
54288
54354
|
];
|
|
54289
|
-
if (data.services) {
|
|
54355
|
+
if (!options?.remote && data.services) {
|
|
54290
54356
|
if (data.services.neo4j) {
|
|
54291
54357
|
services.push({
|
|
54292
54358
|
name: "Neo4j",
|
|
@@ -54309,10 +54375,8 @@ async function checkInfraStatus() {
|
|
|
54309
54375
|
});
|
|
54310
54376
|
}
|
|
54311
54377
|
}
|
|
54312
|
-
|
|
54313
|
-
|
|
54314
|
-
overallHealthy: services.every((s) => s.healthy)
|
|
54315
|
-
};
|
|
54378
|
+
const overallHealthy = options?.remote ? response.ok && data.status === "ok" : services.every((s) => s.healthy);
|
|
54379
|
+
return { services, overallHealthy };
|
|
54316
54380
|
} catch (error49) {
|
|
54317
54381
|
return {
|
|
54318
54382
|
services: [
|
|
@@ -54330,7 +54394,7 @@ async function checkInfraStatus() {
|
|
|
54330
54394
|
function formatStatusIndicator(healthy) {
|
|
54331
54395
|
return healthy ? source_default.green("\u2713 UP") : source_default.red("\u2717 DOWN");
|
|
54332
54396
|
}
|
|
54333
|
-
function formatInfraStatus(result) {
|
|
54397
|
+
function formatInfraStatus(result, options) {
|
|
54334
54398
|
const lines = [];
|
|
54335
54399
|
lines.push("");
|
|
54336
54400
|
lines.push(source_default.bold.cyan(" Infrastructure Status"));
|
|
@@ -54344,6 +54408,10 @@ function formatInfraStatus(result) {
|
|
|
54344
54408
|
}
|
|
54345
54409
|
}
|
|
54346
54410
|
lines.push("");
|
|
54411
|
+
if (options?.remote) {
|
|
54412
|
+
lines.push(source_default.dim(" Backend services are managed infrastructure. Contact support if issues persist."));
|
|
54413
|
+
lines.push("");
|
|
54414
|
+
}
|
|
54347
54415
|
if (result.overallHealthy) {
|
|
54348
54416
|
lines.push(` ${source_default.green.bold("All services healthy.")}`);
|
|
54349
54417
|
} else {
|
|
@@ -54357,12 +54425,13 @@ function registerInfraCommand(program2) {
|
|
|
54357
54425
|
const infra = program2.command("infra").description("Infrastructure management commands");
|
|
54358
54426
|
infra.command("status").description("Check health of API server and underlying infrastructure").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
54359
54427
|
try {
|
|
54428
|
+
const remote = await isRemoteMode();
|
|
54360
54429
|
console.log(source_default.gray(" Checking infrastructure health..."));
|
|
54361
|
-
const result = await checkInfraStatus();
|
|
54430
|
+
const result = await checkInfraStatus({ remote });
|
|
54362
54431
|
if (options.format === "json") {
|
|
54363
54432
|
console.log(JSON.stringify(result, null, 2));
|
|
54364
54433
|
} else {
|
|
54365
|
-
console.log(formatInfraStatus(result));
|
|
54434
|
+
console.log(formatInfraStatus(result, { remote }));
|
|
54366
54435
|
}
|
|
54367
54436
|
if (!result.overallHealthy) {
|
|
54368
54437
|
process.exitCode = 1;
|
|
@@ -54433,6 +54502,7 @@ function registerLoginCommand(program2) {
|
|
|
54433
54502
|
console.log("");
|
|
54434
54503
|
console.log(source_default.bold(" Trading Boy \u2014 Login"));
|
|
54435
54504
|
console.log(source_default.gray(" " + "\u2500".repeat(40)));
|
|
54505
|
+
console.log(source_default.dim(" Don't have a key? Run: trading-boy subscribe"));
|
|
54436
54506
|
console.log("");
|
|
54437
54507
|
apiKey = await password({
|
|
54438
54508
|
message: "Enter your API key",
|
|
@@ -54603,7 +54673,7 @@ function formatWhoamiOutput(result) {
|
|
|
54603
54673
|
const lines = [];
|
|
54604
54674
|
lines.push("");
|
|
54605
54675
|
if (!result.authenticated) {
|
|
54606
|
-
lines.push(source_default.dim(" Not authenticated. Run `trading-boy login` to get started."));
|
|
54676
|
+
lines.push(source_default.dim(" Not authenticated. Run `trading-boy login` or `trading-boy subscribe` to get started."));
|
|
54607
54677
|
lines.push("");
|
|
54608
54678
|
return lines.join("\n");
|
|
54609
54679
|
}
|
|
@@ -54883,9 +54953,9 @@ async function runOnboarding() {
|
|
|
54883
54953
|
console.log(source_default.gray(" " + "\u2500".repeat(50)));
|
|
54884
54954
|
console.log("");
|
|
54885
54955
|
console.log(` ${source_default.white("trading-boy context SOL")} ${source_default.dim("Full context for any token")}`);
|
|
54886
|
-
console.log(` ${source_default.white("trading-boy journal")}
|
|
54956
|
+
console.log(` ${source_default.white("trading-boy journal log entry SOL")} ${source_default.dim("Log a trade entry")}`);
|
|
54887
54957
|
console.log(` ${source_default.white("trading-boy decisions")} ${source_default.dim("View trade history")}`);
|
|
54888
|
-
console.log(` ${source_default.white("trading-boy review daily")}
|
|
54958
|
+
console.log(` ${source_default.white("trading-boy journal review daily")} ${source_default.dim("Review your daily trades")}`);
|
|
54889
54959
|
console.log(` ${source_default.white("trading-boy narrative list")} ${source_default.dim("Active market narratives")}`);
|
|
54890
54960
|
console.log(` ${source_default.white("trading-boy catalysts")} ${source_default.dim("Upcoming events")}`);
|
|
54891
54961
|
if (traderRegistered) {
|
|
@@ -55062,7 +55132,7 @@ function formatSubscribeSuccess(result) {
|
|
|
55062
55132
|
lines.push(` ${source_default.bold("API Key:")} ${source_default.yellow(result.apiKey)}`);
|
|
55063
55133
|
lines.push("");
|
|
55064
55134
|
lines.push(source_default.dim(" \u26A0\uFE0F Copy this key now \u2014 it will not be shown again."));
|
|
55065
|
-
lines.push(source_default.dim(" Use it to connect Telegram: send /start to @
|
|
55135
|
+
lines.push(source_default.dim(" Use it to connect Telegram: send /start to @TradingBoy1_Bot"));
|
|
55066
55136
|
lines.push(source_default.dim(" and paste the key when prompted."));
|
|
55067
55137
|
} else if (result.keyPrefix) {
|
|
55068
55138
|
lines.push(` ${source_default.bold("Key ID:")} ${result.keyPrefix}`);
|
|
@@ -56644,6 +56714,12 @@ function registerSuggestionsCommand(program2) {
|
|
|
56644
56714
|
cmd.help();
|
|
56645
56715
|
});
|
|
56646
56716
|
cmd.command("list").description("List strategy suggestions").option("--status <status>", "Filter by status: pending, approved, rejected", "pending").option("--strategy <id>", "Filter by strategy ID").option("--limit <n>", "Maximum results", parseInt, 20).option("--offset <n>", "Pagination offset", parseInt, 0).addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
56717
|
+
if (!await isRemoteMode()) {
|
|
56718
|
+
console.error(source_default.yellow("This command requires a remote API connection."));
|
|
56719
|
+
console.error(source_default.dim(" Run: trading-boy login or trading-boy subscribe"));
|
|
56720
|
+
process.exitCode = 1;
|
|
56721
|
+
return;
|
|
56722
|
+
}
|
|
56647
56723
|
try {
|
|
56648
56724
|
const params = new URLSearchParams();
|
|
56649
56725
|
params.set("status", options.status);
|
|
@@ -56665,6 +56741,12 @@ function registerSuggestionsCommand(program2) {
|
|
|
56665
56741
|
}
|
|
56666
56742
|
});
|
|
56667
56743
|
cmd.command("approve <id>").description("Approve a suggestion and auto-apply to strategy").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (id, options) => {
|
|
56744
|
+
if (!await isRemoteMode()) {
|
|
56745
|
+
console.error(source_default.yellow("This command requires a remote API connection."));
|
|
56746
|
+
console.error(source_default.dim(" Run: trading-boy login or trading-boy subscribe"));
|
|
56747
|
+
process.exitCode = 1;
|
|
56748
|
+
return;
|
|
56749
|
+
}
|
|
56668
56750
|
try {
|
|
56669
56751
|
const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/approve`, { method: "POST" });
|
|
56670
56752
|
if (options.format === "json") {
|
|
@@ -56682,6 +56764,12 @@ function registerSuggestionsCommand(program2) {
|
|
|
56682
56764
|
}
|
|
56683
56765
|
});
|
|
56684
56766
|
cmd.command("reject <id>").description("Reject a suggestion").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (id, options) => {
|
|
56767
|
+
if (!await isRemoteMode()) {
|
|
56768
|
+
console.error(source_default.yellow("This command requires a remote API connection."));
|
|
56769
|
+
console.error(source_default.dim(" Run: trading-boy login or trading-boy subscribe"));
|
|
56770
|
+
process.exitCode = 1;
|
|
56771
|
+
return;
|
|
56772
|
+
}
|
|
56685
56773
|
try {
|
|
56686
56774
|
const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/reject`, { method: "POST" });
|
|
56687
56775
|
if (options.format === "json") {
|
|
@@ -57049,9 +57137,21 @@ function parseHumanInterval(value) {
|
|
|
57049
57137
|
var MIN_SCAN_INTERVAL_MS = 6e4;
|
|
57050
57138
|
function registerAgentCommand(program2) {
|
|
57051
57139
|
const agent = program2.command("agent").description("Manage autonomous trading agents");
|
|
57052
|
-
agent.command("create").description("Create a new agent").
|
|
57140
|
+
agent.command("create").description("Create a new agent").option("--trader-id <traderId>", "Trader ID").option("--strategy-id <strategyId>", "Strategy ID").option("--name <name>", "Agent name").option("--autonomy <level>", "Autonomy level: OBSERVE_ONLY, SUGGEST, AUTO_WITH_APPROVAL, FULLY_AUTONOMOUS", "OBSERVE_ONLY").option("--scan-interval <ms>", "Scan interval in ms (min 60000)", "300000").option("--scan-interval-human <duration>", "Scan interval in human-readable format (e.g. 1m, 5m, 15m, 30m, 1h)").option("--watchlist <symbols>", "Comma-separated token symbols").option("--max-daily-trades <n>", "Max daily trades", "10").option("--max-daily-loss <usd>", "Max daily loss in USD", "500").option("--max-position-size <pct>", "Max position size as decimal (0.10 = 10%)", "0.10").option("--min-confidence <n>", "Min confidence threshold (0-1)", "0.60").option("--scan-model <model>", "LLM model for market scanning").option("--analyze-model <model>", "LLM model for deep analysis").option("--decide-model <model>", "LLM model for trade decisions").addOption(new Option("--asset-class <class>", "Asset class for this agent").choices(["crypto", "commodities", "mixed"]).default("crypto")).option("--soul-override <text>", "Custom soul/personality for this agent").option("--purpose-override <text>", "Custom purpose/mission for this agent").option("--soul-file <path>", "Load soul from a file").option("--purpose-file <path>", "Load purpose from a file").addOption(new Option("--format <format>", "Output format").choices(["text", "json"]).default("text")).action(async (options) => {
|
|
57053
57141
|
if (!await ensureRemote2())
|
|
57054
57142
|
return;
|
|
57143
|
+
if (!options.traderId) {
|
|
57144
|
+
console.error(source_default.red("Error: --trader-id is required."));
|
|
57145
|
+
console.log(source_default.dim(" Find yours with: trading-boy trader list"));
|
|
57146
|
+
process.exitCode = 1;
|
|
57147
|
+
return;
|
|
57148
|
+
}
|
|
57149
|
+
if (!options.strategyId) {
|
|
57150
|
+
console.error(source_default.red("Error: --strategy-id is required."));
|
|
57151
|
+
console.log(source_default.dim(" Find yours with: trading-boy strategy list"));
|
|
57152
|
+
process.exitCode = 1;
|
|
57153
|
+
return;
|
|
57154
|
+
}
|
|
57055
57155
|
const body = {
|
|
57056
57156
|
traderId: options.traderId,
|
|
57057
57157
|
strategyId: options.strategyId
|
|
@@ -57150,7 +57250,13 @@ function registerAgentCommand(program2) {
|
|
|
57150
57250
|
return;
|
|
57151
57251
|
}
|
|
57152
57252
|
if (result.agents.length === 0) {
|
|
57153
|
-
console.log(source_default.dim(" No agents found"));
|
|
57253
|
+
console.log(source_default.dim(" No agents found."));
|
|
57254
|
+
console.log("");
|
|
57255
|
+
console.log(source_default.dim(" Create one with:"));
|
|
57256
|
+
console.log(source_default.dim(" trading-boy agent create --trader-id <id> --strategy-id <id>"));
|
|
57257
|
+
console.log(source_default.dim(" Find your IDs with:"));
|
|
57258
|
+
console.log(source_default.dim(" trading-boy trader list"));
|
|
57259
|
+
console.log(source_default.dim(" trading-boy strategy list"));
|
|
57154
57260
|
return;
|
|
57155
57261
|
}
|
|
57156
57262
|
console.log("");
|
|
@@ -114,8 +114,8 @@ export function registerAgentCommand(program) {
|
|
|
114
114
|
agent
|
|
115
115
|
.command('create')
|
|
116
116
|
.description('Create a new agent')
|
|
117
|
-
.
|
|
118
|
-
.
|
|
117
|
+
.option('--trader-id <traderId>', 'Trader ID')
|
|
118
|
+
.option('--strategy-id <strategyId>', 'Strategy ID')
|
|
119
119
|
.option('--name <name>', 'Agent name')
|
|
120
120
|
.option('--autonomy <level>', 'Autonomy level: OBSERVE_ONLY, SUGGEST, AUTO_WITH_APPROVAL, FULLY_AUTONOMOUS', 'OBSERVE_ONLY')
|
|
121
121
|
.option('--scan-interval <ms>', 'Scan interval in ms (min 60000)', '300000')
|
|
@@ -137,6 +137,18 @@ export function registerAgentCommand(program) {
|
|
|
137
137
|
.action(async (options) => {
|
|
138
138
|
if (!(await ensureRemote()))
|
|
139
139
|
return;
|
|
140
|
+
if (!options.traderId) {
|
|
141
|
+
console.error(chalk.red('Error: --trader-id is required.'));
|
|
142
|
+
console.log(chalk.dim(' Find yours with: trading-boy trader list'));
|
|
143
|
+
process.exitCode = 1;
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (!options.strategyId) {
|
|
147
|
+
console.error(chalk.red('Error: --strategy-id is required.'));
|
|
148
|
+
console.log(chalk.dim(' Find yours with: trading-boy strategy list'));
|
|
149
|
+
process.exitCode = 1;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
140
152
|
const body = {
|
|
141
153
|
traderId: options.traderId,
|
|
142
154
|
strategyId: options.strategyId,
|
|
@@ -249,7 +261,13 @@ export function registerAgentCommand(program) {
|
|
|
249
261
|
return;
|
|
250
262
|
}
|
|
251
263
|
if (result.agents.length === 0) {
|
|
252
|
-
console.log(chalk.dim(' No agents found'));
|
|
264
|
+
console.log(chalk.dim(' No agents found.'));
|
|
265
|
+
console.log('');
|
|
266
|
+
console.log(chalk.dim(' Create one with:'));
|
|
267
|
+
console.log(chalk.dim(' trading-boy agent create --trader-id <id> --strategy-id <id>'));
|
|
268
|
+
console.log(chalk.dim(' Find your IDs with:'));
|
|
269
|
+
console.log(chalk.dim(' trading-boy trader list'));
|
|
270
|
+
console.log(chalk.dim(' trading-boy strategy list'));
|
|
253
271
|
return;
|
|
254
272
|
}
|
|
255
273
|
console.log('');
|
package/dist/commands/context.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Option } from 'commander';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { createLogger } from '@trading-boy/core';
|
|
4
4
|
import { formatConnectionError, colorChange, colorSentiment, colorRiskScore, formatUsd } from '../utils.js';
|
|
5
|
-
import { apiRequest, ApiError } from '../api-client.js';
|
|
5
|
+
import { isRemoteMode, apiRequest, ApiError } from '../api-client.js';
|
|
6
6
|
// ─── Logger ───
|
|
7
7
|
const logger = createLogger('cli-context');
|
|
8
8
|
// ─── Formatters ───
|
|
@@ -324,6 +324,13 @@ export function registerContextCommand(program) {
|
|
|
324
324
|
.option('--trader-id <id>', 'Trader ID for personalized context')
|
|
325
325
|
.action(async (symbol, options) => {
|
|
326
326
|
try {
|
|
327
|
+
// ─── Auth pre-flight ───
|
|
328
|
+
if (!(await isRemoteMode())) {
|
|
329
|
+
console.error(chalk.yellow('This command requires a remote API connection.'));
|
|
330
|
+
console.error(chalk.dim(' Run: trading-boy login'));
|
|
331
|
+
process.exitCode = 1;
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
327
334
|
// ─── Validate range options ───
|
|
328
335
|
if ((options.from && !options.to) || (!options.from && options.to)) {
|
|
329
336
|
console.error(chalk.red('Error: Both --from and --to must be provided for range queries.'));
|
|
@@ -368,6 +375,13 @@ export function registerContextCommand(program) {
|
|
|
368
375
|
// Live context
|
|
369
376
|
const traderQs = options.traderId ? `?traderId=${encodeURIComponent(options.traderId)}` : '';
|
|
370
377
|
const pkg = await apiRequest(`/api/v1/tokens/${encodeURIComponent(symbol.toUpperCase())}/context${traderQs}`);
|
|
378
|
+
// Check if the token was actually found
|
|
379
|
+
if (pkg.token.name == null && (!Array.isArray(pkg.token.chains) || pkg.token.chains.length === 0) && pkg.market?.price == null) {
|
|
380
|
+
console.error(chalk.red(`Error: Token not found: ${symbol.toUpperCase()}`));
|
|
381
|
+
console.error(chalk.dim(' Check the symbol and try again. Use a symbol like SOL, JUP, or BONK.'));
|
|
382
|
+
process.exitCode = 1;
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
371
385
|
if (options.format === 'json') {
|
|
372
386
|
console.log(JSON.stringify(pkg, null, 2));
|
|
373
387
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Option } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { createLogger } from '@trading-boy/core';
|
|
4
|
-
import { padRight, parseIntOption, formatDate } from '../utils.js';
|
|
4
|
+
import { padRight, parseIntOption, formatDate, formatConnectionError } from '../utils.js';
|
|
5
5
|
import { apiRequest, ApiError } from '../api-client.js';
|
|
6
6
|
// ─── Logger ───
|
|
7
7
|
const logger = createLogger('cli-decisions');
|
|
@@ -222,6 +222,12 @@ export function registerDecisionsCommand(program) {
|
|
|
222
222
|
}
|
|
223
223
|
catch (error) {
|
|
224
224
|
const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
|
|
225
|
+
const connErr = formatConnectionError(message);
|
|
226
|
+
if (connErr) {
|
|
227
|
+
console.error(connErr);
|
|
228
|
+
process.exitCode = 1;
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
225
231
|
logger.error({ error: message }, 'Failed to fetch decisions');
|
|
226
232
|
console.error(chalk.red(`Error: ${message}`));
|
|
227
233
|
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
@@ -262,6 +268,12 @@ export function registerDecisionsCommand(program) {
|
|
|
262
268
|
}
|
|
263
269
|
catch (error) {
|
|
264
270
|
const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
|
|
271
|
+
const connErr = formatConnectionError(message);
|
|
272
|
+
if (connErr) {
|
|
273
|
+
console.error(connErr);
|
|
274
|
+
process.exitCode = 1;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
265
277
|
logger.error({ error: message }, 'Failed to fetch stats');
|
|
266
278
|
console.error(chalk.red(`Error: ${message}`));
|
|
267
279
|
process.exitCode = error instanceof ApiError ? 2 : 1;
|
package/dist/commands/infra.d.ts
CHANGED
|
@@ -13,8 +13,12 @@ export interface InfraStatusResult {
|
|
|
13
13
|
* Check infrastructure health via the API /health endpoint.
|
|
14
14
|
* Falls back to a basic connectivity check if the API is unreachable.
|
|
15
15
|
*/
|
|
16
|
-
export declare function checkInfraStatus(
|
|
17
|
-
|
|
16
|
+
export declare function checkInfraStatus(options?: {
|
|
17
|
+
remote?: boolean;
|
|
18
|
+
}): Promise<InfraStatusResult>;
|
|
19
|
+
export declare function formatInfraStatus(result: InfraStatusResult, options?: {
|
|
20
|
+
remote?: boolean;
|
|
21
|
+
}): string;
|
|
18
22
|
export declare function registerInfraCommand(program: Command): void;
|
|
19
23
|
export {};
|
|
20
24
|
//# sourceMappingURL=infra.d.ts.map
|
package/dist/commands/infra.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Option } from 'commander';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { createLogger } from '@trading-boy/core';
|
|
4
4
|
import { padRight } from '../utils.js';
|
|
5
|
-
import { getApiBase } from '../api-client.js';
|
|
5
|
+
import { getApiBase, isRemoteMode } from '../api-client.js';
|
|
6
6
|
// ─── Logger ───
|
|
7
7
|
const logger = createLogger('cli-infra');
|
|
8
8
|
// ─── Health Check Logic ───
|
|
@@ -10,7 +10,7 @@ const logger = createLogger('cli-infra');
|
|
|
10
10
|
* Check infrastructure health via the API /health endpoint.
|
|
11
11
|
* Falls back to a basic connectivity check if the API is unreachable.
|
|
12
12
|
*/
|
|
13
|
-
export async function checkInfraStatus() {
|
|
13
|
+
export async function checkInfraStatus(options) {
|
|
14
14
|
const apiBase = getApiBase();
|
|
15
15
|
try {
|
|
16
16
|
// Call the API health endpoint directly (no auth needed)
|
|
@@ -24,8 +24,8 @@ export async function checkInfraStatus() {
|
|
|
24
24
|
details: apiBase,
|
|
25
25
|
},
|
|
26
26
|
];
|
|
27
|
-
//
|
|
28
|
-
if (data.services) {
|
|
27
|
+
// In remote mode, skip individual DB statuses — they are managed infrastructure
|
|
28
|
+
if (!options?.remote && data.services) {
|
|
29
29
|
if (data.services.neo4j) {
|
|
30
30
|
services.push({
|
|
31
31
|
name: 'Neo4j',
|
|
@@ -48,10 +48,12 @@ export async function checkInfraStatus() {
|
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
// In remote mode, use API response status to determine health
|
|
52
|
+
// (services array only contains API Server, but backend may be degraded)
|
|
53
|
+
const overallHealthy = options?.remote
|
|
54
|
+
? response.ok && data.status === 'ok'
|
|
55
|
+
: services.every((s) => s.healthy);
|
|
56
|
+
return { services, overallHealthy };
|
|
55
57
|
}
|
|
56
58
|
catch (error) {
|
|
57
59
|
// API is unreachable
|
|
@@ -72,7 +74,7 @@ export async function checkInfraStatus() {
|
|
|
72
74
|
function formatStatusIndicator(healthy) {
|
|
73
75
|
return healthy ? chalk.green('\u2713 UP') : chalk.red('\u2717 DOWN');
|
|
74
76
|
}
|
|
75
|
-
export function formatInfraStatus(result) {
|
|
77
|
+
export function formatInfraStatus(result, options) {
|
|
76
78
|
const lines = [];
|
|
77
79
|
lines.push('');
|
|
78
80
|
lines.push(chalk.bold.cyan(' Infrastructure Status'));
|
|
@@ -86,6 +88,10 @@ export function formatInfraStatus(result) {
|
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
lines.push('');
|
|
91
|
+
if (options?.remote) {
|
|
92
|
+
lines.push(chalk.dim(' Backend services are managed infrastructure. Contact support if issues persist.'));
|
|
93
|
+
lines.push('');
|
|
94
|
+
}
|
|
89
95
|
if (result.overallHealthy) {
|
|
90
96
|
lines.push(` ${chalk.green.bold('All services healthy.')}`);
|
|
91
97
|
}
|
|
@@ -107,13 +113,14 @@ export function registerInfraCommand(program) {
|
|
|
107
113
|
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
108
114
|
.action(async (options) => {
|
|
109
115
|
try {
|
|
116
|
+
const remote = await isRemoteMode();
|
|
110
117
|
console.log(chalk.gray(' Checking infrastructure health...'));
|
|
111
|
-
const result = await checkInfraStatus();
|
|
118
|
+
const result = await checkInfraStatus({ remote });
|
|
112
119
|
if (options.format === 'json') {
|
|
113
120
|
console.log(JSON.stringify(result, null, 2));
|
|
114
121
|
}
|
|
115
122
|
else {
|
|
116
|
-
console.log(formatInfraStatus(result));
|
|
123
|
+
console.log(formatInfraStatus(result, { remote }));
|
|
117
124
|
}
|
|
118
125
|
if (!result.overallHealthy) {
|
|
119
126
|
process.exitCode = 1;
|
package/dist/commands/journal.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Option } from 'commander';
|
|
2
|
-
import { padRight } from '../utils.js';
|
|
2
|
+
import { padRight, formatConnectionError } from '../utils.js';
|
|
3
3
|
import { apiRequest, ApiError } from '../api-client.js';
|
|
4
4
|
import { registerReviewCommand } from './review.js';
|
|
5
5
|
// ─── Default Trader ───
|
|
@@ -73,6 +73,12 @@ export function registerJournalCommand(program) {
|
|
|
73
73
|
}
|
|
74
74
|
catch (error) {
|
|
75
75
|
const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
|
|
76
|
+
const connErr = formatConnectionError(message);
|
|
77
|
+
if (connErr) {
|
|
78
|
+
console.error(connErr);
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
76
82
|
console.error(`Error: ${message}`);
|
|
77
83
|
if (error instanceof ApiError && error.body && typeof error.body === 'object') {
|
|
78
84
|
const detail = error.body.error ?? error.body.code;
|
|
@@ -118,6 +124,12 @@ export function registerJournalCommand(program) {
|
|
|
118
124
|
}
|
|
119
125
|
catch (error) {
|
|
120
126
|
const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
|
|
127
|
+
const connErr = formatConnectionError(message);
|
|
128
|
+
if (connErr) {
|
|
129
|
+
console.error(connErr);
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
121
133
|
console.error(`Error: ${message}`);
|
|
122
134
|
if (error instanceof ApiError && error.body && typeof error.body === 'object') {
|
|
123
135
|
const detail = error.body.error ?? error.body.code;
|
|
@@ -185,6 +197,12 @@ export function registerJournalCommand(program) {
|
|
|
185
197
|
}
|
|
186
198
|
catch (error) {
|
|
187
199
|
const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
|
|
200
|
+
const connErr = formatConnectionError(message);
|
|
201
|
+
if (connErr) {
|
|
202
|
+
console.error(connErr);
|
|
203
|
+
process.exitCode = 1;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
188
206
|
console.error(`Error: ${message}`);
|
|
189
207
|
if (error instanceof ApiError && error.body && typeof error.body === 'object') {
|
|
190
208
|
const detail = error.body.error ?? error.body.code;
|
|
@@ -231,6 +249,12 @@ export function registerJournalCommand(program) {
|
|
|
231
249
|
}
|
|
232
250
|
catch (error) {
|
|
233
251
|
const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
|
|
252
|
+
const connErr = formatConnectionError(message);
|
|
253
|
+
if (connErr) {
|
|
254
|
+
console.error(connErr);
|
|
255
|
+
process.exitCode = 1;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
234
258
|
console.error(`Error: ${message}`);
|
|
235
259
|
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
236
260
|
}
|
|
@@ -263,6 +287,12 @@ export function registerJournalCommand(program) {
|
|
|
263
287
|
}
|
|
264
288
|
catch (error) {
|
|
265
289
|
const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
|
|
290
|
+
const connErr = formatConnectionError(message);
|
|
291
|
+
if (connErr) {
|
|
292
|
+
console.error(connErr);
|
|
293
|
+
process.exitCode = 1;
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
266
296
|
console.error(`Error: ${message}`);
|
|
267
297
|
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
268
298
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -72,6 +72,7 @@ export function registerLoginCommand(program) {
|
|
|
72
72
|
console.log('');
|
|
73
73
|
console.log(chalk.bold(' Trading Boy — Login'));
|
|
74
74
|
console.log(chalk.gray(' ' + '─'.repeat(40)));
|
|
75
|
+
console.log(chalk.dim(' Don\'t have a key? Run: trading-boy subscribe'));
|
|
75
76
|
console.log('');
|
|
76
77
|
apiKey = await password({
|
|
77
78
|
message: 'Enter your API key',
|
|
@@ -112,7 +112,7 @@ export async function runOnboarding() {
|
|
|
112
112
|
}
|
|
113
113
|
console.log('');
|
|
114
114
|
}
|
|
115
|
-
// ─── Step 3: Telegram Bot
|
|
115
|
+
// ─── Step 3: Telegram Bot ───
|
|
116
116
|
try {
|
|
117
117
|
const wantsTelegram = await confirm({
|
|
118
118
|
message: 'Connect Telegram for daily summaries?',
|
|
@@ -136,14 +136,14 @@ export async function runOnboarding() {
|
|
|
136
136
|
throw error;
|
|
137
137
|
}
|
|
138
138
|
console.log('');
|
|
139
|
-
// ─── Step
|
|
139
|
+
// ─── Step 4: Next Steps Cheat Sheet ───
|
|
140
140
|
console.log(chalk.bold.cyan(' Quick Reference'));
|
|
141
141
|
console.log(chalk.gray(' ' + '\u2500'.repeat(50)));
|
|
142
142
|
console.log('');
|
|
143
143
|
console.log(` ${chalk.white('trading-boy context SOL')} ${chalk.dim('Full context for any token')}`);
|
|
144
|
-
console.log(` ${chalk.white('trading-boy journal')}
|
|
144
|
+
console.log(` ${chalk.white('trading-boy journal log entry SOL')} ${chalk.dim('Log a trade entry')}`);
|
|
145
145
|
console.log(` ${chalk.white('trading-boy decisions')} ${chalk.dim('View trade history')}`);
|
|
146
|
-
console.log(` ${chalk.white('trading-boy review daily')}
|
|
146
|
+
console.log(` ${chalk.white('trading-boy journal review daily')} ${chalk.dim('Review your daily trades')}`);
|
|
147
147
|
console.log(` ${chalk.white('trading-boy narrative list')} ${chalk.dim('Active market narratives')}`);
|
|
148
148
|
console.log(` ${chalk.white('trading-boy catalysts')} ${chalk.dim('Upcoming events')}`);
|
|
149
149
|
if (traderRegistered) {
|
package/dist/commands/query.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Option } from 'commander';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { createLogger } from '@trading-boy/core';
|
|
4
4
|
import { formatConnectionError } from '../utils.js';
|
|
5
|
-
import { apiRequest, ApiError } from '../api-client.js';
|
|
5
|
+
import { isRemoteMode, apiRequest, ApiError } from '../api-client.js';
|
|
6
6
|
// ─── Logger ───
|
|
7
7
|
const logger = createLogger('cli-query');
|
|
8
8
|
// ─── Formatter ───
|
|
@@ -102,6 +102,13 @@ export function registerQueryCommand(program) {
|
|
|
102
102
|
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
103
103
|
.action(async (symbol, options) => {
|
|
104
104
|
try {
|
|
105
|
+
// ─── Auth pre-flight ───
|
|
106
|
+
if (!(await isRemoteMode())) {
|
|
107
|
+
console.error(chalk.yellow('This command requires a remote API connection.'));
|
|
108
|
+
console.error(chalk.dim(' Run: trading-boy login'));
|
|
109
|
+
process.exitCode = 1;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
105
112
|
const pkg = await apiRequest(`/api/v1/tokens/${encodeURIComponent(symbol.toUpperCase())}/context`);
|
|
106
113
|
const result = contextToQueryResult(pkg);
|
|
107
114
|
// Check if the token was actually found
|
package/dist/commands/risk.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Option } from 'commander';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { createLogger } from '@trading-boy/core';
|
|
4
4
|
import { formatConnectionError, padRight } from '../utils.js';
|
|
5
|
-
import { apiRequest, ApiError } from '../api-client.js';
|
|
5
|
+
import { isRemoteMode, apiRequest, ApiError } from '../api-client.js';
|
|
6
6
|
// ─── Logger ───
|
|
7
7
|
const logger = createLogger('cli-risk');
|
|
8
8
|
// ─── Formatters ───
|
|
@@ -127,6 +127,12 @@ export function registerRiskCommand(program) {
|
|
|
127
127
|
process.exitCode = 1;
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
|
+
if (!(await isRemoteMode())) {
|
|
131
|
+
console.error(chalk.yellow('This command requires a remote API connection.'));
|
|
132
|
+
console.error(chalk.dim(' Run: trading-boy login or trading-boy subscribe'));
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
130
136
|
try {
|
|
131
137
|
const apiResult = await apiRequest(`/api/v1/protocols/${encodeURIComponent(protocol.toLowerCase())}/risk`);
|
|
132
138
|
const result = {
|
|
@@ -217,7 +217,7 @@ export function formatSubscribeSuccess(result) {
|
|
|
217
217
|
lines.push(` ${chalk.bold('API Key:')} ${chalk.yellow(result.apiKey)}`);
|
|
218
218
|
lines.push('');
|
|
219
219
|
lines.push(chalk.dim(' ⚠️ Copy this key now — it will not be shown again.'));
|
|
220
|
-
lines.push(chalk.dim(' Use it to connect Telegram: send /start to @
|
|
220
|
+
lines.push(chalk.dim(' Use it to connect Telegram: send /start to @TradingBoy1_Bot'));
|
|
221
221
|
lines.push(chalk.dim(' and paste the key when prompted.'));
|
|
222
222
|
}
|
|
223
223
|
else if (result.keyPrefix) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Option } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { createLogger } from '@trading-boy/core';
|
|
4
|
-
import { apiRequest, ApiError } from '../api-client.js';
|
|
4
|
+
import { isRemoteMode, apiRequest, ApiError } from '../api-client.js';
|
|
5
5
|
import { padRight, truncate, formatDate } from '../utils.js';
|
|
6
6
|
// ─── Logger ───
|
|
7
7
|
const logger = createLogger('cli-suggestions');
|
|
@@ -72,6 +72,12 @@ export function registerSuggestionsCommand(program) {
|
|
|
72
72
|
.option('--offset <n>', 'Pagination offset', parseInt, 0)
|
|
73
73
|
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
74
74
|
.action(async (options) => {
|
|
75
|
+
if (!(await isRemoteMode())) {
|
|
76
|
+
console.error(chalk.yellow('This command requires a remote API connection.'));
|
|
77
|
+
console.error(chalk.dim(' Run: trading-boy login or trading-boy subscribe'));
|
|
78
|
+
process.exitCode = 1;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
75
81
|
try {
|
|
76
82
|
const params = new URLSearchParams();
|
|
77
83
|
params.set('status', options.status);
|
|
@@ -100,6 +106,12 @@ export function registerSuggestionsCommand(program) {
|
|
|
100
106
|
.description('Approve a suggestion and auto-apply to strategy')
|
|
101
107
|
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
102
108
|
.action(async (id, options) => {
|
|
109
|
+
if (!(await isRemoteMode())) {
|
|
110
|
+
console.error(chalk.yellow('This command requires a remote API connection.'));
|
|
111
|
+
console.error(chalk.dim(' Run: trading-boy login or trading-boy subscribe'));
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
103
115
|
try {
|
|
104
116
|
const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/approve`, { method: 'POST' });
|
|
105
117
|
if (options.format === 'json') {
|
|
@@ -122,6 +134,12 @@ export function registerSuggestionsCommand(program) {
|
|
|
122
134
|
.description('Reject a suggestion')
|
|
123
135
|
.addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
|
|
124
136
|
.action(async (id, options) => {
|
|
137
|
+
if (!(await isRemoteMode())) {
|
|
138
|
+
console.error(chalk.yellow('This command requires a remote API connection.'));
|
|
139
|
+
console.error(chalk.dim(' Run: trading-boy login or trading-boy subscribe'));
|
|
140
|
+
process.exitCode = 1;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
125
143
|
try {
|
|
126
144
|
const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/reject`, { method: 'POST' });
|
|
127
145
|
if (options.format === 'json') {
|
package/dist/commands/whoami.js
CHANGED
|
@@ -33,7 +33,7 @@ export function formatWhoamiOutput(result) {
|
|
|
33
33
|
const lines = [];
|
|
34
34
|
lines.push('');
|
|
35
35
|
if (!result.authenticated) {
|
|
36
|
-
lines.push(chalk.dim(' Not authenticated. Run `trading-boy login` to get started.'));
|
|
36
|
+
lines.push(chalk.dim(' Not authenticated. Run `trading-boy login` or `trading-boy subscribe` to get started.'));
|
|
37
37
|
lines.push('');
|
|
38
38
|
return lines.join('\n');
|
|
39
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
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": {
|