diff --git a/src/plugins/discovery.test.ts b/src/plugins/discovery.test.ts index ea84b562729..7a6d9d54578 100644 --- a/src/plugins/discovery.test.ts +++ b/src/plugins/discovery.test.ts @@ -219,6 +219,46 @@ describe("discoverOpenClawPlugins", () => { expect(ids).not.toContain("ollama-provider"); }); + it("normalizes bundled speech package ids to canonical plugin ids", async () => { + const stateDir = makeTempDir(); + const extensionsDir = path.join(stateDir, "extensions"); + const elevenlabsDir = path.join(extensionsDir, "elevenlabs-speech-pack"); + const microsoftDir = path.join(extensionsDir, "microsoft-speech-pack"); + + mkdirSafe(path.join(elevenlabsDir, "src")); + mkdirSafe(path.join(microsoftDir, "src")); + + writePluginPackageManifest({ + packageDir: elevenlabsDir, + packageName: "@openclaw/elevenlabs-speech", + extensions: ["./src/index.ts"], + }); + writePluginPackageManifest({ + packageDir: microsoftDir, + packageName: "@openclaw/microsoft-speech", + extensions: ["./src/index.ts"], + }); + + fs.writeFileSync( + path.join(elevenlabsDir, "src", "index.ts"), + "export default function () {}", + "utf-8", + ); + fs.writeFileSync( + path.join(microsoftDir, "src", "index.ts"), + "export default function () {}", + "utf-8", + ); + + const { candidates } = await discoverWithStateDir(stateDir, {}); + + const ids = candidates.map((c) => c.idHint); + expect(ids).toContain("elevenlabs"); + expect(ids).toContain("microsoft"); + expect(ids).not.toContain("elevenlabs-speech"); + expect(ids).not.toContain("microsoft-speech"); + }); + it("treats configured directory paths as plugin packages", async () => { const stateDir = makeTempDir(); const packDir = path.join(stateDir, "packs", "demo-plugin-dir"); diff --git a/src/plugins/discovery.ts b/src/plugins/discovery.ts index 743b0b569f9..24d4765e31b 100644 --- a/src/plugins/discovery.ts +++ b/src/plugins/discovery.ts @@ -16,6 +16,14 @@ import type { PluginBundleFormat, PluginDiagnostic, PluginFormat, PluginOrigin } const EXTENSION_EXTS = new Set([".ts", ".js", ".mts", ".cts", ".mjs", ".cjs"]); +const CANONICAL_PACKAGE_ID_ALIASES: Record = { + "elevenlabs-speech": "elevenlabs", + "microsoft-speech": "microsoft", + "ollama-provider": "ollama", + "sglang-provider": "sglang", + "vllm-provider": "vllm", +}; + export type PluginCandidate = { idHint: string; source: string; @@ -337,12 +345,7 @@ function deriveIdHint(params: { const unscoped = rawPackageName.includes("/") ? (rawPackageName.split("/").pop() ?? rawPackageName) : rawPackageName; - const canonicalPackageId = - { - "ollama-provider": "ollama", - "sglang-provider": "sglang", - "vllm-provider": "vllm", - }[unscoped] ?? unscoped; + const canonicalPackageId = CANONICAL_PACKAGE_ID_ALIASES[unscoped] ?? unscoped; if (!params.hasMultipleExtensions) { return canonicalPackageId;