fix(doctor): preserve third-party plugin dependencies

This commit is contained in:
Vincent Koc
2026-05-02 14:21:42 -07:00
parent 3afd4fdeeb
commit 24d0562d7d
2 changed files with 38 additions and 5 deletions

View File

@@ -29,18 +29,33 @@ describe("cleanupLegacyPluginDependencyState", () => {
"demo",
"node_modules",
);
const legacyExtensionStamp = path.join(
packageRoot,
"dist",
"extensions",
"demo",
".openclaw-runtime-deps-stamp.json",
);
const legacyManifest = path.join(
packageRoot,
"extensions",
"demo",
".openclaw-runtime-deps.json",
);
const thirdPartyNodeModules = path.join(
stateDir,
"extensions",
"lossless-claw",
"node_modules",
);
await fs.mkdir(legacyRuntimeRoot, { recursive: true });
await fs.mkdir(legacyLocalRoot, { recursive: true });
await fs.mkdir(legacyExtensionNodeModules, { recursive: true });
await fs.writeFile(legacyExtensionStamp, "{}");
await fs.mkdir(path.dirname(legacyManifest), { recursive: true });
await fs.writeFile(legacyManifest, "{}");
await fs.mkdir(thirdPartyNodeModules, { recursive: true });
await fs.mkdir(explicitStageDir, { recursive: true });
await fs.mkdir(path.join(stateDirectory, "plugin-runtime-deps"), { recursive: true });
@@ -55,11 +70,13 @@ describe("cleanupLegacyPluginDependencyState", () => {
legacyRuntimeRoot,
legacyLocalRoot,
legacyExtensionNodeModules,
legacyExtensionStamp,
legacyManifest,
explicitStageDir,
path.join(stateDirectory, "plugin-runtime-deps"),
]),
);
expect(targets).not.toContain(thirdPartyNodeModules);
const result = await cleanupLegacyPluginDependencyState({ env, packageRoot });
@@ -68,7 +85,9 @@ describe("cleanupLegacyPluginDependencyState", () => {
await expect(fs.stat(legacyRuntimeRoot)).rejects.toThrow();
await expect(fs.stat(legacyLocalRoot)).rejects.toThrow();
await expect(fs.stat(legacyExtensionNodeModules)).rejects.toThrow();
await expect(fs.stat(legacyExtensionStamp)).rejects.toThrow();
await expect(fs.stat(legacyManifest)).rejects.toThrow();
await expect(fs.stat(thirdPartyNodeModules)).resolves.toBeDefined();
await expect(fs.stat(explicitStageDir)).rejects.toThrow();
await expect(fs.stat(path.join(stateDirectory, "plugin-runtime-deps"))).rejects.toThrow();
});

View File

@@ -34,14 +34,19 @@ async function pathExists(targetPath: string): Promise<boolean> {
}
}
function isLegacyDependencyDebrisName(name: string): boolean {
function isRuntimeDependencyMarkerName(name: string): boolean {
return (
name === "node_modules" ||
name === ".openclaw-runtime-deps.json" ||
name === ".openclaw-runtime-deps-stamp.json" ||
name.startsWith(".openclaw-runtime-deps-")
);
}
function isLegacyDependencyDebrisName(name: string): boolean {
return (
isRuntimeDependencyMarkerName(name) ||
name === ".openclaw-pnpm-store" ||
name === ".openclaw-install-backups" ||
name.startsWith(".openclaw-runtime-deps-") ||
name.startsWith(".openclaw-install-stage-")
);
}
@@ -59,8 +64,17 @@ async function collectLegacyExtensionDebris(extensionsRoot: string): Promise<str
continue;
}
const pluginRoot = path.join(extensionsRoot, entry.name);
for (const childPath of await collectDirectChildren(pluginRoot)) {
if (isLegacyDependencyDebrisName(path.basename(childPath))) {
const children = await collectDirectChildren(pluginRoot);
const hasRuntimeDepsMarker = children.some((childPath) =>
isRuntimeDependencyMarkerName(path.basename(childPath)),
);
for (const childPath of children) {
const basename = path.basename(childPath);
if (basename === "node_modules" && hasRuntimeDepsMarker) {
targets.push(childPath);
continue;
}
if (isLegacyDependencyDebrisName(basename)) {
targets.push(childPath);
}
}