diff --git a/src/utils/package-manager-detector.ts b/src/utils/package-manager-detector.ts index 606c58ed..d5f4a051 100644 --- a/src/utils/package-manager-detector.ts +++ b/src/utils/package-manager-detector.ts @@ -29,7 +29,9 @@ export interface InstalledPackageState { const CCS_PACKAGE_NAME = '@kaitranntt/ccs'; function resolveScriptPath(scriptPath: string): string { - if (path.win32.isAbsolute(scriptPath)) { + // Keep Windows-style absolute test fixtures stable on non-Windows hosts, but + // still resolve real POSIX symlink paths such as ~/.bun/bin/ccs. + if (path.win32.isAbsolute(scriptPath) && !path.isAbsolute(scriptPath)) { return scriptPath; } diff --git a/tests/unit/utils/package-manager-detector.test.ts b/tests/unit/utils/package-manager-detector.test.ts index 693e0920..5bb1164a 100644 --- a/tests/unit/utils/package-manager-detector.test.ts +++ b/tests/unit/utils/package-manager-detector.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it } from 'bun:test'; -import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'fs'; +import { mkdtempSync, mkdirSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; import { @@ -72,6 +72,39 @@ describe('package-manager-detector', () => { expect(readInstalledPackageVersion(install)).toBe('7.67.0-dev.9'); }); + it.if(process.platform !== 'win32')( + 'detects bun installs from a POSIX symlinked ~/.bun/bin/ccs entrypoint', + () => { + const tempRoot = makeTempDir('ccs-install-detector-bun-symlink-'); + const packageRoot = join( + tempRoot, + '.bun', + 'install', + 'global', + 'node_modules', + '@kaitranntt', + 'ccs' + ); + const scriptPath = join(packageRoot, 'dist', 'ccs.js'); + const symlinkPath = join(tempRoot, 'home', '.bun', 'bin', 'ccs'); + + writePackage(packageRoot, '7.67.0-dev.9'); + mkdirSync(join(packageRoot, 'dist'), { recursive: true }); + writeFileSync(scriptPath, '#!/usr/bin/env node\n'); + mkdirSync(join(tempRoot, 'home', '.bun', 'bin'), { recursive: true }); + symlinkSync(scriptPath, symlinkPath); + + const install = detectCurrentInstall(symlinkPath); + const resolvedTempRoot = realpathSync(tempRoot); + const resolvedScriptPath = realpathSync(scriptPath); + + expect(install.manager).toBe('bun'); + expect(install.prefix).toBe(join(resolvedTempRoot, '.bun')); + expect(install.resolvedScriptPath).toBe(resolvedScriptPath); + expect(readInstalledPackageVersion(install)).toBe('7.67.0-dev.9'); + } + ); + it('detects custom bun install roots that still use install/global/node_modules', () => { const tempRoot = makeTempDir('ccs-install-detector-custom-bun-'); const packageRoot = join(