@trading-boy/cli 1.11.0 → 2.0.0

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 (83) hide show
  1. package/README.md +50 -22
  2. package/dist/api-client.d.ts +4 -7
  3. package/dist/api-client.js +8 -13
  4. package/dist/cli.bundle.js +1977 -33976
  5. package/dist/credentials.js +1 -1
  6. package/dist/index.d.ts +0 -28
  7. package/dist/index.js +0 -24
  8. package/dist/logger.d.ts +8 -0
  9. package/dist/logger.js +12 -0
  10. package/dist/utils.js +3 -3
  11. package/package.json +20 -5
  12. package/dist/cli.d.ts +0 -5
  13. package/dist/cli.js +0 -157
  14. package/dist/commands/agent-cmd.d.ts +0 -9
  15. package/dist/commands/agent-cmd.js +0 -572
  16. package/dist/commands/audit.d.ts +0 -18
  17. package/dist/commands/audit.js +0 -73
  18. package/dist/commands/behavioral.d.ts +0 -73
  19. package/dist/commands/behavioral.js +0 -349
  20. package/dist/commands/benchmark-cmd.d.ts +0 -3
  21. package/dist/commands/benchmark-cmd.js +0 -191
  22. package/dist/commands/billing.d.ts +0 -12
  23. package/dist/commands/billing.js +0 -142
  24. package/dist/commands/catalysts.d.ts +0 -17
  25. package/dist/commands/catalysts.js +0 -151
  26. package/dist/commands/coaching-cmd.d.ts +0 -16
  27. package/dist/commands/coaching-cmd.js +0 -222
  28. package/dist/commands/config-cmd.d.ts +0 -30
  29. package/dist/commands/config-cmd.js +0 -515
  30. package/dist/commands/connect-chatgpt.d.ts +0 -5
  31. package/dist/commands/connect-chatgpt.js +0 -293
  32. package/dist/commands/connect-claude.d.ts +0 -5
  33. package/dist/commands/connect-claude.js +0 -280
  34. package/dist/commands/context.d.ts +0 -41
  35. package/dist/commands/context.js +0 -405
  36. package/dist/commands/cron-cmd.d.ts +0 -3
  37. package/dist/commands/cron-cmd.js +0 -305
  38. package/dist/commands/decisions.d.ts +0 -57
  39. package/dist/commands/decisions.js +0 -364
  40. package/dist/commands/edge-cmd.d.ts +0 -78
  41. package/dist/commands/edge-cmd.js +0 -183
  42. package/dist/commands/edge-guard-cmd.d.ts +0 -36
  43. package/dist/commands/edge-guard-cmd.js +0 -169
  44. package/dist/commands/events.d.ts +0 -3
  45. package/dist/commands/events.js +0 -117
  46. package/dist/commands/infra.d.ts +0 -24
  47. package/dist/commands/infra.js +0 -137
  48. package/dist/commands/journal.d.ts +0 -3
  49. package/dist/commands/journal.js +0 -302
  50. package/dist/commands/login.d.ts +0 -18
  51. package/dist/commands/login.js +0 -127
  52. package/dist/commands/logout.d.ts +0 -8
  53. package/dist/commands/logout.js +0 -108
  54. package/dist/commands/narratives.d.ts +0 -3
  55. package/dist/commands/narratives.js +0 -259
  56. package/dist/commands/onboarding.d.ts +0 -7
  57. package/dist/commands/onboarding.js +0 -298
  58. package/dist/commands/query.d.ts +0 -32
  59. package/dist/commands/query.js +0 -135
  60. package/dist/commands/replay-cmd.d.ts +0 -43
  61. package/dist/commands/replay-cmd.js +0 -184
  62. package/dist/commands/review.d.ts +0 -3
  63. package/dist/commands/review.js +0 -443
  64. package/dist/commands/risk.d.ts +0 -47
  65. package/dist/commands/risk.js +0 -158
  66. package/dist/commands/social.d.ts +0 -43
  67. package/dist/commands/social.js +0 -318
  68. package/dist/commands/soul-wizard.d.ts +0 -29
  69. package/dist/commands/soul-wizard.js +0 -155
  70. package/dist/commands/strategy-cmd.d.ts +0 -44
  71. package/dist/commands/strategy-cmd.js +0 -340
  72. package/dist/commands/subscribe.d.ts +0 -78
  73. package/dist/commands/subscribe.js +0 -552
  74. package/dist/commands/suggestions-cmd.d.ts +0 -24
  75. package/dist/commands/suggestions-cmd.js +0 -148
  76. package/dist/commands/thesis-cmd.d.ts +0 -3
  77. package/dist/commands/thesis-cmd.js +0 -129
  78. package/dist/commands/trader.d.ts +0 -30
  79. package/dist/commands/trader.js +0 -971
  80. package/dist/commands/watch.d.ts +0 -16
  81. package/dist/commands/watch.js +0 -104
  82. package/dist/commands/whoami.d.ts +0 -14
  83. 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