traderclaw-cli 1.0.52 → 1.0.54
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/bin/cli.ts +52 -2
- package/bin/openclaw-trader.mjs +66 -15
- package/package.json +1 -1
package/bin/cli.ts
CHANGED
|
@@ -204,6 +204,8 @@ async function cmdSetup(args: string[]) {
|
|
|
204
204
|
let apiKey = "";
|
|
205
205
|
let orchestratorUrl = "";
|
|
206
206
|
|
|
207
|
+
let forwardTelegramRecipientArg = "";
|
|
208
|
+
|
|
207
209
|
for (let i = 0; i < args.length; i++) {
|
|
208
210
|
if ((args[i] === "--api-key" || args[i] === "-k") && args[i + 1]) {
|
|
209
211
|
apiKey = args[++i];
|
|
@@ -211,6 +213,14 @@ async function cmdSetup(args: string[]) {
|
|
|
211
213
|
if ((args[i] === "--url" || args[i] === "-u") && args[i + 1]) {
|
|
212
214
|
orchestratorUrl = args[++i];
|
|
213
215
|
}
|
|
216
|
+
if (
|
|
217
|
+
(args[i] === "--telegram-recipient" ||
|
|
218
|
+
args[i] === "--forward-telegram-chat-id" ||
|
|
219
|
+
args[i] === "--telegram-chat-id") &&
|
|
220
|
+
args[i + 1]
|
|
221
|
+
) {
|
|
222
|
+
forwardTelegramRecipientArg = args[++i];
|
|
223
|
+
}
|
|
214
224
|
}
|
|
215
225
|
|
|
216
226
|
if (!apiKey) {
|
|
@@ -344,6 +354,17 @@ async function cmdSetup(args: string[]) {
|
|
|
344
354
|
process.exit(1);
|
|
345
355
|
}
|
|
346
356
|
|
|
357
|
+
print("\nTelegram delivery (optional)...\n");
|
|
358
|
+
printInfo(" Enter your Telegram @username or numeric chat id so agent replies can be routed to you.");
|
|
359
|
+
printInfo(" Usernames are resolved with Telegram getChat (set TELEGRAM_BOT_TOKEN on the gateway, or");
|
|
360
|
+
printInfo(" export it here for immediate resolution). Private chats: message your bot once first.\n");
|
|
361
|
+
|
|
362
|
+
let forwardTelegramRecipient = forwardTelegramRecipientArg.trim();
|
|
363
|
+
if (!forwardTelegramRecipient) {
|
|
364
|
+
forwardTelegramRecipient = await prompt("Telegram @username or chat id (optional, Enter to skip)", "");
|
|
365
|
+
}
|
|
366
|
+
forwardTelegramRecipient = forwardTelegramRecipient.trim();
|
|
367
|
+
|
|
347
368
|
print("\nWriting configuration...\n");
|
|
348
369
|
|
|
349
370
|
const existingConfig = readConfig();
|
|
@@ -353,6 +374,32 @@ async function cmdSetup(args: string[]) {
|
|
|
353
374
|
apiKey,
|
|
354
375
|
apiTimeout: 120000,
|
|
355
376
|
};
|
|
377
|
+
|
|
378
|
+
if (forwardTelegramRecipient) {
|
|
379
|
+
try {
|
|
380
|
+
const { resolveTelegramRecipientToChatId, looksLikeTelegramChatId } = await import("../src/telegram-resolve.ts");
|
|
381
|
+
const botToken = String(
|
|
382
|
+
process.env.TELEGRAM_BOT_TOKEN || process.env.OPENCLAW_TELEGRAM_BOT_TOKEN || "",
|
|
383
|
+
).trim();
|
|
384
|
+
if (looksLikeTelegramChatId(forwardTelegramRecipient)) {
|
|
385
|
+
pluginConfig.forwardTelegramRecipient = forwardTelegramRecipient;
|
|
386
|
+
printSuccess(` Saved Telegram chat id`);
|
|
387
|
+
} else if (botToken) {
|
|
388
|
+
const id = await resolveTelegramRecipientToChatId({ botToken, raw: forwardTelegramRecipient });
|
|
389
|
+
pluginConfig.forwardTelegramRecipient = id;
|
|
390
|
+
printSuccess(` Resolved @${forwardTelegramRecipient.replace(/^@/, "")} → chat id ${id}`);
|
|
391
|
+
} else {
|
|
392
|
+
pluginConfig.forwardTelegramRecipient = forwardTelegramRecipient;
|
|
393
|
+
printInfo(
|
|
394
|
+
" Saved as-is; start the gateway with TELEGRAM_BOT_TOKEN set to resolve @username on first run.",
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
} catch (err) {
|
|
398
|
+
printWarn(` Telegram resolve failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
399
|
+
printInfo(" Saving your username anyway — fix token or use numeric chat id.");
|
|
400
|
+
pluginConfig.forwardTelegramRecipient = forwardTelegramRecipient;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
356
403
|
setPluginConfig(existingConfig, pluginConfig);
|
|
357
404
|
writeConfig(existingConfig);
|
|
358
405
|
|
|
@@ -365,6 +412,7 @@ async function cmdSetup(args: string[]) {
|
|
|
365
412
|
Orchestrator: ${orchestratorUrl}
|
|
366
413
|
Wallet: ${walletLabel} (ID: ${walletId})
|
|
367
414
|
API Key: ${maskKey(apiKey)}
|
|
415
|
+
Telegram fwd: ${(pluginConfig.forwardTelegramRecipient as string) || "(not set)"}
|
|
368
416
|
Config: ${CONFIG_FILE}
|
|
369
417
|
`);
|
|
370
418
|
print("Next steps:");
|
|
@@ -575,8 +623,9 @@ Commands:
|
|
|
575
623
|
config View and manage configuration
|
|
576
624
|
|
|
577
625
|
Setup options:
|
|
578
|
-
--api-key, -k
|
|
579
|
-
--url, -u
|
|
626
|
+
--api-key, -k API key (skip interactive prompt)
|
|
627
|
+
--url, -u Orchestrator URL (skip interactive prompt)
|
|
628
|
+
--telegram-recipient Telegram @username or chat id (alias: --forward-telegram-chat-id)
|
|
580
629
|
|
|
581
630
|
Config subcommands:
|
|
582
631
|
config show Show current configuration
|
|
@@ -586,6 +635,7 @@ Config subcommands:
|
|
|
586
635
|
Examples:
|
|
587
636
|
openclaw-trader setup
|
|
588
637
|
openclaw-trader setup --api-key sk_live_abc123 --url https://api.traderclaw.ai
|
|
638
|
+
openclaw-trader setup --telegram-recipient @MyChannelOrUser
|
|
589
639
|
openclaw-trader status
|
|
590
640
|
openclaw-trader config show
|
|
591
641
|
openclaw-trader config set apiTimeout 60000
|
package/bin/openclaw-trader.mjs
CHANGED
|
@@ -1856,6 +1856,51 @@ async function loadWizardLlmCatalogAsync() {
|
|
|
1856
1856
|
}
|
|
1857
1857
|
}
|
|
1858
1858
|
|
|
1859
|
+
function buildProvidersFromMap(providerMap) {
|
|
1860
|
+
return providerIds
|
|
1861
|
+
.map((id) => {
|
|
1862
|
+
const rawModels = providerMap.get(id) || [];
|
|
1863
|
+
const sortedIds = sortModelsByPreference(
|
|
1864
|
+
id,
|
|
1865
|
+
rawModels.map((m) => m.id),
|
|
1866
|
+
);
|
|
1867
|
+
const byId = new Map(rawModels.map((m) => [m.id, m]));
|
|
1868
|
+
const limitedIds = sortedIds.slice(0, MAX_MODELS_PER_PROVIDER_SORT);
|
|
1869
|
+
const models = limitedIds.map((mid) => byId.get(mid)).filter(Boolean);
|
|
1870
|
+
return { id, models };
|
|
1871
|
+
})
|
|
1872
|
+
.filter((entry) => supportedProviders.has(entry.id))
|
|
1873
|
+
.filter((entry) => entry.models.length > 0);
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
/** When `openclaw models list --all --json` returns models; used if per-provider calls yield nothing. */
|
|
1877
|
+
function mergeFlatCatalogIntoMap(providerMap) {
|
|
1878
|
+
const raw = execSync("openclaw models list --all --json", {
|
|
1879
|
+
encoding: "utf-8",
|
|
1880
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1881
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
1882
|
+
timeout: 45_000,
|
|
1883
|
+
env: NO_COLOR_ENV,
|
|
1884
|
+
});
|
|
1885
|
+
const parsed = extractJson(raw);
|
|
1886
|
+
if (!parsed) return;
|
|
1887
|
+
const models = Array.isArray(parsed?.models) ? parsed.models : [];
|
|
1888
|
+
for (const entry of models) {
|
|
1889
|
+
if (!entry || typeof entry.key !== "string") continue;
|
|
1890
|
+
const modelId = String(entry.key);
|
|
1891
|
+
const slash = modelId.indexOf("/");
|
|
1892
|
+
if (slash <= 0 || slash === modelId.length - 1) continue;
|
|
1893
|
+
const provider = modelId.slice(0, slash);
|
|
1894
|
+
if (!supportedProviders.has(provider)) continue;
|
|
1895
|
+
const existing = providerMap.get(provider) || [];
|
|
1896
|
+
existing.push({
|
|
1897
|
+
id: modelId,
|
|
1898
|
+
name: typeof entry.name === "string" && entry.name.trim() ? entry.name : modelId,
|
|
1899
|
+
});
|
|
1900
|
+
providerMap.set(provider, existing);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1859
1904
|
try {
|
|
1860
1905
|
const t0 = Date.now();
|
|
1861
1906
|
const batches = await Promise.all(providerIds.map((p) => fetchModelsForProvider(p)));
|
|
@@ -1883,23 +1928,28 @@ async function loadWizardLlmCatalogAsync() {
|
|
|
1883
1928
|
}
|
|
1884
1929
|
}
|
|
1885
1930
|
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1931
|
+
let providers = buildProvidersFromMap(providerMap);
|
|
1932
|
+
let catalogStrategy = "parallel";
|
|
1933
|
+
|
|
1934
|
+
if (providers.length === 0) {
|
|
1935
|
+
catalogStrategy = "legacy_fallback";
|
|
1936
|
+
try {
|
|
1937
|
+
mergeFlatCatalogIntoMap(providerMap);
|
|
1938
|
+
providers = buildProvidersFromMap(providerMap);
|
|
1939
|
+
} catch (legacyErr) {
|
|
1940
|
+
console.error(
|
|
1941
|
+
`[traderclaw] loadWizardLlmCatalog legacy fallback failed: ${legacyErr instanceof Error ? legacyErr.message : String(legacyErr)}`,
|
|
1892
1942
|
);
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
const models = limitedIds.map((mid) => byId.get(mid)).filter(Boolean);
|
|
1896
|
-
return { id, models };
|
|
1897
|
-
})
|
|
1898
|
-
.filter((entry) => supportedProviders.has(entry.id))
|
|
1899
|
-
.filter((entry) => entry.models.length > 0);
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1900
1945
|
|
|
1901
1946
|
if (providers.length === 0) {
|
|
1902
|
-
|
|
1947
|
+
const failedParallel = batches.filter((b) => b.error).length;
|
|
1948
|
+
const hint =
|
|
1949
|
+
failedParallel > 0
|
|
1950
|
+
? ` (${failedParallel}/${batches.length} per-provider openclaw calls failed — check OpenClaw version supports: openclaw models list --all --provider <id> --json)`
|
|
1951
|
+
: "";
|
|
1952
|
+
return { ...fallback, warning: `openclaw_model_catalog_empty${hint}` };
|
|
1903
1953
|
}
|
|
1904
1954
|
|
|
1905
1955
|
const elapsedMs = Date.now() - t0;
|
|
@@ -1908,6 +1958,7 @@ async function loadWizardLlmCatalogAsync() {
|
|
|
1908
1958
|
providers,
|
|
1909
1959
|
generatedAt: new Date().toISOString(),
|
|
1910
1960
|
catalogFetchMs: elapsedMs,
|
|
1961
|
+
catalogStrategy,
|
|
1911
1962
|
};
|
|
1912
1963
|
} catch (err) {
|
|
1913
1964
|
const detail = err?.message || String(err);
|
|
@@ -2211,7 +2262,7 @@ function wizardHtml(defaults) {
|
|
|
2211
2262
|
const updateHint = () => {
|
|
2212
2263
|
const elapsedSeconds = Math.max(1, Math.floor((Date.now() - llmLoadStartedAt) / 1000));
|
|
2213
2264
|
if (elapsedSeconds >= 8) {
|
|
2214
|
-
llmLoadingHintTextEl.textContent = "Still loading provider catalog (" + elapsedSeconds + "s). First run can take up to ~
|
|
2265
|
+
llmLoadingHintTextEl.textContent = "Still loading provider catalog (" + elapsedSeconds + "s). First run can take up to ~60s.";
|
|
2215
2266
|
return;
|
|
2216
2267
|
}
|
|
2217
2268
|
llmLoadingHintTextEl.textContent = "Fetching provider list (" + elapsedSeconds + "s)...";
|
package/package.json
CHANGED