From 14137bef228e25a19fc8f083580a26380859a7e8 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Sun, 15 Mar 2026 21:48:09 +0000 Subject: [PATCH] Plugins: clean stale bundled skill outputs --- scripts/copy-bundled-plugin-metadata.mjs | 12 +++-- .../auth-choice.plugin-providers.runtime.ts | 4 +- .../copy-bundled-plugin-metadata.test.ts | 47 +++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/scripts/copy-bundled-plugin-metadata.mjs b/scripts/copy-bundled-plugin-metadata.mjs index e563e260c6a..2ba04d9cda0 100644 --- a/scripts/copy-bundled-plugin-metadata.mjs +++ b/scripts/copy-bundled-plugin-metadata.mjs @@ -110,6 +110,12 @@ export function copyBundledPluginMetadata(params = {}) { } const sourcePluginDirs = new Set(); + const removeGeneratedPluginArtifacts = (distPluginDir) => { + removeFileIfExists(path.join(distPluginDir, "openclaw.plugin.json")); + removeFileIfExists(path.join(distPluginDir, "package.json")); + removePathIfExists(path.join(distPluginDir, GENERATED_BUNDLED_SKILLS_DIR)); + removePathIfExists(path.join(distPluginDir, "node_modules")); + }; for (const dirent of fs.readdirSync(extensionsRoot, { withFileTypes: true })) { if (!dirent.isDirectory()) { @@ -123,8 +129,7 @@ export function copyBundledPluginMetadata(params = {}) { const distManifestPath = path.join(distPluginDir, "openclaw.plugin.json"); const distPackageJsonPath = path.join(distPluginDir, "package.json"); if (!fs.existsSync(manifestPath)) { - removeFileIfExists(distManifestPath); - removeFileIfExists(distPackageJsonPath); + removeGeneratedPluginArtifacts(distPluginDir); continue; } @@ -165,8 +170,7 @@ export function copyBundledPluginMetadata(params = {}) { continue; } const distPluginDir = path.join(distExtensionsRoot, dirent.name); - removeFileIfExists(path.join(distPluginDir, "openclaw.plugin.json")); - removeFileIfExists(path.join(distPluginDir, "package.json")); + removeGeneratedPluginArtifacts(distPluginDir); } } diff --git a/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.runtime.ts b/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.runtime.ts index fd4a36d4a9f..a19d1861c7e 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.runtime.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.runtime.ts @@ -1,4 +1,2 @@ -export { - resolveProviderPluginChoice, -} from "../../../plugins/provider-wizard.js"; +export { resolveProviderPluginChoice } from "../../../plugins/provider-wizard.js"; export { resolvePluginProviders } from "../../../plugins/providers.js"; diff --git a/src/plugins/copy-bundled-plugin-metadata.test.ts b/src/plugins/copy-bundled-plugin-metadata.test.ts index a02106efef7..9c980381aa8 100644 --- a/src/plugins/copy-bundled-plugin-metadata.test.ts +++ b/src/plugins/copy-bundled-plugin-metadata.test.ts @@ -193,4 +193,51 @@ describe("copyBundledPluginMetadata", () => { ); expect(fs.existsSync(staleNodeModulesDir)).toBe(false); }); + + it("removes generated outputs for plugins no longer present in source", () => { + const repoRoot = makeRepoRoot("openclaw-bundled-plugin-removed-"); + const staleBundledSkillDir = path.join( + repoRoot, + "dist", + "extensions", + "removed-plugin", + "bundled-skills", + "@scope", + "skill", + ); + fs.mkdirSync(staleBundledSkillDir, { recursive: true }); + fs.writeFileSync(path.join(staleBundledSkillDir, "SKILL.md"), "# stale\n", "utf8"); + const staleNodeModulesDir = path.join( + repoRoot, + "dist", + "extensions", + "removed-plugin", + "node_modules", + ); + fs.mkdirSync(staleNodeModulesDir, { recursive: true }); + writeJson(path.join(repoRoot, "dist", "extensions", "removed-plugin", "openclaw.plugin.json"), { + id: "removed-plugin", + configSchema: { type: "object" }, + skills: ["./bundled-skills/@scope/skill"], + }); + writeJson(path.join(repoRoot, "dist", "extensions", "removed-plugin", "package.json"), { + name: "@openclaw/removed-plugin", + }); + fs.mkdirSync(path.join(repoRoot, "extensions"), { recursive: true }); + + copyBundledPluginMetadata({ repoRoot }); + + expect( + fs.existsSync( + path.join(repoRoot, "dist", "extensions", "removed-plugin", "openclaw.plugin.json"), + ), + ).toBe(false); + expect( + fs.existsSync(path.join(repoRoot, "dist", "extensions", "removed-plugin", "package.json")), + ).toBe(false); + expect( + fs.existsSync(path.join(repoRoot, "dist", "extensions", "removed-plugin", "bundled-skills")), + ).toBe(false); + expect(fs.existsSync(staleNodeModulesDir)).toBe(false); + }); });