






















@@ -13,6 +13,8 @@ import {
1313const DEFAULT_UNKNOWN_RUNTIME_DEPS_ROOTS_TO_KEEP = 20;
1414const DEFAULT_UNKNOWN_RUNTIME_DEPS_MIN_AGE_MS = 10 * 60_000;
1515const PACKAGE_KEY_PATH_HASH_RE = /^openclaw-.+-([0-9a-f]{12})$/u;
16+const LEGACY_VERSIONED_RUNTIME_DEPS_ROOT_RE =
17+/^openclaw-\d{4}\.\d+\.\d+(?:-[0-9A-Za-z.]+)*-[A-Za-z][A-Za-z0-9_-]*$/u;
16181719export type BundledRuntimeDepsInstallRootPlan = {
1820installRoot: string;
@@ -143,6 +145,19 @@ export function pruneUnknownBundledRuntimeDepsRoots(
143145let scanned = 0;
144146let removed = 0;
145147let skippedLocked = 0;
148+const removeRoot = (root: string): void => {
149+const lockDir = path.join(root, BUNDLED_RUNTIME_DEPS_LOCK_DIR);
150+if (fs.existsSync(lockDir) && !removeRuntimeDepsLockIfStale(lockDir, nowMs)) {
151+skippedLocked += 1;
152+return;
153+}
154+try {
155+fs.rmSync(root, { recursive: true, force: true });
156+removed += 1;
157+} catch (error) {
158+params.warn?.(`failed to remove stale bundled runtime deps root ${root}: ${String(error)}`);
159+}
160+};
146161147162for (const baseDir of resolveBundledRuntimeDepsExternalBaseDirs(env)) {
148163let entries: fs.Dirent[];
@@ -163,32 +178,39 @@ export function pruneUnknownBundledRuntimeDepsRoots(
163178})
164179.filter((entry): entry is { root: string; mtimeMs: number } => entry !== null)
165180.toSorted((left, right) => right.mtimeMs - left.mtimeMs);
181+const legacyVersionedRoots = entries
182+.filter(
183+(entry) => entry.isDirectory() && isLegacyVersionedBundledRuntimeDepsRootName(entry.name),
184+)
185+.map((entry) => path.join(baseDir, entry.name))
186+.toSorted((left, right) => left.localeCompare(right));
166187scanned += unknownRoots.length;
188+scanned += legacyVersionedRoots.length;
167189168190for (const [index, entry] of unknownRoots.entries()) {
169191const ageMs = nowMs - entry.mtimeMs;
170192if (index < maxRootsToKeep && ageMs < minAgeMs) {
171193continue;
172194}
173-const lockDir = path.join(entry.root, BUNDLED_RUNTIME_DEPS_LOCK_DIR);
174-if (fs.existsSync(lockDir) && !removeRuntimeDepsLockIfStale(lockDir, nowMs)) {
175-skippedLocked += 1;
176-continue;
177-}
178-try {
179-fs.rmSync(entry.root, { recursive: true, force: true });
180-removed += 1;
181-} catch (error) {
182-params.warn?.(
183-`failed to remove stale bundled runtime deps root ${entry.root}: ${String(error)}`,
184-);
185-}
195+removeRoot(entry.root);
196+}
197+198+for (const root of legacyVersionedRoots) {
199+removeRoot(root);
186200}
187201}
188202189203return { scanned, removed, skippedLocked };
190204}
191205206+function isLegacyVersionedBundledRuntimeDepsRootName(name: string): boolean {
207+return (
208+name.startsWith("openclaw-") &&
209+readPackageKeyPathHash(name) === null &&
210+LEGACY_VERSIONED_RUNTIME_DEPS_ROOT_RE.test(name)
211+);
212+}
213+192214export function listSiblingExternalBundledRuntimeDepsRoots(params: {
193215installRoot: string;
194216env?: NodeJS.ProcessEnv;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。