diff --git a/src/config/config.plugin-validation.test.ts b/src/config/config.plugin-validation.test.ts index 96ac5152b065..41445c11c4e5 100644 --- a/src/config/config.plugin-validation.test.ts +++ b/src/config/config.plugin-validation.test.ts @@ -1362,13 +1362,16 @@ describe("config plugin validation", () => { expectRemovedPluginWarnings(res, removedId, removedId); }); - // Regression for #90244: skill-workshop was extracted into a built-in tool; - // upgraded configs that still reference plugins.entries.skill-workshop must warn, - // not block startup with "plugin not found". it("warns for removed skill-workshop plugin id instead of failing validation", () => { const removedId = "skill-workshop"; const res = validateRemovedPluginConfig(removedId); - expectRemovedPluginWarnings(res, removedId, removedId); + expect(res.ok).toBe(true); + const message = + "plugin removed: skill-workshop (stale plugin config ignored; Skill Workshop is built into OpenClaw skills now. Use skills.workshop settings and openclaw skills workshop commands, then remove this plugins config entry)"; + expectPathMessage(res.warnings, `plugins.entries.${removedId}`, message); + expectPathMessage(res.warnings, "plugins.allow", message); + expectPathMessage(res.warnings, "plugins.deny", message); + expectPathMessage(res.warnings, "plugins.slots.memory", message); }); it("does not auto-allow config-loaded overrides of bundled web search plugin ids", () => { diff --git a/src/config/validation.ts b/src/config/validation.ts index 2a45ce594ac4..66c979427a29 100644 --- a/src/config/validation.ts +++ b/src/config/validation.ts @@ -57,6 +57,13 @@ const LEGACY_REMOVED_PLUGIN_IDS = new Set([ ]); const BLOCKED_PLUGIN_CANDIDATE_PREFIX = "blocked plugin candidate:"; +function formatRemovedPluginConfigWarning(pluginId: string): string { + if (pluginId === "skill-workshop") { + return "plugin removed: skill-workshop (stale plugin config ignored; Skill Workshop is built into OpenClaw skills now. Use skills.workshop settings and openclaw skills workshop commands, then remove this plugins config entry)"; + } + return `plugin removed: ${pluginId} (stale config entry ignored; remove it from plugins config)`; +} + type UnknownIssueRecord = Record; type ConfigPathSegment = string | number; type ExplicitPluginReferences = { @@ -1717,7 +1724,7 @@ function validateConfigObjectWithPluginsBase( if (LEGACY_REMOVED_PLUGIN_IDS.has(pluginId)) { warnings.push({ path: pathLocal, - message: `plugin removed: ${pluginId} (stale config entry ignored; remove it from plugins config)`, + message: formatRemovedPluginConfigWarning(pluginId), }); return; }