@tradingboy/cli 0.3.8

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 (142) hide show
  1. package/README.md +8 -0
  2. package/dist/api-client.d.ts +35 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +165 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/cli.d.ts +5 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +143 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/commands/audit.d.ts +18 -0
  11. package/dist/commands/audit.d.ts.map +1 -0
  12. package/dist/commands/audit.js +73 -0
  13. package/dist/commands/audit.js.map +1 -0
  14. package/dist/commands/behavioral.d.ts +73 -0
  15. package/dist/commands/behavioral.d.ts.map +1 -0
  16. package/dist/commands/behavioral.js +349 -0
  17. package/dist/commands/behavioral.js.map +1 -0
  18. package/dist/commands/benchmark-cmd.d.ts +3 -0
  19. package/dist/commands/benchmark-cmd.d.ts.map +1 -0
  20. package/dist/commands/benchmark-cmd.js +196 -0
  21. package/dist/commands/benchmark-cmd.js.map +1 -0
  22. package/dist/commands/billing.d.ts +12 -0
  23. package/dist/commands/billing.d.ts.map +1 -0
  24. package/dist/commands/billing.js +117 -0
  25. package/dist/commands/billing.js.map +1 -0
  26. package/dist/commands/catalysts.d.ts +17 -0
  27. package/dist/commands/catalysts.d.ts.map +1 -0
  28. package/dist/commands/catalysts.js +151 -0
  29. package/dist/commands/catalysts.js.map +1 -0
  30. package/dist/commands/coaching-cmd.d.ts +16 -0
  31. package/dist/commands/coaching-cmd.d.ts.map +1 -0
  32. package/dist/commands/coaching-cmd.js +231 -0
  33. package/dist/commands/coaching-cmd.js.map +1 -0
  34. package/dist/commands/config-cmd.d.ts +30 -0
  35. package/dist/commands/config-cmd.d.ts.map +1 -0
  36. package/dist/commands/config-cmd.js +378 -0
  37. package/dist/commands/config-cmd.js.map +1 -0
  38. package/dist/commands/context.d.ts +41 -0
  39. package/dist/commands/context.d.ts.map +1 -0
  40. package/dist/commands/context.js +391 -0
  41. package/dist/commands/context.js.map +1 -0
  42. package/dist/commands/decisions.d.ts +57 -0
  43. package/dist/commands/decisions.d.ts.map +1 -0
  44. package/dist/commands/decisions.js +352 -0
  45. package/dist/commands/decisions.js.map +1 -0
  46. package/dist/commands/edge-cmd.d.ts +78 -0
  47. package/dist/commands/edge-cmd.d.ts.map +1 -0
  48. package/dist/commands/edge-cmd.js +185 -0
  49. package/dist/commands/edge-cmd.js.map +1 -0
  50. package/dist/commands/edge-guard-cmd.d.ts +36 -0
  51. package/dist/commands/edge-guard-cmd.d.ts.map +1 -0
  52. package/dist/commands/edge-guard-cmd.js +174 -0
  53. package/dist/commands/edge-guard-cmd.js.map +1 -0
  54. package/dist/commands/events.d.ts +3 -0
  55. package/dist/commands/events.d.ts.map +1 -0
  56. package/dist/commands/events.js +117 -0
  57. package/dist/commands/events.js.map +1 -0
  58. package/dist/commands/infra.d.ts +20 -0
  59. package/dist/commands/infra.d.ts.map +1 -0
  60. package/dist/commands/infra.js +130 -0
  61. package/dist/commands/infra.js.map +1 -0
  62. package/dist/commands/journal.d.ts +3 -0
  63. package/dist/commands/journal.d.ts.map +1 -0
  64. package/dist/commands/journal.js +281 -0
  65. package/dist/commands/journal.js.map +1 -0
  66. package/dist/commands/login.d.ts +18 -0
  67. package/dist/commands/login.d.ts.map +1 -0
  68. package/dist/commands/login.js +121 -0
  69. package/dist/commands/login.js.map +1 -0
  70. package/dist/commands/logout.d.ts +7 -0
  71. package/dist/commands/logout.d.ts.map +1 -0
  72. package/dist/commands/logout.js +39 -0
  73. package/dist/commands/logout.js.map +1 -0
  74. package/dist/commands/narratives.d.ts +3 -0
  75. package/dist/commands/narratives.d.ts.map +1 -0
  76. package/dist/commands/narratives.js +259 -0
  77. package/dist/commands/narratives.js.map +1 -0
  78. package/dist/commands/onboarding.d.ts +7 -0
  79. package/dist/commands/onboarding.d.ts.map +1 -0
  80. package/dist/commands/onboarding.js +126 -0
  81. package/dist/commands/onboarding.js.map +1 -0
  82. package/dist/commands/query.d.ts +32 -0
  83. package/dist/commands/query.d.ts.map +1 -0
  84. package/dist/commands/query.js +132 -0
  85. package/dist/commands/query.js.map +1 -0
  86. package/dist/commands/replay-cmd.d.ts +43 -0
  87. package/dist/commands/replay-cmd.d.ts.map +1 -0
  88. package/dist/commands/replay-cmd.js +215 -0
  89. package/dist/commands/replay-cmd.js.map +1 -0
  90. package/dist/commands/review.d.ts +3 -0
  91. package/dist/commands/review.d.ts.map +1 -0
  92. package/dist/commands/review.js +443 -0
  93. package/dist/commands/review.js.map +1 -0
  94. package/dist/commands/risk.d.ts +47 -0
  95. package/dist/commands/risk.d.ts.map +1 -0
  96. package/dist/commands/risk.js +156 -0
  97. package/dist/commands/risk.js.map +1 -0
  98. package/dist/commands/social.d.ts +43 -0
  99. package/dist/commands/social.d.ts.map +1 -0
  100. package/dist/commands/social.js +318 -0
  101. package/dist/commands/social.js.map +1 -0
  102. package/dist/commands/strategy-cmd.d.ts +44 -0
  103. package/dist/commands/strategy-cmd.d.ts.map +1 -0
  104. package/dist/commands/strategy-cmd.js +367 -0
  105. package/dist/commands/strategy-cmd.js.map +1 -0
  106. package/dist/commands/subscribe.d.ts +72 -0
  107. package/dist/commands/subscribe.d.ts.map +1 -0
  108. package/dist/commands/subscribe.js +480 -0
  109. package/dist/commands/subscribe.js.map +1 -0
  110. package/dist/commands/suggestions-cmd.d.ts +24 -0
  111. package/dist/commands/suggestions-cmd.d.ts.map +1 -0
  112. package/dist/commands/suggestions-cmd.js +142 -0
  113. package/dist/commands/suggestions-cmd.js.map +1 -0
  114. package/dist/commands/thesis-cmd.d.ts +3 -0
  115. package/dist/commands/thesis-cmd.d.ts.map +1 -0
  116. package/dist/commands/thesis-cmd.js +132 -0
  117. package/dist/commands/thesis-cmd.js.map +1 -0
  118. package/dist/commands/trader.d.ts +29 -0
  119. package/dist/commands/trader.d.ts.map +1 -0
  120. package/dist/commands/trader.js +292 -0
  121. package/dist/commands/trader.js.map +1 -0
  122. package/dist/commands/watch.d.ts +16 -0
  123. package/dist/commands/watch.d.ts.map +1 -0
  124. package/dist/commands/watch.js +88 -0
  125. package/dist/commands/watch.js.map +1 -0
  126. package/dist/commands/whoami.d.ts +14 -0
  127. package/dist/commands/whoami.d.ts.map +1 -0
  128. package/dist/commands/whoami.js +89 -0
  129. package/dist/commands/whoami.js.map +1 -0
  130. package/dist/credentials.d.ts +18 -0
  131. package/dist/credentials.d.ts.map +1 -0
  132. package/dist/credentials.js +168 -0
  133. package/dist/credentials.js.map +1 -0
  134. package/dist/index.d.ts +33 -0
  135. package/dist/index.d.ts.map +1 -0
  136. package/dist/index.js +28 -0
  137. package/dist/index.js.map +1 -0
  138. package/dist/utils.d.ts +51 -0
  139. package/dist/utils.d.ts.map +1 -0
  140. package/dist/utils.js +118 -0
  141. package/dist/utils.js.map +1 -0
  142. package/package.json +38 -0
@@ -0,0 +1,142 @@
1
+ import { Option } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { createLogger } from '@trading-boy/core';
4
+ import { apiRequest, ApiError } from '../api-client.js';
5
+ import { padRight, truncate, formatDate } from '../utils.js';
6
+ // ─── Logger ───
7
+ const logger = createLogger('cli-suggestions');
8
+ // ─── Formatters ───
9
+ export function formatSuggestionsList(data) {
10
+ const lines = [];
11
+ lines.push('');
12
+ lines.push(chalk.bold.cyan(' Suggestions'));
13
+ lines.push(chalk.gray(' ' + '─'.repeat(90)));
14
+ lines.push('');
15
+ if (data.suggestions.length === 0) {
16
+ lines.push(` ${chalk.dim('No suggestions found.')}`);
17
+ lines.push('');
18
+ return lines.join('\n');
19
+ }
20
+ // Header
21
+ lines.push(' ' +
22
+ padRight('ID', 14) +
23
+ padRight('Parameter', 30) +
24
+ padRight('Suggested', 16) +
25
+ padRight('Confidence', 12) +
26
+ padRight('Status', 12) +
27
+ 'Date');
28
+ lines.push(' ' + '─'.repeat(90));
29
+ for (const s of data.suggestions) {
30
+ const id = truncate(s.id, 12);
31
+ const param = truncate(s.parameter, 28);
32
+ const value = truncate(String(s.suggested_value), 14);
33
+ const conf = `${(s.confidence * 100).toFixed(0)}%`;
34
+ const status = colorStatus(s.status);
35
+ const date = formatDate(s.created_at);
36
+ lines.push(' ' +
37
+ padRight(id, 14) +
38
+ padRight(param, 30) +
39
+ padRight(value, 16) +
40
+ padRight(conf, 12) +
41
+ padRight(status, 12) +
42
+ date);
43
+ }
44
+ lines.push('');
45
+ lines.push(` ${chalk.gray(`Showing ${data.suggestions.length} of ${data.count} suggestion(s)`)}`);
46
+ lines.push('');
47
+ return lines.join('\n');
48
+ }
49
+ function colorStatus(status) {
50
+ switch (status) {
51
+ case 'pending': return chalk.yellow(status);
52
+ case 'approved': return chalk.green(status);
53
+ case 'rejected': return chalk.red(status);
54
+ default: return chalk.dim(status);
55
+ }
56
+ }
57
+ // ─── Command Registration ───
58
+ export function registerSuggestionsCommand(program) {
59
+ const cmd = program
60
+ .command('suggestions')
61
+ .description('View and manage strategy improvement suggestions')
62
+ .action(() => {
63
+ cmd.help();
64
+ });
65
+ // suggestions list
66
+ cmd
67
+ .command('list')
68
+ .description('List strategy suggestions')
69
+ .option('--status <status>', 'Filter by status: pending, approved, rejected', 'pending')
70
+ .option('--strategy <id>', 'Filter by strategy ID')
71
+ .option('--limit <n>', 'Maximum results', parseInt, 20)
72
+ .option('--offset <n>', 'Pagination offset', parseInt, 0)
73
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
74
+ .action(async (options) => {
75
+ try {
76
+ const params = new URLSearchParams();
77
+ params.set('status', options.status);
78
+ if (options.strategy)
79
+ params.set('strategyId', options.strategy);
80
+ params.set('limit', String(options.limit));
81
+ params.set('offset', String(options.offset));
82
+ const data = await apiRequest(`/api/v1/suggestions?${params.toString()}`);
83
+ if (options.format === 'json') {
84
+ console.log(JSON.stringify(data, null, 2));
85
+ }
86
+ else {
87
+ console.log(formatSuggestionsList(data));
88
+ }
89
+ }
90
+ catch (error) {
91
+ const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
92
+ logger.error({ error: message }, 'Failed to list suggestions');
93
+ console.error(chalk.red(`Error: ${message}`));
94
+ process.exitCode = error instanceof ApiError ? 2 : 1;
95
+ }
96
+ });
97
+ // suggestions approve <id>
98
+ cmd
99
+ .command('approve <id>')
100
+ .description('Approve a suggestion and auto-apply to strategy')
101
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
102
+ .action(async (id, options) => {
103
+ try {
104
+ const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/approve`, { method: 'POST' });
105
+ if (options.format === 'json') {
106
+ console.log(JSON.stringify(data, null, 2));
107
+ }
108
+ else {
109
+ console.log(chalk.green(`\n ✓ Suggestion ${data.id} approved. Strategy ${data.strategyId} updated.\n`));
110
+ }
111
+ }
112
+ catch (error) {
113
+ const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
114
+ logger.error({ error: message }, 'Failed to approve suggestion');
115
+ console.error(chalk.red(`Error: ${message}`));
116
+ process.exitCode = error instanceof ApiError ? 2 : 1;
117
+ }
118
+ });
119
+ // suggestions reject <id>
120
+ cmd
121
+ .command('reject <id>')
122
+ .description('Reject a suggestion')
123
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
124
+ .action(async (id, options) => {
125
+ try {
126
+ const data = await apiRequest(`/api/v1/suggestions/${encodeURIComponent(id)}/reject`, { method: 'POST' });
127
+ if (options.format === 'json') {
128
+ console.log(JSON.stringify(data, null, 2));
129
+ }
130
+ else {
131
+ console.log(chalk.red(`\n ✗ Suggestion ${data.id} rejected.\n`));
132
+ }
133
+ }
134
+ catch (error) {
135
+ const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
136
+ logger.error({ error: message }, 'Failed to reject suggestion');
137
+ console.error(chalk.red(`Error: ${message}`));
138
+ process.exitCode = error instanceof ApiError ? 2 : 1;
139
+ }
140
+ });
141
+ }
142
+ //# sourceMappingURL=suggestions-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggestions-cmd.js","sourceRoot":"","sources":["../../src/commands/suggestions-cmd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerThesisCommand(program: Command): void;
3
+ //# sourceMappingURL=thesis-cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thesis-cmd.d.ts","sourceRoot":"","sources":["../../src/commands/thesis-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AA8G5C,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmE5D"}
@@ -0,0 +1,132 @@
1
+ import { Option } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { createLogger } from '@trading-boy/core';
4
+ import { isRemoteMode, apiRequest, ApiError } from '../api-client.js';
5
+ // ─── Logger ───
6
+ const logger = createLogger('cli-thesis');
7
+ // ─── BYOK Error Hint ───
8
+ const BYOK_HINT = `LLM API key required. Run: ${chalk.white('trading-boy config set-llm-key <key>')}`;
9
+ // ─── Formatters ───
10
+ function formatThesisOutput(response) {
11
+ const lines = [];
12
+ const e = response.extraction;
13
+ lines.push('');
14
+ lines.push(chalk.bold.cyan(` Thesis Extraction \u2014 ${response.decisionId}`));
15
+ lines.push(chalk.gray(' ' + '\u2500'.repeat(50)));
16
+ lines.push('');
17
+ if (e.direction) {
18
+ lines.push(` ${chalk.gray('Direction:')} ${chalk.white(e.direction)}`);
19
+ }
20
+ if (e.timeframe) {
21
+ lines.push(` ${chalk.gray('Timeframe:')} ${chalk.white(e.timeframe)}`);
22
+ }
23
+ if (e.keyLevels && e.keyLevels.length > 0) {
24
+ const levelsStr = e.keyLevels.map(l => `$${l.price} (${l.label})`).join(', ');
25
+ lines.push(` ${chalk.gray('Key Levels:')} ${chalk.white(levelsStr)}`);
26
+ }
27
+ if (e.catalysts && e.catalysts.length > 0) {
28
+ lines.push(` ${chalk.gray('Catalysts:')} ${chalk.white(e.catalysts.join(', '))}`);
29
+ }
30
+ if (e.riskFactors && e.riskFactors.length > 0) {
31
+ lines.push(` ${chalk.gray('Risk Factors:')} ${chalk.white(e.riskFactors.join(', '))}`);
32
+ }
33
+ if (e.confidence !== undefined) {
34
+ const confLabel = e.confidence >= 0.8 ? 'HIGH' : e.confidence >= 0.5 ? 'MEDIUM' : 'LOW';
35
+ lines.push(` ${chalk.gray('Conviction:')} ${chalk.white(confLabel)} (${(e.confidence * 100).toFixed(0)}%)`);
36
+ }
37
+ if (e.setupType) {
38
+ lines.push(` ${chalk.gray('Setup:')} ${chalk.white(e.setupType)}`);
39
+ }
40
+ if (e.emotionalTag) {
41
+ lines.push(` ${chalk.gray('Emotional Tag:')} ${chalk.white(e.emotionalTag)}`);
42
+ }
43
+ if (e.triggers && e.triggers.length > 0) {
44
+ lines.push(` ${chalk.gray('Triggers:')} ${chalk.white(e.triggers.join(', '))}`);
45
+ }
46
+ if (e.cleanedThesis) {
47
+ lines.push('');
48
+ lines.push(` ${chalk.gray('Cleaned Thesis:')}`);
49
+ lines.push(` ${chalk.white(e.cleanedThesis)}`);
50
+ }
51
+ if (e.commitments && e.commitments.length > 0) {
52
+ lines.push('');
53
+ lines.push(chalk.gray(' Commitments:'));
54
+ for (const c of e.commitments) {
55
+ lines.push(` ${chalk.dim('\u2022')} ${c.text}`);
56
+ }
57
+ }
58
+ if (e.behavioralFlags && e.behavioralFlags.length > 0) {
59
+ lines.push('');
60
+ lines.push(` ${chalk.yellow('Behavioral Flags:')} ${e.behavioralFlags.join(', ')}`);
61
+ }
62
+ lines.push('');
63
+ return lines.join('\n');
64
+ }
65
+ // ─── Command Registration ───
66
+ export function registerThesisCommand(program) {
67
+ program
68
+ .command('thesis <decisionId>')
69
+ .description('Extract structured thesis from trade decision text (requires BYOK LLM key)')
70
+ .requiredOption('--text <thesis>', 'Thesis text to extract from')
71
+ .requiredOption('--trader <traderId>', 'Trader ID')
72
+ .option('--token <symbol>', 'Token symbol')
73
+ .option('--direction <dir>', 'Trade direction (LONG or SHORT)')
74
+ .option('--entry-price <n>', 'Entry price', parseFloat)
75
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
76
+ .action(async (decisionId, options) => {
77
+ if (!(await isRemoteMode())) {
78
+ console.error(chalk.yellow('Thesis extraction requires a remote API connection.'));
79
+ console.error(chalk.dim(' Run: trading-boy login'));
80
+ process.exitCode = 1;
81
+ return;
82
+ }
83
+ // Validate direction if provided
84
+ if (options.direction && !['LONG', 'SHORT'].includes(options.direction.toUpperCase())) {
85
+ console.error(chalk.red('Error: --direction must be LONG or SHORT'));
86
+ process.exitCode = 1;
87
+ return;
88
+ }
89
+ const body = {
90
+ text: options.text,
91
+ traderId: options.trader,
92
+ };
93
+ if (options.token)
94
+ body.tokenSymbol = options.token.toUpperCase();
95
+ if (options.direction)
96
+ body.direction = options.direction.toUpperCase();
97
+ if (options.entryPrice !== undefined)
98
+ body.entryPrice = options.entryPrice;
99
+ try {
100
+ const result = await apiRequest(`/api/v1/decisions/${encodeURIComponent(decisionId)}/extract-thesis`, { method: 'POST', body });
101
+ if (options.format === 'json') {
102
+ console.log(JSON.stringify(result, null, 2));
103
+ }
104
+ else {
105
+ console.log(formatThesisOutput(result));
106
+ }
107
+ }
108
+ catch (error) {
109
+ if (error instanceof ApiError && error.status === 422) {
110
+ console.error(chalk.yellow(BYOK_HINT));
111
+ process.exitCode = 2;
112
+ return;
113
+ }
114
+ if (error instanceof ApiError && error.status === 404) {
115
+ const body = error.body;
116
+ console.error(chalk.yellow(body?.error ?? 'Decision or trader not found.'));
117
+ process.exitCode = 2;
118
+ return;
119
+ }
120
+ if (error instanceof ApiError && (error.status === 403 || error.status === 401)) {
121
+ console.error(chalk.yellow(error.message));
122
+ process.exitCode = 2;
123
+ return;
124
+ }
125
+ const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
126
+ logger.error({ error: message }, 'Thesis extraction failed');
127
+ console.error(chalk.red(`Error: ${message}`));
128
+ process.exitCode = error instanceof ApiError ? 2 : 1;
129
+ }
130
+ });
131
+ }
132
+ //# sourceMappingURL=thesis-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thesis-cmd.js","sourceRoot":"","sources":["../../src/commands/thesis-cmd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { Command } from 'commander';
2
+ interface TraderRecord {
3
+ id: string;
4
+ name: string;
5
+ maxDrawdownPct?: number;
6
+ riskToleranceMax?: number;
7
+ walletAddresses?: string[];
8
+ createdAt: string;
9
+ updatedAt: string;
10
+ [key: string]: unknown;
11
+ }
12
+ interface TraderWalletRecord {
13
+ address: string;
14
+ chain: string;
15
+ linkedAt: string;
16
+ since?: string;
17
+ [key: string]: unknown;
18
+ }
19
+ /**
20
+ * Format a single trader record for display.
21
+ */
22
+ export declare function formatTraderOutput(trader: TraderRecord, wallets?: TraderWalletRecord[]): string;
23
+ /**
24
+ * Format a list of traders for display.
25
+ */
26
+ export declare function formatTraderListOutput(traders: TraderRecord[]): string;
27
+ export declare function registerTraderCommand(program: Command): void;
28
+ export {};
29
+ //# sourceMappingURL=trader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trader.d.ts","sourceRoot":"","sources":["../../src/commands/trader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAQ5C,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAQD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAkC/F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAyCtE;AAID,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2N5D"}
@@ -0,0 +1,292 @@
1
+ import { Option } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { createLogger } from '@trading-boy/core';
4
+ import { padRight } from '../utils.js';
5
+ import { apiRequest, ApiError } from '../api-client.js';
6
+ // ─── Logger ───
7
+ const logger = createLogger('cli-trader');
8
+ // ─── Formatters ───
9
+ /**
10
+ * Format a single trader record for display.
11
+ */
12
+ export function formatTraderOutput(trader, wallets) {
13
+ const lines = [];
14
+ lines.push('');
15
+ lines.push(chalk.bold.cyan(' Trader Profile'));
16
+ lines.push(chalk.gray(' ' + '\u2500'.repeat(50)));
17
+ lines.push('');
18
+ lines.push(` ${chalk.gray('Name:')} ${chalk.white(trader.name)}`);
19
+ lines.push(` ${chalk.gray('ID:')} ${chalk.dim(trader.id)}`);
20
+ lines.push(` ${chalk.gray('Max Drawdown:')} ${chalk.yellow(String(trader.riskToleranceMax ?? trader.maxDrawdownPct ?? 'n/a') + '%')}`);
21
+ const walletAddrs = trader.walletAddresses ?? [];
22
+ lines.push(` ${chalk.gray('Wallets:')} ${chalk.white(String(walletAddrs.length))}`);
23
+ if (walletAddrs.length > 0) {
24
+ for (const addr of walletAddrs) {
25
+ lines.push(` ${chalk.dim('\u2022')} ${chalk.white(addr)}`);
26
+ }
27
+ }
28
+ if (wallets && wallets.length > 0) {
29
+ lines.push('');
30
+ lines.push(` ${chalk.gray('Wallet Details:')}`);
31
+ for (const w of wallets) {
32
+ lines.push(` ${chalk.dim('\u2022')} ${chalk.white(w.address)} ${chalk.dim(`(${w.chain})`)} ${chalk.dim(`since ${w.since}`)}`);
33
+ }
34
+ }
35
+ lines.push('');
36
+ lines.push(` ${chalk.gray('Created:')} ${chalk.dim(trader.createdAt)}`);
37
+ lines.push(` ${chalk.gray('Updated:')} ${chalk.dim(trader.updatedAt)}`);
38
+ lines.push('');
39
+ return lines.join('\n');
40
+ }
41
+ /**
42
+ * Format a list of traders for display.
43
+ */
44
+ export function formatTraderListOutput(traders) {
45
+ const lines = [];
46
+ lines.push('');
47
+ lines.push(chalk.bold.cyan(' Registered Traders'));
48
+ lines.push(chalk.gray(' ' + '\u2500'.repeat(70)));
49
+ lines.push('');
50
+ if (traders.length === 0) {
51
+ lines.push(` ${chalk.dim('No traders registered.')}`);
52
+ lines.push('');
53
+ lines.push(` ${chalk.dim('Run')} ${chalk.white('trading-boy trader register --name "YourName"')} ${chalk.dim('to get started.')}`);
54
+ lines.push('');
55
+ return lines.join('\n');
56
+ }
57
+ // Header
58
+ lines.push(' ' +
59
+ padRight('Name', 20) +
60
+ padRight('Max DD', 10) +
61
+ padRight('Wallets', 10) +
62
+ 'ID');
63
+ lines.push(' ' + '\u2500'.repeat(70));
64
+ for (const t of traders) {
65
+ lines.push(' ' +
66
+ padRight(String(t.name ?? t.id ?? ''), 20) +
67
+ padRight(String(t.riskToleranceMax ?? 0) + '%', 10) +
68
+ padRight(String(t.walletAddresses?.length ?? 0), 10) +
69
+ chalk.dim(t.id));
70
+ }
71
+ lines.push('');
72
+ lines.push(` ${chalk.gray(`Total: ${traders.length} trader(s)`)}`);
73
+ lines.push('');
74
+ return lines.join('\n');
75
+ }
76
+ // ─── Command Registration ───
77
+ export function registerTraderCommand(program) {
78
+ const trader = program
79
+ .command('trader')
80
+ .description('Manage trader profiles');
81
+ // ─── register ───
82
+ trader
83
+ .command('register')
84
+ .description('Register a new trader profile')
85
+ .requiredOption('--name <name>', 'Trader display name')
86
+ .option('--wallet <address>', 'Initial Solana wallet address')
87
+ .option('--max-drawdown <pct>', 'Max acceptable drawdown percentage', parseFloatOption)
88
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
89
+ .action(async (options) => {
90
+ try {
91
+ const result = await apiRequest('/api/v1/traders', {
92
+ method: 'POST',
93
+ body: {
94
+ name: options.name,
95
+ wallet: options.wallet,
96
+ maxDrawdown: options.maxDrawdown,
97
+ },
98
+ });
99
+ if (options.format === 'json') {
100
+ console.log(JSON.stringify(result, null, 2));
101
+ }
102
+ else {
103
+ console.log(formatTraderOutput(result));
104
+ console.log(chalk.green(' Trader registered successfully.'));
105
+ console.log('');
106
+ }
107
+ }
108
+ catch (error) {
109
+ const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
110
+ logger.error({ error: message }, 'Failed to register trader');
111
+ console.error(chalk.red(`Error: ${message}`));
112
+ process.exitCode = error instanceof ApiError ? 2 : 1;
113
+ }
114
+ });
115
+ // ─── show ───
116
+ trader
117
+ .command('show')
118
+ .description('Show a trader profile by name or ID')
119
+ .argument('<name-or-id>', 'Trader name or ID')
120
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
121
+ .action(async (nameOrId, options) => {
122
+ try {
123
+ const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}`);
124
+ if (options.format === 'json') {
125
+ console.log(JSON.stringify(result, null, 2));
126
+ }
127
+ else {
128
+ const { wallets, ...traderData } = result;
129
+ console.log(formatTraderOutput(traderData, wallets));
130
+ }
131
+ }
132
+ catch (error) {
133
+ if (error instanceof ApiError && error.status === 404) {
134
+ console.error(chalk.yellow(`Trader not found: "${nameOrId}"`));
135
+ }
136
+ else {
137
+ const message = error instanceof Error ? error.message : String(error);
138
+ logger.error({ error: message }, 'Failed to show trader');
139
+ console.error(chalk.red(`Error: ${message}`));
140
+ }
141
+ process.exitCode = error instanceof ApiError ? 2 : 1;
142
+ }
143
+ });
144
+ // ─── list ───
145
+ trader
146
+ .command('list')
147
+ .description('List all registered traders')
148
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
149
+ .action(async (options) => {
150
+ try {
151
+ const result = await apiRequest('/api/v1/traders');
152
+ if (options.format === 'json') {
153
+ console.log(JSON.stringify(result, null, 2));
154
+ }
155
+ else {
156
+ console.log(formatTraderListOutput(result.traders));
157
+ }
158
+ }
159
+ catch (error) {
160
+ const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
161
+ logger.error({ error: message }, 'Failed to list traders');
162
+ console.error(chalk.red(`Error: ${message}`));
163
+ process.exitCode = error instanceof ApiError ? 2 : 1;
164
+ }
165
+ });
166
+ // ─── update ───
167
+ trader
168
+ .command('update')
169
+ .description('Update a trader profile')
170
+ .argument('<name-or-id>', 'Trader name or ID')
171
+ .option('--name <new-name>', 'New display name')
172
+ .option('--max-drawdown <pct>', 'New max acceptable drawdown percentage', parseFloatOption)
173
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
174
+ .action(async (nameOrId, options) => {
175
+ if (options.name === undefined && options.maxDrawdown === undefined) {
176
+ console.error(chalk.yellow('No updates provided. Use --name or --max-drawdown.'));
177
+ process.exitCode = 1;
178
+ return;
179
+ }
180
+ try {
181
+ const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}`, {
182
+ method: 'PATCH',
183
+ body: {
184
+ name: options.name,
185
+ maxDrawdown: options.maxDrawdown,
186
+ },
187
+ });
188
+ if (options.format === 'json') {
189
+ console.log(JSON.stringify(result, null, 2));
190
+ }
191
+ else {
192
+ console.log(formatTraderOutput(result));
193
+ console.log(chalk.green(' Trader updated successfully.'));
194
+ console.log('');
195
+ }
196
+ }
197
+ catch (error) {
198
+ if (error instanceof ApiError && error.status === 404) {
199
+ console.error(chalk.yellow(`Trader not found: "${nameOrId}"`));
200
+ }
201
+ else {
202
+ const message = error instanceof Error ? error.message : String(error);
203
+ logger.error({ error: message }, 'Failed to update trader');
204
+ console.error(chalk.red(`Error: ${message}`));
205
+ }
206
+ process.exitCode = error instanceof ApiError ? 2 : 1;
207
+ }
208
+ });
209
+ // ─── preferences ───
210
+ trader
211
+ .command('preferences')
212
+ .description('Update notification preferences')
213
+ .option('--summary-time <hour>', 'Hour (0-23 UTC) to receive daily email summary', parseInt)
214
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
215
+ .action(async (options) => {
216
+ if (options.summaryTime === undefined) {
217
+ console.error(chalk.yellow('No updates provided. Use --summary-time <hour>.'));
218
+ console.error(chalk.dim(' Example: trading-boy trader preferences --summary-time 14'));
219
+ process.exitCode = 1;
220
+ return;
221
+ }
222
+ if (isNaN(options.summaryTime) || options.summaryTime < 0 || options.summaryTime > 23) {
223
+ console.error(chalk.red('Error: --summary-time must be 0-23 (UTC hour)'));
224
+ process.exitCode = 1;
225
+ return;
226
+ }
227
+ try {
228
+ const result = await apiRequest('/api/v1/preferences/email', {
229
+ method: 'PATCH',
230
+ body: { summaryHourUtc: options.summaryTime },
231
+ });
232
+ if (options.format === 'json') {
233
+ console.log(JSON.stringify(result, null, 2));
234
+ }
235
+ else {
236
+ console.log('');
237
+ console.log(chalk.green(' Email preferences updated.'));
238
+ console.log(` ${chalk.gray('Email:')} ${chalk.white(result.email)}`);
239
+ console.log(` ${chalk.gray('Summary time:')} ${chalk.white(String(result.summaryHourUtc).padStart(2, '0') + ':00 UTC')}`);
240
+ console.log('');
241
+ }
242
+ }
243
+ catch (error) {
244
+ const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
245
+ console.error(chalk.red(`Error: ${message}`));
246
+ process.exitCode = error instanceof ApiError ? 2 : 1;
247
+ }
248
+ });
249
+ // ─── link-wallet ───
250
+ trader
251
+ .command('link-wallet')
252
+ .description('Link a wallet address to a trader')
253
+ .argument('<name-or-id>', 'Trader name or ID')
254
+ .argument('<wallet-address>', 'Solana wallet address')
255
+ .option('--chain <chain>', 'Blockchain name', 'solana')
256
+ .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
257
+ .action(async (nameOrId, walletAddress, options) => {
258
+ try {
259
+ await apiRequest(`/api/v1/traders/${encodeURIComponent(nameOrId)}/wallets`, {
260
+ method: 'POST',
261
+ body: {
262
+ address: walletAddress,
263
+ chain: options.chain,
264
+ },
265
+ });
266
+ if (options.format === 'json') {
267
+ console.log(JSON.stringify({ linked: true, address: walletAddress, chain: options.chain }, null, 2));
268
+ }
269
+ else {
270
+ console.log('');
271
+ console.log(chalk.green(` Wallet linked: ${walletAddress}`));
272
+ console.log('');
273
+ }
274
+ }
275
+ catch (error) {
276
+ if (error instanceof ApiError && error.status === 404) {
277
+ console.error(chalk.yellow(`Trader not found: "${nameOrId}"`));
278
+ }
279
+ else {
280
+ const message = error instanceof Error ? error.message : String(error);
281
+ logger.error({ error: message }, 'Failed to link wallet');
282
+ console.error(chalk.red(`Error: ${message}`));
283
+ }
284
+ process.exitCode = error instanceof ApiError ? 2 : 1;
285
+ }
286
+ });
287
+ }
288
+ // ─── Helpers ───
289
+ function parseFloatOption(value) {
290
+ return parseFloat(value);
291
+ }
292
+ //# sourceMappingURL=trader.js.map