diff --git a/CHANGELOG.md b/CHANGELOG.md index eee0980939b..45fc2566206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ Docs: https://docs.openclaw.ai - Gateway/restart: verify listener PIDs by argv when `lsof` reports only the Node process name, so stale gateway cleanup can find macOS `cnode` listeners. Fixes #70664. - Gateway/logging: expand leading `~` in `logging.file` before creating the file logger, preventing startup crash loops for home-relative log paths. Fixes #73587. - Channels/CLI: keep `openclaw channels list --json` usable when provider usage fetching fails, and report per-provider usage errors without aborting the channel list. Refs #67595. +- Doctor/plugins: do not treat `plugins.allow` entries as configured plugins during missing-plugin repair, so restrictive allowlists no longer install allowed-but-unused plugins. Thanks @vincentkoc. - Agents/messaging: deliver distinct final commentary after same-target `message` tool sends while still deduping text/media already sent by the tool, so short closing remarks are no longer silently dropped. Fixes #76915. Thanks @hclsys. - Agents/messaging: preserve string thread IDs when matching message-tool reply dedupe routes, avoiding precision loss on numeric-looking topic IDs before channel plugin comparison. Thanks @vincentkoc. - Channels/streaming: honor `agents.defaults.toolProgressDetail: "raw"` in Slack, Discord, Telegram, Matrix, and Microsoft Teams progress drafts, so tool-start lines include raw command/detail output when debugging. Thanks @vincentkoc. diff --git a/src/commands/doctor/shared/missing-configured-plugin-install.test.ts b/src/commands/doctor/shared/missing-configured-plugin-install.test.ts index 3e12fd96519..86422b2986a 100644 --- a/src/commands/doctor/shared/missing-configured-plugin-install.test.ts +++ b/src/commands/doctor/shared/missing-configured-plugin-install.test.ts @@ -939,6 +939,23 @@ describe("repairMissingConfiguredPluginInstalls", () => { expect(result).toEqual({ changes: [], warnings: [] }); }); + it("does not install plugins merely listed in plugins.allow", async () => { + const { repairMissingConfiguredPluginInstalls } = + await import("./missing-configured-plugin-install.js"); + const result = await repairMissingConfiguredPluginInstalls({ + cfg: { + plugins: { + allow: ["codex"], + }, + }, + env: {}, + }); + + expect(mocks.installPluginFromNpmSpec).not.toHaveBeenCalled(); + expect(mocks.writePersistedInstalledPluginIndexInstallRecords).not.toHaveBeenCalled(); + expect(result).toEqual({ changes: [], warnings: [] }); + }); + it("installs a missing third-party downloadable plugin from npm only", async () => { mocks.installPluginFromNpmSpec.mockResolvedValueOnce({ ok: true, diff --git a/src/commands/doctor/shared/missing-configured-plugin-install.ts b/src/commands/doctor/shared/missing-configured-plugin-install.ts index 7e78f56be2d..ae4a5cca060 100644 --- a/src/commands/doctor/shared/missing-configured-plugin-install.ts +++ b/src/commands/doctor/shared/missing-configured-plugin-install.ts @@ -109,10 +109,6 @@ function collectConfiguredPluginIds(cfg: OpenClawConfig, env?: NodeJS.ProcessEnv if (plugins?.enabled === false) { return ids; } - const allow = Array.isArray(plugins?.allow) ? plugins.allow : []; - for (const value of allow) { - addConfiguredPluginId(ids, value); - } const entries = asObjectRecord(plugins?.entries); for (const [pluginId, entry] of Object.entries(entries ?? {})) { if (asObjectRecord(entry)?.enabled === false) {