From 2714c83de89e5c2dccf9f98937e14f2bcafee5fc Mon Sep 17 00:00:00 2001 From: w287346141 <57440615+w287346141@users.noreply.github.com> Date: Mon, 1 Jun 2026 11:46:08 +0800 Subject: [PATCH] Fix npm update prefix for symlinked bins --- src/version.ts | 8 +++++++- tests/version.test.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/version.ts b/src/version.ts index 0816ac2..11d5b8b 100644 --- a/src/version.ts +++ b/src/version.ts @@ -172,7 +172,13 @@ export function isNpxInstall(): boolean { export function detectNpmInstallPrefix(bin?: string): string | null { const raw = bin ?? process.argv[1] ?? ""; if (!raw) return null; - const norm = raw.replace(/\\/g, "/"); + let resolved = raw; + try { + resolved = realpathSync(raw); + } catch { + /* synthetic / nonexistent path (e.g. in tests) -- keep the literal argv */ + } + const norm = resolved.replace(/\\/g, "/"); const posix = norm.match(/^(.+?)\/lib\/node_modules\/@carboncode\/cli(?:\/|$)/i); if (posix) return posix[1] ?? null; const win = norm.match(/^(.+?)\/node_modules\/@carboncode\/cli(?:\/|$)/i); diff --git a/tests/version.test.ts b/tests/version.test.ts index e160cf7..06c3444 100644 --- a/tests/version.test.ts +++ b/tests/version.test.ts @@ -209,6 +209,33 @@ describe("detectNpmInstallPrefix", () => { ).toBe("C:/Users/me/AppData/Roaming/npm"); }); + it("resolves a bin symlink before extracting the npm prefix", () => { + const dir = mkdtempSync(join(tmpdir(), "cc-prefix-")); + try { + const target = join( + dir, + "lib", + "node_modules", + "@carboncode", + "cli", + "dist", + "cli", + "index.js", + ); + mkdirSync(join(dir, "lib", "node_modules", "@carboncode", "cli", "dist", "cli"), { + recursive: true, + }); + writeFileSync(target, "#!/usr/bin/env node\n"); + mkdirSync(join(dir, "bin")); + const link = join(dir, "bin", "carboncode"); + symlinkSync(target, link); + + expect(detectNpmInstallPrefix(link)).toBe(dir.replace(/\\/g, "/")); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + it("returns null when no @carboncode/cli node_modules segment is present", () => { expect(detectNpmInstallPrefix("/opt/custom/bin/carboncode")).toBeNull(); });