























@@ -1757,16 +1757,33 @@ function shouldCleanBundledRuntimeDepsInstallExecutionRoot(params: {
17571757return installExecutionRoot.startsWith(`${installRoot}${path.sep}`);
17581758}
175917591760-function ensureNpmInstallExecutionManifest(installExecutionRoot: string): void {
1760+function createNpmInstallExecutionManifest(installSpecs: readonly string[]): JsonObject {
1761+const dependencies: Record<string, string> = {};
1762+for (const spec of installSpecs) {
1763+const dep = parseInstallableRuntimeDepSpec(spec);
1764+dependencies[dep.name] = dep.version;
1765+}
1766+const sortedDependencies = Object.fromEntries(
1767+Object.entries(dependencies).toSorted(([left], [right]) => left.localeCompare(right)),
1768+);
1769+return {
1770+name: "openclaw-runtime-deps-install",
1771+private: true,
1772+ ...(Object.keys(sortedDependencies).length > 0 ? { dependencies: sortedDependencies } : {}),
1773+};
1774+}
1775+1776+function ensureNpmInstallExecutionManifest(
1777+installExecutionRoot: string,
1778+installSpecs: readonly string[] = [],
1779+): void {
17611780const manifestPath = path.join(installExecutionRoot, "package.json");
1762-if (fs.existsSync(manifestPath)) {
1781+const manifest = createNpmInstallExecutionManifest(installSpecs);
1782+const nextContents = `${JSON.stringify(manifest, null, 2)}\n`;
1783+if (fs.existsSync(manifestPath) && fs.readFileSync(manifestPath, "utf8") === nextContents) {
17631784return;
17641785}
1765-fs.writeFileSync(
1766-manifestPath,
1767-`${JSON.stringify({ name: "openclaw-runtime-deps-install", private: true }, null, 2)}\n`,
1768-"utf8",
1769-);
1786+fs.writeFileSync(manifestPath, nextContents, "utf8");
17701787}
1771178817721789function formatBundledRuntimeDepsInstallError(result: {
@@ -1885,6 +1902,7 @@ export function installBundledRuntimeDeps(params: {
18851902installExecutionRoot?: string;
18861903linkNodeModulesFromExecutionRoot?: boolean;
18871904missingSpecs: string[];
1905+installSpecs?: string[];
18881906env: NodeJS.ProcessEnv;
18891907warn?: (message: string) => void;
18901908}): void {
@@ -1911,7 +1929,15 @@ export function installBundledRuntimeDeps(params: {
19111929// doctor repair path installs directly in the external stage dir; without a
19121930// manifest, npm can honor a user's global prefix config and write under
19131931// $HOME/node_modules instead of our managed stage.
1914-ensureNpmInstallExecutionManifest(installExecutionRoot);
1932+//
1933+// The manifest also declares retained staged deps. npm may prune packages
1934+// that are present in node_modules but absent from package dependencies
1935+// while installing a new explicit spec, so keep retained deps in the
1936+// manifest and pass only actually missing specs as install args.
1937+ensureNpmInstallExecutionManifest(
1938+installExecutionRoot,
1939+params.installSpecs ?? params.missingSpecs,
1940+);
19151941const installEnv = createBundledRuntimeDepsInstallEnv(params.env, {
19161942cacheDir: path.join(installExecutionRoot, ".openclaw-npm-cache"),
19171943});
@@ -1955,6 +1981,7 @@ export async function installBundledRuntimeDepsAsync(params: {
19551981installExecutionRoot?: string;
19561982linkNodeModulesFromExecutionRoot?: boolean;
19571983missingSpecs: string[];
1984+installSpecs?: string[];
19581985env: NodeJS.ProcessEnv;
19591986warn?: (message: string) => void;
19601987onProgress?: (message: string) => void;
@@ -1978,7 +2005,10 @@ export async function installBundledRuntimeDepsAsync(params: {
19782005if (diskWarning) {
19792006params.warn?.(diskWarning);
19802007}
1981-ensureNpmInstallExecutionManifest(installExecutionRoot);
2008+ensureNpmInstallExecutionManifest(
2009+installExecutionRoot,
2010+params.installSpecs ?? params.missingSpecs,
2011+);
19822012const installEnv = createBundledRuntimeDepsInstallEnv(params.env, {
19832013cacheDir: path.join(installExecutionRoot, ".openclaw-npm-cache"),
19842014});
@@ -2035,7 +2065,8 @@ export function repairBundledRuntimeDepsInstallRoot(params: {
20352065((installParams) =>
20362066installBundledRuntimeDeps({
20372067installRoot: installParams.installRoot,
2038-missingSpecs: installParams.installSpecs ?? installParams.missingSpecs,
2068+missingSpecs: installParams.missingSpecs,
2069+installSpecs: installParams.installSpecs,
20392070env: params.env,
20402071warn: params.warn,
20412072}));
@@ -2129,7 +2160,8 @@ export async function repairBundledRuntimeDepsInstallRootAsync(params: {
21292160((installParams) =>
21302161installBundledRuntimeDepsAsync({
21312162installRoot: installParams.installRoot,
2132-missingSpecs: installParams.installSpecs ?? installParams.missingSpecs,
2163+missingSpecs: installParams.missingSpecs,
2164+installSpecs: installParams.installSpecs,
21332165env: params.env,
21342166warn: params.warn,
21352167onProgress: params.onProgress,
@@ -2268,14 +2300,22 @@ export function ensureBundledPluginRuntimeDeps(params: {
2268230022692301const install =
22702302params.installDeps ??
2271-((installParams) =>
2272-installBundledRuntimeDeps({
2303+((installParams) => {
2304+const isolatedExecutionRoot =
2305+installParams.installExecutionRoot &&
2306+path.resolve(installParams.installExecutionRoot) !==
2307+path.resolve(installParams.installRoot);
2308+return installBundledRuntimeDeps({
22732309installRoot: installParams.installRoot,
22742310installExecutionRoot: installParams.installExecutionRoot,
22752311linkNodeModulesFromExecutionRoot: installParams.linkNodeModulesFromExecutionRoot,
2276-missingSpecs: installParams.installSpecs ?? installParams.missingSpecs,
2312+missingSpecs: isolatedExecutionRoot
2313+ ? (installParams.installSpecs ?? installParams.missingSpecs)
2314+ : installParams.missingSpecs,
2315+installSpecs: installParams.installSpecs,
22772316env: params.env,
2278-}));
2317+});
2318+});
22792319const finishActivity = beginBundledRuntimeDepsInstall({
22802320 installRoot,
22812321 missingSpecs,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。