@trading-boy/cli 1.5.1 → 1.6.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.
- package/dist/cli.bundle.js +47466 -45359
- package/dist/commands/onboarding.js +20 -12
- package/dist/commands/soul-wizard.d.ts +29 -0
- package/dist/commands/soul-wizard.js +155 -0
- package/dist/commands/subscribe.js +2 -2
- package/dist/commands/trader.js +26 -0
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// 3. Next steps cheat sheet
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import { isRemoteMode, apiRequest, ApiError } from '../api-client.js';
|
|
9
|
+
import { runSoulWizardAndUpload } from './soul-wizard.js';
|
|
9
10
|
// ─── Onboarding Flow ───
|
|
10
11
|
/**
|
|
11
12
|
* Run the interactive onboarding wizard.
|
|
@@ -21,6 +22,7 @@ export async function runOnboarding() {
|
|
|
21
22
|
console.log('');
|
|
22
23
|
// ─── Step 1: Register Trader ───
|
|
23
24
|
let traderRegistered = false;
|
|
25
|
+
let traderName = 'default';
|
|
24
26
|
try {
|
|
25
27
|
const wantsTrader = await confirm({
|
|
26
28
|
message: 'Register your trader profile?',
|
|
@@ -54,6 +56,7 @@ export async function runOnboarding() {
|
|
|
54
56
|
console.log(chalk.dim(' This alias is public on the leaderboard. Change it anytime:'));
|
|
55
57
|
console.log(chalk.dim(' trading-boy trader set-alias <name> <new-alias>'));
|
|
56
58
|
}
|
|
59
|
+
traderName = name.trim();
|
|
57
60
|
traderRegistered = true;
|
|
58
61
|
}
|
|
59
62
|
else {
|
|
@@ -63,6 +66,7 @@ export async function runOnboarding() {
|
|
|
63
66
|
catch (error) {
|
|
64
67
|
if (error instanceof ApiError && error.status === 409) {
|
|
65
68
|
console.log(chalk.green(' \u2713 Trader profile already exists.'));
|
|
69
|
+
traderName = name.trim();
|
|
66
70
|
traderRegistered = true;
|
|
67
71
|
}
|
|
68
72
|
else {
|
|
@@ -86,7 +90,7 @@ export async function runOnboarding() {
|
|
|
86
90
|
if (traderRegistered) {
|
|
87
91
|
try {
|
|
88
92
|
const wantsIdentity = await confirm({
|
|
89
|
-
message: 'Set up your trading identity? (SOUL
|
|
93
|
+
message: 'Set up your trading identity? (interactive SOUL wizard)',
|
|
90
94
|
default: true,
|
|
91
95
|
});
|
|
92
96
|
if (wantsIdentity) {
|
|
@@ -94,15 +98,19 @@ export async function runOnboarding() {
|
|
|
94
98
|
console.log(chalk.dim(' Your identity personalizes context — bias warnings, scope checks,'));
|
|
95
99
|
console.log(chalk.dim(' and tailored synthesis based on who you are as a trader.'));
|
|
96
100
|
console.log('');
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
try {
|
|
102
|
+
await runSoulWizardAndUpload(traderName);
|
|
103
|
+
}
|
|
104
|
+
catch (wizardError) {
|
|
105
|
+
if (isUserAbort(wizardError))
|
|
106
|
+
return;
|
|
107
|
+
const msg = wizardError instanceof Error ? wizardError.message : String(wizardError);
|
|
108
|
+
console.log(chalk.yellow(` Could not complete SOUL wizard: ${msg}`));
|
|
109
|
+
console.log(chalk.dim(' You can do this later: trading-boy trader soul-wizard <name>'));
|
|
110
|
+
}
|
|
103
111
|
}
|
|
104
112
|
else {
|
|
105
|
-
console.log(chalk.dim(' Skipped.
|
|
113
|
+
console.log(chalk.dim(' Skipped. Run later: trading-boy trader soul-wizard <name>'));
|
|
106
114
|
}
|
|
107
115
|
}
|
|
108
116
|
catch (error) {
|
|
@@ -120,14 +128,14 @@ export async function runOnboarding() {
|
|
|
120
128
|
});
|
|
121
129
|
if (wantsTelegram) {
|
|
122
130
|
console.log('');
|
|
123
|
-
console.log(chalk.white('
|
|
124
|
-
console.log(chalk.white(' Send ') + chalk.cyan('/start') + chalk.white('
|
|
131
|
+
console.log(chalk.white(' Click to open the bot: ') + chalk.cyan.underline('https://t.me/TradingBoy1_Bot'));
|
|
132
|
+
console.log(chalk.white(' Send ') + chalk.cyan('/start') + chalk.white(' and paste your API key to connect.'));
|
|
125
133
|
console.log('');
|
|
126
134
|
console.log(chalk.dim(' The bot will send you a daily trading summary at 08:00 UTC.'));
|
|
127
|
-
console.log(chalk.dim(' You can also use /summary, /
|
|
135
|
+
console.log(chalk.dim(' You can also use /summary, /agents, /positions, /pause, and /soul.'));
|
|
128
136
|
}
|
|
129
137
|
else {
|
|
130
|
-
console.log(chalk.dim(' Skipped.
|
|
138
|
+
console.log(chalk.dim(' Skipped. Connect anytime: ') + chalk.dim.underline('https://t.me/TradingBoy1_Bot'));
|
|
131
139
|
}
|
|
132
140
|
}
|
|
133
141
|
catch (error) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface SoulWizardAnswers {
|
|
2
|
+
style: string;
|
|
3
|
+
riskTolerance: string;
|
|
4
|
+
assets: string[];
|
|
5
|
+
timeHorizon: string;
|
|
6
|
+
biases: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Run the interactive SOUL wizard and return the generated SOUL text.
|
|
10
|
+
* Throws if user aborts (Ctrl+C).
|
|
11
|
+
*/
|
|
12
|
+
export declare function runSoulWizard(): Promise<{
|
|
13
|
+
answers: SoulWizardAnswers;
|
|
14
|
+
soulText: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Upload a SOUL document to the trader's profile.
|
|
18
|
+
*/
|
|
19
|
+
export declare function uploadSoul(traderName: string, soulText: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Print the generated SOUL document with chalk styling.
|
|
22
|
+
*/
|
|
23
|
+
export declare function displaySoul(soulText: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Run wizard + upload + display. Used by both onboarding and standalone command.
|
|
26
|
+
* Returns true if SOUL was uploaded successfully.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runSoulWizardAndUpload(traderName: string): Promise<boolean>;
|
|
29
|
+
//# sourceMappingURL=soul-wizard.d.ts.map
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// ─── SOUL Wizard ───
|
|
2
|
+
//
|
|
3
|
+
// Interactive wizard to generate a SOUL document from guided questions.
|
|
4
|
+
// Shared between onboarding flow and standalone `trader soul-wizard` command.
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { apiRequest, ApiError } from '../api-client.js';
|
|
7
|
+
// ─── Labels ───
|
|
8
|
+
const STYLE_LABELS = {
|
|
9
|
+
aggressive_momentum: 'Aggressive Momentum',
|
|
10
|
+
conservative_value: 'Conservative Value',
|
|
11
|
+
balanced: 'Balanced',
|
|
12
|
+
degen: 'Degen / High Risk',
|
|
13
|
+
macro: 'Macro / Fundamentals',
|
|
14
|
+
};
|
|
15
|
+
const RISK_LABELS = {
|
|
16
|
+
low: 'Low (1-3% per trade)',
|
|
17
|
+
medium: 'Medium (3-7%)',
|
|
18
|
+
high: 'High (7-15%)',
|
|
19
|
+
degen: 'Degen (15%+)',
|
|
20
|
+
};
|
|
21
|
+
const ASSET_LABELS = {
|
|
22
|
+
crypto: 'Crypto',
|
|
23
|
+
commodities: 'Commodities',
|
|
24
|
+
equities: 'Equities',
|
|
25
|
+
forex: 'Forex',
|
|
26
|
+
};
|
|
27
|
+
const HORIZON_LABELS = {
|
|
28
|
+
scalping: 'Scalping (minutes)',
|
|
29
|
+
day: 'Day trading (hours)',
|
|
30
|
+
swing: 'Swing (days)',
|
|
31
|
+
position: 'Position (weeks+)',
|
|
32
|
+
};
|
|
33
|
+
// ─── Wizard ───
|
|
34
|
+
/**
|
|
35
|
+
* Run the interactive SOUL wizard and return the generated SOUL text.
|
|
36
|
+
* Throws if user aborts (Ctrl+C).
|
|
37
|
+
*/
|
|
38
|
+
export async function runSoulWizard() {
|
|
39
|
+
const { select, checkbox, input } = await import('@inquirer/prompts');
|
|
40
|
+
const style = await select({
|
|
41
|
+
message: 'What\'s your trading style?',
|
|
42
|
+
choices: [
|
|
43
|
+
{ value: 'aggressive_momentum', name: 'Aggressive Momentum' },
|
|
44
|
+
{ value: 'conservative_value', name: 'Conservative Value' },
|
|
45
|
+
{ value: 'balanced', name: 'Balanced' },
|
|
46
|
+
{ value: 'degen', name: 'Degen / High Risk' },
|
|
47
|
+
{ value: 'macro', name: 'Macro / Fundamentals' },
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
const riskTolerance = await select({
|
|
51
|
+
message: 'Risk tolerance?',
|
|
52
|
+
choices: [
|
|
53
|
+
{ value: 'low', name: 'Low (1-3% per trade)' },
|
|
54
|
+
{ value: 'medium', name: 'Medium (3-7%)' },
|
|
55
|
+
{ value: 'high', name: 'High (7-15%)' },
|
|
56
|
+
{ value: 'degen', name: 'Degen (15%+)' },
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
const assets = await checkbox({
|
|
60
|
+
message: 'What assets do you trade?',
|
|
61
|
+
choices: [
|
|
62
|
+
{ value: 'crypto', name: 'Crypto' },
|
|
63
|
+
{ value: 'commodities', name: 'Commodities' },
|
|
64
|
+
{ value: 'equities', name: 'Equities' },
|
|
65
|
+
{ value: 'forex', name: 'Forex' },
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
const timeHorizon = await select({
|
|
69
|
+
message: 'Time horizon?',
|
|
70
|
+
choices: [
|
|
71
|
+
{ value: 'scalping', name: 'Scalping (minutes)' },
|
|
72
|
+
{ value: 'day', name: 'Day trading (hours)' },
|
|
73
|
+
{ value: 'swing', name: 'Swing (days)' },
|
|
74
|
+
{ value: 'position', name: 'Position (weeks+)' },
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
const biases = await input({
|
|
78
|
+
message: 'Any biases to watch for? (optional, press Enter to skip)',
|
|
79
|
+
});
|
|
80
|
+
const answers = { style, riskTolerance, assets, timeHorizon, biases };
|
|
81
|
+
const soulText = buildSoulDocument(answers);
|
|
82
|
+
return { answers, soulText };
|
|
83
|
+
}
|
|
84
|
+
// ─── SOUL Document Builder ───
|
|
85
|
+
function buildSoulDocument(answers) {
|
|
86
|
+
const styleLabel = STYLE_LABELS[answers.style] ?? answers.style;
|
|
87
|
+
const riskLabel = RISK_LABELS[answers.riskTolerance] ?? answers.riskTolerance;
|
|
88
|
+
const assetLabels = answers.assets.map(a => ASSET_LABELS[a] ?? a).join(', ') || 'Not specified';
|
|
89
|
+
const horizonLabel = HORIZON_LABELS[answers.timeHorizon] ?? answers.timeHorizon;
|
|
90
|
+
const lines = [];
|
|
91
|
+
lines.push(`Trading Style: ${styleLabel}`);
|
|
92
|
+
lines.push(`Risk Tolerance: ${riskLabel}`);
|
|
93
|
+
lines.push(`Asset Classes: ${assetLabels}`);
|
|
94
|
+
lines.push(`Time Horizon: ${horizonLabel}`);
|
|
95
|
+
if (answers.biases.trim()) {
|
|
96
|
+
lines.push(`Known Biases: ${answers.biases.trim()}`);
|
|
97
|
+
}
|
|
98
|
+
lines.push('');
|
|
99
|
+
lines.push(`This trader favors ${styleLabel.toLowerCase()} approaches with ${riskLabel.toLowerCase()} risk tolerance,`);
|
|
100
|
+
lines.push(`primarily trading ${assetLabels.toLowerCase()}. They operate on a ${horizonLabel.toLowerCase()} timeframe.`);
|
|
101
|
+
if (answers.biases.trim()) {
|
|
102
|
+
lines.push(`Watch for: ${answers.biases.trim()}`);
|
|
103
|
+
}
|
|
104
|
+
return lines.join('\n');
|
|
105
|
+
}
|
|
106
|
+
// ─── Upload ───
|
|
107
|
+
/**
|
|
108
|
+
* Upload a SOUL document to the trader's profile.
|
|
109
|
+
*/
|
|
110
|
+
export async function uploadSoul(traderName, soulText) {
|
|
111
|
+
await apiRequest(`/api/v1/traders/${encodeURIComponent(traderName)}/soul`, {
|
|
112
|
+
method: 'PUT',
|
|
113
|
+
body: { document: soulText },
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// ─── Display ───
|
|
117
|
+
/**
|
|
118
|
+
* Print the generated SOUL document with chalk styling.
|
|
119
|
+
*/
|
|
120
|
+
export function displaySoul(soulText) {
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log(chalk.bold.cyan(' Generated SOUL Document'));
|
|
123
|
+
console.log(chalk.gray(' ' + '\u2500'.repeat(50)));
|
|
124
|
+
console.log('');
|
|
125
|
+
for (const line of soulText.split('\n')) {
|
|
126
|
+
console.log(` ${chalk.white(line)}`);
|
|
127
|
+
}
|
|
128
|
+
console.log('');
|
|
129
|
+
}
|
|
130
|
+
// ─── Combined Flow ───
|
|
131
|
+
/**
|
|
132
|
+
* Run wizard + upload + display. Used by both onboarding and standalone command.
|
|
133
|
+
* Returns true if SOUL was uploaded successfully.
|
|
134
|
+
*/
|
|
135
|
+
export async function runSoulWizardAndUpload(traderName) {
|
|
136
|
+
const { soulText } = await runSoulWizard();
|
|
137
|
+
displaySoul(soulText);
|
|
138
|
+
try {
|
|
139
|
+
await uploadSoul(traderName, soulText);
|
|
140
|
+
console.log(chalk.green(` \u2713 SOUL uploaded for trader "${traderName}"`));
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (error instanceof ApiError) {
|
|
145
|
+
console.log(chalk.yellow(` Could not upload SOUL: ${error.message}`));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
149
|
+
console.log(chalk.yellow(` Could not upload SOUL: ${msg}`));
|
|
150
|
+
}
|
|
151
|
+
console.log(chalk.dim(' You can upload it later: trading-boy trader soul <name> --file soul.md'));
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=soul-wizard.js.map
|
|
@@ -217,8 +217,8 @@ export function formatSubscribeSuccess(result) {
|
|
|
217
217
|
lines.push(` ${chalk.bold('API Key:')} ${chalk.yellow(result.apiKey)}`);
|
|
218
218
|
lines.push('');
|
|
219
219
|
lines.push(chalk.dim(' ⚠️ Copy this key now — it will not be shown again.'));
|
|
220
|
-
lines.push(chalk.dim('
|
|
221
|
-
lines.push(chalk.dim(' and paste
|
|
220
|
+
lines.push(chalk.dim(' Connect Telegram: ') + chalk.dim.underline('https://t.me/TradingBoy1_Bot'));
|
|
221
|
+
lines.push(chalk.dim(' Send /start and paste this key when prompted.'));
|
|
222
222
|
}
|
|
223
223
|
else if (result.keyPrefix) {
|
|
224
224
|
lines.push(` ${chalk.bold('Key ID:')} ${result.keyPrefix}`);
|
package/dist/commands/trader.js
CHANGED
|
@@ -443,6 +443,32 @@ export function registerTraderCommand(program) {
|
|
|
443
443
|
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
444
444
|
}
|
|
445
445
|
});
|
|
446
|
+
// ─── soul-wizard ───
|
|
447
|
+
trader
|
|
448
|
+
.command('soul-wizard')
|
|
449
|
+
.description('Interactive wizard to create your trading identity')
|
|
450
|
+
.argument('<name>', 'Trader name')
|
|
451
|
+
.action(async (name) => {
|
|
452
|
+
try {
|
|
453
|
+
const { runSoulWizardAndUpload } = await import('./soul-wizard.js');
|
|
454
|
+
console.log('');
|
|
455
|
+
console.log(chalk.bold.cyan(' SOUL Wizard'));
|
|
456
|
+
console.log(chalk.gray(' ' + '\u2500'.repeat(50)));
|
|
457
|
+
console.log(chalk.dim(' Answer a few questions to generate your trading identity.'));
|
|
458
|
+
console.log('');
|
|
459
|
+
await runSoulWizardAndUpload(name);
|
|
460
|
+
}
|
|
461
|
+
catch (error) {
|
|
462
|
+
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
463
|
+
console.log('');
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
467
|
+
logger.error({ error: message }, 'Soul wizard failed');
|
|
468
|
+
console.error(chalk.red(` Error: ${message}`));
|
|
469
|
+
process.exitCode = error instanceof ApiError ? 2 : 1;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
446
472
|
// ─── purpose ───
|
|
447
473
|
trader
|
|
448
474
|
.command('purpose')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "Trading Boy CLI — crypto context intelligence for traders and AI agents. Query real-time prices, funding rates, whale activity, and DeFi risk for 100+ Solana tokens and 229 Hyperliquid perpetuals.",
|
|
5
5
|
"homepage": "https://cabal.ventures",
|
|
6
6
|
"repository": {
|