@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,142 +0,0 @@
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 } from '../utils.js';
6
- const logger = createLogger('cli-billing');
7
- // ─── Security ───
8
- const ALLOWED_PORTAL_DOMAINS = new Set([
9
- 'billing.stripe.com',
10
- 'checkout.stripe.com',
11
- ]);
12
- // ─── Formatters ───
13
- function formatStatusLabel(status) {
14
- switch (status) {
15
- case 'active':
16
- case 'trialing':
17
- return chalk.green(status);
18
- case 'past_due':
19
- return chalk.yellow(status);
20
- case 'canceled':
21
- case 'unpaid':
22
- case 'incomplete_expired':
23
- return chalk.red(status);
24
- default:
25
- return chalk.gray(status);
26
- }
27
- }
28
- function formatDate(isoDate) {
29
- return new Date(isoDate).toLocaleDateString('en-US', {
30
- year: 'numeric',
31
- month: 'short',
32
- day: 'numeric',
33
- });
34
- }
35
- export function formatBillingStatus(status) {
36
- const lines = [];
37
- lines.push('');
38
- lines.push(chalk.bold.cyan(' Billing Status'));
39
- lines.push(chalk.gray(' ' + '\u2500'.repeat(50)));
40
- lines.push('');
41
- lines.push(` ${chalk.bold(padRight('Account:', 18))} ${status.email}`);
42
- lines.push(` ${chalk.bold(padRight('Plan:', 18))} ${status.plan}`);
43
- lines.push(` ${chalk.bold(padRight('Status:', 18))} ${formatStatusLabel(status.status)}`);
44
- if (status.keyPrefix) {
45
- lines.push(` ${chalk.bold(padRight('API Key:', 18))} ${status.keyPrefix}...`);
46
- }
47
- if (status.nextBillingDate) {
48
- lines.push(` ${chalk.bold(padRight('Next billing:', 18))} ${formatDate(status.nextBillingDate)}`);
49
- }
50
- else if (status.currentPeriodEnd) {
51
- lines.push(` ${chalk.bold(padRight('Period ends:', 18))} ${formatDate(status.currentPeriodEnd)}`);
52
- }
53
- lines.push('');
54
- if (status.status === 'past_due') {
55
- lines.push(chalk.yellow(' Warning: Payment is past due. Update your payment method:'));
56
- lines.push(chalk.yellow(' Run: trading-boy billing manage'));
57
- lines.push('');
58
- }
59
- else if (status.status === 'canceled' || status.status === 'unpaid') {
60
- lines.push(chalk.red(' Your subscription is inactive.'));
61
- lines.push(chalk.red(' Run: trading-boy subscribe -e <email> to resubscribe'));
62
- lines.push('');
63
- }
64
- return lines.join('\n');
65
- }
66
- // ─── Command Registration ───
67
- export function registerBillingCommand(program) {
68
- const billingCmd = program
69
- .command('billing')
70
- .description('Subscription billing management');
71
- // billing manage — open customer portal
72
- billingCmd
73
- .command('manage')
74
- .description('Open Stripe Customer Portal to manage your subscription')
75
- .action(async () => {
76
- try {
77
- const { createSpinner } = await import('../utils.js');
78
- const spinner = (await createSpinner(' Creating billing portal session...')).start();
79
- const result = await apiRequest('/api/v1/billing/portal', {
80
- method: 'POST',
81
- });
82
- spinner.succeed(' Opening billing portal...');
83
- // Validate URL before opening browser (prevent phishing via MITM)
84
- const portalUrl = new URL(result.url);
85
- if (portalUrl.protocol !== 'https:') {
86
- throw new Error(`Refusing to open non-HTTPS portal URL: ${result.url}`);
87
- }
88
- if (!ALLOWED_PORTAL_DOMAINS.has(portalUrl.hostname)) {
89
- throw new Error(`Refusing to open URL with untrusted domain: ${portalUrl.hostname}`);
90
- }
91
- const { default: open } = await import('open');
92
- await open(result.url);
93
- console.log('');
94
- console.log(chalk.dim(' Billing portal opened in your browser.'));
95
- console.log(chalk.dim(' If it didn\'t open, visit:'));
96
- console.log(` ${chalk.cyan(result.url)}`);
97
- console.log('');
98
- }
99
- catch (error) {
100
- const message = error instanceof Error ? error.message : String(error);
101
- logger.error({ error: message }, 'Billing portal failed');
102
- console.error(chalk.red(` Error: ${message}`));
103
- process.exitCode = error instanceof ApiError ? 2 : 1;
104
- }
105
- });
106
- // billing status — show current subscription
107
- billingCmd
108
- .command('status')
109
- .alias('subscription')
110
- .description('Show your current subscription status')
111
- .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
112
- .action(async (options) => {
113
- try {
114
- const result = await apiRequest('/api/v1/billing/status');
115
- if (options.format === 'json') {
116
- console.log(JSON.stringify(result, null, 2));
117
- }
118
- else {
119
- console.log(formatBillingStatus(result));
120
- }
121
- }
122
- catch (error) {
123
- if (error instanceof ApiError && error.status === 404) {
124
- if (options.format === 'json') {
125
- console.log(JSON.stringify({ plan: 'starter', status: 'free' }, null, 2));
126
- }
127
- else {
128
- console.log('');
129
- console.log(chalk.dim(' You\'re on the free Starter plan.'));
130
- console.log(chalk.dim(' Run: trading-boy subscribe to upgrade.'));
131
- console.log('');
132
- }
133
- return;
134
- }
135
- const message = error instanceof Error ? error.message : String(error);
136
- logger.error({ error: message }, 'Billing status failed');
137
- console.error(chalk.red(` Error: ${message}`));
138
- process.exitCode = error instanceof ApiError ? 2 : 1;
139
- }
140
- });
141
- }
142
- //# sourceMappingURL=billing.js.map
@@ -1,17 +0,0 @@
1
- import { Command } from 'commander';
2
- interface EventRecord {
3
- id: string;
4
- type: string;
5
- title: string;
6
- scheduledDate: string | null;
7
- severity: string;
8
- tokensAffected?: string[];
9
- [key: string]: unknown;
10
- }
11
- /**
12
- * Format the catalysts list output.
13
- */
14
- export declare function formatCatalystsOutput(events: EventRecord[]): string;
15
- export declare function registerCatalystsCommand(program: Command): void;
16
- export {};
17
- //# sourceMappingURL=catalysts.d.ts.map
@@ -1,151 +0,0 @@
1
- import { Option } from 'commander';
2
- import chalk from 'chalk';
3
- import { createLogger, EventType } from '@trading-boy/core';
4
- import { formatConnectionError, padRight, truncate, formatDate, parseIntOption } from '../utils.js';
5
- import { apiRequest, ApiError } from '../api-client.js';
6
- // ─── Logger ───
7
- const logger = createLogger('cli-catalysts');
8
- // ─── Formatters ───
9
- /**
10
- * Color-code severity labels.
11
- */
12
- function colorSeverity(severity) {
13
- switch (severity) {
14
- case 'CRITICAL':
15
- return chalk.bgRed.white.bold(` ${severity} `);
16
- case 'HIGH':
17
- return chalk.red(severity);
18
- case 'MEDIUM':
19
- return chalk.yellow(severity);
20
- case 'LOW':
21
- return chalk.green(severity);
22
- default:
23
- return chalk.dim(severity);
24
- }
25
- }
26
- /**
27
- * Compute days until a scheduled date.
28
- */
29
- function daysUntil(isoString) {
30
- if (!isoString) {
31
- return chalk.dim('-');
32
- }
33
- try {
34
- const date = new Date(isoString);
35
- const now = new Date();
36
- const diffMs = date.getTime() - now.getTime();
37
- const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
38
- if (diffDays < 0) {
39
- return chalk.dim(`${diffDays}d ago`);
40
- }
41
- if (diffDays === 0) {
42
- return chalk.red.bold('TODAY');
43
- }
44
- if (diffDays <= 3) {
45
- return chalk.red(`${diffDays}d`);
46
- }
47
- if (diffDays <= 7) {
48
- return chalk.yellow(`${diffDays}d`);
49
- }
50
- return chalk.white(`${diffDays}d`);
51
- }
52
- catch {
53
- return chalk.dim('-');
54
- }
55
- }
56
- /**
57
- * Format the catalysts list output.
58
- */
59
- export function formatCatalystsOutput(events) {
60
- const lines = [];
61
- lines.push('');
62
- lines.push(chalk.bold.cyan(' Upcoming Catalysts'));
63
- lines.push(chalk.gray(' ' + '\u2500'.repeat(100)));
64
- lines.push('');
65
- if (events.length === 0) {
66
- lines.push(` ${chalk.dim('No upcoming catalysts found.')}`);
67
- lines.push('');
68
- return lines.join('\n');
69
- }
70
- // Header
71
- lines.push(' ' +
72
- padRight('Date', 14) +
73
- padRight('In', 10) +
74
- padRight('Type', 22) +
75
- padRight('Severity', 12) +
76
- padRight('Tokens', 16) +
77
- 'Title');
78
- lines.push(' ' + '\u2500'.repeat(100));
79
- for (const event of events) {
80
- const date = formatDate(event.scheduledDate);
81
- const until = daysUntil(event.scheduledDate);
82
- const severity = colorSeverity(event.severity);
83
- const tokens = event.tokensAffected
84
- ? event.tokensAffected.join(', ')
85
- : '-';
86
- const title = truncate(event.title, 30);
87
- lines.push(' ' +
88
- padRight(date, 14) +
89
- padRight(until, 10) +
90
- padRight(event.type, 22) +
91
- padRight(severity, 12) +
92
- padRight(tokens, 16) +
93
- title);
94
- }
95
- lines.push('');
96
- lines.push(` ${chalk.gray(`Total: ${events.length} catalyst(s)`)}`);
97
- lines.push('');
98
- return lines.join('\n');
99
- }
100
- // ─── Command Registration ───
101
- export function registerCatalystsCommand(program) {
102
- program
103
- .command('catalysts')
104
- .description('Show upcoming catalysts and events sorted by date')
105
- .option('--type <type>', `Filter by event type (${Object.values(EventType).join(', ')})`)
106
- .option('--days <n>', 'Number of days to look ahead', parseIntOption, 30)
107
- .option('--limit <n>', 'Maximum number of results', parseIntOption, 50)
108
- .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
109
- .action(async (options) => {
110
- // Validate event type if provided
111
- if (options.type && !Object.values(EventType).includes(options.type)) {
112
- console.error(chalk.red(`Error: Invalid event type "${options.type}". Valid types: ${Object.values(EventType).join(', ')}`));
113
- process.exitCode = 1;
114
- return;
115
- }
116
- // Validate --days
117
- if (!Number.isFinite(options.days) || options.days <= 0) {
118
- console.error(chalk.red('Error: --days must be a positive number'));
119
- process.exitCode = 1;
120
- return;
121
- }
122
- try {
123
- const params = new URLSearchParams();
124
- if (options.days)
125
- params.set('days', String(options.days));
126
- if (options.type)
127
- params.set('type', options.type);
128
- if (options.limit)
129
- params.set('limit', String(options.limit));
130
- const qs = params.toString() ? `?${params.toString()}` : '';
131
- const result = await apiRequest(`/api/v1/catalysts${qs}`);
132
- const events = result.events ?? [];
133
- if (options.format === 'json') {
134
- console.log(JSON.stringify(events, null, 2));
135
- }
136
- else {
137
- console.log(formatCatalystsOutput(events));
138
- }
139
- }
140
- catch (error) {
141
- const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
142
- logger.error({ error: message }, 'Failed to fetch catalysts');
143
- console.error(chalk.red(`Error: ${message}`));
144
- const guidance = formatConnectionError(message);
145
- if (guidance)
146
- console.error(guidance);
147
- process.exitCode = error instanceof ApiError ? 2 : 1;
148
- }
149
- });
150
- }
151
- //# sourceMappingURL=catalysts.js.map
@@ -1,16 +0,0 @@
1
- import { Command } from 'commander';
2
- interface CoachingIntervention {
3
- level: string;
4
- reason: string;
5
- message: string;
6
- suggestions?: string[];
7
- requiredAcknowledgment?: boolean;
8
- }
9
- interface CoachingResponse {
10
- traderId: string;
11
- intervention: CoachingIntervention | null;
12
- }
13
- export declare function formatIntervention(response: CoachingResponse): string;
14
- export declare function registerCoachingCommand(program: Command): void;
15
- export {};
16
- //# sourceMappingURL=coaching-cmd.d.ts.map
@@ -1,222 +0,0 @@
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 { ensureRemote } from '../utils.js';
6
- // ─── Logger ───
7
- const logger = createLogger('cli-coaching');
8
- // ─── BYOK Error Hint ───
9
- const BYOK_HINT = `LLM API key required. Run: ${chalk.white('trading-boy config set-llm-key <key>')}`;
10
- function isByokError(error) {
11
- if (error instanceof ApiError && error.status === 422)
12
- return true;
13
- // Also catch LLM provider errors that bubble up as 500/502
14
- if (error instanceof ApiError && (error.status === 500 || error.status === 502)) {
15
- const msg = typeof error.body === 'object' && error.body !== null && 'error' in error.body
16
- ? String(error.body.error)
17
- : error.message;
18
- if (msg.toLowerCase().includes('llm') || msg.toLowerCase().includes('anthropic') || msg.toLowerCase().includes('openai')) {
19
- return true;
20
- }
21
- }
22
- return false;
23
- }
24
- // ─── Formatters ───
25
- export function formatIntervention(response) {
26
- const lines = [];
27
- lines.push('');
28
- lines.push(chalk.bold.cyan(` Coaching — ${response.traderId}`));
29
- lines.push(chalk.gray(' ' + '\u2500'.repeat(50)));
30
- lines.push('');
31
- if (!response.intervention) {
32
- lines.push(chalk.green(' No intervention needed. You are clear to trade.'));
33
- lines.push('');
34
- return lines.join('\n');
35
- }
36
- const i = response.intervention;
37
- const levelColor = i.level === 'BLOCK' ? chalk.red
38
- : i.level === 'WARN' ? chalk.yellow
39
- : chalk.blue;
40
- lines.push(` ${chalk.gray('Level:')} ${levelColor(i.level)}`);
41
- lines.push(` ${chalk.gray('Reason:')} ${chalk.white(i.reason)}`);
42
- lines.push('');
43
- lines.push(` ${chalk.white(i.message)}`);
44
- if (i.suggestions && i.suggestions.length > 0) {
45
- lines.push('');
46
- lines.push(chalk.gray(' Suggestions:'));
47
- for (const s of i.suggestions) {
48
- lines.push(` ${chalk.dim('\u2022')} ${s}`);
49
- }
50
- }
51
- if (i.requiredAcknowledgment) {
52
- lines.push('');
53
- lines.push(chalk.yellow(' This intervention requires acknowledgment before proceeding.'));
54
- lines.push(chalk.dim(` Run: trading-boy coaching acknowledge ${response.traderId} --reason "your reason"`));
55
- }
56
- lines.push('');
57
- return lines.join('\n');
58
- }
59
- // ─── Command Registration ───
60
- export function registerCoachingCommand(program) {
61
- const coaching = program
62
- .command('coaching')
63
- .description('Trading coach — pre/post-trade interventions (requires BYOK LLM key)');
64
- // ─── coaching pre-trade <traderId> ───
65
- coaching
66
- .command('pre-trade <traderId>')
67
- .description('Get pre-trade coaching intervention check')
68
- .option('--tilt-score <n>', 'Tilt score (0-100)', parseFloat)
69
- .option('--flags <flags>', 'Active behavioral flags (comma-separated)')
70
- .option('--token <symbol>', 'Token being traded')
71
- .option('--direction <dir>', 'Trade direction (LONG or SHORT)')
72
- .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
73
- .action(async (traderId, options) => {
74
- if (!(await ensureRemote()))
75
- return;
76
- // Build extraction object from flags
77
- const extraction = {
78
- decisionType: 'TRADE_ENTRY',
79
- tokenSymbol: options.token?.toUpperCase() ?? 'UNKNOWN',
80
- direction: options.direction?.toUpperCase() ?? null,
81
- confidence: 0.5,
82
- cleanedThesis: '',
83
- triggers: [],
84
- emotionalTag: 'NEUTRAL',
85
- behavioralFlags: options.flags ? options.flags.split(',').map((f) => f.trim()) : [],
86
- commitments: [],
87
- };
88
- const body = {
89
- extraction,
90
- tiltScore: options.tiltScore ?? 0,
91
- activeFlags: options.flags ? options.flags.split(',').map((f) => f.trim()) : [],
92
- recentOutcomes: [],
93
- baseline: {
94
- winRate: 0.5,
95
- avgPnlPercent: 0,
96
- avgConfidence: 0.5,
97
- avgTradesPerDay: 1,
98
- commitmentHonorRate: 1,
99
- overallBehavioralScore: 0.8,
100
- setupWinRates: {},
101
- },
102
- };
103
- try {
104
- const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(traderId)}/coaching/pre-trade`, { method: 'POST', body });
105
- if (options.format === 'json') {
106
- console.log(JSON.stringify(result, null, 2));
107
- }
108
- else {
109
- console.log(formatIntervention(result));
110
- }
111
- }
112
- catch (error) {
113
- if (isByokError(error)) {
114
- console.error(chalk.yellow(BYOK_HINT));
115
- process.exitCode = 2;
116
- return;
117
- }
118
- if (error instanceof ApiError && (error.status === 403 || error.status === 401)) {
119
- console.error(chalk.yellow(error.message));
120
- process.exitCode = 2;
121
- return;
122
- }
123
- const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
124
- logger.error({ error: message }, 'Pre-trade coaching failed');
125
- console.error(chalk.red(`Error: ${message}`));
126
- process.exitCode = error instanceof ApiError ? 2 : 1;
127
- }
128
- });
129
- // ─── coaching post-trade <traderId> ───
130
- coaching
131
- .command('post-trade <traderId>')
132
- .description('Get post-trade coaching session reflection')
133
- .option('--tilt-score <n>', 'Tilt score (0-100)', parseFloat)
134
- .option('--flags <flags>', 'Active behavioral flags (comma-separated)')
135
- .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
136
- .action(async (traderId, options) => {
137
- if (!(await ensureRemote()))
138
- return;
139
- const body = {
140
- tiltScore: options.tiltScore ?? 0,
141
- activeFlags: options.flags ? options.flags.split(',').map((f) => f.trim()) : [],
142
- recentOutcomes: [],
143
- baseline: {
144
- winRate: 0.5,
145
- avgPnlPercent: 0,
146
- avgConfidence: 0.5,
147
- avgTradesPerDay: 1,
148
- commitmentHonorRate: 1,
149
- overallBehavioralScore: 0.8,
150
- setupWinRates: {},
151
- },
152
- };
153
- try {
154
- const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(traderId)}/coaching/post-trade`, { method: 'POST', body });
155
- if (options.format === 'json') {
156
- console.log(JSON.stringify(result, null, 2));
157
- }
158
- else {
159
- console.log(formatIntervention(result));
160
- }
161
- }
162
- catch (error) {
163
- if (isByokError(error)) {
164
- console.error(chalk.yellow(BYOK_HINT));
165
- process.exitCode = 2;
166
- return;
167
- }
168
- if (error instanceof ApiError && (error.status === 403 || error.status === 401)) {
169
- console.error(chalk.yellow(error.message));
170
- process.exitCode = 2;
171
- return;
172
- }
173
- const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
174
- logger.error({ error: message }, 'Post-trade coaching failed');
175
- console.error(chalk.red(`Error: ${message}`));
176
- process.exitCode = error instanceof ApiError ? 2 : 1;
177
- }
178
- });
179
- // ─── coaching acknowledge <traderId> ───
180
- coaching
181
- .command('acknowledge <traderId>')
182
- .description('Acknowledge a coaching intervention')
183
- .requiredOption('--reason <reason>', 'Reason for acknowledgment')
184
- .action(async (traderId, options) => {
185
- if (!(await ensureRemote()))
186
- return;
187
- try {
188
- const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(traderId)}/coaching/acknowledge`, { method: 'POST', body: { reason: options.reason } });
189
- console.log('');
190
- console.log(chalk.green(` Intervention acknowledged for ${result.traderId}`));
191
- console.log(` ${chalk.gray('Reason:')} ${result.reason}`);
192
- console.log('');
193
- }
194
- catch (error) {
195
- const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
196
- logger.error({ error: message }, 'Acknowledge failed');
197
- console.error(chalk.red(`Error: ${message}`));
198
- process.exitCode = error instanceof ApiError ? 2 : 1;
199
- }
200
- });
201
- // ─── coaching reset <traderId> ───
202
- coaching
203
- .command('reset <traderId>')
204
- .description('Reset coaching session state')
205
- .action(async (traderId) => {
206
- if (!(await ensureRemote()))
207
- return;
208
- try {
209
- const result = await apiRequest(`/api/v1/traders/${encodeURIComponent(traderId)}/coaching/reset-session`, { method: 'POST', body: {} });
210
- console.log('');
211
- console.log(chalk.green(` Coaching session reset for ${result.traderId}`));
212
- console.log('');
213
- }
214
- catch (error) {
215
- const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
216
- logger.error({ error: message }, 'Reset failed');
217
- console.error(chalk.red(`Error: ${message}`));
218
- process.exitCode = error instanceof ApiError ? 2 : 1;
219
- }
220
- });
221
- }
222
- //# sourceMappingURL=coaching-cmd.js.map
@@ -1,30 +0,0 @@
1
- import { Command } from 'commander';
2
- import { type Config } from '@trading-boy/core';
3
- /**
4
- * Redact a config value if it's a sensitive key.
5
- * Shows first 3 chars + '****' for non-empty sensitive values.
6
- */
7
- export declare function redactValue(key: string, value: string | number | boolean): string;
8
- /**
9
- * Format the full config for display.
10
- */
11
- export declare function formatConfigOutput(config: Config): string;
12
- /**
13
- * Resolve the .env file path from the project root.
14
- */
15
- export declare function resolveEnvPath(): string;
16
- /**
17
- * Parse a .env file into a Map of key-value pairs.
18
- * Preserves comments and blank lines by returning the full lines array too.
19
- */
20
- export declare function parseEnvFile(filePath: string): {
21
- entries: Map<string, string>;
22
- lines: string[];
23
- };
24
- /**
25
- * Write a key-value pair to the .env file.
26
- * If the key already exists, update the line; otherwise append.
27
- */
28
- export declare function writeEnvValue(filePath: string, key: string, value: string): void;
29
- export declare function registerConfigCommand(program: Command): void;
30
- //# sourceMappingURL=config-cmd.d.ts.map