Skip to content

Instantly share code, notes, and snippets.

@selfagency
Created May 16, 2026 22:36
Show Gist options
  • Select an option

  • Save selfagency/62b878cab58506c28395b594b45b0321 to your computer and use it in GitHub Desktop.

Select an option

Save selfagency/62b878cab58506c28395b594b45b0321 to your computer and use it in GitHub Desktop.
Automatically add the current repo and subpackages' `node_modules/.bin` to your `$PATH`
# source this file in your ~/.zshrc
autoload -Uz add-zsh-hook
typeset -ga _git_nm_bins_current=()
_git_nm_path_remove_exact() {
local needle="$1"
local -a filtered=()
local p
for p in "${path[@]}"; do
[[ "$p" == "$needle" ]] || filtered+=("$p")
done
path=("${filtered[@]}")
}
_git_nm_bin_hook() {
emulate -L zsh
setopt localoptions no_shwordsplit
local repo_root dir bin
local -a desired_bins=()
# Remove bins previously injected by this hook.
for bin in "${_git_nm_bins_current[@]}"; do
_git_nm_path_remove_exact "$bin"
done
_git_nm_bins_current=()
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
[[ -n "$repo_root" ]] || return 0
# Canonicalize paths so comparisons work reliably.
repo_root="${repo_root:A}"
dir="${PWD:A}"
# Collect every node_modules/.bin from the current dir up to the git root.
while :; do
bin="$dir/node_modules/.bin"
[[ -d "$bin" ]] && desired_bins+=("$bin")
[[ "$dir" == "$repo_root" ]] && break
[[ "$dir" == "/" ]] && break
dir="${dir:h}"
done
# Remove any existing occurrences so order is correct, then prepend.
for bin in "${desired_bins[@]}"; do
_git_nm_path_remove_exact "$bin"
done
if (( ${#desired_bins} )); then
path=("${desired_bins[@]}" "${path[@]}")
_git_nm_bins_current=("${desired_bins[@]}")
fi
}
add-zsh-hook chpwd _git_nm_bin_hook
_git_nm_bin_hook
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment