authorgravatar for 93147993+hey-jj@users.noreply.github.comJJ <93147993+hey-jj@users.noreply.github.com> 2026-08-15 06:26:32-06:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-15 12:26:32+00:00
logdc0ff8f13eaa9753fdf0de60203c9e819f1cee27
tree22a9a62c9a4aa47190c1cf5fc2693b53bb8b5d27
parent160c76c6d1c5ab78441e21503cd10e7942b917f6
signature Signed by PGP key B5690EEEBB952194

fix(server): allow install scripts in npm-global provider updates (#5646)


2 files changed, 55 insertions(+), 4 deletions(-)

apps/server/src/provider/providerMaintenance.test.ts+44-3
......@@ -176,7 +176,8 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
176176 status: "behind_latest",
177177 currentVersion: "2.1.110",
178178 latestVersion: "2.1.117",
179 updateCommand: "npm install -g @example/native-package-tool@latest",
179 updateCommand:
180 "npm install -g --allow-scripts=@example/native-package-tool @example/native-package-tool@latest",
180181 canUpdate: true,
181182 message: "Install the update now or review provider settings.",
182183 });
......@@ -482,11 +483,17 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
482483 provider: driver("packageTool"),
483484 packageName: "@example/package-tool",
484485 update: {
485 command: "npm install -g @example/package-tool@latest",
486 command:
487 "npm install -g --allow-scripts=@example/package-tool @example/package-tool@latest",
486488
487489 executable: "npm",
488490
489 args: ["install", "-g", "@example/package-tool@latest"],
491 args: [
492 "install",
493 "-g",
494 "--allow-scripts=@example/package-tool",
495 "@example/package-tool@latest",
496 ],
490497
491498 lockKey: "npm-global",
492499 },
......@@ -541,6 +548,40 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
541548 }),
542549 );
543550
551 it("allows the package's own install scripts in npm global updates", () => {
552 const claudeUpdate = makePackageManagedProviderMaintenanceResolver({
553 provider: driver("claudeAgent"),
554 npmPackageName: "@anthropic-ai/claude-code",
555 homebrewFormula: "claude-code",
556 nativeUpdate: {
557 executable: "claude",
558 args: ["update"],
559 lockKey: "claude-native",
560 isCommandPath: isNativeTestCommandPath("/.local/bin/claude"),
561 },
562 });
563
564 expect(claudeUpdate.resolve()).toEqual({
565 provider: driver("claudeAgent"),
566 packageName: "@anthropic-ai/claude-code",
567 update: {
568 command:
569 "npm install -g --allow-scripts=@anthropic-ai/claude-code @anthropic-ai/claude-code@latest",
570
571 executable: "npm",
572
573 args: [
574 "install",
575 "-g",
576 "--allow-scripts=@anthropic-ai/claude-code",
577 "@anthropic-ai/claude-code@latest",
578 ],
579
580 lockKey: "npm-global",
581 },
582 });
583 });
584
544585 it("disables one-click updates for explicit custom binary paths it cannot safely map", () => {
545586 expect(
546587 packageToolUpdate.resolve({
apps/server/src/provider/providerMaintenance.ts+11-1
......@@ -137,7 +137,17 @@ function makeNpmGlobalProviderMaintenanceCapabilities(
137137 provider: definition.provider,
138138 packageName: definition.npmPackageName,
139139 updateExecutable: "npm",
140 updateArgs: ["install", "-g", `${definition.npmPackageName}@latest`],
140 // npm 12 blocks install scripts by default (empty allow-scripts allowlist)
141 // and still exits 0, so a package whose postinstall finishes the install
142 // (claude copies its native binary over a placeholder stub) is left broken
143 // while the update reports success. Allow this one package's scripts.
144 // Older npm warns about the unknown config and continues.
145 updateArgs: [
146 "install",
147 "-g",
148 `--allow-scripts=${definition.npmPackageName}`,
149 `${definition.npmPackageName}@latest`,
150 ],
141151 updateLockKey: "npm-global",
142152 });
143153}