From ad185dd4a89d71600092c89954d235d4e5cde384 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 17 Mar 2026 23:27:17 -0700 Subject: [PATCH] CLI: make config compatibility advice opt-in --- src/commands/config-validation.test.ts | 40 ++++++++++++++++++++++++-- src/commands/config-validation.ts | 4 +++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/commands/config-validation.test.ts b/src/commands/config-validation.test.ts index 6d809a3b50b..83876477b43 100644 --- a/src/commands/config-validation.test.ts +++ b/src/commands/config-validation.test.ts @@ -18,7 +18,7 @@ describe("requireValidConfigSnapshot", () => { vi.clearAllMocks(); }); - it("returns config and emits a non-blocking compatibility advisory", async () => { + it("returns config without emitting compatibility advice by default", async () => { readConfigFileSnapshot.mockResolvedValue({ exists: true, valid: true, @@ -43,6 +43,40 @@ describe("requireValidConfigSnapshot", () => { const { requireValidConfigSnapshot } = await import("./config-validation.js"); const config = await requireValidConfigSnapshot(runtime); + expect(config).toEqual({ plugins: {} }); + expect(runtime.error).not.toHaveBeenCalled(); + expect(runtime.exit).not.toHaveBeenCalled(); + expect(buildPluginCompatibilityNotices).not.toHaveBeenCalled(); + expect(runtime.log).not.toHaveBeenCalled(); + }); + + it("emits a non-blocking compatibility advisory when explicitly requested", async () => { + readConfigFileSnapshot.mockResolvedValue({ + exists: true, + valid: true, + config: { plugins: {} }, + issues: [], + }); + buildPluginCompatibilityNotices.mockReturnValue([ + { + pluginId: "legacy-plugin", + code: "legacy-before-agent-start", + severity: "warn", + message: + "still uses legacy before_agent_start; keep regression coverage on this plugin, and prefer before_model_resolve/before_prompt_build for new work.", + }, + ]); + const runtime = { + log: vi.fn(), + error: vi.fn(), + exit: vi.fn(), + }; + + const { requireValidConfigSnapshot } = await import("./config-validation.js"); + const config = await requireValidConfigSnapshot(runtime, { + includeCompatibilityAdvisory: true, + }); + expect(config).toEqual({ plugins: {} }); expect(runtime.error).not.toHaveBeenCalled(); expect(runtime.exit).not.toHaveBeenCalled(); @@ -66,7 +100,9 @@ describe("requireValidConfigSnapshot", () => { }; const { requireValidConfigSnapshot } = await import("./config-validation.js"); - const config = await requireValidConfigSnapshot(runtime); + const config = await requireValidConfigSnapshot(runtime, { + includeCompatibilityAdvisory: true, + }); expect(config).toBeNull(); expect(runtime.error).toHaveBeenCalled(); diff --git a/src/commands/config-validation.ts b/src/commands/config-validation.ts index 5ece0a1cf36..97c1ffc665e 100644 --- a/src/commands/config-validation.ts +++ b/src/commands/config-validation.ts @@ -9,6 +9,7 @@ import type { RuntimeEnv } from "../runtime.js"; export async function requireValidConfigSnapshot( runtime: RuntimeEnv, + opts?: { includeCompatibilityAdvisory?: boolean }, ): Promise { const snapshot = await readConfigFileSnapshot(); if (snapshot.exists && !snapshot.valid) { @@ -21,6 +22,9 @@ export async function requireValidConfigSnapshot( runtime.exit(1); return null; } + if (opts?.includeCompatibilityAdvisory !== true) { + return snapshot.config; + } const compatibility = buildPluginCompatibilityNotices({ config: snapshot.config }); if (compatibility.length > 0) { runtime.log(