From d2628e430ccd2c8f9d32a1577ac10b7cf4545ab4 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 12 Aug 2026 20:40:30 -0700 Subject: [PATCH] fix(cli): avoid restart hint for unchanged config (#122953) * fix(cli): avoid restart hint for unchanged config * docs(cli): clarify no-op restart guidance --- docs/cli/config.md | 2 +- src/cli/config-cli-runner.ts | 8 ++++---- src/cli/config-cli.test.ts | 30 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/docs/cli/config.md b/docs/cli/config.md index eaf945d88d6c..f6a63c1adeb1 100644 --- a/docs/cli/config.md +++ b/docs/cli/config.md @@ -461,7 +461,7 @@ After every successful `config set` / `config patch` / `config unset`, the CLI p | `Change will apply without restarting the gateway.` | Hot reload picks it up automatically. | | `No gateway restart needed.` | Nothing runtime-relevant changed. | -Writes to `plugins.entries` (or any subpath) always require a restart, since the CLI cannot prove every plugin's reload metadata is loaded. +Effective changes to `plugins.entries` (or any subpath) require a restart, since the CLI cannot prove every plugin's reload metadata is loaded. Idempotent writes with no effective diff report `No gateway restart needed.` ## Write safety diff --git a/src/cli/config-cli-runner.ts b/src/cli/config-cli-runner.ts index 510e1ade0883..36389a8127e7 100644 --- a/src/cli/config-cli-runner.ts +++ b/src/cli/config-cli-runner.ts @@ -235,10 +235,10 @@ export function configApplyHintForOperations( beforeConfig, afterConfig, ); - if ( - paths.length === 0 || - paths.some((path) => path === "plugins.entries" || path.startsWith("plugins.entries.")) - ) { + if (paths.length === 0) { + return "No gateway restart needed."; + } + if (paths.some((path) => path === "plugins.entries" || path.startsWith("plugins.entries."))) { return "Restart the gateway to apply."; } const plan = buildGatewayReloadPlan(paths, { candidateConfig: afterConfig }); diff --git a/src/cli/config-cli.test.ts b/src/cli/config-cli.test.ts index 36044fd6f928..4152fc472366 100644 --- a/src/cli/config-cli.test.ts +++ b/src/cli/config-cli.test.ts @@ -4215,6 +4215,35 @@ describe("config cli", () => { }); describe("config apply hints - issue #80722", () => { + it("prints a no-restart hint for a same-value config set", async () => { + setGatewaySnapshot(); + + await runConfigSet("gateway.port", "18789", "--strict-json"); + + expect(mockWriteConfigFile).toHaveBeenCalledTimes(1); + expectLogIncludes("Updated gateway.port. No gateway restart needed."); + expectLogExcludes("Restart the gateway to apply."); + expectLogExcludes("Change will apply without restarting the gateway."); + }); + + it("prints a no-restart hint for a same-value config patch", async () => { + setGatewaySnapshot(); + const pathname = writeTempJson5File("openclaw-config-patch-same-value", { + gateway: { port: 18789 }, + }); + + try { + await runConfigCommand(["config", "patch", "--file", pathname]); + } finally { + fs.rmSync(pathname, { force: true }); + } + + expect(mockWriteConfigFile).toHaveBeenCalledTimes(1); + expectLogIncludes("Applied 1 config update(s). No gateway restart needed."); + expectLogExcludes("Restart the gateway to apply."); + expectLogExcludes("Change will apply without restarting the gateway."); + }); + it("prints a hot-reload hint for agents.list model changes", async () => { const resolved: OpenClawConfig = { agents: { @@ -4429,6 +4458,7 @@ describe("config cli", () => { expectLogIncludes("Updated plugins.entries.canvas.enabled"); expectLogIncludes("Restart the gateway to apply."); expectLogExcludes("Change will apply without restarting the gateway."); + expectLogExcludes("No gateway restart needed."); }); it("keeps the restart hint for mixed hot and restart batch updates", async () => {