traderclaw-cli 1.0.65 → 1.0.68

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.
@@ -308,17 +308,25 @@ function privilegeRemediationMessage(cmd, args = [], customLines = []) {
308
308
 
309
309
  function gatewayTimeoutRemediation() {
310
310
  return [
311
- "Gateway bootstrap timed out waiting for health checks.",
312
- "Run these commands in terminal, then click Start Installation again:",
313
- "1) openclaw gateway status --json || true",
314
- "2) openclaw gateway probe || true",
311
+ "Gateway failed to start: service stayed stopped and health checks did not pass.",
312
+ "This usually means the gateway service is misconfigured, crashed at launch, or the system is out of resources.",
313
+ "",
314
+ "Run these commands in your VPS terminal to diagnose and recover:",
315
+ "1) openclaw gateway status --json || true # check current state",
316
+ "2) journalctl --user -u openclaw-gateway -n 50 --no-pager || true # check service logs",
315
317
  "3) openclaw gateway stop || true",
316
318
  "4) openclaw gateway install",
317
319
  "5) openclaw gateway restart",
318
- "6) openclaw gateway status --json",
320
+ "6) openclaw gateway status --json # should show running + rpc.ok=true",
319
321
  "7) tailscale funnel --bg 18789",
320
322
  "8) tailscale funnel status",
321
- "If gateway still fails on a low-memory VM, add swap or use a larger staging size (>=2GB RAM recommended).",
323
+ "",
324
+ "If the gateway still fails:",
325
+ "- Check RAM: openclaw gateway requires >=512MB free (>=2GB total recommended)",
326
+ "- Check disk: df -h ~/.openclaw",
327
+ "- Try: openclaw config validate && openclaw gateway doctor || true",
328
+ "- If config schema error appears, run: npm install -g openclaw@latest",
329
+ "Once the gateway shows 'running' in status, click Start Installation again.",
322
330
  ].join("\n");
323
331
  }
324
332
 
@@ -1332,6 +1340,58 @@ function ensureAgentsDefaultsSchemaCompat(config) {
1332
1340
  }
1333
1341
 
1334
1342
  /** Re-read config from disk and re-apply defaults shape before gateway/plugin commands that validate the file. */
1343
+ /**
1344
+ * Proactively writes the minimum gateway fields required for OpenClaw to start.
1345
+ *
1346
+ * OpenClaw (post-2025) requires `gateway.mode` to be explicitly set to "local"
1347
+ * before `openclaw gateway install` / `gateway restart` are called — the service
1348
+ * crashes immediately at launch when the field is absent, producing
1349
+ * "service stayed stopped / health checks never came up".
1350
+ *
1351
+ * We write these proactively rather than waiting for the first failure and
1352
+ * hoping auto-recovery catches it, because newer OpenClaw validates the config
1353
+ * during `gateway install` itself, before the process even starts.
1354
+ */
1355
+ function ensureGatewayBootstrapDefaults(configPath = CONFIG_FILE, log = () => {}) {
1356
+ let config = {};
1357
+ try {
1358
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
1359
+ } catch {
1360
+ config = {};
1361
+ }
1362
+
1363
+ if (!config.gateway || typeof config.gateway !== "object") {
1364
+ config.gateway = {};
1365
+ }
1366
+
1367
+ const changed = [];
1368
+ if (!config.gateway.mode) {
1369
+ config.gateway.mode = "local";
1370
+ changed.push("gateway.mode=local");
1371
+ }
1372
+ if (!config.gateway.bind) {
1373
+ config.gateway.bind = "loopback";
1374
+ changed.push("gateway.bind=loopback");
1375
+ }
1376
+ if (!Number.isInteger(config.gateway.port)) {
1377
+ config.gateway.port = 18789;
1378
+ changed.push("gateway.port=18789");
1379
+ }
1380
+
1381
+ ensureAgentsDefaultsSchemaCompat(config);
1382
+
1383
+ if (changed.length > 0) {
1384
+ log(`Gateway bootstrap: pre-writing required config fields: ${changed.join(", ")}`);
1385
+ }
1386
+
1387
+ try {
1388
+ mkdirSync(dirname(configPath), { recursive: true });
1389
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
1390
+ } catch (err) {
1391
+ log(`Gateway bootstrap: could not write config defaults (${err?.message || err}) — will proceed anyway`);
1392
+ }
1393
+ }
1394
+
1335
1395
  function normalizeOpenClawConfigFileShape(configPath = CONFIG_FILE) {
1336
1396
  let config = {};
1337
1397
  try {
@@ -1868,19 +1928,27 @@ export class InstallerStepEngine {
1868
1928
  });
1869
1929
  await this.runStep("gateway_bootstrap", "Starting OpenClaw gateway and Funnel", async () => {
1870
1930
  try {
1871
- normalizeOpenClawConfigFileShape(CONFIG_FILE);
1931
+ // Ensure required gateway fields are present BEFORE install/restart.
1932
+ // OpenClaw now requires gateway.mode="local" to be explicitly set;
1933
+ // without it the service crashes immediately at startup.
1934
+ ensureGatewayBootstrapDefaults(CONFIG_FILE, (msg) =>
1935
+ this.emitLog("gateway_bootstrap", "info", msg),
1936
+ );
1872
1937
  await this.runWithPrivilegeGuidance("gateway_bootstrap", "openclaw", ["gateway", "install"]);
1873
1938
  await this.runWithPrivilegeGuidance("gateway_bootstrap", "openclaw", ["gateway", "restart"]);
1874
1939
  return this.runFunnel();
1875
1940
  } catch (err) {
1876
1941
  const text = `${err?.message || ""}\n${err?.stderr || ""}\n${err?.stdout || ""}`.toLowerCase();
1877
1942
  const gatewayModeUnset = text.includes("gateway.mode=local") && text.includes("current: unset");
1878
- if (
1943
+ const gatewayStartFailed =
1879
1944
  text.includes("gateway restart timed out")
1880
1945
  || text.includes("timed out after 60s waiting for health checks")
1881
1946
  || text.includes("waiting for gateway port")
1882
- || gatewayModeUnset
1883
- ) {
1947
+ // OpenClaw ≥ current: shorter-timeout variant of the same class of failure
1948
+ || (text.includes("gateway restart failed") && text.includes("service stayed stopped"))
1949
+ || text.includes("health checks never came up")
1950
+ || text.includes("service stayed stopped");
1951
+ if (gatewayStartFailed || gatewayModeUnset) {
1884
1952
  const recovered = await this.tryAutoRecoverGatewayMode("gateway_bootstrap");
1885
1953
  if (recovered.success) {
1886
1954
  return this.runFunnel();
@@ -9,27 +9,23 @@ import { randomUUID, createPrivateKey, sign as cryptoSign } from "crypto";
9
9
  import { execFile, execSync } from "child_process";
10
10
  import { promisify } from "util";
11
11
  import { createServer } from "http";
12
- import { sortModelsByPreference, MAX_MODELS_PER_PROVIDER_SORT } from "./llm-model-preference.mjs";
13
12
  import { resolvePluginPackageRoot } from "./resolve-plugin-root.mjs";
14
13
 
15
14
  const execFileAsync = promisify(execFile);
16
15
 
17
16
  /**
18
- * Fast wizard catalog lookup: prefer one full list, then only probe key providers.
19
- * Timeouts are intentionally short on a fresh install the CLI can't reach providers
20
- * (no credentials yet) so we want to fail fast and show the curated fallback list
21
- * rather than making the user wait 10+ seconds. Target total: ≤ 5 s.
17
+ * Ordered list of providers for display in the wizard dropdown.
18
+ * The most commonly used providers appear first.
22
19
  */
23
- const OPENCLAW_MODELS_FLAT_TIMEOUT_MS = 3_000;
24
- const OPENCLAW_MODELS_PER_PROVIDER_TIMEOUT_MS = 2_500;
25
- const WIZARD_PRIORITY_PROVIDERS = [
20
+ const WIZARD_PROVIDER_PRIORITY = [
26
21
  "anthropic",
27
22
  "openai",
28
23
  "google",
29
24
  "openrouter",
30
- ];
31
- const WIZARD_PROVIDER_PRIORITY = [
32
- ...WIZARD_PRIORITY_PROVIDERS,
25
+ "xai",
26
+ "deepseek",
27
+ "groq",
28
+ "mistral",
33
29
  "perplexity",
34
30
  "together",
35
31
  "openai-codex",
@@ -44,14 +40,6 @@ const WIZARD_PROVIDER_PRIORITY = [
44
40
  ];
45
41
  let wizardLlmCatalogPromise = null;
46
42
 
47
- function compareWizardProviderPriority(a, b) {
48
- const ai = WIZARD_PROVIDER_PRIORITY.indexOf(a);
49
- const bi = WIZARD_PROVIDER_PRIORITY.indexOf(b);
50
- const aRank = ai >= 0 ? ai : Number.MAX_SAFE_INTEGER;
51
- const bRank = bi >= 0 ? bi : Number.MAX_SAFE_INTEGER;
52
- return aRank - bRank || a.localeCompare(b);
53
- }
54
-
55
43
  const PLUGIN_ROOT = resolvePluginPackageRoot(import.meta.url);
56
44
  const PLUGIN_PACKAGE_JSON = JSON.parse(readFileSync(join(PLUGIN_ROOT, "package.json"), "utf-8"));
57
45
  const PLUGIN_VERSION =
@@ -1917,35 +1905,29 @@ function parseJsonBody(req) {
1917
1905
  });
1918
1906
  }
1919
1907
 
1908
+ /**
1909
+ * Returns the wizard LLM catalog immediately from the curated static list.
1910
+ *
1911
+ * WHY we no longer call `openclaw models list --all`:
1912
+ * The OpenClaw CLI enumerates models by making live network calls to each
1913
+ * provider's API (provider plugins inject catalogs via network). The wizard
1914
+ * runs BEFORE any API credentials have been configured, so every probe will
1915
+ * always ETIMEDOUT — there is nothing to authenticate with yet. Calling the
1916
+ * CLI here is architecturally wrong for this stage of setup.
1917
+ *
1918
+ * The curated list below is the correct source for the wizard: it covers all
1919
+ * supported providers with their recommended models and loads in < 1 ms.
1920
+ * After installation the user can run `openclaw models list` to see the full
1921
+ * live catalog for their configured providers.
1922
+ */
1920
1923
  async function loadWizardLlmCatalogAsync() {
1921
- const supportedProviders = new Set([
1922
- "anthropic",
1923
- "openai",
1924
- "openai-codex",
1925
- "openrouter",
1926
- "groq",
1927
- "mistral",
1928
- "google",
1929
- "google-vertex",
1930
- "xai",
1931
- "deepseek",
1932
- "together",
1933
- "perplexity",
1934
- "amazon-bedrock",
1935
- "vercel-ai-gateway",
1936
- "minimax",
1937
- "moonshot",
1938
- "nvidia",
1939
- "qwen",
1940
- "cerebras",
1941
- ]);
1942
- const fallback = {
1943
- source: "fallback",
1924
+ return {
1925
+ source: "curated",
1944
1926
  providers: [
1945
1927
  {
1946
1928
  id: "anthropic",
1947
1929
  models: [
1948
- { id: "anthropic/claude-sonnet-4-6", name: "Claude Sonnet 4.6 (recommended default)" },
1930
+ { id: "anthropic/claude-sonnet-4-6", name: "Claude Sonnet 4.6 (recommended)" },
1949
1931
  { id: "anthropic/claude-opus-4-6", name: "Claude Opus 4.6" },
1950
1932
  { id: "anthropic/claude-haiku-4-5", name: "Claude Haiku 4.5" },
1951
1933
  ],
@@ -1953,7 +1935,7 @@ async function loadWizardLlmCatalogAsync() {
1953
1935
  {
1954
1936
  id: "openai",
1955
1937
  models: [
1956
- { id: "openai/gpt-5.4", name: "GPT-5.4 (recommended default)" },
1938
+ { id: "openai/gpt-5.4", name: "GPT-5.4 (recommended)" },
1957
1939
  { id: "openai/gpt-5.4-mini", name: "GPT-5.4 mini" },
1958
1940
  { id: "openai/gpt-5.4-nano", name: "GPT-5.4 nano" },
1959
1941
  ],
@@ -1962,29 +1944,48 @@ async function loadWizardLlmCatalogAsync() {
1962
1944
  id: "openai-codex",
1963
1945
  models: [{ id: "openai-codex/gpt-5-codex", name: "GPT-5 Codex" }],
1964
1946
  },
1947
+ {
1948
+ id: "google",
1949
+ models: [
1950
+ { id: "google/gemini-2.5-flash", name: "Gemini 2.5 Flash (recommended)" },
1951
+ { id: "google/gemini-2.5-pro", name: "Gemini 2.5 Pro" },
1952
+ ],
1953
+ },
1965
1954
  {
1966
1955
  id: "xai",
1967
- models: [{ id: "xai/grok-4", name: "Grok 4" }],
1956
+ models: [
1957
+ { id: "xai/grok-4", name: "Grok 4 (recommended)" },
1958
+ { id: "xai/grok-3", name: "Grok 3" },
1959
+ ],
1968
1960
  },
1969
1961
  {
1970
1962
  id: "deepseek",
1971
- models: [{ id: "deepseek/deepseek-chat", name: "DeepSeek Chat (V3.2)" }],
1963
+ models: [
1964
+ { id: "deepseek/deepseek-chat", name: "DeepSeek Chat V3 (recommended)" },
1965
+ { id: "deepseek/deepseek-reasoner", name: "DeepSeek Reasoner R1" },
1966
+ ],
1972
1967
  },
1973
1968
  {
1974
- id: "google",
1975
- models: [{ id: "google/gemini-2.5-flash", name: "Gemini 2.5 Flash" }],
1969
+ id: "openrouter",
1970
+ models: [
1971
+ { id: "openrouter/anthropic/claude-sonnet-4-6", name: "Claude Sonnet 4.6 via OpenRouter (recommended)" },
1972
+ { id: "openrouter/openai/gpt-5.4", name: "GPT-5.4 via OpenRouter" },
1973
+ { id: "openrouter/google/gemini-2.5-flash", name: "Gemini 2.5 Flash via OpenRouter" },
1974
+ ],
1976
1975
  },
1977
1976
  {
1978
1977
  id: "groq",
1979
- models: [{ id: "groq/llama-4-scout-17b-16e-instruct", name: "Llama 4 Scout" }],
1980
- },
1981
- {
1982
- id: "openrouter",
1983
- models: [{ id: "openrouter/anthropic/claude-sonnet-4-6", name: "Claude Sonnet 4.6 (via OpenRouter)" }],
1978
+ models: [
1979
+ { id: "groq/llama-4-scout-17b-16e-instruct", name: "Llama 4 Scout (recommended)" },
1980
+ { id: "groq/llama-4-maverick-17b-128e-instruct", name: "Llama 4 Maverick" },
1981
+ ],
1984
1982
  },
1985
1983
  {
1986
1984
  id: "mistral",
1987
- models: [{ id: "mistral/mistral-large-latest", name: "Mistral Large" }],
1985
+ models: [
1986
+ { id: "mistral/mistral-large-latest", name: "Mistral Large (recommended)" },
1987
+ { id: "mistral/mistral-medium-latest", name: "Mistral Medium" },
1988
+ ],
1988
1989
  },
1989
1990
  {
1990
1991
  id: "perplexity",
@@ -2002,174 +2003,13 @@ async function loadWizardLlmCatalogAsync() {
2002
2003
  id: "qwen",
2003
2004
  models: [{ id: "qwen/qwen3-235b-a22b", name: "Qwen3 235B A22B" }],
2004
2005
  },
2006
+ {
2007
+ id: "moonshot",
2008
+ models: [{ id: "moonshot/kimi-k2", name: "Kimi K2" }],
2009
+ },
2005
2010
  ],
2011
+ generatedAt: new Date().toISOString(),
2006
2012
  };
2007
-
2008
- if (!commandExists("openclaw")) {
2009
- return { ...fallback, warning: "openclaw_not_found" };
2010
- }
2011
-
2012
- const providerIds = [...supportedProviders].sort(compareWizardProviderPriority);
2013
- const priorityProviderIds = providerIds.filter((id) => WIZARD_PRIORITY_PROVIDERS.includes(id));
2014
-
2015
- async function fetchModelsForProvider(provider) {
2016
- try {
2017
- const { stdout } = await execFileAsync(
2018
- "openclaw",
2019
- ["models", "list", "--all", "--provider", provider, "--json"],
2020
- {
2021
- encoding: "utf-8",
2022
- maxBuffer: 25 * 1024 * 1024,
2023
- timeout: OPENCLAW_MODELS_PER_PROVIDER_TIMEOUT_MS,
2024
- env: NO_COLOR_ENV,
2025
- },
2026
- );
2027
- return { provider, stdout };
2028
- } catch (err) {
2029
- return { provider, error: err };
2030
- }
2031
- }
2032
-
2033
- function seedFallbackProviderMap() {
2034
- return new Map(
2035
- fallback.providers.map((entry) => [
2036
- entry.id,
2037
- entry.models.map((model) => ({ ...model })),
2038
- ]),
2039
- );
2040
- }
2041
-
2042
- function mergeCatalogModelsIntoMap(providerMap, models, expectedProvider = "") {
2043
- let added = 0;
2044
- for (const entry of models) {
2045
- if (!entry || typeof entry.key !== "string") continue;
2046
- const modelId = String(entry.key);
2047
- const slash = modelId.indexOf("/");
2048
- if (slash <= 0 || slash === modelId.length - 1) continue;
2049
- const provider = modelId.slice(0, slash);
2050
- if (!supportedProviders.has(provider)) continue;
2051
- if (expectedProvider && provider !== expectedProvider) continue;
2052
- const existing = providerMap.get(provider) || [];
2053
- existing.push({
2054
- id: modelId,
2055
- name: typeof entry.name === "string" && entry.name.trim() ? entry.name : modelId,
2056
- });
2057
- providerMap.set(provider, existing);
2058
- added += 1;
2059
- }
2060
- return added;
2061
- }
2062
-
2063
- function buildProvidersFromMap(providerMap) {
2064
- return providerIds
2065
- .map((id) => {
2066
- const rawModels = providerMap.get(id) || [];
2067
- const sortedIds = sortModelsByPreference(
2068
- id,
2069
- rawModels.map((m) => m.id),
2070
- );
2071
- const byId = new Map(rawModels.map((m) => [m.id, m]));
2072
- const limitedIds = sortedIds.slice(0, MAX_MODELS_PER_PROVIDER_SORT);
2073
- const models = limitedIds.map((mid) => byId.get(mid)).filter(Boolean);
2074
- return { id, models };
2075
- })
2076
- .filter((entry) => supportedProviders.has(entry.id))
2077
- .filter((entry) => entry.models.length > 0);
2078
- }
2079
-
2080
- /** When `openclaw models list --all --json` returns models; used if per-provider calls yield nothing. */
2081
- function mergeFlatCatalogIntoMap(providerMap) {
2082
- const raw = execSync("openclaw models list --all --json", {
2083
- encoding: "utf-8",
2084
- stdio: ["ignore", "pipe", "pipe"],
2085
- maxBuffer: 50 * 1024 * 1024,
2086
- timeout: OPENCLAW_MODELS_FLAT_TIMEOUT_MS,
2087
- env: NO_COLOR_ENV,
2088
- });
2089
- const parsed = extractJson(raw);
2090
- if (!parsed) return 0;
2091
- const models = Array.isArray(parsed?.models) ? parsed.models : [];
2092
- return mergeCatalogModelsIntoMap(providerMap, models);
2093
- }
2094
-
2095
- try {
2096
- const t0 = Date.now();
2097
- const liveProviderMap = new Map();
2098
- let catalogStrategy = "flat_all";
2099
- let flatError = "";
2100
- let liveAdded = 0;
2101
- try {
2102
- liveAdded = mergeFlatCatalogIntoMap(liveProviderMap);
2103
- } catch (err) {
2104
- flatError = err instanceof Error ? err.message : String(err);
2105
- }
2106
-
2107
- let batches = [];
2108
- if (liveAdded === 0) {
2109
- catalogStrategy = "priority_parallel";
2110
- batches = await Promise.all(priorityProviderIds.map((p) => fetchModelsForProvider(p)));
2111
- for (const batch of batches) {
2112
- if (batch.error || !batch.stdout) continue;
2113
- const parsed = extractJson(batch.stdout);
2114
- if (!parsed) continue;
2115
- const models = Array.isArray(parsed?.models) ? parsed.models : [];
2116
- liveAdded += mergeCatalogModelsIntoMap(liveProviderMap, models, batch.provider);
2117
- }
2118
- }
2119
-
2120
- let providers = buildProvidersFromMap(liveProviderMap);
2121
- if (providers.length === 0) {
2122
- const failedParallel = batches.filter((b) => b.error).length;
2123
- const details = [];
2124
- if (flatError) details.push(`flat list failed: ${flatError.slice(0, 160)}`);
2125
- if (failedParallel > 0) {
2126
- details.push(
2127
- `${failedParallel}/${priorityProviderIds.length} priority provider lookups failed`,
2128
- );
2129
- }
2130
- return {
2131
- ...fallback,
2132
- warning: `openclaw_model_catalog_unavailable${details.length ? ` (${details.join("; ")})` : ""}`,
2133
- };
2134
- }
2135
-
2136
- const mergedProviderMap = new Map(liveProviderMap);
2137
- for (const [provider, models] of seedFallbackProviderMap()) {
2138
- if (!mergedProviderMap.has(provider) || (mergedProviderMap.get(provider) || []).length === 0) {
2139
- mergedProviderMap.set(provider, models);
2140
- }
2141
- }
2142
- providers = buildProvidersFromMap(mergedProviderMap);
2143
-
2144
- const elapsedMs = Date.now() - t0;
2145
- const source =
2146
- providers.length > buildProvidersFromMap(liveProviderMap).length ? "hybrid" : "openclaw";
2147
- const warning =
2148
- source === "hybrid" && flatError
2149
- ? `loaded priority providers; kept curated defaults for the rest (${flatError.slice(0, 160)})`
2150
- : source === "hybrid"
2151
- ? "loaded priority providers; kept curated defaults for the rest"
2152
- : "";
2153
- return {
2154
- source,
2155
- providers,
2156
- generatedAt: new Date().toISOString(),
2157
- catalogFetchMs: elapsedMs,
2158
- catalogStrategy,
2159
- ...(warning ? { warning } : {}),
2160
- };
2161
- } catch (err) {
2162
- const detail = err?.message || String(err);
2163
- const isBufferErr = detail.includes("maxBuffer") || detail.includes("ENOBUFS");
2164
- const hint = isBufferErr
2165
- ? " (stdout exceeded buffer — OpenClaw model catalog may have grown; this version raises the limit)"
2166
- : "";
2167
- console.error(`[traderclaw] loadWizardLlmCatalog failed${hint}: ${detail.slice(0, 500)}`);
2168
- return {
2169
- ...fallback,
2170
- warning: `openclaw_models_list_failed: ${detail}`,
2171
- };
2172
- }
2173
2013
  }
2174
2014
 
2175
2015
  function wizardHtml(defaults) {
@@ -2468,11 +2308,11 @@ function wizardHtml(defaults) {
2468
2308
  startBtn.textContent = "Loading providers...";
2469
2309
  const updateHint = () => {
2470
2310
  const elapsedSeconds = Math.max(1, Math.floor((Date.now() - llmLoadStartedAt) / 1000));
2471
- if (elapsedSeconds >= 8) {
2472
- llmLoadingHintTextEl.textContent = "Still loading provider catalog (" + elapsedSeconds + "s). This should usually finish in under ~10s.";
2311
+ if (elapsedSeconds >= 5) {
2312
+ llmLoadingHintTextEl.textContent = "Still loading (" + elapsedSeconds + "s). Check network or reload.";
2473
2313
  return;
2474
2314
  }
2475
- llmLoadingHintTextEl.textContent = "Fetching provider list (" + elapsedSeconds + "s)...";
2315
+ llmLoadingHintTextEl.textContent = "Loading provider list (" + elapsedSeconds + "s)...";
2476
2316
  };
2477
2317
  updateHint();
2478
2318
  stopLlmLoadTicker();
@@ -2523,7 +2363,7 @@ function wizardHtml(defaults) {
2523
2363
  setLlmCatalogLoading(true);
2524
2364
  setSelectOptions(llmProviderEl, [{ value: "", label: "Loading providers..." }], "");
2525
2365
  setSelectOptions(llmModelEl, [{ value: "", label: "Loading models..." }], "");
2526
- setLlmCatalogReady(false, "Loading LLM provider catalog... this can take a few seconds.");
2366
+ setLlmCatalogReady(false, "Loading provider list...");
2527
2367
  try {
2528
2368
  const res = await fetch("/api/llm/options");
2529
2369
  const data = await res.json();
@@ -2532,21 +2372,15 @@ function wizardHtml(defaults) {
2532
2372
  if (providers.length === 0) {
2533
2373
  setSelectOptions(llmProviderEl, [{ value: "", label: "No providers available" }], "");
2534
2374
  refreshModelOptions("");
2535
- setLlmCatalogReady(false, "No LLM providers were found from OpenClaw. Please check OpenClaw model setup.", true);
2375
+ setLlmCatalogReady(false, "No LLM providers found. Reload the page to try again.", true);
2536
2376
  return;
2537
2377
  }
2538
2378
  setSelectOptions(llmProviderEl, providers, "${defaults.llmProvider}");
2539
2379
  refreshModelOptions("${defaults.llmModel}");
2540
- const isFallback = llmCatalog.source === "fallback";
2541
- const isHybrid = llmCatalog.source === "hybrid";
2542
- const catalogMsg = isFallback
2543
- ? "Showing curated safe defaults only (could not load live OpenClaw catalog" + (llmCatalog.warning ? ": " + llmCatalog.warning : "") + "). Anthropic and OpenAI stay ready first, with several other providers still available."
2544
- : isHybrid
2545
- ? "Loaded priority providers first and filled the rest with curated defaults" + (llmCatalog.warning ? " (" + llmCatalog.warning + ")" : "") + "."
2546
- : "LLM providers loaded. Select provider and paste credential to continue. Model selection is optional.";
2547
- setLlmCatalogReady(true, catalogMsg, isFallback || isHybrid);
2380
+ const catalogMsg = "Select your provider, paste your API key, and start installation. After setup, run \`openclaw models list\` to explore your live catalog.";
2381
+ setLlmCatalogReady(true, catalogMsg, false);
2548
2382
  } catch (err) {
2549
- setLlmCatalogReady(false, "Failed to load LLM providers. Check OpenClaw and reload this page.", true);
2383
+ setLlmCatalogReady(false, "Failed to load LLM providers. Reload the page and try again.", true);
2550
2384
  manualEl.textContent = "Failed to load LLM provider catalog: " + (err && err.message ? err.message : String(err));
2551
2385
  } finally {
2552
2386
  setLlmCatalogLoading(false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "traderclaw-cli",
3
- "version": "1.0.65",
3
+ "version": "1.0.68",
4
4
  "description": "Global TraderClaw CLI (install --wizard, setup, precheck). Installs solana-traderclaw as a dependency for OpenClaw plugin files.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,7 @@
17
17
  "node": ">=22"
18
18
  },
19
19
  "dependencies": {
20
- "solana-traderclaw": "^1.0.65"
20
+ "solana-traderclaw": "^1.0.68"
21
21
  },
22
22
  "keywords": [
23
23
  "traderclaw",