fix(cli): surface validated plugin doctor warnings (#118526)

Co-authored-by: Peter Steinberger <steipete@macos.shared>
This commit is contained in:
Peter Steinberger
2026-08-02 23:23:18 -07:00
committed by GitHub
parent 6e51a68ea9
commit b65cc592cc
2 changed files with 161 additions and 22 deletions
+20 -21
View File
@@ -12,6 +12,7 @@ import {
readConfigFileSnapshot,
replaceConfigFile,
} from "../config/config.js";
import { formatConfigIssueLines } from "../config/issue-format.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { emitDiagnosticsTimelineEvent } from "../infra/diagnostics-timeline.js";
import { withPluginLifecycleLease } from "../plugins/plugin-lifecycle-lease.js";
@@ -141,7 +142,6 @@ function formatDisabledRuntimePluginGuidance(params: {
function collectConfiguredRuntimePluginWarnings(params: {
cfg: OpenClawConfig;
env: NodeJS.ProcessEnv;
plugins: readonly { enabled?: boolean; id: string; status?: string }[];
}): string[] {
const enabledPluginIds = new Set(
@@ -369,9 +369,7 @@ export async function runPluginsDoctorCommand(opts: PluginDoctorOptions = {}): P
} = await import("../commands/doctor/shared/stale-plugin-config.js");
const cfg = getRuntimeConfig();
const configSnapshot = await readConfigFileSnapshot().catch(() => null);
const sourceCfg = (configSnapshot?.sourceConfig ?? configSnapshot?.config ?? cfg) as
| OpenClawConfig
| undefined;
const sourceCfg = configSnapshot?.sourceConfig ?? configSnapshot?.config ?? cfg;
const report = buildPluginDiagnosticsReport({ config: cfg, effectiveOnly: true });
const errors = report.plugins.filter((p) => p.status === "error");
const diags = report.diagnostics.filter((entry) => !isConfigSelectedShadowDiagnostic(entry));
@@ -379,24 +377,25 @@ export async function runPluginsDoctorCommand(opts: PluginDoctorOptions = {}): P
isErroredConfigSelectedShadowDiagnostic({ entry, plugins: report.plugins }),
);
const compatibility = buildPluginCompatibilityNotices({ report });
const stalePluginConfigHits = scanStalePluginConfig(sourceCfg ?? cfg, process.env);
const stalePluginConfigWarnings = collectStalePluginConfigWarnings({
hits: stalePluginConfigHits,
doctorFixCommand: "openclaw doctor --fix",
autoRepairBlocked: isStalePluginAutoRepairBlocked(sourceCfg ?? cfg, process.env),
});
const configuredRuntimePluginWarnings = collectConfiguredRuntimePluginWarnings({
cfg: sourceCfg ?? cfg,
env: process.env,
plugins: report.plugins,
});
const pluginConfigWarnings = new Set([
...formatConfigIssueLines(
(configSnapshot?.warnings ?? []).filter(
({ path }) => path === "plugins" || path.startsWith("plugins."),
),
),
...collectStalePluginConfigWarnings({
hits: scanStalePluginConfig(sourceCfg, process.env),
doctorFixCommand: "openclaw doctor --fix",
autoRepairBlocked: isStalePluginAutoRepairBlocked(sourceCfg, process.env),
}),
...collectConfiguredRuntimePluginWarnings({ cfg: sourceCfg, plugins: report.plugins }),
]);
const hasInstallTreeIssues =
errors.length > 0 || diags.length > 0 || shadowed.length > 0 || compatibility.length > 0;
const pluginConfigWarnings = [...stalePluginConfigWarnings, ...configuredRuntimePluginWarnings];
if (opts.json) {
defaultRuntime.writeJson({
ok: !hasInstallTreeIssues && pluginConfigWarnings.length === 0,
ok: !hasInstallTreeIssues && pluginConfigWarnings.size === 0,
pluginErrors: errors.map((entry) => ({
id: entry.id,
...(entry.failurePhase ? { failurePhase: entry.failurePhase } : {}),
@@ -437,12 +436,12 @@ export async function runPluginsDoctorCommand(opts: PluginDoctorOptions = {}): P
...notice,
message: shortenHomeInString(notice.message),
})),
configurationWarnings: pluginConfigWarnings.map(shortenHomeInString),
configurationWarnings: Array.from(pluginConfigWarnings, shortenHomeInString),
});
return;
}
if (!hasInstallTreeIssues && pluginConfigWarnings.length === 0) {
if (!hasInstallTreeIssues && pluginConfigWarnings.size === 0) {
defaultRuntime.log(
"Plugin discovery, module loading, compatibility, and configuration checks passed. " +
'Run "openclaw health" to check the running Gateway, including runtime quarantines and fallbacks.',
@@ -503,14 +502,14 @@ export async function runPluginsDoctorCommand(opts: PluginDoctorOptions = {}): P
lines.push(`- ${formatPluginCompatibilityNotice(notice)} [${marker}]`);
}
}
if (pluginConfigWarnings.length > 0) {
if (pluginConfigWarnings.size > 0) {
if (lines.length > 0) {
lines.push("");
}
lines.push(theme.warn("Plugin configuration:"));
lines.push(...pluginConfigWarnings);
}
if (!hasInstallTreeIssues && pluginConfigWarnings.length > 0) {
if (!hasInstallTreeIssues && pluginConfigWarnings.size > 0) {
if (lines.length > 0) {
lines.push("");
}