diff --git a/cli/src/__tests__/install-command.test.ts b/cli/src/__tests__/install-command.test.ts index 620504e348a..9c8c06c1716 100644 --- a/cli/src/__tests__/install-command.test.ts +++ b/cli/src/__tests__/install-command.test.ts @@ -10,6 +10,7 @@ import { resolveGitInstallRequest, resolveGitInstallWorkspacePackages, resolveNpmInstallRequest, + resolvePublishedVersion, runCommandWithDiagnostics, } from "../commands/install.js"; import { uninstallCommand } from "../commands/uninstall.js"; @@ -62,6 +63,15 @@ describe("managed install commands", () => { expect(() => resolveNpmInstallRequest({ version: "latest" })).toThrow(); }); + it("parses npm view version output from npm 11 and npm 12", async () => { + for (const stdout of ['"2026.916.1"\n', '[\n "2026.916.1"\n]\n', "2026.916.1\n"]) { + const runCommand = vi.fn(async () => ({ stdout, stderr: "" })); + await expect(resolvePublishedVersion("latest", runCommand)).resolves.toBe("2026.916.1"); + } + const multiple = vi.fn(async () => ({ stdout: '["2026.916.0","2026.916.1"]', stderr: "" })); + await expect(resolvePublishedVersion("latest", multiple)).rejects.toThrow("unexpected version response"); + }); + it("resolves branch, tag, full SHA, and short SHA refs through GitHub", async () => { const sha = "a".repeat(40); const runCommand = vi.fn(async (_file: string, _args: string[]) => ({ stdout: JSON.stringify({ sha }), stderr: "" })); diff --git a/cli/src/commands/install.ts b/cli/src/commands/install.ts index 3fd4a5b1985..b8083a140f0 100644 --- a/cli/src/commands/install.ts +++ b/cli/src/commands/install.ts @@ -111,6 +111,8 @@ function parseResolvedVersion(stdout: string): string { try { const parsed = JSON.parse(trimmed) as unknown; if (typeof parsed === "string") return parsed; + // npm 12 wraps single-value `npm view --json` output in an array. + if (Array.isArray(parsed) && parsed.length === 1 && typeof parsed[0] === "string") return parsed[0]; } catch { if (EXACT_VERSION_PATTERN.test(trimmed)) return trimmed; }