
























@@ -19,6 +19,29 @@ function writeDistPluginFile(repoRoot: string, root: "dist" | "dist-runtime", pl
1919fs.writeFileSync(path.join(pluginDir, "openclaw.plugin.json"), "{}\n", "utf8");
2020}
212122+function writePluginSourcePackage(repoRoot: string, pluginId: string) {
23+const pluginDir = path.join(repoRoot, "extensions", pluginId);
24+fs.mkdirSync(pluginDir, { recursive: true });
25+writeJsonFile(path.join(pluginDir, "package.json"), {
26+name: `@openclaw/${pluginId}`,
27+version: "0.0.0",
28+});
29+}
30+31+function writeNodePackage(
32+repoRoot: string,
33+packageName: string,
34+packageJson: Record<string, unknown> = {},
35+) {
36+const packageDir = path.join(repoRoot, "node_modules", ...packageName.split("/"));
37+fs.mkdirSync(packageDir, { recursive: true });
38+writeJsonFile(path.join(packageDir, "package.json"), {
39+name: packageName,
40+version: "0.0.0",
41+ ...packageJson,
42+});
43+}
44+2245afterEach(() => {
2346cleanupTempDirs(tempDirs);
2447});
@@ -32,11 +55,14 @@ describe("pruneDockerPluginDist", () => {
3255]);
3356});
345735-it("removes package-excluded plugin dist unless Docker explicitly opts it in", () => {
58+it("removes package-excluded plugin runtime artifacts unless Docker explicitly opts it in", () => {
3659const repoRoot = makeRepoRoot("openclaw-docker-plugin-dist-");
3760writeJsonFile(path.join(repoRoot, "package.json"), {
3861files: ["dist/**", "!dist/extensions/diagnostics-otel/**", "!dist/extensions/feishu/**"],
3962});
63+writePluginSourcePackage(repoRoot, "diagnostics-otel");
64+writePluginSourcePackage(repoRoot, "feishu");
65+writePluginSourcePackage(repoRoot, "telegram");
4066writeDistPluginFile(repoRoot, "dist", "diagnostics-otel");
4167writeDistPluginFile(repoRoot, "dist", "feishu");
4268writeDistPluginFile(repoRoot, "dist-runtime", "feishu");
@@ -47,10 +73,100 @@ describe("pruneDockerPluginDist", () => {
4773env: { OPENCLAW_EXTENSIONS: "diagnostics-otel" } as NodeJS.ProcessEnv,
4874});
497550-expect(removed).toEqual(["dist/extensions/feishu", "dist-runtime/extensions/feishu"]);
76+expect(removed).toEqual([
77+"extensions/feishu",
78+"dist/extensions/feishu",
79+"dist-runtime/extensions/feishu",
80+]);
81+expect(fs.existsSync(path.join(repoRoot, "extensions", "diagnostics-otel"))).toBe(true);
82+expect(fs.existsSync(path.join(repoRoot, "extensions", "feishu"))).toBe(false);
83+expect(fs.existsSync(path.join(repoRoot, "extensions", "telegram"))).toBe(true);
5184expect(fs.existsSync(path.join(repoRoot, "dist", "extensions", "diagnostics-otel"))).toBe(true);
5285expect(fs.existsSync(path.join(repoRoot, "dist", "extensions", "feishu"))).toBe(false);
5386expect(fs.existsSync(path.join(repoRoot, "dist-runtime", "extensions", "feishu"))).toBe(false);
5487expect(fs.existsSync(path.join(repoRoot, "dist", "extensions", "telegram"))).toBe(true);
5588});
89+90+it("honors custom bundled plugin source roots when pruning Docker runtime importers", () => {
91+const repoRoot = makeRepoRoot("openclaw-docker-plugin-source-");
92+writeJsonFile(path.join(repoRoot, "package.json"), {
93+files: ["dist/**", "!dist/extensions/acpx/**"],
94+});
95+const pluginDir = path.join(repoRoot, "plugins", "acpx");
96+fs.mkdirSync(pluginDir, { recursive: true });
97+writeJsonFile(path.join(pluginDir, "package.json"), {
98+name: "@openclaw/acpx",
99+version: "0.0.0",
100+});
101+102+const removed = pruneDockerPluginDist({
103+ repoRoot,
104+env: {
105+OPENCLAW_BUNDLED_PLUGIN_DIR: "plugins",
106+} as NodeJS.ProcessEnv,
107+});
108+109+expect(removed).toEqual(["plugins/acpx"]);
110+expect(fs.existsSync(pluginDir)).toBe(false);
111+});
112+113+it("removes node_modules dependency closure that only omitted Docker plugins need", () => {
114+const repoRoot = makeRepoRoot("openclaw-docker-plugin-node-modules-");
115+writeJsonFile(path.join(repoRoot, "package.json"), {
116+files: ["dist/**", "!dist/extensions/acpx/**", "!dist/extensions/codex/**"],
117+dependencies: {
118+zod: "0.0.0",
119+},
120+});
121+writeJsonFile(path.join(repoRoot, "extensions", "acpx", "package.json"), {
122+name: "@openclaw/acpx",
123+version: "0.0.0",
124+dependencies: {
125+"@zed-industries/codex-acp": "0.0.0",
126+zod: "0.0.0",
127+},
128+});
129+writeJsonFile(path.join(repoRoot, "extensions", "codex", "package.json"), {
130+name: "@openclaw/codex",
131+version: "0.0.0",
132+dependencies: {
133+"@openai/codex": "0.0.0",
134+zod: "0.0.0",
135+},
136+});
137+writeNodePackage(repoRoot, "@openclaw/acpx");
138+writeNodePackage(repoRoot, "@openclaw/codex");
139+writeNodePackage(repoRoot, "zod");
140+writeNodePackage(repoRoot, "@openai/codex", {
141+optionalDependencies: {
142+"@openai/codex-linux-x64": "0.0.0",
143+},
144+});
145+writeNodePackage(repoRoot, "@openai/codex-linux-x64");
146+writeNodePackage(repoRoot, "@zed-industries/codex-acp", {
147+optionalDependencies: {
148+"@zed-industries/codex-acp-linux-x64": "0.0.0",
149+},
150+});
151+writeNodePackage(repoRoot, "@zed-industries/codex-acp-linux-x64");
152+153+const removed = pruneDockerPluginDist({
154+ repoRoot,
155+env: { OPENCLAW_EXTENSIONS: "codex" } as NodeJS.ProcessEnv,
156+});
157+158+expect(removed).toEqual([
159+"node_modules/@openclaw/acpx",
160+"node_modules/@zed-industries/codex-acp",
161+"node_modules/@zed-industries/codex-acp-linux-x64",
162+"extensions/acpx",
163+]);
164+expect(fs.existsSync(path.join(repoRoot, "node_modules", "zod"))).toBe(true);
165+expect(fs.existsSync(path.join(repoRoot, "node_modules", "@openai", "codex"))).toBe(true);
166+expect(fs.existsSync(path.join(repoRoot, "node_modules", "@openai", "codex-linux-x64"))).toBe(
167+true,
168+);
169+expect(fs.existsSync(path.join(repoRoot, "node_modules", "@zed-industries"))).toBe(false);
170+expect(fs.existsSync(path.join(repoRoot, "extensions", "codex"))).toBe(true);
171+});
56172});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。