

























@@ -387,4 +387,72 @@ describe("installPackageDir", () => {
387387listMatchingEntries(targetDir, ".openclaw-install-hidden-npmrc-"),
388388).resolves.toHaveLength(0);
389389});
390+391+it("forces dependency installs to stay project-local when npm global config leaks in", async () => {
392+await fixtureRootTracker.setup();
393+const fixtureRoot = await fixtureRootTracker.make("case");
394+const sourceDir = path.join(fixtureRoot, "source");
395+const targetDir = path.join(fixtureRoot, "plugins", "demo");
396+await fs.mkdir(sourceDir, { recursive: true });
397+await fs.writeFile(
398+path.join(sourceDir, "package.json"),
399+JSON.stringify({
400+name: "demo-plugin",
401+version: "1.0.0",
402+dependencies: {
403+zod: "^4.0.0",
404+},
405+}),
406+"utf-8",
407+);
408+409+vi.stubEnv("NPM_CONFIG_GLOBAL", "true");
410+vi.stubEnv("npm_config_global", "true");
411+vi.stubEnv("NPM_CONFIG_LOCATION", "global");
412+vi.stubEnv("npm_config_location", "global");
413+vi.stubEnv("NPM_CONFIG_PREFIX", path.join(fixtureRoot, "global-prefix-uppercase"));
414+vi.stubEnv("npm_config_prefix", path.join(fixtureRoot, "global-prefix"));
415+vi.mocked(runCommandWithTimeout).mockResolvedValue({
416+stdout: "",
417+stderr: "",
418+code: 0,
419+signal: null,
420+killed: false,
421+termination: "exit",
422+});
423+424+const result = await installPackageDir({
425+ sourceDir,
426+ targetDir,
427+mode: "install",
428+timeoutMs: 1_000,
429+copyErrorPrefix: "failed to copy plugin",
430+hasDeps: true,
431+depsLogMessage: "Installing deps…",
432+});
433+434+expect(result).toEqual({ ok: true });
435+expect(vi.mocked(runCommandWithTimeout)).toHaveBeenCalledWith(
436+["npm", "install", "--omit=dev", "--silent", "--ignore-scripts"],
437+expect.objectContaining({
438+env: expect.objectContaining({
439+npm_config_global: "false",
440+npm_config_location: "project",
441+npm_config_package_lock: "false",
442+npm_config_save: "false",
443+}),
444+}),
445+);
446+expect(vi.mocked(runCommandWithTimeout)).toHaveBeenCalledWith(
447+expect.any(Array),
448+expect.objectContaining({
449+env: expect.not.objectContaining({
450+NPM_CONFIG_GLOBAL: expect.any(String),
451+NPM_CONFIG_LOCATION: expect.any(String),
452+NPM_CONFIG_PREFIX: expect.any(String),
453+npm_config_prefix: expect.any(String),
454+}),
455+}),
456+);
457+});
390458});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。