A flake.nix file plus a direnv `.envrc` file with `use flake` has solved this for me.
When I cd into a project directory I get all of the tools that project needs, at the exact versions they were tested with. When I cd out of the directory, they go away. If the dependencies are well behaved (e.g. they don't do any self-modification, which is annoyingly common in the npm world) then it's often pretty easy to track all of your deps this way, imported from your npm package-lock.json or similar.
Ask your favorite LLM to write your flake.nix file for you, they're pretty good at it. I've been able to drop all of the bespoke language-specific tool versioning stuff `nvm`, `uv`, `rvm`, etc for all my personal projects, and it makes it easy to add deps from outside the language-specific package managers, like ffmpeg and lame.