





















@@ -4,6 +4,7 @@ import { spawn } from "node:child_process";
44import fs from "node:fs";
55import path from "node:path";
66import { pathToFileURL } from "node:url";
7+import { collectBundledPluginBuildEntries } from "./lib/bundled-plugin-build-entries.mjs";
78import { BUNDLED_PLUGIN_PATH_PREFIX } from "./lib/bundled-plugin-paths.mjs";
89import { resolvePnpmRunner } from "./pnpm-runner.mjs";
910import {
@@ -21,6 +22,7 @@ const DEFAULT_CAPTURE_BYTES = 8 * 1024 * 1024;
2122const DEFAULT_HEARTBEAT_MS = 30_000;
2223const TERMINATION_GRACE_MS = 5_000;
2324const TSDOWN_OUTPUT_ROOTS = ["dist", "dist-runtime"];
25+const DIST_RUNTIME_DEPS_ROOT = "extensions";
24262527function removeDistPluginNodeModulesSymlinks(rootDir) {
2628const extensionsDir = path.join(rootDir, "extensions");
@@ -54,9 +56,17 @@ function pruneStaleRuntimeSymlinks() {
54565557export function cleanTsdownOutputRoots(params = {}) {
5658const cwd = params.cwd ?? process.cwd();
59+const stagedRuntimeDependencyPluginIds = collectStagedRuntimeDependencyPluginIds({
60+ cwd,
61+env: params.env ?? process.env,
62+});
5763const fsImpl = params.fs ?? fs;
5864for (const root of TSDOWN_OUTPUT_ROOTS) {
5965const rootPath = path.join(cwd, root);
66+if (root === "dist") {
67+cleanDistOutputRoot(rootPath, stagedRuntimeDependencyPluginIds, fsImpl);
68+continue;
69+}
6070try {
6171fsImpl.rmSync(rootPath, { force: true, recursive: true });
6272} catch {
@@ -65,6 +75,86 @@ export function cleanTsdownOutputRoots(params = {}) {
6575}
6676}
677778+function collectStagedRuntimeDependencyPluginIds(params) {
79+try {
80+return new Set(
81+collectBundledPluginBuildEntries(params)
82+.filter(({ packageJson }) => shouldStageBundledPluginRuntimeDependencies(packageJson))
83+.map(({ id }) => id),
84+);
85+} catch {
86+return new Set();
87+}
88+}
89+90+function shouldStageBundledPluginRuntimeDependencies(packageJson) {
91+return packageJson?.openclaw?.bundle?.stageRuntimeDependencies === true;
92+}
93+94+function cleanDistOutputRoot(distRoot, stagedRuntimeDependencyPluginIds, fsImpl) {
95+let entries = [];
96+try {
97+entries = fsImpl.readdirSync(distRoot, { withFileTypes: true });
98+} catch {
99+return;
100+}
101+102+for (const entry of entries) {
103+const entryPath = path.join(distRoot, entry.name);
104+try {
105+if (entry.isDirectory() && entry.name === DIST_RUNTIME_DEPS_ROOT) {
106+cleanDistExtensionsRoot(entryPath, stagedRuntimeDependencyPluginIds, fsImpl);
107+continue;
108+}
109+fsImpl.rmSync(entryPath, { force: true, recursive: true });
110+} catch {
111+// Best-effort cleanup. tsdown will overwrite or recreate generated output.
112+}
113+}
114+}
115+116+function cleanDistExtensionsRoot(extensionsDistRoot, stagedRuntimeDependencyPluginIds, fsImpl) {
117+let entries = [];
118+try {
119+entries = fsImpl.readdirSync(extensionsDistRoot, { withFileTypes: true });
120+} catch {
121+return;
122+}
123+124+for (const entry of entries) {
125+const pluginDistRoot = path.join(extensionsDistRoot, entry.name);
126+try {
127+if (!entry.isDirectory() || !stagedRuntimeDependencyPluginIds.has(entry.name)) {
128+fsImpl.rmSync(pluginDistRoot, { force: true, recursive: true });
129+continue;
130+}
131+cleanDistPluginOutputRoot(pluginDistRoot, fsImpl);
132+} catch {
133+// Best-effort cleanup. Runtime postbuild validates current plugin metadata next.
134+}
135+}
136+}
137+138+function cleanDistPluginOutputRoot(pluginDistRoot, fsImpl) {
139+let entries = [];
140+try {
141+entries = fsImpl.readdirSync(pluginDistRoot, { withFileTypes: true });
142+} catch {
143+return;
144+}
145+146+for (const entry of entries) {
147+if (entry.isDirectory() && entry.name === "node_modules") {
148+continue;
149+}
150+try {
151+fsImpl.rmSync(path.join(pluginDistRoot, entry.name), { force: true, recursive: true });
152+} catch {
153+// Best-effort cleanup. tsdown/runtime-postbuild will rewrite generated files.
154+}
155+}
156+}
157+68158export function pruneStaleRootChunkFiles(params = {}) {
69159const cwd = params.cwd ?? process.cwd();
70160const fsImpl = params.fs ?? fs;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。