Public/Tools/Enable-FastNodeManager.ps1
|
function Enable-FastNodeManager { <# .SYNOPSIS Installs (if necessary) and activates Fast Node Manager (fnm) for the session. .DESCRIPTION Runs two nested Invoke-Step substeps: - Install: if fnm.exe isn't on PATH, installs it with winget (Schniz.fnm, a portable package) and patches the current session's PATH so the Initialize substep can see it immediately. - Initialize: applies `fnm env` (multishell PATH + FNM_* variables, recursive version-file strategy) and registers fnm completions. When zoxide is also active, wraps zoxide's shared __zoxide_cd helper so every directory change triggers `fnm use`, switching node versions automatically. If the install doesn't produce fnm.exe on PATH, a warning is emitted (with winget's captured output) and Initialize is skipped (guarded by Get-Command) so profile startup continues. .EXAMPLE Enable-FastNodeManager .NOTES Call after Enable-Zoxide so the __zoxide_cd wrapping can take effect; without zoxide the env/completions setup still applies. #> [CmdletBinding()] param() Invoke-Step "Install" { # fnm is a winget portable: its exe lands in the Links dir. Install-WingetPackageSafe -Id 'Schniz.fnm' -Exe 'fnm.exe' ` -PathDir (Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Links') ` -CallerName 'Enable-FastNodeManager' } Invoke-Step "Initialize" { if (Get-Command fnm.exe -ErrorAction SilentlyContinue) { # Run in the global scope (not this module's) so the emitted env/completion helpers # aren't tagged to the module — see Private/Invoke-InGlobalScope.ps1. Invoke-InGlobalScope (fnm env --version-file-strategy=recursive --shell powershell | Out-String) Invoke-InGlobalScope (fnm completions --shell powershell | Out-String) if (Get-Command zoxide.exe -ErrorAction SilentlyContinue) { # Wrap the shared __zoxide_cd helper (used by both cd and cdi) so every # directory change triggers fnm. Run in the global scope so the redefined # function isn't tagged to the module; $function:__zoxide_cd then resolves to # zoxide's global helper, and $global:__zoxide_cd_base must be global so it's # in scope when the wrapper runs later from the prompt. Invoke-InGlobalScope @' $global:__zoxide_cd_base = $function:__zoxide_cd function global:__zoxide_cd($dir, $literal) { & $global:__zoxide_cd_base $dir $literal fnm use --silent-if-unchanged } '@ } } } } |