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