@trading-boy/cli 1.5.0 → 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 +104 -2
- 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/journal.js +31 -1
- package/dist/commands/query.js +8 -1
- package/dist/commands/risk.js +7 -1
- package/dist/commands/suggestions-cmd.js +19 -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
|
}
|
|
@@ -56648,6 +56714,12 @@ function registerSuggestionsCommand(program2) {
|
|
|
56648
56714
|
cmd.help();
|
|
56649
56715
|
});
|
|
56650
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
|
+
}
|
|
56651
56723
|
try {
|
|
56652
56724
|
const params = new URLSearchParams();
|
|
56653
56725
|
params.set("status", options.status);
|
|
@@ -56669,6 +56741,12 @@ function registerSuggestionsCommand(program2) {
|
|
|
56669
56741
|
}
|
|
56670
56742
|
});
|
|
56671
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
|
+
}
|
|
56672
56750
|
try {
|
|
56673
56751
|
const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/approve`, { method: "POST" });
|
|
56674
56752
|
if (options.format === "json") {
|
|
@@ -56686,6 +56764,12 @@ function registerSuggestionsCommand(program2) {
|
|
|
56686
56764
|
}
|
|
56687
56765
|
});
|
|
56688
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
|
+
}
|
|
56689
56773
|
try {
|
|
56690
56774
|
const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/reject`, { method: "POST" });
|
|
56691
56775
|
if (options.format === "json") {
|
|
@@ -57053,9 +57137,21 @@ function parseHumanInterval(value) {
|
|
|
57053
57137
|
var MIN_SCAN_INTERVAL_MS = 6e4;
|
|
57054
57138
|
function registerAgentCommand(program2) {
|
|
57055
57139
|
const agent = program2.command("agent").description("Manage autonomous trading agents");
|
|
57056
|
-
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) => {
|
|
57057
57141
|
if (!await ensureRemote2())
|
|
57058
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
|
+
}
|
|
57059
57155
|
const body = {
|
|
57060
57156
|
traderId: options.traderId,
|
|
57061
57157
|
strategyId: options.strategyId
|
|
@@ -57154,7 +57250,13 @@ function registerAgentCommand(program2) {
|
|
|
57154
57250
|
return;
|
|
57155
57251
|
}
|
|
57156
57252
|
if (result.agents.length === 0) {
|
|
57157
|
-
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"));
|
|
57158
57260
|
return;
|
|
57159
57261
|
}
|
|
57160
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/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/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 = {
|
|
@@ -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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "1.5.
|
|
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": {
|