fix(plugins): derive media aliases from exports (#122523)

This commit is contained in:
Vincent Koc
2026-08-12 16:03:34 +08:00
committed by GitHub
parent 5a643e3543
commit b8a0fa2e7a
4 changed files with 94 additions and 45 deletions
+37 -2
View File
@@ -93,6 +93,23 @@ function writeInternalCorePackageSource(
return sourcePath;
}
function writeInternalCorePackageExports(
root: string,
packageDir: string,
subpaths: readonly string[],
): void {
writeJsonFile(path.join(root, "packages", packageDir, "package.json"), {
name: `@openclaw/${packageDir}`,
exports: Object.fromEntries(
subpaths.map((subpath) => {
const exportKey = subpath ? `./${subpath}` : ".";
const distFile = `./dist/${subpath || "index"}.mjs`;
return [exportKey, { import: distFile, default: distFile }];
}),
),
});
}
function addFakePluginSdkDistExport(root: string, subpath: string): string {
const packageJsonPath = path.join(root, "package.json");
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) as {
@@ -521,7 +538,19 @@ describe("installOpenClawPluginSdkNativeResolver", () => {
);
const resultSource = writeInternalCorePackageSource(root, "normalization-core", "result.ts");
const agentIdSource = writeInternalCorePackageSource(root, "normalization-core", "agent-id.ts");
const mediaCoreSource = writeInternalCorePackageSource(root, "media-core", "mime.ts");
writeInternalCorePackageExports(root, "normalization-core", [
"agent-id",
"boolean-coercion",
"result",
"string-coerce",
]);
writeInternalCorePackageExports(root, "media-core", ["attachment-classify", "mime"]);
const mediaMimeSource = writeInternalCorePackageSource(root, "media-core", "mime.ts");
const mediaAttachmentClassifySource = writeInternalCorePackageSource(
root,
"media-core",
"attachment-classify.ts",
);
const markdownCoreSource = writeInternalCorePackageSource(
root,
"markdown-core",
@@ -543,6 +572,7 @@ describe("installOpenClawPluginSdkNativeResolver", () => {
"acp-core",
path.join("runtime", "types.ts"),
);
writeInternalCorePackageExports(root, "acp-core", ["runtime/types"]);
const llmCoreSource = writeInternalCorePackageSource(root, "llm-core", "index.ts");
const externalPluginEntry = writeExternalPluginEntry(path.join(root, "external-plugin"));
const coreSourceParent = path.join(root, "src", "config", "plugin-web-search-config.ts");
@@ -560,6 +590,7 @@ describe("installOpenClawPluginSdkNativeResolver", () => {
expect(installedAliases).toContain("@openclaw/normalization-core/result");
expect(installedAliases).toContain("@openclaw/normalization-core/agent-id");
expect(installedAliases).toContain("@openclaw/media-core/mime");
expect(installedAliases).toContain("@openclaw/media-core/attachment-classify");
expect(installedAliases).toContain("@openclaw/markdown-core/code-spans");
expect(installedAliases).toContain("@openclaw/ai/transports");
expect(installedAliases).toContain("@openclaw/ai/internal/retry-after");
@@ -583,8 +614,11 @@ describe("installOpenClawPluginSdkNativeResolver", () => {
fs.realpathSync(requireFromCoreSource.resolve("@openclaw/normalization-core/agent-id")),
).toBe(fs.realpathSync(agentIdSource));
expect(fs.realpathSync(requireFromCoreSource.resolve("@openclaw/media-core/mime"))).toBe(
fs.realpathSync(mediaCoreSource),
fs.realpathSync(mediaMimeSource),
);
expect(
fs.realpathSync(requireFromCoreSource.resolve("@openclaw/media-core/attachment-classify")),
).toBe(fs.realpathSync(mediaAttachmentClassifySource));
expect(
fs.realpathSync(requireFromCoreSource.resolve("@openclaw/markdown-core/code-spans")),
).toBe(fs.realpathSync(markdownCoreSource));
@@ -609,6 +643,7 @@ describe("installOpenClawPluginSdkNativeResolver", () => {
).toThrow();
expect(() => requireFromPlugin.resolve("@openclaw/normalization-core/result")).toThrow();
expect(() => requireFromPlugin.resolve("@openclaw/media-core/mime")).toThrow();
expect(() => requireFromPlugin.resolve("@openclaw/media-core/attachment-classify")).toThrow();
expect(() => requireFromPlugin.resolve("@openclaw/markdown-core/code-spans")).toThrow();
expect(() => requireFromPlugin.resolve("@openclaw/ai/transports")).toThrow();
expect(() => requireFromPlugin.resolve("@openclaw/ai/internal/retry-after")).toThrow();
+1 -17
View File
@@ -91,22 +91,6 @@ const INTERNAL_CORE_PACKAGE_ALIASES = [
["internal/shared", path.join("internal", "shared.ts")],
],
},
{
packageName: "@openclaw/media-core",
packageDir: "media-core",
subpaths: [
["", "index.ts"],
["base64", "base64.ts"],
["constants", "constants.ts"],
["content-length", "content-length.ts"],
["file-name", "file-name.ts"],
["inbound-path-policy", "inbound-path-policy.ts"],
["inline-image-data-url", "inline-image-data-url.ts"],
["media-source-url", "media-source-url.ts"],
["mime", "mime.ts"],
["read-byte-stream-with-limit", "read-byte-stream-with-limit.ts"],
],
},
{
packageName: "@openclaw/llm-core",
packageDir: "llm-core",
@@ -341,7 +325,7 @@ function listInternalCorePackageNativeAliases(
}> = [];
const internalCorePackageAliases = [
...INTERNAL_CORE_PACKAGE_ALIASES,
...["normalization-core", "acp-core"].map((packageDir) => ({
...["media-core", "normalization-core", "acp-core"].map((packageDir) => ({
packageName: `@openclaw/${packageDir}`,
packageDir,
subpaths: listWorkspacePackageExportAliasEntries({
+54 -2
View File
@@ -154,6 +154,32 @@ function writeWorkspacePackageEntry(params: {
return { srcFile, distFile };
}
function writeWorkspacePackageExports(
root: string,
packageDir: string,
subpaths: readonly string[],
) {
mkdirSafeDir(path.join(root, "packages", packageDir));
fs.writeFileSync(
path.join(root, "packages", packageDir, "package.json"),
JSON.stringify(
{
name: `@openclaw/${packageDir}`,
exports: Object.fromEntries(
subpaths.map((subpath) => {
const exportKey = subpath ? `./${subpath}` : ".";
const distFile = `./dist/${subpath || "index"}.mjs`;
return [exportKey, { import: distFile, default: distFile }];
}),
),
},
null,
2,
),
"utf-8",
);
}
type WorkspaceAliasFixture = readonly [
alias: `@openclaw/${string}`,
packageDir: string,
@@ -1148,6 +1174,15 @@ describe("plugin sdk alias helpers", () => {
it("aliases workspace packages to source when dist artifacts are missing", () => {
const fixture = createPluginSdkAliasFixture();
writeWorkspacePackageExports(fixture.root, "media-core", ["", "attachment-classify", "mime"]);
writeWorkspacePackageExports(fixture.root, "acp-core", ["", "runtime/types"]);
writeWorkspacePackageExports(fixture.root, "normalization-core", [
"",
"agent-id",
"boolean-coercion",
"result",
"string-coerce",
]);
const workspaceAliases = writeWorkspaceAliasFixtures(fixture.root, [
["@openclaw/gateway-client", "gateway-client", "index"],
["@openclaw/gateway-client/timeouts", "gateway-client", "timeouts"],
@@ -1160,6 +1195,7 @@ describe("plugin sdk alias helpers", () => {
["@openclaw/media-generation-core", "media-generation-core", "index"],
["@openclaw/media-generation-core/model-ref", "media-generation-core", "model-ref"],
["@openclaw/media-core", "media-core", "index"],
["@openclaw/media-core/attachment-classify", "media-core", "attachment-classify"],
["@openclaw/media-core/mime", "media-core", "mime"],
["@openclaw/acp-core", "acp-core", "index"],
["@openclaw/acp-core/runtime/types", "acp-core", "runtime/types"],
@@ -1193,6 +1229,9 @@ describe("plugin sdk alias helpers", () => {
it("aliases workspace package subpaths to dist when available", () => {
const fixture = createPluginSdkAliasFixture();
writeWorkspacePackageExports(fixture.root, "media-core", ["attachment-classify"]);
writeWorkspacePackageExports(fixture.root, "acp-core", ["normalize-text"]);
writeWorkspacePackageExports(fixture.root, "normalization-core", ["record-coerce"]);
const workspaceAliases = writeWorkspaceAliasFixtures(fixture.root, [
["@openclaw/gateway-client/readiness", "gateway-client", "readiness"],
[
@@ -1203,6 +1242,7 @@ describe("plugin sdk alias helpers", () => {
["@openclaw/gateway-protocol/frame-guards", "gateway-protocol", "frame-guards"],
["@openclaw/markdown-core/render", "markdown-core", "render"],
["@openclaw/media-generation-core/catalog", "media-generation-core", "catalog"],
["@openclaw/media-core/attachment-classify", "media-core", "attachment-classify"],
[
"@openclaw/acp-core/normalize-text",
"acp-core",
@@ -1254,9 +1294,18 @@ describe("plugin sdk alias helpers", () => {
);
mkdirSafeDir(path.dirname(normalizationAgentId));
fs.writeFileSync(normalizationAgentId, "export {};\n", "utf-8");
const cwdWithoutOpenClawPackage = makeTempDir();
const mediaAttachmentClassify = path.join(
fixture.root,
"dist",
"media-core",
"attachment-classify.js",
);
mkdirSafeDir(path.dirname(mediaAttachmentClassify));
fs.writeFileSync(mediaAttachmentClassify, "export {};\n", "utf-8");
const staleCheckout = createPluginSdkAliasFixture();
writeWorkspacePackageExports(staleCheckout.root, "media-core", ["mime"]);
const aliases = withCwd(cwdWithoutOpenClawPackage, () =>
const aliases = withCwd(staleCheckout.root, () =>
withEnv({ NODE_ENV: undefined }, () =>
buildPluginLoaderAliasMap(sourcePluginEntry, undefined, undefined, "dist"),
),
@@ -1268,6 +1317,9 @@ describe("plugin sdk alias helpers", () => {
expect(fs.realpathSync(aliases["@openclaw/normalization-core/agent-id"] ?? "")).toBe(
fs.realpathSync(normalizationAgentId),
);
expect(fs.realpathSync(aliases["@openclaw/media-core/attachment-classify"] ?? "")).toBe(
fs.realpathSync(mediaAttachmentClassify),
);
});
it("aliases bundled plugin package public surfaces for source plugin transforms", () => {
+2 -24
View File
@@ -517,21 +517,6 @@ const WORKSPACE_PACKAGE_ALIAS_SUBPATHS = [
],
],
["media-generation-core", ["", "capability-model-ref", "catalog", "model-ref", "normalization"]],
[
"media-core",
[
"",
"base64",
"constants",
"content-length",
"file-name",
"inbound-path-policy",
"inline-image-data-url",
"media-source-url",
"mime",
"read-byte-stream-with-limit",
],
],
["retry", [""]],
[
"terminal-core",
@@ -669,14 +654,7 @@ export function listWorkspacePackageExportAliasEntries(params: {
params.packageDir,
"package.json",
);
const fallbackPackageRoot = resolveOpenClawPackageRootSync({ cwd: process.cwd() });
const packageJson =
tryReadJsonSync<PluginSdkPackageJson>(packageJsonPath) ??
(fallbackPackageRoot
? tryReadJsonSync<PluginSdkPackageJson>(
path.join(fallbackPackageRoot, "packages", params.packageDir, "package.json"),
)
: null);
const packageJson = tryReadJsonSync<PluginSdkPackageJson>(packageJsonPath);
const exports = packageJson?.exports;
if (!exports || typeof exports !== "object" || Array.isArray(exports)) {
return listRootPackagedWorkspacePackageAliasEntries(params);
@@ -914,7 +892,7 @@ function resolveWorkspacePackageAliasMap(params: {
const aliasMap: Record<string, string> = {};
const workspacePackageAliasEntries = [
...WORKSPACE_PACKAGE_ALIAS_ENTRIES,
...["normalization-core", "acp-core"].flatMap((packageDir) =>
...["media-core", "normalization-core", "acp-core"].flatMap((packageDir) =>
listWorkspacePackageExportAliasEntries({
packageRoot,
packageName: `@openclaw/${packageDir}`,