CLI: dedupe config validate errors and expose allowed values

This commit is contained in:
Gustavo Madeira Santana
2026-03-02 20:05:12 -05:00
parent a44843507f
commit f26853f14c
41 changed files with 1393 additions and 134 deletions

View File

@@ -1,6 +1,7 @@
import type { Command } from "commander";
import JSON5 from "json5";
import { readConfigFileSnapshot, writeConfigFile } from "../config/config.js";
import { formatConfigIssueLines, normalizeConfigIssues } from "../config/issue-format.js";
import { CONFIG_PATH } from "../config/paths.js";
import { isBlockedObjectKey } from "../config/prototype-keys.js";
import { redactConfigObject } from "../config/redact-snapshot.js";
@@ -16,10 +17,6 @@ type PathSegment = string;
type ConfigSetParseOpts = {
strictJson?: boolean;
};
type ConfigIssue = {
path: string;
message: string;
};
const OLLAMA_API_KEY_PATH: PathSegment[] = ["models", "providers", "ollama", "apiKey"];
const OLLAMA_PROVIDER_PATH: PathSegment[] = ["models", "providers", "ollama"];
@@ -102,17 +99,6 @@ function hasOwnPathKey(value: Record<string, unknown>, key: string): boolean {
return Object.prototype.hasOwnProperty.call(value, key);
}
function normalizeConfigIssues(issues: ReadonlyArray<ConfigIssue>): ConfigIssue[] {
return issues.map((issue) => ({
path: issue.path || "<root>",
message: issue.message,
}));
}
function formatConfigIssueLines(issues: ReadonlyArray<ConfigIssue>, marker: string): string[] {
return normalizeConfigIssues(issues).map((issue) => `${marker} ${issue.path}: ${issue.message}`);
}
function formatDoctorHint(message: string): string {
return `Run \`${formatCliCommand("openclaw doctor")}\` ${message}`;
}
@@ -249,7 +235,7 @@ async function loadValidConfig(runtime: RuntimeEnv = defaultRuntime) {
return snapshot;
}
runtime.error(`Config invalid at ${shortenHomePath(snapshot.path)}.`);
for (const line of formatConfigIssueLines(snapshot.issues, "-")) {
for (const line of formatConfigIssueLines(snapshot.issues, "-", { normalizeRoot: true })) {
runtime.error(line);
}
runtime.error(formatDoctorHint("to repair, then retry."));
@@ -381,7 +367,7 @@ export async function runConfigValidate(opts: { json?: boolean; runtime?: Runtim
runtime.log(JSON.stringify({ valid: false, path: outputPath, issues }, null, 2));
} else {
runtime.error(danger(`Config invalid at ${shortPath}:`));
for (const line of formatConfigIssueLines(issues, danger("×"))) {
for (const line of formatConfigIssueLines(issues, danger("×"), { normalizeRoot: true })) {
runtime.error(` ${line}`);
}
runtime.error("");