@trading-boy/cli 1.12.0 → 2.0.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.
Files changed (84) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +64 -29
  3. package/dist/api-client.d.ts +4 -7
  4. package/dist/api-client.js +8 -13
  5. package/dist/cli.bundle.js +2314 -33711
  6. package/dist/credentials.js +1 -1
  7. package/dist/index.d.ts +0 -28
  8. package/dist/index.js +0 -24
  9. package/dist/logger.d.ts +8 -0
  10. package/dist/logger.js +12 -0
  11. package/dist/utils.js +3 -3
  12. package/package.json +30 -16
  13. package/dist/cli.d.ts +0 -5
  14. package/dist/cli.js +0 -157
  15. package/dist/commands/agent-cmd.d.ts +0 -9
  16. package/dist/commands/agent-cmd.js +0 -567
  17. package/dist/commands/audit.d.ts +0 -18
  18. package/dist/commands/audit.js +0 -73
  19. package/dist/commands/behavioral.d.ts +0 -73
  20. package/dist/commands/behavioral.js +0 -349
  21. package/dist/commands/benchmark-cmd.d.ts +0 -3
  22. package/dist/commands/benchmark-cmd.js +0 -191
  23. package/dist/commands/billing.d.ts +0 -12
  24. package/dist/commands/billing.js +0 -142
  25. package/dist/commands/catalysts.d.ts +0 -17
  26. package/dist/commands/catalysts.js +0 -151
  27. package/dist/commands/coaching-cmd.d.ts +0 -16
  28. package/dist/commands/coaching-cmd.js +0 -222
  29. package/dist/commands/config-cmd.d.ts +0 -30
  30. package/dist/commands/config-cmd.js +0 -515
  31. package/dist/commands/connect-chatgpt.d.ts +0 -5
  32. package/dist/commands/connect-chatgpt.js +0 -293
  33. package/dist/commands/connect-claude.d.ts +0 -5
  34. package/dist/commands/connect-claude.js +0 -280
  35. package/dist/commands/context.d.ts +0 -41
  36. package/dist/commands/context.js +0 -405
  37. package/dist/commands/cron-cmd.d.ts +0 -3
  38. package/dist/commands/cron-cmd.js +0 -305
  39. package/dist/commands/decisions.d.ts +0 -57
  40. package/dist/commands/decisions.js +0 -364
  41. package/dist/commands/edge-cmd.d.ts +0 -78
  42. package/dist/commands/edge-cmd.js +0 -183
  43. package/dist/commands/edge-guard-cmd.d.ts +0 -36
  44. package/dist/commands/edge-guard-cmd.js +0 -169
  45. package/dist/commands/events.d.ts +0 -3
  46. package/dist/commands/events.js +0 -117
  47. package/dist/commands/infra.d.ts +0 -24
  48. package/dist/commands/infra.js +0 -137
  49. package/dist/commands/journal.d.ts +0 -3
  50. package/dist/commands/journal.js +0 -302
  51. package/dist/commands/login.d.ts +0 -18
  52. package/dist/commands/login.js +0 -127
  53. package/dist/commands/logout.d.ts +0 -8
  54. package/dist/commands/logout.js +0 -108
  55. package/dist/commands/narratives.d.ts +0 -3
  56. package/dist/commands/narratives.js +0 -259
  57. package/dist/commands/onboarding.d.ts +0 -7
  58. package/dist/commands/onboarding.js +0 -281
  59. package/dist/commands/query.d.ts +0 -32
  60. package/dist/commands/query.js +0 -135
  61. package/dist/commands/replay-cmd.d.ts +0 -43
  62. package/dist/commands/replay-cmd.js +0 -184
  63. package/dist/commands/review.d.ts +0 -3
  64. package/dist/commands/review.js +0 -443
  65. package/dist/commands/risk.d.ts +0 -47
  66. package/dist/commands/risk.js +0 -158
  67. package/dist/commands/social.d.ts +0 -43
  68. package/dist/commands/social.js +0 -318
  69. package/dist/commands/soul-wizard.d.ts +0 -29
  70. package/dist/commands/soul-wizard.js +0 -155
  71. package/dist/commands/strategy-cmd.d.ts +0 -44
  72. package/dist/commands/strategy-cmd.js +0 -335
  73. package/dist/commands/subscribe.d.ts +0 -78
  74. package/dist/commands/subscribe.js +0 -552
  75. package/dist/commands/suggestions-cmd.d.ts +0 -24
  76. package/dist/commands/suggestions-cmd.js +0 -148
  77. package/dist/commands/thesis-cmd.d.ts +0 -3
  78. package/dist/commands/thesis-cmd.js +0 -129
  79. package/dist/commands/trader.d.ts +0 -30
  80. package/dist/commands/trader.js +0 -971
  81. package/dist/commands/watch.d.ts +0 -16
  82. package/dist/commands/watch.js +0 -104
  83. package/dist/commands/whoami.d.ts +0 -14
  84. package/dist/commands/whoami.js +0 -105
@@ -1,135 +0,0 @@
1
- import { Option } from 'commander';
2
- import chalk from 'chalk';
3
- import { createLogger } from '@trading-boy/core';
4
- import { formatConnectionError, ensureRemote } from '../utils.js';
5
- import { apiRequest, ApiError } from '../api-client.js';
6
- // ─── Logger ───
7
- const logger = createLogger('cli-query');
8
- // ─── Formatter ───
9
- export function formatQueryOutput(result) {
10
- const lines = [];
11
- // Header
12
- lines.push('');
13
- lines.push(chalk.bold.cyan(` ${result.token.symbol}`) + (result.token.name ? chalk.gray(` (${result.token.name})`) : ''));
14
- lines.push(chalk.gray(' ' + '─'.repeat(50)));
15
- // Chains
16
- if (result.token.chains.length > 0) {
17
- lines.push(` ${chalk.gray('Chains:')} ${result.token.chains.join(', ')}`);
18
- }
19
- else {
20
- lines.push(` ${chalk.gray('Chains:')} ${chalk.dim('none')}`);
21
- }
22
- // Narratives
23
- if (result.token.narratives.length > 0) {
24
- const narrs = result.token.narratives
25
- .map((n) => `${n.name} ${chalk.dim(`(${n.status})`)}`)
26
- .join(', ');
27
- lines.push(` ${chalk.gray('Narratives:')} ${narrs}`);
28
- }
29
- else {
30
- lines.push(` ${chalk.gray('Narratives:')} ${chalk.dim('none')}`);
31
- }
32
- lines.push('');
33
- // Price
34
- if (result.price.price !== null) {
35
- const priceStr = `$${result.price.price.toLocaleString('en-US', {
36
- minimumFractionDigits: 2,
37
- maximumFractionDigits: 6,
38
- })}`;
39
- lines.push(` ${chalk.gray('Price:')} ${chalk.white.bold(priceStr)}`);
40
- if (result.price.change24h !== null) {
41
- const changeStr = `${result.price.change24h >= 0 ? '+' : ''}${result.price.change24h.toFixed(2)}%`;
42
- const colorFn = result.price.change24h >= 0 ? chalk.green : chalk.red;
43
- lines.push(` ${chalk.gray('24h Change:')} ${colorFn(changeStr)}`);
44
- }
45
- else {
46
- lines.push(` ${chalk.gray('24h Change:')} ${chalk.dim('n/a')}`);
47
- }
48
- }
49
- else {
50
- lines.push(` ${chalk.gray('Price:')} ${chalk.dim('no data')}`);
51
- }
52
- // Funding rate
53
- if (result.funding.fundingRate !== null) {
54
- const rateStr = `${result.funding.fundingRate >= 0 ? '+' : ''}${(result.funding.fundingRate * 100).toFixed(4)}%`;
55
- const colorFn = result.funding.fundingRate >= 0 ? chalk.green : chalk.red;
56
- lines.push(` ${chalk.gray('Funding:')} ${colorFn(rateStr)}`);
57
- }
58
- else {
59
- lines.push(` ${chalk.gray('Funding:')} ${chalk.dim('no perp data')}`);
60
- }
61
- // Whale activity
62
- lines.push(` ${chalk.gray('Whales:')} ${result.whaleActivity.count > 0 ? chalk.yellow(String(result.whaleActivity.count)) : chalk.dim('0')} active`);
63
- // Last updated
64
- if (result.price.lastUpdated) {
65
- const timeStr = new Date(result.price.lastUpdated).toLocaleString();
66
- lines.push('');
67
- lines.push(` ${chalk.dim(`Last updated: ${timeStr}`)}`);
68
- }
69
- lines.push('');
70
- return lines.join('\n');
71
- }
72
- // ─── API Response → QueryResult Mapper ───
73
- function contextToQueryResult(pkg) {
74
- return {
75
- token: {
76
- name: pkg.token.name ?? null,
77
- symbol: pkg.token.symbol,
78
- chains: Array.isArray(pkg.token.chains) ? pkg.token.chains : [],
79
- narratives: Array.isArray(pkg.social?.narrativeMembership)
80
- ? pkg.social.narrativeMembership.map((n) => ({ name: n.narrative, status: n.status }))
81
- : [],
82
- },
83
- price: {
84
- price: pkg.market?.price ?? null,
85
- change24h: pkg.market?.priceChange24h ?? null,
86
- lastUpdated: pkg._meta?.assembledAt ? new Date(pkg._meta.assembledAt) : null,
87
- },
88
- funding: {
89
- fundingRate: pkg.market?.fundingRate ?? null,
90
- lastUpdated: null,
91
- },
92
- whaleActivity: {
93
- count: pkg.onchain?.whaleTransactions24h ?? 0,
94
- },
95
- };
96
- }
97
- // ─── Command Registration ───
98
- export function registerQueryCommand(program) {
99
- program
100
- .command('query <symbol>')
101
- .description('Query token info, price, funding rate, and whale activity')
102
- .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
103
- .action(async (symbol, options) => {
104
- try {
105
- // ─── Auth pre-flight ───
106
- if (!(await ensureRemote()))
107
- return;
108
- const pkg = await apiRequest(`/api/v1/tokens/${encodeURIComponent(symbol.toUpperCase())}/context`);
109
- const result = contextToQueryResult(pkg);
110
- // Check if the token was actually found
111
- if (result.token.name === null && result.token.chains.length === 0 && result.price.price === null) {
112
- console.error(chalk.red(`Error: Token not found: ${symbol.toUpperCase()}`));
113
- console.error(chalk.dim(' Check the symbol and try again. Use a symbol like SOL, JUP, or BONK.'));
114
- process.exitCode = 1;
115
- return;
116
- }
117
- if (options.format === 'json') {
118
- console.log(JSON.stringify(result, null, 2));
119
- }
120
- else {
121
- console.log(formatQueryOutput(result));
122
- }
123
- }
124
- catch (error) {
125
- const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
126
- logger.error({ error: message }, 'Query failed');
127
- console.error(chalk.red(`Error: ${message}`));
128
- const guidance = formatConnectionError(message);
129
- if (guidance)
130
- console.error(guidance);
131
- process.exitCode = error instanceof ApiError ? 2 : 1;
132
- }
133
- });
134
- }
135
- //# sourceMappingURL=query.js.map
@@ -1,43 +0,0 @@
1
- import { Command } from 'commander';
2
- interface ReplayTrade {
3
- entryTime: string;
4
- exitTime?: string;
5
- direction: string;
6
- setupType?: string;
7
- entryPrice: number;
8
- exitPrice?: number;
9
- pnlPercent?: number;
10
- pnlAbsolute?: number;
11
- regime?: string;
12
- }
13
- interface ReplayRegimeBreakdown {
14
- regime: string;
15
- trades: number;
16
- winRate: number;
17
- avgPnlPercent: number;
18
- }
19
- interface ReplayResult {
20
- jobId: string;
21
- strategyId: string;
22
- tokenSymbol: string;
23
- from: string;
24
- to: string;
25
- status: 'COMPLETE' | 'FAILED';
26
- error?: string;
27
- summary?: {
28
- totalTrades: number;
29
- winRate: number;
30
- avgPnlPercent: number;
31
- totalPnlPercent: number;
32
- maxDrawdownPercent: number;
33
- sharpeRatio?: number;
34
- profitFactor?: number;
35
- };
36
- regimeBreakdown?: ReplayRegimeBreakdown[];
37
- trades?: ReplayTrade[];
38
- completedAt?: string;
39
- }
40
- export declare function formatReplayResult(result: ReplayResult): string;
41
- export declare function registerReplayCommand(program: Command): void;
42
- export {};
43
- //# sourceMappingURL=replay-cmd.d.ts.map
@@ -1,184 +0,0 @@
1
- import { Option } from 'commander';
2
- import chalk from 'chalk';
3
- import { createLogger } from '@trading-boy/core';
4
- import { apiRequest } from '../api-client.js';
5
- import { padRight, handleApiError, ensureRemote } from '../utils.js';
6
- // ─── Logger ───
7
- const logger = createLogger('cli-replay');
8
- // ─── Helpers ───
9
- function formatPercent(val) {
10
- const sign = val >= 0 ? '+' : '';
11
- const str = `${sign}${val.toFixed(2)}%`;
12
- return val >= 0 ? chalk.green(str) : chalk.red(str);
13
- }
14
- function formatShortDate(isoString) {
15
- try {
16
- return new Date(isoString).toISOString().slice(0, 10);
17
- }
18
- catch {
19
- return isoString;
20
- }
21
- }
22
- // ─── Formatters ───
23
- export function formatReplayResult(result) {
24
- const lines = [];
25
- lines.push('');
26
- lines.push(chalk.bold.cyan(` Replay Results — ${result.tokenSymbol} (strategy: ${result.strategyId})`));
27
- lines.push(chalk.gray(' ' + '─'.repeat(60)));
28
- lines.push('');
29
- if (result.status === 'FAILED') {
30
- lines.push(chalk.red(` Replay failed: ${result.error ?? 'Unknown error'}`));
31
- lines.push('');
32
- return lines.join('\n');
33
- }
34
- lines.push(` ${chalk.gray('Period:')} ${formatShortDate(result.from)} → ${formatShortDate(result.to)}`);
35
- if (result.completedAt) {
36
- lines.push(` ${chalk.gray('Completed:')} ${chalk.dim(new Date(result.completedAt).toISOString().slice(0, 19).replace('T', ' '))}`);
37
- }
38
- if (result.summary) {
39
- const s = result.summary;
40
- lines.push('');
41
- lines.push(chalk.bold(' Summary'));
42
- lines.push(` ${chalk.gray('Total Trades:')} ${chalk.white(String(s.totalTrades))}`);
43
- lines.push(` ${chalk.gray('Win Rate:')} ${formatWinRate(s.winRate)}`);
44
- lines.push(` ${chalk.gray('Avg PnL %:')} ${formatPercent(s.avgPnlPercent)}`);
45
- lines.push(` ${chalk.gray('Total PnL %:')} ${formatPercent(s.totalPnlPercent)}`);
46
- lines.push(` ${chalk.gray('Max Drawdown:')} ${chalk.red('-' + Math.abs(s.maxDrawdownPercent).toFixed(2) + '%')}`);
47
- if (s.sharpeRatio !== undefined) {
48
- const sharpeColor = s.sharpeRatio >= 1.0 ? chalk.green : s.sharpeRatio >= 0.5 ? chalk.yellow : chalk.red;
49
- lines.push(` ${chalk.gray('Sharpe Ratio:')} ${sharpeColor(s.sharpeRatio.toFixed(2))}`);
50
- }
51
- if (s.profitFactor !== undefined) {
52
- const pfColor = s.profitFactor >= 1.5 ? chalk.green : s.profitFactor >= 1.0 ? chalk.yellow : chalk.red;
53
- lines.push(` ${chalk.gray('Profit Factor:')} ${pfColor(s.profitFactor.toFixed(2))}`);
54
- }
55
- }
56
- if (result.regimeBreakdown && result.regimeBreakdown.length > 0) {
57
- lines.push('');
58
- lines.push(chalk.bold(' Regime Breakdown'));
59
- lines.push(' ' +
60
- padRight('Regime', 20) +
61
- padRight('Trades', 8) +
62
- padRight('Win Rate', 10) +
63
- 'Avg PnL %');
64
- lines.push(chalk.gray(' ' + '─'.repeat(48)));
65
- for (const r of result.regimeBreakdown) {
66
- lines.push(' ' +
67
- padRight(r.regime, 20) +
68
- padRight(String(r.trades), 8) +
69
- padRight(formatWinRate(r.winRate), 10) +
70
- formatPercent(r.avgPnlPercent));
71
- }
72
- }
73
- lines.push('');
74
- return lines.join('\n');
75
- }
76
- function formatWinRate(rate) {
77
- const str = `${(rate * 100).toFixed(1)}%`;
78
- if (rate >= 0.6)
79
- return chalk.green(str);
80
- if (rate >= 0.4)
81
- return chalk.yellow(str);
82
- return chalk.red(str);
83
- }
84
- // ─── Polling ───
85
- const POLL_INTERVAL_MS = 2000;
86
- const POLL_TIMEOUT_MS = 60000;
87
- async function pollReplayJob(jobId) {
88
- const deadline = Date.now() + POLL_TIMEOUT_MS;
89
- while (Date.now() < deadline) {
90
- const status = await apiRequest(`/api/v1/replay/${encodeURIComponent(jobId)}`);
91
- if (status.status === 'COMPLETE' || status.status === 'FAILED') {
92
- return status;
93
- }
94
- // Wait before next poll
95
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
96
- }
97
- throw new Error(`Replay job ${jobId} did not complete within ${POLL_TIMEOUT_MS / 1000}s timeout.`);
98
- }
99
- // ─── Command Registration ───
100
- export function registerReplayCommand(program) {
101
- program
102
- .command('replay')
103
- .description('Run strategy replay (backtest) over a historical period')
104
- .requiredOption('--strategy <id>', 'Strategy ID')
105
- .requiredOption('--token <symbol>', 'Token symbol')
106
- .requiredOption('--from <date>', 'Start date (ISO-8601, e.g. 2025-01-01)')
107
- .requiredOption('--to <date>', 'End date (ISO-8601, e.g. 2025-03-01)')
108
- .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
109
- .action(async (options) => {
110
- if (!(await ensureRemote()))
111
- return;
112
- // Validate dates
113
- const fromDate = new Date(options.from);
114
- const toDate = new Date(options.to);
115
- if (isNaN(fromDate.getTime())) {
116
- console.error(chalk.red(`Error: Invalid --from date: ${options.from}`));
117
- process.exitCode = 1;
118
- return;
119
- }
120
- if (isNaN(toDate.getTime())) {
121
- console.error(chalk.red(`Error: Invalid --to date: ${options.to}`));
122
- process.exitCode = 1;
123
- return;
124
- }
125
- if (fromDate >= toDate) {
126
- console.error(chalk.red('Error: --from must be before --to'));
127
- process.exitCode = 1;
128
- return;
129
- }
130
- // Use createSpinner for TTY-aware spinners (silent when piped)
131
- const { createSpinner } = await import('../utils.js');
132
- // ─── Submit replay job ───
133
- let jobId;
134
- const submitSpinner = (await createSpinner('Submitting replay job…')).start();
135
- try {
136
- const submitted = await apiRequest('/api/v1/replay', {
137
- method: 'POST',
138
- body: {
139
- strategyId: options.strategy,
140
- tokenSymbol: options.token.toUpperCase(),
141
- from: fromDate.toISOString(),
142
- to: toDate.toISOString(),
143
- },
144
- });
145
- jobId = submitted.jobId;
146
- submitSpinner.succeed(chalk.dim(`Job submitted: ${jobId}`));
147
- }
148
- catch (error) {
149
- submitSpinner.fail('Failed to submit replay job');
150
- handleApiError(error, 'Replay submit failed', logger);
151
- return;
152
- }
153
- // ─── Poll until complete ───
154
- const pollSpinner = (await createSpinner('Running replay…')).start();
155
- let finalStatus;
156
- try {
157
- finalStatus = await pollReplayJob(jobId);
158
- pollSpinner.stop();
159
- }
160
- catch (error) {
161
- pollSpinner.fail('Replay timed out or encountered an error');
162
- handleApiError(error, 'Replay polling failed', logger);
163
- return;
164
- }
165
- // ─── Display results ───
166
- if (!finalStatus.result) {
167
- if (finalStatus.status === 'FAILED') {
168
- console.error(chalk.red(`Error: Replay job failed — ${finalStatus.error ?? 'unknown error'}`));
169
- }
170
- else {
171
- console.error(chalk.red('Error: Replay completed but returned no result data.'));
172
- }
173
- process.exitCode = 1;
174
- return;
175
- }
176
- if (options.format === 'json') {
177
- console.log(JSON.stringify(finalStatus.result, null, 2));
178
- }
179
- else {
180
- console.log(formatReplayResult(finalStatus.result));
181
- }
182
- });
183
- }
184
- //# sourceMappingURL=replay-cmd.js.map
@@ -1,3 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerReviewCommand(journal: Command): void;
3
- //# sourceMappingURL=review.d.ts.map