






















@@ -4,10 +4,12 @@ import { tmpdir } from "node:os";
44import path from "node:path";
55import { describe, expect, it, vi } from "vitest";
66import {
7+collectLegacyPluginRuntimeDepsStateRoots,
78isSourceCheckoutRoot,
89isDirectPostinstallInvocation,
910pruneOpenClawCompileCache,
1011pruneInstalledPackageDist,
12+pruneLegacyPluginRuntimeDepsState,
1113pruneBundledPluginSourceNodeModules,
1214runBundledPluginPostinstall,
1315runPluginRegistryPostinstallMigration,
@@ -208,6 +210,25 @@ describe("bundled plugin postinstall", () => {
208210);
209211});
210212213+it("does not prune user-state legacy runtime deps during source-checkout postinstall", async () => {
214+const packageRoot = await createTempDirAsync("openclaw-source-checkout-state-skip-");
215+const home = await createTempDirAsync("openclaw-source-checkout-home-");
216+const legacyRuntimeRoot = path.join(home, ".openclaw", "plugin-runtime-deps");
217+await fs.mkdir(path.join(packageRoot, ".git"), { recursive: true });
218+await fs.mkdir(path.join(packageRoot, "src"), { recursive: true });
219+await fs.mkdir(path.join(packageRoot, "extensions"), { recursive: true });
220+await fs.mkdir(legacyRuntimeRoot, { recursive: true });
221+await fs.writeFile(path.join(legacyRuntimeRoot, "package.json"), "{}\n");
222+223+runBundledPluginPostinstall({
224+env: { HOME: home },
225+ packageRoot,
226+log: { log: vi.fn(), warn: vi.fn() },
227+});
228+229+await expect(fs.stat(legacyRuntimeRoot)).resolves.toBeTruthy();
230+});
231+211232it("honors disable env before source-checkout pruning", async () => {
212233const packageRoot = await createTempDirAsync("openclaw-source-checkout-disabled-");
213234const extensionsDir = path.join(packageRoot, "extensions");
@@ -373,6 +394,103 @@ describe("bundled plugin postinstall", () => {
373394await expect(fs.stat(staleFile)).rejects.toMatchObject({ code: "ENOENT" });
374395});
375396397+it("prunes legacy plugin runtime deps state during packaged postinstall", async () => {
398+const packageRoot = await createTempDirAsync("openclaw-packaged-state-cleanup-");
399+const home = await createTempDirAsync("openclaw-packaged-home-");
400+const stateOverride = path.join(home, "custom-state");
401+const systemState = path.join(home, "system-state");
402+const defaultLegacyRoot = path.join(home, ".openclaw", "plugin-runtime-deps");
403+const oldBrandLegacyRoot = path.join(home, ".clawdbot", "plugin-runtime-deps");
404+const overrideLegacyRoot = path.join(stateOverride, "plugin-runtime-deps");
405+const systemLegacyRoot = path.join(systemState, "plugin-runtime-deps");
406+const thirdPartyNodeModules = path.join(
407+home,
408+".openclaw",
409+"extensions",
410+"lossless-claw",
411+"node_modules",
412+);
413+const currentFile = path.join(packageRoot, "dist", "entry.js");
414+415+await fs.mkdir(path.dirname(currentFile), { recursive: true });
416+await fs.writeFile(currentFile, "export {};\n");
417+await writePackageDistInventory(packageRoot);
418+for (const root of [
419+defaultLegacyRoot,
420+oldBrandLegacyRoot,
421+overrideLegacyRoot,
422+systemLegacyRoot,
423+thirdPartyNodeModules,
424+]) {
425+await fs.mkdir(root, { recursive: true });
426+await fs.writeFile(path.join(root, "package.json"), "{}\n");
427+}
428+429+const log = { log: vi.fn(), warn: vi.fn() };
430+runBundledPluginPostinstall({
431+env: {
432+HOME: home,
433+OPENCLAW_STATE_DIR: stateOverride,
434+STATE_DIRECTORY: systemState,
435+},
436+ packageRoot,
437+ log,
438+});
439+440+await expect(fs.stat(defaultLegacyRoot)).rejects.toMatchObject({ code: "ENOENT" });
441+await expect(fs.stat(oldBrandLegacyRoot)).rejects.toMatchObject({ code: "ENOENT" });
442+await expect(fs.stat(overrideLegacyRoot)).rejects.toMatchObject({ code: "ENOENT" });
443+await expect(fs.stat(systemLegacyRoot)).rejects.toMatchObject({ code: "ENOENT" });
444+await expect(fs.stat(thirdPartyNodeModules)).resolves.toBeTruthy();
445+expect(log.warn).not.toHaveBeenCalled();
446+expect(log.log).toHaveBeenCalledWith(
447+expect.stringContaining("[postinstall] pruned legacy plugin runtime deps:"),
448+);
449+});
450+451+it("keeps legacy plugin runtime deps cleanup non-fatal", () => {
452+const warn = vi.fn();
453+454+expect(() =>
455+pruneLegacyPluginRuntimeDepsState({
456+env: { HOME: "/home/alice" },
457+existsSync: vi.fn(() => true),
458+rmSync: vi.fn(() => {
459+throw new Error("locked");
460+}),
461+log: { log: vi.fn(), warn },
462+homedir: () => "/home/alice",
463+}),
464+).not.toThrow();
465+466+expect(warn).toHaveBeenCalledWith(
467+expect.stringContaining(
468+"[postinstall] could not prune legacy plugin runtime deps /home/alice/.openclaw/plugin-runtime-deps: Error: locked",
469+),
470+);
471+});
472+473+it("resolves legacy plugin runtime deps roots from OpenClaw state env", () => {
474+expect(
475+collectLegacyPluginRuntimeDepsStateRoots({
476+env: {
477+HOME: "/users/alice",
478+OPENCLAW_HOME: "/srv/openclaw-home",
479+OPENCLAW_CONFIG_PATH: "~/profile/openclaw.json",
480+OPENCLAW_STATE_DIR: "~/state",
481+STATE_DIRECTORY: "/var/lib/openclaw",
482+},
483+homedir: () => "/users/alice",
484+}),
485+).toEqual([
486+"/srv/openclaw-home/.clawdbot/plugin-runtime-deps",
487+"/srv/openclaw-home/.openclaw/plugin-runtime-deps",
488+"/srv/openclaw-home/profile/plugin-runtime-deps",
489+"/srv/openclaw-home/state/plugin-runtime-deps",
490+"/var/lib/openclaw/plugin-runtime-deps",
491+]);
492+});
493+376494it("keeps imported dist chunks even when inventory is stale", async () => {
377495const packageRoot = await createTempDirAsync("openclaw-packaged-install-import-");
378496const entryFile = path.join(packageRoot, "dist", "cli", "run-main.js");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。