
























@@ -5,6 +5,7 @@ import { tracePluginLifecyclePhaseAsync } from "../plugins/plugin-lifecycle-trac
55import { defaultRuntime } from "../runtime.js";
66import { formatDocsLink } from "../terminal/links.js";
77import { theme } from "../terminal/theme.js";
8+import { shortenHomeInString } from "../utils.js";
89import type { PluginInspectOptions } from "./plugins-inspect-command.js";
910import type { PluginsListOptions } from "./plugins-list-command.js";
1011import { applyParentDefaultHelpAction } from "./program/parent-default-help.js";
@@ -62,6 +63,14 @@ function matchesPluginId(plugin: { id: string }, id: string) {
6263return plugin.id === id;
6364}
646566+function isConfigSelectedShadowDiagnostic(entry: { level?: string; message?: string }): boolean {
67+return (
68+entry.level === "warn" &&
69+typeof entry.message === "string" &&
70+entry.message.includes("duplicate plugin id resolved by explicit config-selected plugin")
71+);
72+}
73+6574export function registerPluginsCli(program: Command) {
6675const plugins = program
6776.command("plugins")
@@ -336,9 +345,15 @@ export function registerPluginsCli(program: Command) {
336345const report = buildPluginDiagnosticsReport({ effectiveOnly: true });
337346const errors = report.plugins.filter((p) => p.status === "error");
338347const diags = report.diagnostics.filter((d) => d.level === "error");
348+const shadowed = report.diagnostics.filter(isConfigSelectedShadowDiagnostic);
339349const compatibility = buildPluginCompatibilityNotices({ report });
340350341-if (errors.length === 0 && diags.length === 0 && compatibility.length === 0) {
351+if (
352+errors.length === 0 &&
353+diags.length === 0 &&
354+shadowed.length === 0 &&
355+compatibility.length === 0
356+) {
342357defaultRuntime.log("No plugin issues detected.");
343358return;
344359}
@@ -361,6 +376,31 @@ export function registerPluginsCli(program: Command) {
361376lines.push(`- ${target}${diag.message}`);
362377}
363378}
379+if (shadowed.length > 0) {
380+if (lines.length > 0) {
381+lines.push("");
382+}
383+lines.push(theme.warn("Plugin source shadowing:"));
384+for (const diag of shadowed) {
385+const active = report.plugins.find((plugin) => plugin.id === diag.pluginId);
386+const target = diag.pluginId ? `${diag.pluginId}: ` : "";
387+lines.push(`- ${target}${diag.message}`);
388+if (active) {
389+lines.push(` active: ${shortenHomeInString(active.source)} (${active.origin})`);
390+if (active.status === "error") {
391+lines.push(` active status: error${active.error ? `: ${active.error}` : ""}`);
392+}
393+}
394+if (diag.source) {
395+lines.push(` shadowed: ${shortenHomeInString(diag.source)}`);
396+}
397+lines.push(" repair:");
398+lines.push(" openclaw plugins inspect " + (diag.pluginId ?? "<plugin-id>"));
399+lines.push(" edit or remove the config-selected plugin source");
400+lines.push(" openclaw plugins registry --refresh");
401+lines.push(" openclaw gateway restart --force");
402+}
403+}
364404if (compatibility.length > 0) {
365405if (lines.length > 0) {
366406lines.push("");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。