diff --git a/libs/platform/src/node-finder.ts b/libs/platform/src/node-finder.ts index 8dabfa3b..9b45d9e8 100644 --- a/libs/platform/src/node-finder.ts +++ b/libs/platform/src/node-finder.ts @@ -180,13 +180,14 @@ function findNodeWindows(homeDir: string): NodeFinderResult | null { return { nodePath: nvmNode, source: 'nvm-windows' }; } - // fnm on Windows + // fnm on Windows (prioritize canonical installation path over shell shims) const fnmWindowsPaths = [ + path.join(homeDir, '.fnm', 'node-versions'), path.join( process.env.LOCALAPPDATA || path.join(homeDir, 'AppData', 'Local'), - 'fnm_multishells' + 'fnm', + 'node-versions' ), - path.join(homeDir, '.fnm', 'node-versions'), ]; for (const fnmBasePath of fnmWindowsPaths) { @@ -332,7 +333,9 @@ export function buildEnhancedPath(nodePath: string, currentPath: string = ''): s const nodeDir = path.dirname(nodePath); // Don't add if already present or if it's just '.' - if (nodeDir === '.' || currentPath.includes(nodeDir)) { + // Use path segment matching to avoid false positives (e.g., /opt/node vs /opt/node-v18) + const pathSegments = currentPath.split(path.delimiter); + if (nodeDir === '.' || pathSegments.includes(nodeDir)) { return currentPath; } diff --git a/libs/platform/tests/node-finder.test.ts b/libs/platform/tests/node-finder.test.ts index 98521636..f37d0d85 100644 --- a/libs/platform/tests/node-finder.test.ts +++ b/libs/platform/tests/node-finder.test.ts @@ -96,12 +96,21 @@ describe('node-finder', () => { }); it('should handle Windows-style paths', () => { + // On Windows, path.dirname recognizes backslash paths + // On other platforms, backslash is not a path separator const nodePath = 'C:\\Program Files\\nodejs\\node.exe'; const currentPath = 'C:\\Windows\\System32'; const result = buildEnhancedPath(nodePath, currentPath); - expect(result).toBe(`C:\\Program Files\\nodejs${delimiter}${currentPath}`); + if (process.platform === 'win32') { + // On Windows, should prepend the node directory + expect(result).toBe(`C:\\Program Files\\nodejs${delimiter}${currentPath}`); + } else { + // On non-Windows, backslash paths are treated as relative paths + // path.dirname returns '.' so the function returns currentPath unchanged + expect(result).toBe(currentPath); + } }); it('should use default empty string for currentPath', () => {