fix(cli): explain plugin and secrets failures

This commit is contained in:
Vincent Koc
2026-05-09 08:07:28 +08:00
parent d47b64609c
commit 05414e2ac3
4 changed files with 64 additions and 17 deletions

View File

@@ -3,6 +3,7 @@ import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
import { resolveOptionFromCommand, runCommandWithRuntime } from "./cli-utils.js";
import { formatCliCommand } from "./command-format.js";
function runModelsCommand(action: () => Promise<void>) {
return runCommandWithRuntime(defaultRuntime, action);
@@ -14,7 +15,7 @@ function rejectAgentScopedModelWrite(command: Command, commandName: "set" | "set
return;
}
throw new Error(
`\`openclaw models ${commandName}\` does not support \`--agent\`; it only updates global model defaults. Remove \`--agent\` or use agent config to set a per-agent model override.`,
`openclaw models ${commandName} does not support --agent; it only updates global model defaults. Remove --agent, or run ${formatCliCommand("openclaw agents list")} and set the per-agent model in agent config.`,
);
}

View File

@@ -33,6 +33,7 @@ import { validateJsonSchemaValue } from "../plugins/schema-validator.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { theme } from "../terminal/theme.js";
import { shortenHomePath } from "../utils.js";
import { formatCliCommand } from "./command-format.js";
import { looksLikeLocalInstallSpec } from "./install-spec.js";
import { resolvePinnedNpmInstallRecordForCli } from "./npm-resolution.js";
import {
@@ -587,30 +588,42 @@ export async function runPluginInstallCommand(params: {
};
if (opts.marketplace) {
if (opts.link) {
runtime.error("`--link` is not supported with `--marketplace`.");
runtime.error(
`--link is not supported with --marketplace. Remove --link, or install a local path with ${formatCliCommand("openclaw plugins install --link <path>")}.`,
);
return runtime.exit(1);
}
if (opts.pin) {
runtime.error("`--pin` is not supported with `--marketplace`.");
runtime.error(
`--pin is not supported with --marketplace. Use ${formatCliCommand("openclaw plugins install <plugin> --marketplace <name>")} without --pin.`,
);
return runtime.exit(1);
}
}
const gitPrefix = raw.trim().toLowerCase().startsWith("git:");
const gitSpec = parseGitPluginSpec(raw);
if (gitPrefix && !gitSpec) {
runtime.error(`unsupported git: plugin spec: ${raw}`);
runtime.error(
`Unsupported git plugin spec: ${raw}. Use ${formatCliCommand("openclaw plugins install git:<repo>@<ref>")}.`,
);
return runtime.exit(1);
}
if (gitSpec && opts.link) {
runtime.error("`--link` is not supported with `git:` installs.");
runtime.error(
`--link is not supported with git: installs. Use ${formatCliCommand("openclaw plugins install git:<repo>@<ref>")} for Git installs or ${formatCliCommand("openclaw plugins install --link <path>")} for local paths.`,
);
return runtime.exit(1);
}
if (gitSpec && opts.pin) {
runtime.error("`--pin` is not supported with `git:` installs; use `git:<repo>@<ref>`.");
runtime.error(
`--pin is not supported with git: installs. Pin the ref in the spec instead, for example ${formatCliCommand("openclaw plugins install git:<repo>@<ref>")}.`,
);
return runtime.exit(1);
}
if (opts.link && opts.force) {
runtime.error("`--force` is not supported with `--link`.");
runtime.error(
`--force is not supported with --link. Linked plugins point at the source path directly; remove --force and re-run ${formatCliCommand("openclaw plugins install --link <path>")}.`,
);
return runtime.exit(1);
}
const requestResolution = resolvePluginInstallRequestContext({
@@ -766,14 +779,18 @@ export async function runPluginInstallCommand(params: {
}
if (opts.link) {
runtime.error("`--link` requires a local path.");
runtime.error(
`--link requires a local path. Run ${formatCliCommand("openclaw plugins install --link <path>")}.`,
);
return runtime.exit(1);
}
const npmPrefixSpec = parseNpmPrefixSpec(raw);
if (npmPrefixSpec !== null) {
if (!npmPrefixSpec) {
runtime.error("unsupported npm: spec: missing package");
runtime.error(
`Unsupported npm plugin spec: missing package. Use ${formatCliCommand("openclaw plugins install npm:<package>")}.`,
);
return runtime.exit(1);
}
const officialNpmTrust = resolveOfficialExternalNpmPackageTrust({
@@ -808,7 +825,9 @@ export async function runPluginInstallCommand(params: {
const npmPackPath = parseNpmPackPrefixPath(raw);
if (npmPackPath !== null) {
if (!npmPackPath) {
runtime.error("unsupported npm-pack: spec: missing pack archive path");
runtime.error(
`Unsupported npm-pack plugin spec: missing archive path. Use ${formatCliCommand("openclaw plugins install npm-pack:<path-to.tgz>")}.`,
);
return runtime.exit(1);
}
const npmPackResult = await tryInstallPluginFromNpmPackArchive({
@@ -852,7 +871,9 @@ export async function runPluginInstallCommand(params: {
".zip",
])
) {
runtime.error(`Path not found: ${resolved}`);
runtime.error(
`Plugin path not found: ${resolved}. Check the path, or install from npm with ${formatCliCommand("openclaw plugins install npm:<package>")}.`,
);
return runtime.exit(1);
}

View File

@@ -3,6 +3,7 @@ import { formatPluginSourceForTable, resolvePluginSourceRoots } from "../plugins
import { defaultRuntime, writeRuntimeJson, type RuntimeEnv } from "../runtime.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";
import { theme } from "../terminal/theme.js";
import { formatCliCommand } from "./command-format.js";
import { quietPluginJsonLogger } from "./plugins-command-helpers.js";
import { formatPluginLine } from "./plugins-list-format.js";
@@ -39,7 +40,11 @@ export async function runPluginsListCommand(
}
if (list.length === 0) {
runtime.log(theme.muted("No plugins found."));
runtime.log(
theme.muted(
`No plugins found. Run ${formatCliCommand("openclaw plugins install <plugin>")} to add one, or ${formatCliCommand("openclaw plugins list --json")} to inspect raw discovery state.`,
),
);
return;
}

View File

@@ -2,6 +2,7 @@ import fs from "node:fs";
import { confirm } from "@clack/prompts";
import type { Command } from "commander";
import { danger } from "../globals.js";
import { formatErrorMessage } from "../infra/errors.js";
import { defaultRuntime } from "../runtime.js";
import { runSecretsApply } from "../secrets/apply.js";
import { resolveSecretsAuditExitCode, runSecretsAudit } from "../secrets/audit.js";
@@ -9,6 +10,7 @@ import { runSecretsConfigureInteractive } from "../secrets/configure.js";
import { isSecretsApplyPlan, type SecretsApplyPlan } from "../secrets/plan.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
import { formatCliCommand } from "./command-format.js";
import { addGatewayClientOptions, callGatewayFromCli, type GatewayRpcOpts } from "./gateway-rpc.js";
type SecretsReloadOptions = GatewayRpcOpts & { json?: boolean };
@@ -38,7 +40,9 @@ function readPlanFile(pathname: string): SecretsApplyPlan {
const raw = fs.readFileSync(pathname, "utf8");
const parsed = JSON.parse(raw) as unknown;
if (!isSecretsApplyPlan(parsed)) {
throw new Error(`Invalid secrets plan file: ${pathname}`);
throw new Error(
`Invalid secrets plan file: ${pathname}. Generate a fresh plan with ${formatCliCommand("openclaw secrets configure --plan-out <path>")}.`,
);
}
return parsed;
}
@@ -76,7 +80,11 @@ export function registerSecretsCli(program: Command) {
}
defaultRuntime.log("Secrets reloaded.");
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.error(
danger(
`Secrets reload failed: ${formatErrorMessage(err)}. Run ${formatCliCommand("openclaw gateway status --deep")} to inspect the active gateway.`,
),
);
defaultRuntime.exit(1);
}
});
@@ -123,7 +131,11 @@ export function registerSecretsCli(program: Command) {
defaultRuntime.exit(exitCode);
}
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.error(
danger(
`Secrets audit failed: ${formatErrorMessage(err)}. Run ${formatCliCommand("openclaw doctor")} to inspect config and credential state.`,
),
);
defaultRuntime.exit(2);
}
});
@@ -232,7 +244,11 @@ export function registerSecretsCli(program: Command) {
);
}
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.error(
danger(
`Secrets configure failed: ${formatErrorMessage(err)}. Re-run ${formatCliCommand("openclaw secrets audit")} before applying changes.`,
),
);
defaultRuntime.exit(1);
}
});
@@ -275,7 +291,11 @@ export function registerSecretsCli(program: Command) {
: "Secrets apply: no changes.",
);
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.error(
danger(
`Secrets apply failed: ${formatErrorMessage(err)}. Re-run ${formatCliCommand("openclaw secrets apply --from <path> --dry-run")} to inspect the plan without writing.`,
),
);
defaultRuntime.exit(1);
}
});