From b441e59d258f6fbafd7c06f5bdabab0699a4981b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Wed, 1 Apr 2026 04:15:08 +0900 Subject: [PATCH] fix(build): isolate bundled runtime dependency staging --- scripts/stage-bundled-plugin-runtime-deps.mjs | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/scripts/stage-bundled-plugin-runtime-deps.mjs b/scripts/stage-bundled-plugin-runtime-deps.mjs index ca34964bdb9..6ee975355d2 100644 --- a/scripts/stage-bundled-plugin-runtime-deps.mjs +++ b/scripts/stage-bundled-plugin-runtime-deps.mjs @@ -1,6 +1,7 @@ import { spawnSync } from "node:child_process"; import { createHash } from "node:crypto"; import fs from "node:fs"; +import os from "node:os"; import path from "node:path"; import { pathToFileURL } from "node:url"; @@ -22,6 +23,25 @@ function makeTempDir(parentDir, prefix) { return fs.mkdtempSync(path.join(parentDir, prefix)); } +function sanitizeTempPrefixSegment(value) { + const normalized = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-"); + return normalized.length > 0 ? normalized : "plugin"; +} + +function replaceDir(targetPath, sourcePath) { + removePathIfExists(targetPath); + try { + fs.renameSync(sourcePath, targetPath); + return; + } catch (error) { + if (error?.code !== "EXDEV") { + throw error; + } + } + fs.cpSync(sourcePath, targetPath, { recursive: true, force: true }); + removePathIfExists(sourcePath); +} + function listBundledPluginRuntimeDirs(repoRoot) { const extensionsRoot = path.join(repoRoot, "dist", "extensions"); if (!fs.existsSync(extensionsRoot)) { @@ -220,7 +240,10 @@ function installPluginRuntimeDeps(params) { const { fingerprint, packageJson, pluginDir, pluginId } = params; const nodeModulesDir = path.join(pluginDir, "node_modules"); const stampPath = resolveRuntimeDepsStampPath(pluginDir); - const tempInstallDir = makeTempDir(pluginDir, ".runtime-deps-"); + const tempInstallDir = makeTempDir( + os.tmpdir(), + `openclaw-runtime-deps-${sanitizeTempPrefixSegment(pluginId)}-`, + ); const npmRunner = resolveNpmRunner({ npmArgs: [ "install", @@ -255,8 +278,7 @@ function installPluginRuntimeDeps(params) { ); } - removePathIfExists(nodeModulesDir); - fs.renameSync(stagedNodeModulesDir, nodeModulesDir); + replaceDir(nodeModulesDir, stagedNodeModulesDir); writeJson(stampPath, { fingerprint, generatedAt: new Date().toISOString(),