diff --git a/src/plugins/sdk-alias.test.ts b/src/plugins/sdk-alias.test.ts index 905ce458ee3..e9feca30634 100644 --- a/src/plugins/sdk-alias.test.ts +++ b/src/plugins/sdk-alias.test.ts @@ -148,9 +148,12 @@ function createPluginRuntimeAliasFixture(params?: { srcBody?: string; distBody?: return { root, srcFile, distFile }; } -function createPluginSdkAliasTargetFixture() { +function createPluginSdkAliasTargetFixture(params?: { + sourceChannelRuntimeExtension?: ".ts" | ".mts" | ".js" | ".mjs" | ".cts" | ".cjs"; +}) { + const sourceChannelRuntimeExtension = params?.sourceChannelRuntimeExtension ?? ".ts"; const fixture = createPluginSdkAliasFixture({ - srcFile: "channel-runtime.ts", + srcFile: `channel-runtime${sourceChannelRuntimeExtension}`, distFile: "channel-runtime.js", packageExports: { "./plugin-sdk/channel-runtime": { default: "./dist/plugin-sdk/channel-runtime.js" }, @@ -160,7 +163,18 @@ function createPluginSdkAliasTargetFixture() { const distRootAlias = path.join(fixture.root, "dist", "plugin-sdk", "root-alias.cjs"); fs.writeFileSync(sourceRootAlias, "module.exports = {};\n", "utf-8"); fs.writeFileSync(distRootAlias, "module.exports = {};\n", "utf-8"); - return { fixture, sourceRootAlias, distRootAlias }; + return { + fixture, + sourceRootAlias, + distRootAlias, + sourceChannelRuntimePath: path.join( + fixture.root, + "src", + "plugin-sdk", + `channel-runtime${sourceChannelRuntimeExtension}`, + ), + distChannelRuntimePath: path.join(fixture.root, "dist", "plugin-sdk", "channel-runtime.js"), + }; } function writePluginEntry(root: string, relativePath: string) { @@ -533,7 +547,13 @@ describe("plugin sdk alias helpers", () => { }); it("builds plugin-sdk aliases from the module being loaded, not the loader location", () => { - const { fixture, sourceRootAlias, distRootAlias } = createPluginSdkAliasTargetFixture(); + const { + fixture, + sourceRootAlias, + distRootAlias, + sourceChannelRuntimePath, + distChannelRuntimePath, + } = createPluginSdkAliasTargetFixture(); const sourcePluginEntry = writePluginEntry( fixture.root, bundledPluginFile("demo", "src/index.ts"), @@ -544,7 +564,7 @@ describe("plugin sdk alias helpers", () => { ); expectPluginSdkAliasTargets(sourceAliases, { rootAliasPath: sourceRootAlias, - channelRuntimePath: path.join(fixture.root, "src", "plugin-sdk", "channel-runtime.ts"), + channelRuntimePath: sourceChannelRuntimePath, }); const distPluginEntry = writePluginEntry( @@ -557,12 +577,12 @@ describe("plugin sdk alias helpers", () => { ); expectPluginSdkAliasTargets(distAliases, { rootAliasPath: distRootAlias, - channelRuntimePath: path.join(fixture.root, "dist", "plugin-sdk", "channel-runtime.js"), + channelRuntimePath: distChannelRuntimePath, }); }); it("applies explicit dist resolution to plugin-sdk subpath aliases too", () => { - const { fixture, distRootAlias } = createPluginSdkAliasTargetFixture(); + const { fixture, distRootAlias, distChannelRuntimePath } = createPluginSdkAliasTargetFixture(); const sourcePluginEntry = writePluginEntry( fixture.root, bundledPluginFile("demo", "src/index.ts"), @@ -574,13 +594,38 @@ describe("plugin sdk alias helpers", () => { expectPluginSdkAliasTargets(distAliases, { rootAliasPath: distRootAlias, - channelRuntimePath: path.join(fixture.root, "dist", "plugin-sdk", "channel-runtime.js"), + channelRuntimePath: distChannelRuntimePath, + }); + }); + + it("builds source plugin-sdk subpath aliases through the wider source extension family", () => { + const { fixture, sourceRootAlias, sourceChannelRuntimePath } = + createPluginSdkAliasTargetFixture({ + sourceChannelRuntimeExtension: ".mts", + }); + const sourcePluginEntry = writePluginEntry( + fixture.root, + bundledPluginFile("demo", "src/index.ts"), + ); + + const sourceAliases = withEnv({ NODE_ENV: undefined }, () => + buildPluginLoaderAliasMap(sourcePluginEntry), + ); + + expectPluginSdkAliasTargets(sourceAliases, { + rootAliasPath: sourceRootAlias, + channelRuntimePath: sourceChannelRuntimePath, }); }); it("resolves plugin-sdk aliases for user-installed plugins via the running openclaw argv hint", () => { - const { externalPluginEntry, externalPluginRoot, fixture, sourceRootAlias } = - createUserInstalledPluginSdkAliasFixture(); + const { + externalPluginEntry, + externalPluginRoot, + fixture, + sourceRootAlias, + sourceChannelRuntimePath, + } = createUserInstalledPluginSdkAliasFixture(); const aliases = withCwd(externalPluginRoot, () => withEnv({ NODE_ENV: undefined }, () => @@ -590,13 +635,18 @@ describe("plugin sdk alias helpers", () => { expectPluginSdkAliasTargets(aliases, { rootAliasPath: sourceRootAlias, - channelRuntimePath: path.join(fixture.root, "src", "plugin-sdk", "channel-runtime.ts"), + channelRuntimePath: sourceChannelRuntimePath, }); }); it("resolves plugin-sdk aliases for user-installed plugins via moduleUrl hint", () => { - const { externalPluginEntry, externalPluginRoot, fixture, sourceRootAlias } = - createUserInstalledPluginSdkAliasFixture(); + const { + externalPluginEntry, + externalPluginRoot, + fixture, + sourceRootAlias, + sourceChannelRuntimePath, + } = createUserInstalledPluginSdkAliasFixture(); // Simulate loader.ts passing its own import.meta.url as the moduleUrl hint. // This covers installations where argv1 does not resolve to the openclaw root @@ -624,7 +674,7 @@ describe("plugin sdk alias helpers", () => { expectPluginSdkAliasTargets(aliases, { rootAliasPath: sourceRootAlias, - channelRuntimePath: path.join(fixture.root, "src", "plugin-sdk", "channel-runtime.ts"), + channelRuntimePath: sourceChannelRuntimePath, }); }); diff --git a/src/plugins/sdk-alias.ts b/src/plugins/sdk-alias.ts index 85af7cb24cd..6c8d6ca3429 100644 --- a/src/plugins/sdk-alias.ts +++ b/src/plugins/sdk-alias.ts @@ -252,7 +252,7 @@ export function resolvePluginSdkAliasFile(params: { const cachedPluginSdkExportedSubpaths = new Map(); const cachedPluginSdkScopedAliasMaps = new Map>(); const PLUGIN_SDK_PACKAGE_NAMES = ["openclaw/plugin-sdk", "@openclaw/plugin-sdk"] as const; -const EXTENSION_API_SOURCE_CANDIDATE_EXTENSIONS = [ +const PLUGIN_SDK_SOURCE_CANDIDATE_EXTENSIONS = [ ".ts", ".mts", ".js", @@ -321,18 +321,30 @@ export function resolvePluginSdkScopedAliasMap( moduleUrl: params.moduleUrl, pluginSdkResolution: params.pluginSdkResolution, })) { - const candidateMap = { - src: path.join(packageRoot, "src", "plugin-sdk", `${subpath}.ts`), - dist: path.join(packageRoot, "dist", "plugin-sdk", `${subpath}.js`), - } as const; for (const kind of orderedKinds) { - const candidate = candidateMap[kind]; - if (fs.existsSync(candidate)) { + if (kind === "dist") { + const candidate = path.join(packageRoot, "dist", "plugin-sdk", `${subpath}.js`); + if (fs.existsSync(candidate)) { + for (const packageName of PLUGIN_SDK_PACKAGE_NAMES) { + aliasMap[`${packageName}/${subpath}`] = candidate; + } + break; + } + continue; + } + for (const ext of PLUGIN_SDK_SOURCE_CANDIDATE_EXTENSIONS) { + const candidate = path.join(packageRoot, "src", "plugin-sdk", `${subpath}${ext}`); + if (!fs.existsSync(candidate)) { + continue; + } for (const packageName of PLUGIN_SDK_PACKAGE_NAMES) { aliasMap[`${packageName}/${subpath}`] = candidate; } break; } + if (Object.prototype.hasOwnProperty.call(aliasMap, `openclaw/plugin-sdk/${subpath}`)) { + break; + } } } cachedPluginSdkScopedAliasMaps.set(cacheKey, aliasMap); @@ -360,7 +372,7 @@ export function resolveExtensionApiAlias(params: LoaderModuleResolveParams = {}) } continue; } - for (const ext of EXTENSION_API_SOURCE_CANDIDATE_EXTENSIONS) { + for (const ext of PLUGIN_SDK_SOURCE_CANDIDATE_EXTENSIONS) { const candidate = path.join(packageRoot, "src", `extensionAPI${ext}`); if (fs.existsSync(candidate)) { return candidate;