@trading-boy/cli 1.8.0 → 1.9.2
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 +99 -21
- package/dist/commands/agent-cmd.js +2 -2
- package/dist/commands/config-cmd.js +27 -15
- package/dist/commands/onboarding.js +87 -6
- package/package.json +1 -1
package/dist/cli.bundle.js
CHANGED
|
@@ -56362,7 +56362,7 @@ function registerConfigCommand(program2) {
|
|
|
56362
56362
|
process.exitCode = 1;
|
|
56363
56363
|
}
|
|
56364
56364
|
});
|
|
56365
|
-
configCmd.command("set-llm-key <apiKey>").description("Store your LLM API key for thesis extraction + coaching (BYOK)").addOption(new Option("-p, --provider <provider>", "LLM provider (auto-detected from key prefix if omitted)").choices(["anthropic", "openai", "openrouter", "ollama", "gemini", "custom"])).option("-m, --model <model>", "Model name (default for all phases)").option("--base-url <url>", "Custom base URL (for openrouter/ollama/custom providers)").option("--scan-model <model>", "Model for market scanning (e.g. claude-haiku-4-5)").option("--analyze-model <model>", "Model for deep analysis (e.g. claude-sonnet-4-6)").option("--decide-model <model>", "Model for trade decisions (e.g. claude-opus-4-6)").action(async (apiKey, opts) => {
|
|
56365
|
+
configCmd.command("set-llm-key <apiKey>").description("Store your LLM API key for thesis extraction + coaching (BYOK)").addOption(new Option("-p, --provider <provider>", "LLM provider (auto-detected from key prefix if omitted)").choices(["anthropic", "openai", "openrouter", "ollama", "gemini", "custom"])).option("-m, --model <model>", "Model name (default for all phases)").option("--base-url <url>", "Custom base URL (for openrouter/ollama/custom providers)").option("--scan-model <model>", "Model for market scanning (e.g. claude-haiku-4-5)").option("--analyze-model <model>", "Model for deep analysis (e.g. claude-sonnet-4-6)").option("--decide-model <model>", "Model for trade decisions (e.g. claude-opus-4-6)").addOption(new Option("--scan-provider <provider>", "Provider for scan phase").choices(["anthropic", "openai", "openrouter", "ollama", "gemini", "custom"])).option("--scan-key <key>", "API key for scan phase provider").addOption(new Option("--analyze-provider <provider>", "Provider for analyze phase").choices(["anthropic", "openai", "openrouter", "ollama", "gemini", "custom"])).option("--analyze-key <key>", "API key for analyze phase provider").addOption(new Option("--decide-provider <provider>", "Provider for decide phase").choices(["anthropic", "openai", "openrouter", "ollama", "gemini", "custom"])).option("--decide-key <key>", "API key for decide phase provider").action(async (apiKey, opts) => {
|
|
56366
56366
|
try {
|
|
56367
56367
|
const result = await apiRequest("/api/v1/llm-config", {
|
|
56368
56368
|
method: "PUT",
|
|
@@ -56373,23 +56373,29 @@ function registerConfigCommand(program2) {
|
|
|
56373
56373
|
...opts.baseUrl ? { baseUrl: opts.baseUrl } : {},
|
|
56374
56374
|
...opts.scanModel ? { scanModel: opts.scanModel } : {},
|
|
56375
56375
|
...opts.analyzeModel ? { analyzeModel: opts.analyzeModel } : {},
|
|
56376
|
-
...opts.decideModel ? { decideModel: opts.decideModel } : {}
|
|
56376
|
+
...opts.decideModel ? { decideModel: opts.decideModel } : {},
|
|
56377
|
+
...opts.scanProvider ? { scanProvider: opts.scanProvider } : {},
|
|
56378
|
+
...opts.scanKey ? { scanApiKey: opts.scanKey } : {},
|
|
56379
|
+
...opts.analyzeProvider ? { analyzeProvider: opts.analyzeProvider } : {},
|
|
56380
|
+
...opts.analyzeKey ? { analyzeApiKey: opts.analyzeKey } : {},
|
|
56381
|
+
...opts.decideProvider ? { decideProvider: opts.decideProvider } : {},
|
|
56382
|
+
...opts.decideKey ? { decideApiKey: opts.decideKey } : {}
|
|
56377
56383
|
}
|
|
56378
56384
|
});
|
|
56379
56385
|
console.log("");
|
|
56380
56386
|
console.log(source_default.green(" LLM API key saved successfully"));
|
|
56381
|
-
console.log(` ${source_default.gray("Provider:")}
|
|
56382
|
-
console.log(` ${source_default.gray("Model:")}
|
|
56383
|
-
if (result.scanModel) {
|
|
56384
|
-
console.log(` ${source_default.gray("Scan
|
|
56387
|
+
console.log(` ${source_default.gray("Provider:")} ${result.provider}`);
|
|
56388
|
+
console.log(` ${source_default.gray("Model:")} ${result.model}`);
|
|
56389
|
+
if (result.scanProvider || result.scanModel) {
|
|
56390
|
+
console.log(` ${source_default.gray("Scan:")} ${result.scanProvider ?? result.provider} / ${result.scanModel ?? result.model}${opts.scanKey ? " (own key)" : ""}`);
|
|
56385
56391
|
}
|
|
56386
|
-
if (result.analyzeModel) {
|
|
56387
|
-
console.log(` ${source_default.gray("Analyze
|
|
56392
|
+
if (result.analyzeProvider || result.analyzeModel) {
|
|
56393
|
+
console.log(` ${source_default.gray("Analyze:")} ${result.analyzeProvider ?? result.provider} / ${result.analyzeModel ?? result.model}${opts.analyzeKey ? " (own key)" : ""}`);
|
|
56388
56394
|
}
|
|
56389
|
-
if (result.decideModel) {
|
|
56390
|
-
console.log(` ${source_default.gray("Decide
|
|
56395
|
+
if (result.decideProvider || result.decideModel) {
|
|
56396
|
+
console.log(` ${source_default.gray("Decide:")} ${result.decideProvider ?? result.provider} / ${result.decideModel ?? result.model}${opts.decideKey ? " (own key)" : ""}`);
|
|
56391
56397
|
}
|
|
56392
|
-
console.log(` ${source_default.gray("Key:")}
|
|
56398
|
+
console.log(` ${source_default.gray("Key:")} ${apiKey.slice(0, 8)}${"*".repeat(Math.max(0, apiKey.length - 8))}`);
|
|
56393
56399
|
console.log("");
|
|
56394
56400
|
console.log(source_default.dim(" Your key is encrypted at rest. Thesis extraction and coaching are now enabled."));
|
|
56395
56401
|
console.log("");
|
|
@@ -56411,14 +56417,14 @@ function registerConfigCommand(program2) {
|
|
|
56411
56417
|
console.log(source_default.gray(" " + "\u2500".repeat(40)));
|
|
56412
56418
|
console.log(` ${source_default.gray("Provider:")} ${result.provider}`);
|
|
56413
56419
|
console.log(` ${source_default.gray("Model:")} ${result.model}`);
|
|
56414
|
-
if (result.scanModel) {
|
|
56415
|
-
console.log(` ${source_default.gray("Scan
|
|
56420
|
+
if (result.scanProvider || result.scanModel) {
|
|
56421
|
+
console.log(` ${source_default.gray("Scan:")} ${result.scanProvider ?? result.provider} / ${result.scanModel ?? result.model}`);
|
|
56416
56422
|
}
|
|
56417
|
-
if (result.analyzeModel) {
|
|
56418
|
-
console.log(` ${source_default.gray("Analyze
|
|
56423
|
+
if (result.analyzeProvider || result.analyzeModel) {
|
|
56424
|
+
console.log(` ${source_default.gray("Analyze:")} ${result.analyzeProvider ?? result.provider} / ${result.analyzeModel ?? result.model}`);
|
|
56419
56425
|
}
|
|
56420
|
-
if (result.decideModel) {
|
|
56421
|
-
console.log(` ${source_default.gray("Decide
|
|
56426
|
+
if (result.decideProvider || result.decideModel) {
|
|
56427
|
+
console.log(` ${source_default.gray("Decide:")} ${result.decideProvider ?? result.provider} / ${result.decideModel ?? result.model}`);
|
|
56422
56428
|
}
|
|
56423
56429
|
if (result.baseUrl) {
|
|
56424
56430
|
console.log(` ${source_default.gray("Base URL:")} ${result.baseUrl}`);
|
|
@@ -57095,6 +57101,58 @@ async function runOnboarding() {
|
|
|
57095
57101
|
}
|
|
57096
57102
|
console.log("");
|
|
57097
57103
|
}
|
|
57104
|
+
try {
|
|
57105
|
+
console.log(source_default.bold.cyan(" LLM API Key (required for agents)"));
|
|
57106
|
+
console.log(source_default.gray(" " + "\u2500".repeat(50)));
|
|
57107
|
+
console.log(source_default.dim(" Your agent needs an LLM to analyze markets and make decisions."));
|
|
57108
|
+
console.log(source_default.dim(" Bring your own key from any supported provider:"));
|
|
57109
|
+
console.log("");
|
|
57110
|
+
console.log(` ${source_default.white("Anthropic")} ${source_default.dim("(default) \u2014 Claude Sonnet/Opus/Haiku")}`);
|
|
57111
|
+
console.log(` ${source_default.white("Gemini")} ${source_default.dim("\u2014 Gemini 2.5 Pro")}`);
|
|
57112
|
+
console.log(` ${source_default.white("OpenAI")} ${source_default.dim("\u2014 GPT-4o")}`);
|
|
57113
|
+
console.log(` ${source_default.white("OpenRouter")} ${source_default.dim("\u2014 Any model via OpenRouter")}`);
|
|
57114
|
+
console.log(` ${source_default.white("Ollama")} ${source_default.dim("\u2014 Local models")}`);
|
|
57115
|
+
console.log("");
|
|
57116
|
+
console.log(source_default.dim(" The provider is auto-detected from the key prefix."));
|
|
57117
|
+
console.log(source_default.dim(" The model defaults to a sensible choice per provider."));
|
|
57118
|
+
console.log("");
|
|
57119
|
+
const wantsLlmKey = await confirm({
|
|
57120
|
+
message: "Set up your LLM API key now?",
|
|
57121
|
+
default: true
|
|
57122
|
+
});
|
|
57123
|
+
if (wantsLlmKey) {
|
|
57124
|
+
const llmKey = await input({
|
|
57125
|
+
message: "Paste your API key",
|
|
57126
|
+
validate: (v) => v.trim().length > 5 ? true : "Key is too short"
|
|
57127
|
+
});
|
|
57128
|
+
try {
|
|
57129
|
+
if (await isRemoteMode()) {
|
|
57130
|
+
const result = await apiRequest("/api/v1/llm-config", {
|
|
57131
|
+
method: "PUT",
|
|
57132
|
+
body: { apiKey: llmKey.trim() }
|
|
57133
|
+
});
|
|
57134
|
+
console.log(source_default.green(` \u2713 LLM key saved \u2014 ${result.provider} / ${result.model}`));
|
|
57135
|
+
console.log(source_default.dim(" Change model later: trading-boy config set-llm-key <key> --model <model>"));
|
|
57136
|
+
} else {
|
|
57137
|
+
console.log(source_default.yellow(" Skipped \u2014 not connected to API."));
|
|
57138
|
+
}
|
|
57139
|
+
} catch (error49) {
|
|
57140
|
+
const msg = error49 instanceof Error ? error49.message : String(error49);
|
|
57141
|
+
console.log(source_default.yellow(` Could not save LLM key: ${msg}`));
|
|
57142
|
+
console.log(source_default.dim(" Set it later: trading-boy config set-llm-key <your-api-key>"));
|
|
57143
|
+
}
|
|
57144
|
+
} else {
|
|
57145
|
+
console.log("");
|
|
57146
|
+
console.log(source_default.yellow(" \u26A0 Without an LLM key, agents can scan prices but cannot"));
|
|
57147
|
+
console.log(source_default.yellow(" analyze markets or make trade decisions."));
|
|
57148
|
+
console.log(source_default.dim(" Set it later: trading-boy config set-llm-key <your-api-key>"));
|
|
57149
|
+
}
|
|
57150
|
+
} catch (error49) {
|
|
57151
|
+
if (isUserAbort(error49))
|
|
57152
|
+
return;
|
|
57153
|
+
throw error49;
|
|
57154
|
+
}
|
|
57155
|
+
console.log("");
|
|
57098
57156
|
try {
|
|
57099
57157
|
const wantsTelegram = await confirm({
|
|
57100
57158
|
message: "Connect Telegram for daily summaries?",
|
|
@@ -57116,13 +57174,33 @@ async function runOnboarding() {
|
|
|
57116
57174
|
throw error49;
|
|
57117
57175
|
}
|
|
57118
57176
|
console.log("");
|
|
57177
|
+
console.log(source_default.bold.cyan(" How Agents Work"));
|
|
57178
|
+
console.log(source_default.gray(" " + "\u2500".repeat(50)));
|
|
57179
|
+
console.log("");
|
|
57180
|
+
console.log(source_default.dim(" Once you create an agent, it runs continuously on our servers:"));
|
|
57181
|
+
console.log("");
|
|
57182
|
+
console.log(` ${source_default.white("Scan")} ${source_default.dim("Every 5 min (configurable) \u2014 scans your watchlist for setups")}`);
|
|
57183
|
+
console.log(` ${source_default.white("Analyze")} ${source_default.dim("When a setup is found \u2014 deep context analysis via your LLM")}`);
|
|
57184
|
+
console.log(` ${source_default.white("Decide")} ${source_default.dim("After analysis \u2014 enter/exit/hold based on your strategy")}`);
|
|
57185
|
+
console.log(` ${source_default.white("Learn")} ${source_default.dim("After trades close \u2014 updates edge profile from outcomes")}`);
|
|
57186
|
+
console.log("");
|
|
57187
|
+
console.log(source_default.dim(" Autonomy levels:"));
|
|
57188
|
+
console.log(` ${source_default.cyan("OBSERVE_ONLY")} ${source_default.dim("Scans and analyzes \u2014 takes no action")}`);
|
|
57189
|
+
console.log(` ${source_default.cyan("SUGGEST")} ${source_default.dim("Sends trade ideas to your Telegram")}`);
|
|
57190
|
+
console.log(` ${source_default.cyan("AUTO_WITH_APPROVAL")} ${source_default.dim("Proposes trades, waits for your OK")}`);
|
|
57191
|
+
console.log(` ${source_default.cyan("FULLY_AUTONOMOUS")} ${source_default.dim("Trades within your guardrails, no human in the loop")}`);
|
|
57192
|
+
console.log("");
|
|
57193
|
+
console.log(source_default.dim(" Create your first agent:"));
|
|
57194
|
+
console.log(` ${source_default.white("trading-boy agent create --help")}`);
|
|
57195
|
+
console.log("");
|
|
57119
57196
|
console.log(source_default.bold.cyan(" Quick Reference"));
|
|
57120
57197
|
console.log(source_default.gray(" " + "\u2500".repeat(50)));
|
|
57121
57198
|
console.log("");
|
|
57122
57199
|
console.log(` ${source_default.white("trading-boy context SOL")} ${source_default.dim("Full context for any token")}`);
|
|
57123
|
-
console.log(` ${source_default.white("trading-boy
|
|
57200
|
+
console.log(` ${source_default.white("trading-boy agent create")} ${source_default.dim("Create an autonomous agent")}`);
|
|
57201
|
+
console.log(` ${source_default.white("trading-boy agent list")} ${source_default.dim("View your running agents")}`);
|
|
57124
57202
|
console.log(` ${source_default.white("trading-boy decisions")} ${source_default.dim("View trade history")}`);
|
|
57125
|
-
console.log(` ${source_default.white("trading-boy
|
|
57203
|
+
console.log(` ${source_default.white("trading-boy stats")} ${source_default.dim("Track performance")}`);
|
|
57126
57204
|
console.log(` ${source_default.white("trading-boy narrative list")} ${source_default.dim("Active market narratives")}`);
|
|
57127
57205
|
console.log(` ${source_default.white("trading-boy catalysts")} ${source_default.dim("Upcoming events")}`);
|
|
57128
57206
|
if (traderRegistered) {
|
|
@@ -59213,7 +59291,7 @@ function registerAgentCommand(program2) {
|
|
|
59213
59291
|
if (options.assetClass)
|
|
59214
59292
|
body.assetClass = options.assetClass;
|
|
59215
59293
|
if (options.exitReasoner)
|
|
59216
|
-
body.
|
|
59294
|
+
body.exitReasonerEnabled = true;
|
|
59217
59295
|
if (options.soulFile) {
|
|
59218
59296
|
const path5 = resolve2(options.soulFile);
|
|
59219
59297
|
if (!existsSync3(path5)) {
|
|
@@ -59449,7 +59527,7 @@ function registerAgentCommand(program2) {
|
|
|
59449
59527
|
if (options.name)
|
|
59450
59528
|
body.name = options.name;
|
|
59451
59529
|
if (options.exitReasoner)
|
|
59452
|
-
body.
|
|
59530
|
+
body.exitReasonerEnabled = true;
|
|
59453
59531
|
if (options.autonomy)
|
|
59454
59532
|
body.autonomyLevel = options.autonomy;
|
|
59455
59533
|
if (options.scanIntervalHuman) {
|
|
@@ -159,7 +159,7 @@ export function registerAgentCommand(program) {
|
|
|
159
159
|
if (options.assetClass)
|
|
160
160
|
body.assetClass = options.assetClass;
|
|
161
161
|
if (options.exitReasoner)
|
|
162
|
-
body.
|
|
162
|
+
body.exitReasonerEnabled = true;
|
|
163
163
|
// Soul override — file takes precedence over inline text
|
|
164
164
|
if (options.soulFile) {
|
|
165
165
|
const path = resolve(options.soulFile);
|
|
@@ -482,7 +482,7 @@ export function registerAgentCommand(program) {
|
|
|
482
482
|
if (options.name)
|
|
483
483
|
body.name = options.name;
|
|
484
484
|
if (options.exitReasoner)
|
|
485
|
-
body.
|
|
485
|
+
body.exitReasonerEnabled = true;
|
|
486
486
|
if (options.autonomy)
|
|
487
487
|
body.autonomyLevel = options.autonomy;
|
|
488
488
|
// Resolve scan interval: --scan-interval-human takes precedence
|
|
@@ -328,6 +328,12 @@ export function registerConfigCommand(program) {
|
|
|
328
328
|
.option('--scan-model <model>', 'Model for market scanning (e.g. claude-haiku-4-5)')
|
|
329
329
|
.option('--analyze-model <model>', 'Model for deep analysis (e.g. claude-sonnet-4-6)')
|
|
330
330
|
.option('--decide-model <model>', 'Model for trade decisions (e.g. claude-opus-4-6)')
|
|
331
|
+
.addOption(new Option('--scan-provider <provider>', 'Provider for scan phase').choices(['anthropic', 'openai', 'openrouter', 'ollama', 'gemini', 'custom']))
|
|
332
|
+
.option('--scan-key <key>', 'API key for scan phase provider')
|
|
333
|
+
.addOption(new Option('--analyze-provider <provider>', 'Provider for analyze phase').choices(['anthropic', 'openai', 'openrouter', 'ollama', 'gemini', 'custom']))
|
|
334
|
+
.option('--analyze-key <key>', 'API key for analyze phase provider')
|
|
335
|
+
.addOption(new Option('--decide-provider <provider>', 'Provider for decide phase').choices(['anthropic', 'openai', 'openrouter', 'ollama', 'gemini', 'custom']))
|
|
336
|
+
.option('--decide-key <key>', 'API key for decide phase provider')
|
|
331
337
|
.action(async (apiKey, opts) => {
|
|
332
338
|
try {
|
|
333
339
|
const result = await apiRequest('/api/v1/llm-config', {
|
|
@@ -340,22 +346,28 @@ export function registerConfigCommand(program) {
|
|
|
340
346
|
...(opts.scanModel ? { scanModel: opts.scanModel } : {}),
|
|
341
347
|
...(opts.analyzeModel ? { analyzeModel: opts.analyzeModel } : {}),
|
|
342
348
|
...(opts.decideModel ? { decideModel: opts.decideModel } : {}),
|
|
349
|
+
...(opts.scanProvider ? { scanProvider: opts.scanProvider } : {}),
|
|
350
|
+
...(opts.scanKey ? { scanApiKey: opts.scanKey } : {}),
|
|
351
|
+
...(opts.analyzeProvider ? { analyzeProvider: opts.analyzeProvider } : {}),
|
|
352
|
+
...(opts.analyzeKey ? { analyzeApiKey: opts.analyzeKey } : {}),
|
|
353
|
+
...(opts.decideProvider ? { decideProvider: opts.decideProvider } : {}),
|
|
354
|
+
...(opts.decideKey ? { decideApiKey: opts.decideKey } : {}),
|
|
343
355
|
},
|
|
344
356
|
});
|
|
345
357
|
console.log('');
|
|
346
358
|
console.log(chalk.green(' LLM API key saved successfully'));
|
|
347
|
-
console.log(` ${chalk.gray('Provider:')}
|
|
348
|
-
console.log(` ${chalk.gray('Model:')}
|
|
349
|
-
if (result.scanModel) {
|
|
350
|
-
console.log(` ${chalk.gray('Scan
|
|
359
|
+
console.log(` ${chalk.gray('Provider:')} ${result.provider}`);
|
|
360
|
+
console.log(` ${chalk.gray('Model:')} ${result.model}`);
|
|
361
|
+
if (result.scanProvider || result.scanModel) {
|
|
362
|
+
console.log(` ${chalk.gray('Scan:')} ${result.scanProvider ?? result.provider} / ${result.scanModel ?? result.model}${opts.scanKey ? ' (own key)' : ''}`);
|
|
351
363
|
}
|
|
352
|
-
if (result.analyzeModel) {
|
|
353
|
-
console.log(` ${chalk.gray('Analyze
|
|
364
|
+
if (result.analyzeProvider || result.analyzeModel) {
|
|
365
|
+
console.log(` ${chalk.gray('Analyze:')} ${result.analyzeProvider ?? result.provider} / ${result.analyzeModel ?? result.model}${opts.analyzeKey ? ' (own key)' : ''}`);
|
|
354
366
|
}
|
|
355
|
-
if (result.decideModel) {
|
|
356
|
-
console.log(` ${chalk.gray('Decide
|
|
367
|
+
if (result.decideProvider || result.decideModel) {
|
|
368
|
+
console.log(` ${chalk.gray('Decide:')} ${result.decideProvider ?? result.provider} / ${result.decideModel ?? result.model}${opts.decideKey ? ' (own key)' : ''}`);
|
|
357
369
|
}
|
|
358
|
-
console.log(` ${chalk.gray('Key:')}
|
|
370
|
+
console.log(` ${chalk.gray('Key:')} ${apiKey.slice(0, 8)}${'*'.repeat(Math.max(0, apiKey.length - 8))}`);
|
|
359
371
|
console.log('');
|
|
360
372
|
console.log(chalk.dim(' Your key is encrypted at rest. Thesis extraction and coaching are now enabled.'));
|
|
361
373
|
console.log('');
|
|
@@ -384,14 +396,14 @@ export function registerConfigCommand(program) {
|
|
|
384
396
|
console.log(chalk.gray(' ' + '\u2500'.repeat(40)));
|
|
385
397
|
console.log(` ${chalk.gray('Provider:')} ${result.provider}`);
|
|
386
398
|
console.log(` ${chalk.gray('Model:')} ${result.model}`);
|
|
387
|
-
if (result.scanModel) {
|
|
388
|
-
console.log(` ${chalk.gray('Scan
|
|
399
|
+
if (result.scanProvider || result.scanModel) {
|
|
400
|
+
console.log(` ${chalk.gray('Scan:')} ${result.scanProvider ?? result.provider} / ${result.scanModel ?? result.model}`);
|
|
389
401
|
}
|
|
390
|
-
if (result.analyzeModel) {
|
|
391
|
-
console.log(` ${chalk.gray('Analyze
|
|
402
|
+
if (result.analyzeProvider || result.analyzeModel) {
|
|
403
|
+
console.log(` ${chalk.gray('Analyze:')} ${result.analyzeProvider ?? result.provider} / ${result.analyzeModel ?? result.model}`);
|
|
392
404
|
}
|
|
393
|
-
if (result.decideModel) {
|
|
394
|
-
console.log(` ${chalk.gray('Decide
|
|
405
|
+
if (result.decideProvider || result.decideModel) {
|
|
406
|
+
console.log(` ${chalk.gray('Decide:')} ${result.decideProvider ?? result.provider} / ${result.decideModel ?? result.model}`);
|
|
395
407
|
}
|
|
396
408
|
if (result.baseUrl) {
|
|
397
409
|
console.log(` ${chalk.gray('Base URL:')} ${result.baseUrl}`);
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Guided setup after a new user subscribes. Walks through:
|
|
4
4
|
// 1. Register a trader profile (name + risk tolerance)
|
|
5
|
-
// 2.
|
|
6
|
-
// 3.
|
|
5
|
+
// 2. Identity setup (SOUL wizard)
|
|
6
|
+
// 3. LLM API key (BYOK — required for agents to analyze/decide)
|
|
7
|
+
// 4. Connect Telegram bot for daily summaries
|
|
8
|
+
// 5. Agent runtime overview (scan intervals, autonomy levels)
|
|
9
|
+
// 6. Quick reference cheat sheet
|
|
7
10
|
import chalk from 'chalk';
|
|
8
11
|
import { isRemoteMode, apiRequest, ApiError } from '../api-client.js';
|
|
9
12
|
import { runSoulWizardAndUpload } from './soul-wizard.js';
|
|
@@ -120,7 +123,64 @@ export async function runOnboarding() {
|
|
|
120
123
|
}
|
|
121
124
|
console.log('');
|
|
122
125
|
}
|
|
123
|
-
// ─── Step 3:
|
|
126
|
+
// ─── Step 3: LLM API Key (BYOK) ───
|
|
127
|
+
try {
|
|
128
|
+
console.log(chalk.bold.cyan(' LLM API Key (required for agents)'));
|
|
129
|
+
console.log(chalk.gray(' ' + '\u2500'.repeat(50)));
|
|
130
|
+
console.log(chalk.dim(' Your agent needs an LLM to analyze markets and make decisions.'));
|
|
131
|
+
console.log(chalk.dim(' Bring your own key from any supported provider:'));
|
|
132
|
+
console.log('');
|
|
133
|
+
console.log(` ${chalk.white('Anthropic')} ${chalk.dim('(default) — Claude Sonnet/Opus/Haiku')}`);
|
|
134
|
+
console.log(` ${chalk.white('Gemini')} ${chalk.dim('— Gemini 2.5 Pro')}`);
|
|
135
|
+
console.log(` ${chalk.white('OpenAI')} ${chalk.dim('— GPT-4o')}`);
|
|
136
|
+
console.log(` ${chalk.white('OpenRouter')} ${chalk.dim('— Any model via OpenRouter')}`);
|
|
137
|
+
console.log(` ${chalk.white('Ollama')} ${chalk.dim('— Local models')}`);
|
|
138
|
+
console.log('');
|
|
139
|
+
console.log(chalk.dim(' The provider is auto-detected from the key prefix.'));
|
|
140
|
+
console.log(chalk.dim(' The model defaults to a sensible choice per provider.'));
|
|
141
|
+
console.log('');
|
|
142
|
+
const wantsLlmKey = await confirm({
|
|
143
|
+
message: 'Set up your LLM API key now?',
|
|
144
|
+
default: true,
|
|
145
|
+
});
|
|
146
|
+
if (wantsLlmKey) {
|
|
147
|
+
const llmKey = await input({
|
|
148
|
+
message: 'Paste your API key',
|
|
149
|
+
validate: (v) => (v.trim().length > 5 ? true : 'Key is too short'),
|
|
150
|
+
});
|
|
151
|
+
try {
|
|
152
|
+
if (await isRemoteMode()) {
|
|
153
|
+
const result = await apiRequest('/api/v1/llm-config', {
|
|
154
|
+
method: 'PUT',
|
|
155
|
+
body: { apiKey: llmKey.trim() },
|
|
156
|
+
});
|
|
157
|
+
console.log(chalk.green(` ✓ LLM key saved — ${result.provider} / ${result.model}`));
|
|
158
|
+
console.log(chalk.dim(' Change model later: trading-boy config set-llm-key <key> --model <model>'));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
console.log(chalk.yellow(' Skipped — not connected to API.'));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
166
|
+
console.log(chalk.yellow(` Could not save LLM key: ${msg}`));
|
|
167
|
+
console.log(chalk.dim(' Set it later: trading-boy config set-llm-key <your-api-key>'));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log('');
|
|
172
|
+
console.log(chalk.yellow(' ⚠ Without an LLM key, agents can scan prices but cannot'));
|
|
173
|
+
console.log(chalk.yellow(' analyze markets or make trade decisions.'));
|
|
174
|
+
console.log(chalk.dim(' Set it later: trading-boy config set-llm-key <your-api-key>'));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
if (isUserAbort(error))
|
|
179
|
+
return;
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
console.log('');
|
|
183
|
+
// ─── Step 4: Telegram Bot ───
|
|
124
184
|
try {
|
|
125
185
|
const wantsTelegram = await confirm({
|
|
126
186
|
message: 'Connect Telegram for daily summaries?',
|
|
@@ -144,14 +204,35 @@ export async function runOnboarding() {
|
|
|
144
204
|
throw error;
|
|
145
205
|
}
|
|
146
206
|
console.log('');
|
|
147
|
-
// ─── Step
|
|
207
|
+
// ─── Step 5: Agent Runtime Overview ───
|
|
208
|
+
console.log(chalk.bold.cyan(' How Agents Work'));
|
|
209
|
+
console.log(chalk.gray(' ' + '\u2500'.repeat(50)));
|
|
210
|
+
console.log('');
|
|
211
|
+
console.log(chalk.dim(' Once you create an agent, it runs continuously on our servers:'));
|
|
212
|
+
console.log('');
|
|
213
|
+
console.log(` ${chalk.white('Scan')} ${chalk.dim('Every 5 min (configurable) — scans your watchlist for setups')}`);
|
|
214
|
+
console.log(` ${chalk.white('Analyze')} ${chalk.dim('When a setup is found — deep context analysis via your LLM')}`);
|
|
215
|
+
console.log(` ${chalk.white('Decide')} ${chalk.dim('After analysis — enter/exit/hold based on your strategy')}`);
|
|
216
|
+
console.log(` ${chalk.white('Learn')} ${chalk.dim('After trades close — updates edge profile from outcomes')}`);
|
|
217
|
+
console.log('');
|
|
218
|
+
console.log(chalk.dim(' Autonomy levels:'));
|
|
219
|
+
console.log(` ${chalk.cyan('OBSERVE_ONLY')} ${chalk.dim('Scans and analyzes — takes no action')}`);
|
|
220
|
+
console.log(` ${chalk.cyan('SUGGEST')} ${chalk.dim('Sends trade ideas to your Telegram')}`);
|
|
221
|
+
console.log(` ${chalk.cyan('AUTO_WITH_APPROVAL')} ${chalk.dim('Proposes trades, waits for your OK')}`);
|
|
222
|
+
console.log(` ${chalk.cyan('FULLY_AUTONOMOUS')} ${chalk.dim('Trades within your guardrails, no human in the loop')}`);
|
|
223
|
+
console.log('');
|
|
224
|
+
console.log(chalk.dim(' Create your first agent:'));
|
|
225
|
+
console.log(` ${chalk.white('trading-boy agent create --help')}`);
|
|
226
|
+
console.log('');
|
|
227
|
+
// ─── Step 6: Quick Reference ───
|
|
148
228
|
console.log(chalk.bold.cyan(' Quick Reference'));
|
|
149
229
|
console.log(chalk.gray(' ' + '\u2500'.repeat(50)));
|
|
150
230
|
console.log('');
|
|
151
231
|
console.log(` ${chalk.white('trading-boy context SOL')} ${chalk.dim('Full context for any token')}`);
|
|
152
|
-
console.log(` ${chalk.white('trading-boy
|
|
232
|
+
console.log(` ${chalk.white('trading-boy agent create')} ${chalk.dim('Create an autonomous agent')}`);
|
|
233
|
+
console.log(` ${chalk.white('trading-boy agent list')} ${chalk.dim('View your running agents')}`);
|
|
153
234
|
console.log(` ${chalk.white('trading-boy decisions')} ${chalk.dim('View trade history')}`);
|
|
154
|
-
console.log(` ${chalk.white('trading-boy
|
|
235
|
+
console.log(` ${chalk.white('trading-boy stats')} ${chalk.dim('Track performance')}`);
|
|
155
236
|
console.log(` ${chalk.white('trading-boy narrative list')} ${chalk.dim('Active market narratives')}`);
|
|
156
237
|
console.log(` ${chalk.white('trading-boy catalysts')} ${chalk.dim('Upcoming events')}`);
|
|
157
238
|
if (traderRegistered) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trading-boy/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.2",
|
|
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": {
|