fix(cli): guide onboarding option errors

This commit is contained in:
Vincent Koc
2026-05-10 05:40:47 +08:00
parent 021565bd71
commit 346e327586
7 changed files with 32 additions and 8 deletions

View File

@@ -477,7 +477,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
wsLogRaw !== "compact" &&
wsLogRaw !== "full"
) {
defaultRuntime.error('Invalid --ws-log (use "auto", "full", "compact")');
defaultRuntime.error('Invalid --ws-log. Use "auto", "full", or "compact".');
defaultRuntime.exit(1);
}
setGatewayWsLogStyle(wsLogStyle);
@@ -560,7 +560,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
toOptionString(opts.bind) ?? cfg.gateway?.bind,
);
if (bindExplicitRawStr !== undefined && !VALID_BIND_MODES.has(bindExplicitRawStr)) {
defaultRuntime.error('Invalid --bind (use "loopback", "lan", "tailnet", "auto", or "custom")');
defaultRuntime.error('Invalid --bind. Use "loopback", "lan", "tailnet", "auto", or "custom".');
defaultRuntime.exit(1);
return;
}

View File

@@ -1,5 +1,6 @@
import { ensureAuthProfileStore } from "../agents/auth-profiles.js";
import { resolveDefaultAgentWorkspaceDir } from "../agents/workspace.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { OpenClawConfig, GatewayAuthConfig } from "../config/config.js";
import { isSecretRef, type SecretInput } from "../config/types.secrets.js";
import type { RuntimeEnv } from "../runtime.js";
@@ -161,7 +162,9 @@ export function buildGatewayAuthConfig(params: {
}
if (params.mode === "trusted-proxy") {
if (!params.trustedProxy) {
throw new Error("trustedProxy config is required when mode is trusted-proxy");
throw new Error(
`trustedProxy config is required when mode is trusted-proxy. Run ${formatCliCommand("openclaw configure --section gateway")} to configure Gateway auth interactively.`,
);
}
return { ...base, mode: "trusted-proxy", trustedProxy: params.trustedProxy };
}

View File

@@ -1,3 +1,4 @@
import { formatCliCommand } from "../../cli/command-format.js";
import { logConfigUpdated } from "../../config/logging.js";
import { type RuntimeEnv, writeRuntimeJson } from "../../runtime.js";
import { loadModelsConfig } from "./load-config.js";
@@ -95,7 +96,9 @@ export async function modelsAliasesRemoveCommand(aliasRaw: string, runtime: Runt
}
}
if (!found) {
throw new Error(`Alias not found: ${alias}`);
throw new Error(
`Alias not found: ${alias}. Run ${formatCliCommand("openclaw models aliases list")} to see configured aliases.`,
);
}
return {
...cfg,

View File

@@ -1,4 +1,5 @@
import { buildModelAliasIndex, resolveModelRefFromString } from "../../agents/model-selection.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { logConfigUpdated } from "../../config/logging.js";
import { resolveAgentModelFallbackValues, toAgentModelListLike } from "../../config/model-input.js";
import type { AgentModelEntryConfig } from "../../config/types.agent-defaults.js";
@@ -18,6 +19,12 @@ import {
type DefaultsFallbackKey = "model" | "imageModel";
function listCommandForFallbackKey(key: DefaultsFallbackKey): string {
return key === "imageModel"
? "openclaw models image-fallbacks list"
: "openclaw models fallbacks list";
}
function getFallbacks(cfg: OpenClawConfig, key: DefaultsFallbackKey): string[] {
return resolveAgentModelFallbackValues(cfg.agents?.defaults?.[key]);
}
@@ -133,7 +140,9 @@ export async function removeFallbackCommand(
});
if (filtered.length === existing.length) {
throw new Error(`${params.notFoundLabel} not found: ${targetKey}`);
throw new Error(
`${params.notFoundLabel} not found: ${targetKey}. Run ${formatCliCommand(listCommandForFallbackKey(params.key))} to see configured fallbacks.`,
);
}
return patchDefaultsFallbacks(cfg, { key: params.key, fallbacks: filtered });

View File

@@ -2,6 +2,7 @@ import { cancel, multiselect as clackMultiselect, isCancel } from "@clack/prompt
import { getEnvApiKey } from "@mariozechner/pi-ai";
import { resolveApiKeyForProvider } from "../../agents/model-auth.js";
import { type ModelScanResult, scanOpenRouterModels } from "../../agents/model-scan.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { withProgressTotals } from "../../cli/progress.js";
import { logConfigUpdated } from "../../config/logging.js";
import { toAgentModelListLike } from "../../config/model-input.js";
@@ -266,7 +267,9 @@ export async function modelsScanCommand(
const toolOk = results.filter((entry) => entry.tool.ok);
if (toolOk.length === 0) {
throw new Error("No tool-capable OpenRouter free models found.");
throw new Error(
`No tool-capable OpenRouter free models found. Try ${formatCliCommand("openclaw models scan --no-probe")} to inspect metadata-only candidates, or configure OPENROUTER_API_KEY before probing.`,
);
}
const sorted = sortScanResults(results);

View File

@@ -4,6 +4,7 @@ import {
resolveAuthProfileOrder,
} from "../../agents/auth-profiles.js";
import { resolveEnvApiKey } from "../../agents/model-auth.js";
import { formatCliCommand } from "../../cli/command-format.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { RuntimeEnv } from "../../runtime.js";
import { normalizeOptionalSecretInput } from "../../utils/normalize-secret-input.js";
@@ -134,7 +135,9 @@ export async function resolveNonInteractiveApiKey(params: {
const profileHint =
params.allowProfile === false ? "" : `, or existing ${params.provider} API-key profile`;
params.runtime.error(`Missing ${params.flagName} (or ${params.envVar} in env${profileHint}).`);
params.runtime.error(
`Missing ${params.flagName} (or ${params.envVar} in env${profileHint}). Export ${params.envVar}, pass ${params.flagName}, or run ${formatCliCommand("openclaw onboard")} for interactive setup.`,
);
params.runtime.exit(1);
return null;
}

View File

@@ -1,4 +1,5 @@
import type { ApiKeyCredential } from "../../../agents/auth-profiles/types.js";
import { formatCliCommand } from "../../../cli/command-format.js";
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import type { SecretInput } from "../../../config/types.secrets.js";
import { formatErrorMessage } from "../../../infra/errors.js";
@@ -42,7 +43,9 @@ export async function applyNonInteractiveAuthChoice(params: {
let nextConfig = params.nextConfig;
const requestedSecretInputMode = normalizeSecretInputModeInput(opts.secretInputMode);
if (opts.secretInputMode && !requestedSecretInputMode) {
runtime.error('Invalid --secret-input-mode. Use "plaintext" or "ref".');
runtime.error(
`Invalid --secret-input-mode. Use "plaintext" or "ref", or run ${formatCliCommand("openclaw onboard")} for interactive setup.`,
);
runtime.exit(1);
return null;
}