fix(plugins): surface actionable doctor warnings (#117357)

Co-authored-by: Peter Steinberger <steipete@macos.shared>
This commit is contained in:
Peter Steinberger
2026-08-01 04:51:43 -07:00
committed by GitHub
parent 2d545c16c3
commit 7bd7d7d2a1
2 changed files with 50 additions and 1 deletions

View File

@@ -100,6 +100,55 @@ describe("plugins cli list", () => {
expect(runtimeLogs).toContain(cleanDoctorMessage);
});
it.each([
{
description: "a required plugin is missing",
diagnostic: {
level: "warn" as const,
pluginId: "calendar",
message: 'plugin "calendar" requires plugin "contacts"; install "contacts" to use it',
},
expected: 'calendar: plugin "calendar" requires plugin "contacts"',
},
{
description: "discovery cannot read an extensions directory",
diagnostic: {
level: "warn" as const,
message: "failed to read extensions dir: /tmp/plugins (permission denied)",
},
expected: "failed to read extensions dir: /tmp/plugins (permission denied)",
},
])(
"reports actionable discovery warnings when $description",
async ({ diagnostic, expected }) => {
buildPluginDiagnosticsReport.mockReturnValue({ plugins: [], diagnostics: [diagnostic] });
await runPluginsCommand(["plugins", "doctor"]);
const output = runtimeLogs.join("\n");
expect(output).toContain("Diagnostics:");
expect(output).toContain(expected);
expect(output).not.toContain(cleanDoctorMessage);
},
);
it("keeps actionable discovery warnings alongside existing errors", async () => {
buildPluginDiagnosticsReport.mockReturnValue({
plugins: [],
diagnostics: [
{ level: "error", pluginId: "broken", message: "plugin manifest invalid" },
{ level: "warn", pluginId: "calendar", message: "required plugin contacts is missing" },
],
});
await runPluginsCommand(["plugins", "doctor"]);
const output = runtimeLogs.join("\n");
expect(output).toContain("broken: plugin manifest invalid");
expect(output).toContain("calendar: required plugin contacts is missing");
expect(output).not.toContain(cleanDoctorMessage);
});
it("reports stale plugin config in doctor output without claiming full plugin health", async () => {
const sourceConfig = {
plugins: {

View File

@@ -375,7 +375,7 @@ export async function runPluginsDoctorCommand(): Promise<void> {
| 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 diags = report.diagnostics.filter((entry) => !isConfigSelectedShadowDiagnostic(entry));
const shadowed = report.diagnostics.filter((entry) =>
isErroredConfigSelectedShadowDiagnostic({ entry, plugins: report.plugins }),
);