mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
fix(cli): report stale plugin doctor config
This commit is contained in:
+1
-1
@@ -386,7 +386,7 @@ The `--json` flag outputs a machine-readable report suitable for scripting and a
|
||||
openclaw plugins doctor
|
||||
```
|
||||
|
||||
`doctor` reports plugin load errors, manifest/discovery diagnostics, and compatibility notices. When everything is clean it prints `No plugin issues detected.`
|
||||
`doctor` reports plugin load errors, manifest/discovery diagnostics, compatibility notices, and stale plugin config references such as missing plugin slots. When the install tree and plugin config are clean it prints `No plugin issues detected.` If stale config remains but the install tree is otherwise healthy, the summary says so instead of implying full plugin health.
|
||||
|
||||
If a configured plugin is present on disk but blocked by the loader's path-safety checks, config validation keeps the plugin entry and reports it as `present but blocked`. Fix the preceding blocked-plugin diagnostic, such as path ownership or world-writable permissions, instead of removing the `plugins.entries.<id>` or `plugins.allow` config.
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
buildPluginRegistrySnapshotReport,
|
||||
buildPluginSnapshotReport,
|
||||
inspectPluginRegistry,
|
||||
loadConfig,
|
||||
readConfigFileSnapshot,
|
||||
resetPluginsCliTestState,
|
||||
refreshPluginRegistry,
|
||||
runPluginsCommand,
|
||||
@@ -79,10 +81,63 @@ describe("plugins cli list", () => {
|
||||
|
||||
await runPluginsCommand(["plugins", "doctor"]);
|
||||
|
||||
expect(buildPluginDiagnosticsReport).toHaveBeenCalledWith({ effectiveOnly: true });
|
||||
expect(buildPluginDiagnosticsReport).toHaveBeenCalledWith({ config: {}, effectiveOnly: true });
|
||||
expect(runtimeLogs).toContain("No plugin issues detected.");
|
||||
});
|
||||
|
||||
it("reports stale plugin config in doctor output without claiming full plugin health", async () => {
|
||||
const sourceConfig = {
|
||||
plugins: {
|
||||
allow: ["lossless-claw"],
|
||||
entries: {
|
||||
"lossless-claw": { enabled: true },
|
||||
},
|
||||
slots: {
|
||||
contextEngine: "lossless-claw",
|
||||
},
|
||||
},
|
||||
};
|
||||
loadConfig.mockReturnValue({});
|
||||
readConfigFileSnapshot.mockResolvedValueOnce({
|
||||
path: "/tmp/openclaw-config.json5",
|
||||
exists: true,
|
||||
raw: "{}",
|
||||
parsed: sourceConfig,
|
||||
resolved: sourceConfig,
|
||||
sourceConfig,
|
||||
runtimeConfig: {},
|
||||
config: {},
|
||||
valid: true,
|
||||
hash: "mock",
|
||||
issues: [],
|
||||
warnings: [],
|
||||
legacyIssues: [],
|
||||
});
|
||||
buildPluginDiagnosticsReport.mockReturnValue({
|
||||
plugins: [],
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
await runPluginsCommand(["plugins", "doctor"]);
|
||||
|
||||
const output = runtimeLogs.join("\n");
|
||||
expect(output).toContain("Plugin configuration:");
|
||||
expect(output).toContain('plugins.allow: stale plugin reference "lossless-claw" was found.');
|
||||
expect(output).toContain(
|
||||
'plugins.entries.lossless-claw: stale plugin reference "lossless-claw" was found.',
|
||||
);
|
||||
expect(output).toContain(
|
||||
'plugins.slots.contextEngine: slot references missing plugin "lossless-claw".',
|
||||
);
|
||||
expect(output).toContain(
|
||||
'Run "openclaw doctor --fix" to remove stale plugin ids and dangling channel references.',
|
||||
);
|
||||
expect(output).toContain(
|
||||
"No plugin install-tree issues detected; configuration warnings remain.",
|
||||
);
|
||||
expect(output).not.toContain("No plugin issues detected.");
|
||||
});
|
||||
|
||||
it("reports config-selected plugin source shadowing in doctor output", async () => {
|
||||
buildPluginDiagnosticsReport.mockReturnValue({
|
||||
plugins: [
|
||||
|
||||
+33
-7
@@ -365,20 +365,33 @@ export function registerPluginsCli(program: Command) {
|
||||
buildPluginDiagnosticsReport,
|
||||
formatPluginCompatibilityNotice,
|
||||
} = await import("../plugins/status.js");
|
||||
const report = buildPluginDiagnosticsReport({ effectiveOnly: true });
|
||||
const {
|
||||
collectStalePluginConfigWarnings,
|
||||
isStalePluginAutoRepairBlocked,
|
||||
scanStalePluginConfig,
|
||||
} = 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 report = buildPluginDiagnosticsReport({ config: cfg, effectiveOnly: true });
|
||||
const errors = report.plugins.filter((p) => p.status === "error");
|
||||
const diags = report.diagnostics.filter((d) => d.level === "error");
|
||||
const shadowed = report.diagnostics.filter((entry) =>
|
||||
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 hasInstallTreeIssues =
|
||||
errors.length > 0 || diags.length > 0 || shadowed.length > 0 || compatibility.length > 0;
|
||||
|
||||
if (
|
||||
errors.length === 0 &&
|
||||
diags.length === 0 &&
|
||||
shadowed.length === 0 &&
|
||||
compatibility.length === 0
|
||||
) {
|
||||
if (!hasInstallTreeIssues && stalePluginConfigWarnings.length === 0) {
|
||||
defaultRuntime.log("No plugin issues detected.");
|
||||
return;
|
||||
}
|
||||
@@ -436,6 +449,19 @@ export function registerPluginsCli(program: Command) {
|
||||
lines.push(`- ${formatPluginCompatibilityNotice(notice)} [${marker}]`);
|
||||
}
|
||||
}
|
||||
if (stalePluginConfigWarnings.length > 0) {
|
||||
if (lines.length > 0) {
|
||||
lines.push("");
|
||||
}
|
||||
lines.push(theme.warn("Plugin configuration:"));
|
||||
lines.push(...stalePluginConfigWarnings);
|
||||
}
|
||||
if (!hasInstallTreeIssues && stalePluginConfigWarnings.length > 0) {
|
||||
if (lines.length > 0) {
|
||||
lines.push("");
|
||||
}
|
||||
lines.push("No plugin install-tree issues detected; configuration warnings remain.");
|
||||
}
|
||||
const docs = formatDocsLink("/plugin", "docs.openclaw.ai/plugin");
|
||||
lines.push("");
|
||||
lines.push(`${theme.muted("Docs:")} ${docs}`);
|
||||
|
||||
Reference in New Issue
Block a user