fix(worker): keep source bundles npm-installable (#122430)

This commit is contained in:
Peter Steinberger
2026-08-11 21:50:56 -07:00
committed by GitHub
parent f6459a3255
commit e30df72045
4 changed files with 81 additions and 6 deletions
+3 -1
View File
@@ -101,11 +101,13 @@
"@anthropic-ai/sdk": "0.115.0",
"@google/genai": "2.13.0",
"@mistralai/mistralai": "2.5.0",
"@openclaw/normalization-core": "workspace:*",
"openai": "6.49.0",
"partial-json": "0.1.7",
"typebox": "1.3.6"
},
"devDependencies": {
"@openclaw/normalization-core": "workspace:*"
},
"engines": {
"node": ">=22.19.0"
},
+3 -2
View File
@@ -44,7 +44,7 @@ async function productionImportsPackage(packageName: string): Promise<boolean> {
}
describe("@openclaw/ai source dependency contract", () => {
it("declares normalization-core while production source imports it", async () => {
it("declares bundled normalization-core imports as a workspace dev dependency", async () => {
const manifest = JSON.parse(
await fs.readFile(path.join(PACKAGE_ROOT, "package.json"), "utf8"),
) as {
@@ -53,6 +53,7 @@ describe("@openclaw/ai source dependency contract", () => {
};
expect(await productionImportsPackage("@openclaw/normalization-core")).toBe(true);
expect(manifest.dependencies?.["@openclaw/normalization-core"]).toBe("workspace:*");
expect(manifest.dependencies?.["@openclaw/normalization-core"]).toBeUndefined();
expect(manifest.devDependencies?.["@openclaw/normalization-core"]).toBe("workspace:*");
});
});
+4 -3
View File
@@ -2167,9 +2167,6 @@ importers:
'@mistralai/mistralai':
specifier: 2.5.0
version: 2.5.0(@opentelemetry/api@1.9.1)
'@openclaw/normalization-core':
specifier: workspace:*
version: link:../normalization-core
openai:
specifier: 6.49.0
version: 6.49.0(@aws-sdk/credential-provider-node@3.972.72)(@smithy/hash-node@4.4.14)(@smithy/signature-v4@5.6.10)(ws@8.21.1)(zod@4.4.3)
@@ -2179,6 +2176,10 @@ importers:
typebox:
specifier: 1.3.6
version: 1.3.6
devDependencies:
'@openclaw/normalization-core':
specifier: workspace:*
version: link:../normalization-core
packages/gateway-client:
dependencies:
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
import path from "node:path";
import * as tar from "tar";
import { describe, expect, it, vi } from "vitest";
import { runCommandWithTimeout } from "../../process/exec.js";
import { withTestDir } from "../../test-helpers/temp-dir.js";
import {
createWorkerBundleProducer,
@@ -246,6 +247,76 @@ describe("worker bundle producer", () => {
});
});
it("installs a source bundle when the AI workspace import is bundled", async () => {
await withTestDir({ prefix: "openclaw-worker-bundle-npm-install-" }, async (root) => {
const repoRoot = path.resolve(import.meta.dirname, "../../..");
const aiManifest = JSON.parse(
await fs.readFile(path.join(repoRoot, "packages/ai/package.json"), "utf8"),
) as {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
};
const dependencyFields = (["dependencies", "devDependencies"] as const).filter(
(field) => aiManifest[field]?.["@openclaw/normalization-core"] !== undefined,
);
if (dependencyFields.length !== 1) {
throw new Error(
"@openclaw/ai must classify normalization-core in exactly one dependency field",
);
}
const dependencyField = dependencyFields[0]!;
const normalizationCoreSpec = aiManifest[dependencyField]?.["@openclaw/normalization-core"];
if (!normalizationCoreSpec?.startsWith("workspace:")) {
throw new Error("@openclaw/ai must use a workspace normalization-core dependency");
}
const packageRoot = path.join(root, "package");
await writeFixture(packageRoot, [["dist/entry.js", 'import "@openclaw/ai";\nexport {};\n']]);
await fs.writeFile(
path.join(packageRoot, "package.json"),
`${JSON.stringify({
name: "openclaw",
version: "1.2.3",
type: "module",
files: ["dist/"],
dependencies: { "@openclaw/ai": "workspace:*" },
})}\n`,
"utf8",
);
const vendorSource = path.join(packageRoot, "node_modules/@openclaw/ai");
await fs.mkdir(path.join(vendorSource, "dist"), { recursive: true });
await fs.writeFile(
path.join(vendorSource, "package.json"),
`${JSON.stringify({
name: "@openclaw/ai",
version: "1.2.3",
type: "module",
main: "./dist/index.js",
[dependencyField]: { "@openclaw/normalization-core": normalizationCoreSpec },
})}\n`,
"utf8",
);
await fs.writeFile(path.join(vendorSource, "dist/index.js"), "export {};\n", "utf8");
const bundle = await createWorkerBundleProducer({
packageRoot,
cacheDir: path.join(root, "cache"),
}).prepare();
const extractRoot = path.join(root, "extract");
await fs.mkdir(extractRoot);
await tar.extract({ file: bundle.tarballPath, cwd: extractRoot });
const install = await runCommandWithTimeout(
["npm", "install", "--ignore-scripts", "--omit=dev", "--no-audit", "--no-fund"],
{
cwd: extractRoot,
env: { NPM_CONFIG_CACHE: path.join(root, "npm-cache") },
timeoutMs: 30_000,
},
);
expect(install.code, install.stderr).toBe(0);
});
});
it("fails closed when a dist-referenced workspace package is not installed", async () => {
await withTestDir({ prefix: "openclaw-worker-bundle-vendor-missing-" }, async (root) => {
const packageRoot = path.join(root, "package");