fix(cli): clarify remaining required options

This commit is contained in:
Vincent Koc
2026-05-09 09:22:04 +08:00
parent 737d5253e5
commit e45b9d7a74
11 changed files with 40 additions and 15 deletions

View File

@@ -2,6 +2,7 @@ import type { Command } from "commander";
import { runAcpClientInteractive } from "../acp/client.js";
import { serveAcpGateway } from "../acp/server.js";
import { normalizeAcpProvenanceMode } from "../acp/types.js";
import { formatErrorMessage } from "../infra/errors.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
@@ -33,7 +34,7 @@ export function registerAcpCli(program: Command) {
const { gatewayToken, gatewayPassword } = resolveGatewayAuthOptions(opts);
const provenanceMode = normalizeAcpProvenanceMode(opts.provenance as string | undefined);
if (opts.provenance && !provenanceMode) {
throw new Error("Invalid --provenance value. Use off, meta, or meta+receipt.");
throw new Error('Invalid --provenance. Use "off", "meta", or "meta+receipt".');
}
await serveAcpGateway({
gatewayUrl: opts.url as string | undefined,
@@ -48,7 +49,7 @@ export function registerAcpCli(program: Command) {
verbose: Boolean(opts.verbose),
});
} catch (err) {
defaultRuntime.error(String(err));
defaultRuntime.error(`ACP bridge failed: ${formatErrorMessage(err)}`);
defaultRuntime.exit(1);
}
});

View File

@@ -232,7 +232,7 @@ export function registerCronAddCommand(cron: Command) {
const name = normalizeOptionalString(opts.name) ?? "";
if (!name) {
throw new Error("--name is required");
throw new Error("Cron job name is required. Pass --name <name>.");
}
const description = normalizeOptionalString(opts.description);

View File

@@ -104,14 +104,14 @@ function resolveDirectSchedule(options: NormalizedScheduleOptions): CronSchedule
if (options.at) {
const atIso = parseAt(options.at, options.tz);
if (!atIso) {
throw new Error("Invalid --at; use ISO time or duration like 20m");
throw new Error("Invalid --at. Use an ISO timestamp or a duration like 20m.");
}
return { kind: "at", at: atIso };
}
if (options.every) {
const everyMs = parseDurationMs(options.every);
if (!everyMs) {
throw new Error("Invalid --every; use e.g. 10m, 1h, 1d");
throw new Error("Invalid --every. Use a duration like 10m, 1h, or 1d.");
}
return { kind: "every", everyMs };
}

View File

@@ -7,7 +7,9 @@ import type { DaemonStatusOptions } from "./types.js";
export async function runDaemonStatus(opts: DaemonStatusOptions) {
try {
if (opts.requireRpc && !opts.probe) {
defaultRuntime.error("Gateway status failed: --require-rpc cannot be used with --no-probe.");
defaultRuntime.error(
"Gateway status failed: --require-rpc needs probing enabled. Remove --no-probe or drop --require-rpc.",
);
defaultRuntime.exit(1);
return;
}

View File

@@ -30,6 +30,7 @@ import {
import { sanitizeForLog } from "../terminal/ansi.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { formatCliCommand } from "./command-format.js";
import { applyParentDefaultHelpAction } from "./program/parent-default-help.js";
import { withProgress } from "./progress.js";
@@ -509,7 +510,9 @@ function resolveRequiredDeviceRole(
if (deviceId && role) {
return { deviceId, role };
}
defaultRuntime.error("--device and --role required");
defaultRuntime.error(
`--device and --role are required. Run ${formatCliCommand("openclaw devices list")} to choose a paired device.`,
);
defaultRuntime.exit(1);
return null;
}
@@ -608,7 +611,9 @@ export function registerDevicesCli(program: Command) {
.action(async (deviceId: string, opts: DevicesRpcOpts) => {
const trimmed = deviceId.trim();
if (!trimmed) {
defaultRuntime.error("deviceId is required");
defaultRuntime.error(
`deviceId is required. Run ${formatCliCommand("openclaw devices list")} to choose a paired device.`,
);
defaultRuntime.exit(1);
return;
}

View File

@@ -2,6 +2,7 @@ import type { Command } from "commander";
import { defaultRuntime } from "../../runtime.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { getTerminalTableWidth } from "../../terminal/table.js";
import { formatCliCommand } from "../command-format.js";
import { getNodesTheme, runNodesCommand } from "./cli-utils.js";
import { parsePairingList } from "./format.js";
import { renderPendingPairingRequestsTable } from "./pairing-render.js";
@@ -80,7 +81,9 @@ export function registerNodesPairingCommands(nodes: Command) {
await runNodesCommand("remove", async () => {
const nodeId = await resolveNodeId(opts, normalizeOptionalString(opts.node) ?? "");
if (!nodeId) {
defaultRuntime.error("--node required");
defaultRuntime.error(
`--node is required. Run ${formatCliCommand("openclaw nodes pairing pending")} to choose a node request.`,
);
defaultRuntime.exit(1);
return;
}
@@ -106,7 +109,9 @@ export function registerNodesPairingCommands(nodes: Command) {
const nodeId = await resolveNodeId(opts, normalizeOptionalString(opts.node) ?? "");
const name = normalizeOptionalString(opts.name) ?? "";
if (!nodeId || !name) {
defaultRuntime.error("--node and --name required");
defaultRuntime.error(
`--node and --name are required. Run ${formatCliCommand("openclaw nodes pairing pending")} to choose a node, then rerun with --name <displayName>.`,
);
defaultRuntime.exit(1);
return;
}

View File

@@ -4,6 +4,7 @@ import { defaultRuntime } from "../runtime.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
import { formatCliCommand } from "./command-format.js";
import type { GatewayRpcOpts } from "./gateway-rpc.js";
import { addGatewayClientOptions, callGatewayFromCli } from "./gateway-rpc.js";
@@ -62,7 +63,9 @@ export function registerSystemCli(program: Command) {
async () => {
const text = normalizeOptionalString(opts.text) ?? "";
if (!text) {
throw new Error("--text is required");
throw new Error(
`--text is required. Example: ${formatCliCommand('openclaw system event --text "deploy finished"')}.`,
);
}
const mode = normalizeWakeMode(opts.mode);
return await callGatewayFromCli("wake", opts, { mode, text }, { expectFinal: false });

View File

@@ -20,6 +20,7 @@ import { defaultRuntime } from "../runtime.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
import { formatCliCommand } from "./command-format.js";
export function registerWebhooksCli(program: Command) {
const webhooks = program
@@ -109,7 +110,9 @@ function parseGmailSetupOptions(raw: Record<string, unknown>): GmailSetupOptions
const accountRaw = raw.account;
const account = normalizeOptionalString(accountRaw) ?? "";
if (!account) {
throw new Error("--account is required");
throw new Error(
`--account is required. Example: ${formatCliCommand("openclaw webhooks gmail setup --account default")}.`,
);
}
const common = parseGmailCommonOptions(raw);
return {

View File

@@ -413,7 +413,9 @@ export async function modelsAuthPasteTokenCommand(
const agentDir = await resolveModelsAuthAgentDir(opts.agent);
const rawProvider = normalizeOptionalString(opts.provider);
if (!rawProvider) {
throw new Error("Missing --provider.");
throw new Error(
`Missing --provider. Run ${formatCliCommand("openclaw models status")} or ${formatCliCommand("openclaw plugins list")} to choose a provider.`,
);
}
const provider = normalizeProviderId(rawProvider);
const profileId =

View File

@@ -146,7 +146,9 @@ export function applyNonInteractiveGatewayConfig(params: {
if (authMode === "password") {
const password = opts.gatewayPassword?.trim();
if (!password) {
runtime.error("Missing --gateway-password for password auth.");
runtime.error(
"Missing --gateway-password for password auth. Pass --gateway-password or use --gateway-auth token.",
);
runtime.exit(1);
return null;
}

View File

@@ -19,7 +19,9 @@ export async function runNonInteractiveRemoteSetup(params: {
const remoteUrl = normalizeOptionalString(opts.remoteUrl);
if (!remoteUrl) {
runtime.error("Missing --remote-url for remote mode.");
runtime.error(
`Missing --remote-url for remote mode. Example: ${formatCliCommand("openclaw onboard --non-interactive --mode remote --remote-url ws://127.0.0.1:3000")}.`,
);
runtime.exit(1);
return;
}