@trading-boy/cli 1.12.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 +1896 -33657
  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 -567
  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 -281
  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 -335
  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,443 +0,0 @@
1
- // ─── Journal Review Commands ───
2
- //
3
- // trading-boy journal review daily|weekly|monthly
4
- // Structured review cadence for trade journaling.
5
- import { createLogger } from '@trading-boy/core';
6
- import { formatConnectionError, padRight, truncate } from '../utils.js';
7
- import { apiRequest, ApiError } from '../api-client.js';
8
- // ─── Logger ───
9
- const logger = createLogger('cli-review');
10
- // ─── Default Trader ───
11
- const DEFAULT_TRADER_ID = 'default';
12
- // ─── Helpers ───
13
- function formatUsd(n) {
14
- const sign = n >= 0 ? '+' : '';
15
- return `${sign}$${Math.abs(n).toFixed(0)}`;
16
- }
17
- function formatPct(n) {
18
- const sign = n >= 0 ? '+' : '';
19
- return `${sign}${n.toFixed(1)}%`;
20
- }
21
- function formatMs(ms) {
22
- if (ms < 60_000)
23
- return `${(ms / 1000).toFixed(0)}s`;
24
- if (ms < 3_600_000)
25
- return `${(ms / 60_000).toFixed(0)}m`;
26
- if (ms < 86_400_000)
27
- return `${(ms / 3_600_000).toFixed(1)}h`;
28
- return `${(ms / 86_400_000).toFixed(1)}d`;
29
- }
30
- function brierLabel(score) {
31
- if (score <= 0.1)
32
- return 'Excellent';
33
- if (score <= 0.2)
34
- return 'Good';
35
- if (score <= 0.3)
36
- return 'Fair';
37
- return 'Poor';
38
- }
39
- // ─── Formatters ───
40
- function printDailyReview(review) {
41
- console.log('');
42
- console.log(`═══ Daily Review — ${review.date} ═══`);
43
- console.log('');
44
- console.log(`Trades Today: ${review.entries.length} entries, ${review.exits.length} exits`);
45
- console.log(`PnL Today: ${formatUsd(review.pnlToday)} (${formatPct(review.pnlPercent)})`);
46
- // Behavioral flags
47
- if (review.behavioralFlags.length > 0) {
48
- console.log('');
49
- console.log('Behavioral Flags:');
50
- for (const { flag, count } of review.behavioralFlags) {
51
- console.log(` ⚠ ${flag}: ${count} occurrence(s)`);
52
- }
53
- }
54
- // Commitment stats
55
- if (review.commitmentStats.total > 0) {
56
- console.log('');
57
- console.log('Process Adherence:');
58
- console.log(` Honored: ${review.commitmentStats.honored}/${review.commitmentStats.total} (${(review.commitmentStats.honorRate * 100).toFixed(0)}%)`);
59
- if (review.commitmentStats.violated > 0) {
60
- console.log(` Violated: ${review.commitmentStats.violated}`);
61
- }
62
- }
63
- // Emotional timeline
64
- if (review.emotionalTimeline.length > 0) {
65
- console.log('');
66
- console.log('Emotional Timeline:');
67
- for (const { time, emotion, token } of review.emotionalTimeline) {
68
- console.log(` ${time} ${emotion} ${token}`);
69
- }
70
- }
71
- // Reflection questions
72
- console.log('');
73
- console.log('Questions for reflection:');
74
- for (let i = 0; i < review.reflectionQuestions.length; i++) {
75
- console.log(` ${i + 1}. "${review.reflectionQuestions[i]}"`);
76
- }
77
- console.log('');
78
- }
79
- function printWeeklyReview(review) {
80
- console.log('');
81
- console.log(`═══ Weekly Review — ${review.weekStart} to ${review.weekEnd} ═══`);
82
- console.log('');
83
- console.log(`Total Trades: ${review.tradeCount}`);
84
- if (review.stats.totalTrades > 0) {
85
- console.log(`Win Rate: ${(review.stats.winRate * 100).toFixed(1)}%`);
86
- console.log(`Total PnL: ${formatUsd(review.stats.totalPnl)}`);
87
- console.log(`Avg PnL: ${formatUsd(review.stats.avgPnl)}`);
88
- console.log(`Avg Hold: ${formatMs(review.stats.avgHoldDurationMs)}`);
89
- }
90
- // Top setups
91
- if (review.topSetups.length > 0) {
92
- console.log('');
93
- console.log('Top Setups (by PnL):');
94
- for (const { setup, stats } of review.topSetups) {
95
- console.log(` ${padRight(setup, 20)} ${padRight(`${stats.totalTrades} trades`, 12)} ` +
96
- `WR: ${(stats.winRate * 100).toFixed(0)}% PnL: ${formatUsd(stats.totalPnl)}`);
97
- }
98
- }
99
- // Worst setup
100
- if (review.worstSetup && review.topSetups.length > 1) {
101
- console.log('');
102
- console.log('Worst Setup:');
103
- const { setup, stats } = review.worstSetup;
104
- console.log(` ${setup} — ${stats.totalTrades} trades, WR: ${(stats.winRate * 100).toFixed(0)}%, PnL: ${formatUsd(stats.totalPnl)}`);
105
- }
106
- // Commitment trend
107
- if (review.commitmentTrend.some((w) => w.honorRate > 0)) {
108
- console.log('');
109
- console.log('Commitment Honor Rate Trend (5 weeks):');
110
- for (const { week, honorRate } of review.commitmentTrend) {
111
- const bar = '█'.repeat(Math.round(honorRate * 20));
112
- console.log(` ${week} ${bar} ${(honorRate * 100).toFixed(0)}%`);
113
- }
114
- }
115
- // Behavioral trend
116
- console.log('');
117
- console.log('Behavioral Flag Trend (5 weeks):');
118
- for (const { week, flagCount } of review.behavioralHealthTrend) {
119
- console.log(` ${week} ${flagCount} flag(s)`);
120
- }
121
- console.log('');
122
- }
123
- // Formatter for monthly review — will be used once the API endpoint ships
124
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
125
- function printMonthlyReview(review) {
126
- console.log('');
127
- console.log(`═══ Monthly Review — ${review.monthStart} to ${review.monthEnd} ═══`);
128
- console.log('');
129
- if (review.stats.totalTrades === 0) {
130
- console.log('No completed trades this month.');
131
- return;
132
- }
133
- console.log(`Total Trades: ${review.stats.totalTrades}`);
134
- console.log(`Win Rate: ${(review.stats.winRate * 100).toFixed(1)}%`);
135
- console.log(`Total PnL: ${formatUsd(review.stats.totalPnl)}`);
136
- console.log(`Avg PnL: ${formatUsd(review.stats.avgPnl)}`);
137
- // Setup breakdown with progressive confidence
138
- if (review.setupBreakdown.length > 0) {
139
- console.log('');
140
- console.log('Setup Breakdown:');
141
- console.log(padRight('Setup', 20) + padRight('N', 6) + padRight('Win Rate', 12) +
142
- padRight('Avg PnL', 12) + padRight('Total PnL', 12) + 'Confidence');
143
- console.log('-'.repeat(74));
144
- for (const { setup, stats, sampleSize } of review.setupBreakdown) {
145
- let confidence = '';
146
- if (sampleSize < 10)
147
- confidence = 'low (N<10)';
148
- else if (sampleSize < 30)
149
- confidence = 'moderate';
150
- else
151
- confidence = 'high';
152
- console.log(padRight(truncate(setup, 18), 20) +
153
- padRight(String(sampleSize), 6) +
154
- padRight(`${(stats.winRate * 100).toFixed(0)}%`, 12) +
155
- padRight(formatUsd(stats.avgPnl), 12) +
156
- padRight(formatUsd(stats.totalPnl), 12) +
157
- confidence);
158
- }
159
- }
160
- // Confidence calibration
161
- printCalibration(review.calibration);
162
- // Process-outcome matrix
163
- printProcessOutcomeMatrix(review.processOutcomeMatrix);
164
- // Regime breakdown
165
- if (review.regimeBreakdown.length > 0) {
166
- console.log('');
167
- console.log('Performance by Market Regime:');
168
- for (const { regime, stats } of review.regimeBreakdown) {
169
- console.log(` ${padRight(regime, 16)} ${stats.totalTrades} trades ` +
170
- `WR: ${(stats.winRate * 100).toFixed(0)}% PnL: ${formatUsd(stats.totalPnl)}`);
171
- }
172
- }
173
- // Edge detection
174
- if (review.edgeDetection.length > 0) {
175
- console.log('');
176
- console.log('Edge Detection (z-score test, p<0.05):');
177
- for (const edge of review.edgeDetection) {
178
- const symbol = edge.hasEdge ? '✓' : '✗';
179
- console.log(` ${symbol} ${padRight(edge.setup, 20)} z=${edge.zScore.toFixed(2)} p=${edge.pValue.toFixed(3)} ` +
180
- `WR: ${(edge.winRate * 100).toFixed(0)}% N=${edge.sampleSize}`);
181
- }
182
- }
183
- console.log('');
184
- }
185
- function printCalibration(cal) {
186
- if (cal.totalTrades === 0) {
187
- console.log('');
188
- console.log('No decisions found. Log trades with `journal log entry` first.');
189
- return;
190
- }
191
- console.log('');
192
- console.log(`═══ Confidence Calibration (${cal.totalTrades} trades) ═══`);
193
- console.log('');
194
- console.log(padRight('Confidence', 14) + padRight('Trades', 9) + padRight('Predicted', 11) +
195
- padRight('Actual', 9) + padRight('Delta', 10) + 'Avg PnL');
196
- console.log('-'.repeat(65));
197
- for (const bucket of cal.buckets) {
198
- if (bucket.tradeCount === 0) {
199
- console.log(padRight(`${bucket.range.min.toFixed(1)} - ${bucket.range.max.toFixed(1)}`, 14) +
200
- padRight('-', 9) + padRight('-', 11) + padRight('-', 9) + padRight('-', 10) + '-');
201
- continue;
202
- }
203
- let deltaIndicator = '✓';
204
- if (Math.abs(bucket.delta) > 0.15)
205
- deltaIndicator = bucket.delta > 0 ? '⚠' : '↑';
206
- else if (Math.abs(bucket.delta) > 0.05)
207
- deltaIndicator = bucket.delta > 0 ? '↓' : '↑';
208
- console.log(padRight(`${bucket.range.min.toFixed(1)} - ${bucket.range.max.toFixed(1)}`, 14) +
209
- padRight(String(bucket.tradeCount), 9) +
210
- padRight(`${(bucket.predictedWinRate * 100).toFixed(0)}%`, 11) +
211
- padRight(`${(bucket.actualWinRate * 100).toFixed(0)}%`, 9) +
212
- padRight(`${formatPct(bucket.delta * 100)} ${deltaIndicator}`, 10) +
213
- formatUsd(bucket.avgPnl));
214
- }
215
- console.log('');
216
- console.log(`Brier Score: ${cal.brierScore.toFixed(2)} (${brierLabel(cal.brierScore)})`);
217
- if (cal.overconfidenceIndex > 0.1) {
218
- console.log(`⚠ You are overconfident (index: ${formatPct(cal.overconfidenceIndex * 100)})`);
219
- }
220
- else if (cal.overconfidenceIndex < -0.1) {
221
- console.log(`You are underconfident (index: ${formatPct(cal.overconfidenceIndex * 100)})`);
222
- }
223
- if (cal.optimalConfidenceRange) {
224
- console.log(`Best-calibrated range: ${cal.optimalConfidenceRange.min.toFixed(1)}-${cal.optimalConfidenceRange.max.toFixed(1)}`);
225
- }
226
- }
227
- function printProcessOutcomeMatrix(matrix) {
228
- const total = matrix.earnedReward.count + matrix.variance.count +
229
- matrix.dumbLuck.count + matrix.mistake.count;
230
- if (total === 0) {
231
- console.log('');
232
- console.log('No decisions found. Log trades with `journal log entry` first.');
233
- return;
234
- }
235
- console.log('');
236
- console.log(`═══ Process-Outcome Matrix (${total} trades) ═══`);
237
- console.log('');
238
- console.log(' GOOD OUTCOME (+PnL) BAD OUTCOME (-PnL)');
239
- console.log(' ───────────────────── ──────────────────');
240
- console.log(`GOOD PROCESS ✅ Earned: ${padRight(String(matrix.earnedReward.count), 12)}` +
241
- `📊 Variance: ${matrix.variance.count}`);
242
- console.log(`(correct thesis) Avg: ${padRight(formatUsd(matrix.earnedReward.avgPnl), 16)}` +
243
- `Avg: ${formatUsd(matrix.variance.avgPnl)}`);
244
- console.log('');
245
- console.log(`BAD PROCESS ⚠ Dumb Luck: ${padRight(String(matrix.dumbLuck.count), 9)}` +
246
- `💀 Mistake: ${matrix.mistake.count}`);
247
- console.log(`(wrong thesis) Avg: ${padRight(formatUsd(matrix.dumbLuck.avgPnl), 16)}` +
248
- `Avg: ${formatUsd(matrix.mistake.avgPnl)}`);
249
- console.log('');
250
- console.log(`Process Win Rate: ${(matrix.processWinRate * 100).toFixed(0)}%`);
251
- console.log(`Outcome Win Rate: ${(matrix.outcomeWinRate * 100).toFixed(0)}%`);
252
- console.log(`Lucky Profit Rate: ${(matrix.luckyProfitRate * 100).toFixed(0)}% of wins from wrong thesis`);
253
- if (matrix.luckyProfitRate > 0.2) {
254
- console.log('');
255
- console.log('⚠ CRITICAL: >20% of your wins came from wrong thesis.');
256
- console.log(' These are reinforcing bad habits. Review your Dumb Luck trades.');
257
- if (matrix.dumbLuck.trades.length > 0) {
258
- const shown = matrix.dumbLuck.trades.slice(0, 3);
259
- for (const t of shown) {
260
- console.log(` - ${t.tokenSymbol} ${t.direction ?? ''} ${new Date(t.eventTime).toLocaleDateString()} ` +
261
- `(${formatUsd(t.pnlAbsolute ?? 0)}): "${truncate(t.thesis ?? 'no thesis', 50)}"`);
262
- }
263
- }
264
- }
265
- }
266
- // ─── Command Registration ───
267
- export function registerReviewCommand(journal) {
268
- const review = journal
269
- .command('review')
270
- .description('Structured trading review');
271
- // ─── journal review daily ───
272
- review
273
- .command('daily')
274
- .description('Daily review — process adherence + emotional recalibration')
275
- .option('--date <date>', 'Review date (YYYY-MM-DD, defaults to today)')
276
- .option('--trader <traderId>', 'Trader ID', DEFAULT_TRADER_ID)
277
- .option('--process-first', 'Hide PnL until process is graded')
278
- .option('--format <format>', 'Output format (text or json)', 'text')
279
- .action(async (options) => {
280
- try {
281
- const date = options.date ?? new Date().toISOString().slice(0, 10);
282
- const review = await apiRequest(`/api/v1/reviews/daily?traderId=${encodeURIComponent(options.trader)}&date=${encodeURIComponent(date)}`);
283
- if (options.format === 'json') {
284
- console.log(JSON.stringify(review, null, 2));
285
- }
286
- else if (options.processFirst) {
287
- printProcessFirstReview(review);
288
- }
289
- else {
290
- printDailyReview(review);
291
- }
292
- }
293
- catch (error) {
294
- const message = error instanceof Error ? error.message : String(error);
295
- logger.error({ error: message }, 'Failed to generate daily review');
296
- console.error(`Error: ${message}`);
297
- if (!(error instanceof ApiError)) {
298
- const guidance = formatConnectionError(message);
299
- if (guidance)
300
- console.error(guidance);
301
- }
302
- process.exitCode = error instanceof ApiError ? 2 : 1;
303
- }
304
- });
305
- // ─── journal review weekly ───
306
- review
307
- .command('weekly')
308
- .description('Weekly review — pattern identification + strengths audit')
309
- .option('--date <date>', 'A date in the target week (YYYY-MM-DD, defaults to today)')
310
- .option('--trader <traderId>', 'Trader ID', DEFAULT_TRADER_ID)
311
- .option('--format <format>', 'Output format (text or json)', 'text')
312
- .action(async (options) => {
313
- try {
314
- const date = options.date ?? new Date().toISOString().slice(0, 10);
315
- const review = await apiRequest(`/api/v1/reviews/weekly?traderId=${encodeURIComponent(options.trader)}&date=${encodeURIComponent(date)}`);
316
- if (options.format === 'json') {
317
- console.log(JSON.stringify(review, null, 2));
318
- }
319
- else {
320
- printWeeklyReview(review);
321
- }
322
- }
323
- catch (error) {
324
- const message = error instanceof Error ? error.message : String(error);
325
- logger.error({ error: message }, 'Failed to generate weekly review');
326
- console.error(`Error: ${message}`);
327
- if (!(error instanceof ApiError)) {
328
- const guidance = formatConnectionError(message);
329
- if (guidance)
330
- console.error(guidance);
331
- }
332
- process.exitCode = error instanceof ApiError ? 2 : 1;
333
- }
334
- });
335
- // ─── journal review monthly ───
336
- review
337
- .command('monthly')
338
- .description('Monthly review — statistical validation + strategy refinement')
339
- .option('--date <date>', 'A date in the target month (YYYY-MM-DD, defaults to today)')
340
- .option('--trader <traderId>', 'Trader ID', DEFAULT_TRADER_ID)
341
- .option('--format <format>', 'Output format (text or json)', 'text')
342
- .action(async (options) => {
343
- try {
344
- const date = options.date || new Date().toISOString().slice(0, 10);
345
- const data = await apiRequest(`/api/v1/reviews/monthly?traderId=${encodeURIComponent(options.trader)}&date=${date}`);
346
- if (options.format === 'json') {
347
- console.log(JSON.stringify(data, null, 2));
348
- }
349
- else {
350
- printMonthlyReview(data);
351
- }
352
- }
353
- catch (error) {
354
- const message = error instanceof Error ? error.message : String(error);
355
- logger.error({ error: message }, 'Failed to generate monthly review');
356
- console.error(`Error: ${message}`);
357
- process.exitCode = error instanceof ApiError ? 2 : 1;
358
- }
359
- });
360
- // ─── journal review matrix ───
361
- review
362
- .command('matrix')
363
- .description('Process-outcome matrix — thesis accuracy analysis')
364
- .option('--trader <traderId>', 'Trader ID', DEFAULT_TRADER_ID)
365
- .option('--format <format>', 'Output format (text or json)', 'text')
366
- .action(async (options) => {
367
- try {
368
- const data = await apiRequest(`/api/v1/reviews/matrix?traderId=${encodeURIComponent(options.trader)}`);
369
- if (options.format === 'json') {
370
- console.log(JSON.stringify(data, null, 2));
371
- }
372
- else {
373
- console.log('\n Process-Outcome Matrix:\n');
374
- console.log(JSON.stringify(data, null, 2));
375
- console.log('');
376
- }
377
- }
378
- catch (error) {
379
- const message = error instanceof Error ? error.message : String(error);
380
- logger.error({ error: message }, 'Failed to generate matrix');
381
- console.error(`Error: ${message}`);
382
- process.exitCode = error instanceof ApiError ? 2 : 1;
383
- }
384
- });
385
- // ─── journal review calibration ───
386
- review
387
- .command('calibration')
388
- .description('Confidence calibration — predicted vs actual win rates')
389
- .option('--trader <traderId>', 'Trader ID', DEFAULT_TRADER_ID)
390
- .option('--format <format>', 'Output format (text or json)', 'text')
391
- .action(async (options) => {
392
- try {
393
- const data = await apiRequest(`/api/v1/reviews/calibration?traderId=${encodeURIComponent(options.trader)}`);
394
- if (options.format === 'json') {
395
- console.log(JSON.stringify(data, null, 2));
396
- }
397
- else {
398
- console.log('\n Confidence Calibration:\n');
399
- console.log(JSON.stringify(data, null, 2));
400
- console.log('');
401
- }
402
- }
403
- catch (error) {
404
- const message = error instanceof Error ? error.message : String(error);
405
- logger.error({ error: message }, 'Failed to generate calibration');
406
- console.error(`Error: ${message}`);
407
- process.exitCode = error instanceof ApiError ? 2 : 1;
408
- }
409
- });
410
- }
411
- // ─── Process-First Mode ───
412
- function printProcessFirstReview(review) {
413
- console.log('');
414
- console.log(`═══ Daily Review (Process-First) — ${review.date} ═══`);
415
- console.log('');
416
- console.log('PnL is hidden. Grade each trade on process before seeing results.');
417
- console.log('');
418
- if (review.exits.length === 0) {
419
- console.log('No exits today. Nothing to grade.');
420
- return;
421
- }
422
- for (let i = 0; i < review.exits.length; i++) {
423
- const t = review.exits[i];
424
- console.log(`Trade ${i + 1}/${review.exits.length}:`);
425
- console.log(` Token: ${t.tokenSymbol} Direction: ${t.direction ?? '-'} Setup: ${t.setupType ?? '-'}`);
426
- console.log(` Emotion: ${t.emotionalTag} Confidence: ${t.confidence.toFixed(2)}`);
427
- if (t.thesis)
428
- console.log(` Thesis: "${truncate(t.thesis, 60)}"`);
429
- console.log(` Process grade: [A] [B] [C] [D] [F]`);
430
- console.log('');
431
- }
432
- console.log('─── Revealing PnL ───');
433
- console.log('');
434
- for (let i = 0; i < review.exits.length; i++) {
435
- const t = review.exits[i];
436
- console.log(`Trade ${i + 1}: ${t.tokenSymbol} — PnL: ${formatUsd(t.pnlAbsolute ?? 0)} ` +
437
- `(${formatPct(t.pnlPercent ?? 0)}) Thesis: ${t.thesisAccuracy}`);
438
- }
439
- console.log('');
440
- console.log(`Total PnL: ${formatUsd(review.pnlToday)}`);
441
- console.log('');
442
- }
443
- //# sourceMappingURL=review.js.map
@@ -1,47 +0,0 @@
1
- import { Command } from 'commander';
2
- interface ProtocolRiskFactors {
3
- oracleConcentration: number;
4
- bridgeDependency: number;
5
- adminCentralization: number;
6
- auditStatus: number;
7
- tvlConcentration: number;
8
- dependencyDepth: number;
9
- [key: string]: number;
10
- }
11
- interface ProtocolRiskResult {
12
- protocolName: string;
13
- protocolId: string;
14
- riskScore: number;
15
- factors: ProtocolRiskFactors;
16
- }
17
- interface ContagionSimulationResult {
18
- sourceProtocol: string;
19
- sourceProtocolName: string;
20
- totalAffected: number;
21
- maxDepthReached: number;
22
- affected: Array<{
23
- protocolName: string;
24
- impactFactor: number;
25
- pathLength: number;
26
- transmissionEdge: string;
27
- path: string[];
28
- }>;
29
- }
30
- /**
31
- * Format a risk score (0-100) with color coding.
32
- * - 0-30: green (low risk)
33
- * - 31-60: yellow (moderate risk)
34
- * - 61-100: red (high risk)
35
- */
36
- export declare function formatRiskScore(score: number): string;
37
- /**
38
- * Format the full risk assessment output for a protocol.
39
- */
40
- export declare function formatRiskOutput(result: ProtocolRiskResult): string;
41
- /**
42
- * Format contagion simulation output.
43
- */
44
- export declare function formatContagionOutput(result: ContagionSimulationResult): string;
45
- export declare function registerRiskCommand(program: Command): void;
46
- export {};
47
- //# sourceMappingURL=risk.d.ts.map
@@ -1,158 +0,0 @@
1
- import { Option } from 'commander';
2
- import chalk from 'chalk';
3
- import { createLogger } from '@trading-boy/core';
4
- import { formatConnectionError, padRight, ensureRemote } from '../utils.js';
5
- import { apiRequest, ApiError } from '../api-client.js';
6
- // ─── Logger ───
7
- const logger = createLogger('cli-risk');
8
- // ─── Formatters ───
9
- /**
10
- * Format a risk score (0-100) with color coding.
11
- * - 0-30: green (low risk)
12
- * - 31-60: yellow (moderate risk)
13
- * - 61-100: red (high risk)
14
- */
15
- export function formatRiskScore(score) {
16
- const label = `${score}/100`;
17
- if (score <= 30) {
18
- return chalk.green(label);
19
- }
20
- if (score <= 60) {
21
- return chalk.yellow(label);
22
- }
23
- return chalk.red(label);
24
- }
25
- /**
26
- * Format a factor score with a visual bar.
27
- */
28
- function formatFactorBar(score, width = 20) {
29
- const filled = Math.round((score / 100) * width);
30
- const empty = width - filled;
31
- const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(empty);
32
- if (score <= 30) {
33
- return chalk.green(bar);
34
- }
35
- if (score <= 60) {
36
- return chalk.yellow(bar);
37
- }
38
- return chalk.red(bar);
39
- }
40
- /**
41
- * Format the full risk assessment output for a protocol.
42
- */
43
- export function formatRiskOutput(result) {
44
- const lines = [];
45
- lines.push('');
46
- lines.push(chalk.bold.cyan(` Protocol: ${result.protocolName}`));
47
- lines.push(chalk.gray(' ' + '\u2500'.repeat(50)));
48
- lines.push('');
49
- lines.push(` ${chalk.gray('Risk Score:')} ${formatRiskScore(result.riskScore)}`);
50
- lines.push('');
51
- lines.push(chalk.bold(' Factor Breakdown:'));
52
- lines.push('');
53
- const factors = [
54
- { name: 'Oracle Concentration', score: result.factors.oracleConcentration, weight: '25%' },
55
- { name: 'Bridge Dependency', score: result.factors.bridgeDependency, weight: '15%' },
56
- { name: 'Admin Centralization', score: result.factors.adminCentralization, weight: '20%' },
57
- { name: 'Audit Status', score: result.factors.auditStatus, weight: '15%' },
58
- { name: 'TVL Concentration', score: result.factors.tvlConcentration, weight: '10%' },
59
- { name: 'Dependency Depth', score: result.factors.dependencyDepth, weight: '15%' },
60
- ];
61
- for (const factor of factors) {
62
- const nameStr = padRight(factor.name, 24);
63
- const scoreStr = padRight(String(factor.score), 4);
64
- const bar = formatFactorBar(factor.score);
65
- lines.push(` ${chalk.gray(nameStr)} ${bar} ${scoreStr} ${chalk.dim(`(${factor.weight})`)}`);
66
- }
67
- lines.push('');
68
- return lines.join('\n');
69
- }
70
- /**
71
- * Format contagion simulation output.
72
- */
73
- export function formatContagionOutput(result) {
74
- const lines = [];
75
- lines.push('');
76
- lines.push(chalk.bold.red(` Contagion Simulation: ${result.sourceProtocolName} failure`));
77
- lines.push(chalk.gray(' ' + '\u2500'.repeat(50)));
78
- lines.push('');
79
- lines.push(` ${chalk.gray('Affected Protocols:')} ${chalk.yellow(String(result.totalAffected))}`);
80
- lines.push(` ${chalk.gray('Max Depth Reached:')} ${result.maxDepthReached}`);
81
- lines.push('');
82
- if (result.affected.length === 0) {
83
- lines.push(` ${chalk.dim('No downstream protocols affected.')}`);
84
- }
85
- else {
86
- lines.push(' ' +
87
- padRight('Protocol', 24) +
88
- padRight('Impact', 10) +
89
- padRight('Hops', 6) +
90
- padRight('Edge', 22) +
91
- 'Path');
92
- lines.push(' ' + '\u2500'.repeat(90));
93
- for (const affected of result.affected) {
94
- const impactStr = (affected.impactFactor * 100).toFixed(1) + '%';
95
- const impactColor = affected.impactFactor >= 0.5
96
- ? chalk.red
97
- : affected.impactFactor >= 0.25
98
- ? chalk.yellow
99
- : chalk.dim;
100
- lines.push(' ' +
101
- padRight(affected.protocolName, 24) +
102
- impactColor(padRight(impactStr, 10)) +
103
- padRight(String(affected.pathLength), 6) +
104
- padRight(affected.transmissionEdge, 22) +
105
- chalk.dim(affected.path.join(' -> ')));
106
- }
107
- }
108
- lines.push('');
109
- return lines.join('\n');
110
- }
111
- // ─── Command Registration ───
112
- export function registerRiskCommand(program) {
113
- program
114
- .command('risk <protocol>')
115
- .description('Assess DeFi protocol risk — dependency tree, risk score, concentration risks')
116
- .option('--contagion', 'Run contagion simulation to show affected protocols')
117
- .option('--update-all', 'Update risk scores for all protocols in the graph')
118
- .addOption(new Option('--format <format>', 'Output format').choices(['text', 'json']).default('text'))
119
- .action(async (protocol, options) => {
120
- if (options.updateAll) {
121
- console.error(chalk.yellow('--update-all is not yet supported via the API. Use the admin interface.'));
122
- process.exitCode = 1;
123
- return;
124
- }
125
- if (options.contagion) {
126
- console.error(chalk.yellow('--contagion is not yet supported via the API.'));
127
- process.exitCode = 1;
128
- return;
129
- }
130
- if (!(await ensureRemote()))
131
- return;
132
- try {
133
- const apiResult = await apiRequest(`/api/v1/protocols/${encodeURIComponent(protocol.toLowerCase())}/risk`);
134
- const result = {
135
- protocolName: apiResult.protocol,
136
- protocolId: protocol.toLowerCase(),
137
- riskScore: apiResult.riskScore,
138
- factors: apiResult.factors,
139
- };
140
- if (options.format === 'json') {
141
- console.log(JSON.stringify(result, null, 2));
142
- }
143
- else {
144
- console.log(formatRiskOutput(result));
145
- }
146
- }
147
- catch (error) {
148
- const message = error instanceof ApiError ? error.message : (error instanceof Error ? error.message : String(error));
149
- logger.error({ error: message }, 'Risk assessment failed');
150
- console.error(chalk.red(`Error: ${message}`));
151
- const guidance = formatConnectionError(message);
152
- if (guidance)
153
- console.error(guidance);
154
- process.exitCode = error instanceof ApiError ? 2 : 1;
155
- }
156
- });
157
- }
158
- //# sourceMappingURL=risk.js.map