From cd86d8cf2d89f93162b48f041a415759ff5ed23b Mon Sep 17 00:00:00 2001 From: Chip Warden Date: Sat, 30 May 2026 23:39:12 -0500 Subject: [PATCH 1/6] perf(shell): lazy-init version managers and cache op completion Defer nodenv, rbenv, and goenv shell initialization to first use in both bash and fish. Shims remain on PATH eagerly so managed runtimes resolve immediately without spawning a subprocess at startup. The shell function for each manager is a placeholder that runs the real init on first invocation. Cache `op completion fish` output to disk and regenerate only when the op binary is newer than the cached file, avoiding a subprocess on every interactive shell start. Also pass an explicit shell name to `brew shellenv` in bash and fish, and remove the now-redundant Intel-Mac Homebrew fallback from bashrc. Co-Authored-By: Claude Sonnet 4.6 --- private_dot_bashrc | 4 +--- .../private_tools/private_golang.bash.tmpl | 6 +++++- .../private_tools/private_node.bash.tmpl | 7 ++++++- .../private_tools/private_ruby.bash.tmpl | 7 ++++++- .../private_conf.d/private_00-path-base.fish.tmpl | 2 +- .../private_conf.d/private_00-path-golang.fish.tmpl | 6 +++++- .../private_conf.d/private_00-path-node.fish.tmpl | 7 ++++++- .../private_conf.d/private_00-path-ruby.fish.tmpl | 11 ++++++++--- .../private_conf.d/private_20-config-op.fish.tmpl | 6 +++++- 9 files changed, 43 insertions(+), 13 deletions(-) diff --git a/private_dot_bashrc b/private_dot_bashrc index 512f4be..dd9a9bd 100644 --- a/private_dot_bashrc +++ b/private_dot_bashrc @@ -43,9 +43,7 @@ if [[ -d "/usr/local/bin" ]]; then fi if [[ -e "/opt/homebrew/bin/brew" ]]; then - eval "$(/opt/homebrew/bin/brew shellenv)" -elif [[ -e "/usr/local/bin/brew" ]]; then - eval "$(/usr/local/bin/brew shellenv)" + eval "$(/opt/homebrew/bin/brew shellenv bash)" fi # Import files from $HOME/.bashrc.d diff --git a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl index 8fb54ae..1236d96 100644 --- a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl @@ -11,8 +11,12 @@ fi {{- end }} if command -v goenv >/dev/null 2>&1; then - eval "$(goenv init -)" path_prepend "$GOENV_ROOT/shims" + goenv() { + unset -f goenv + eval "$(command goenv init -)" + goenv "$@" + } fi if [[ -d "$HOME/Developer/go" ]]; then diff --git a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl index 52cda4b..400877a 100644 --- a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl @@ -15,5 +15,10 @@ fi {{- end }} if command -v nodenv >/dev/null 2>&1; then - eval "$(nodenv init -)" + path_prepend "$NODENV_ROOT/shims" + nodenv() { + unset -f nodenv + eval "$(command nodenv init -)" + nodenv "$@" + } fi diff --git a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl index 2f1109b..b2f4f28 100644 --- a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl @@ -11,5 +11,10 @@ fi {{- end }} if command -v rbenv >/dev/null 2>&1; then - eval "$(rbenv init -)" + path_prepend "$RBENV_ROOT/shims" + rbenv() { + unset -f rbenv + eval "$(command rbenv init -)" + rbenv "$@" + } fi diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-base.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-base.fish.tmpl index 079f74d..e55479c 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-base.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-base.fish.tmpl @@ -7,7 +7,7 @@ if test -d "/usr/local/bin" end {{ if eq .chezmoi.os "darwin" }} if test -x "/opt/homebrew/bin/brew" - eval "$(/opt/homebrew/bin/brew shellenv)" + eval "$(/opt/homebrew/bin/brew shellenv fish)" end if test -n "$HOMEBREW_PREFIX" diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl index 5022707..5f8bf33 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl @@ -10,8 +10,12 @@ end if type -q goenv && status --is-interactive set -x GOENV_PATH_ORDER front - goenv init - fish | source fish_add_path -mpP $GOENV_ROOT/shims + function goenv + functions -e goenv + goenv init - fish | source + goenv $argv + end end if test -d "$HOME/Developer/go" diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl index 66a1f64..7a10d02 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl @@ -15,8 +15,13 @@ end {{- end }} if type -q nodenv && status --is-interactive - nodenv init - fish | source + fish_add_path -mpP $NODENV_ROOT/shims {{- if eq .chezmoi.os "darwin" }} set -x NODE_BUILD_DEFINITIONS "$HOMEBREW_PREFIX/opt/node-build-update-defs/share/node-build" {{- end }} + function nodenv + functions -e nodenv + nodenv init - fish | source + nodenv $argv + end end diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl index b07984e..6a7d3c4 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl @@ -9,7 +9,12 @@ end {{- end }} if type -q rbenv && status --is-interactive - rbenv init - fish | source - set -l rbenv_commands (rbenv commands) - complete -f -c rbenv -n "not __fish_seen_subcommand_from $rbenv_commands" -a update -d 'Update rbenv and rbenv plugins' + fish_add_path -mpP $RBENV_ROOT/shims + function rbenv + functions -e rbenv + rbenv init - fish | source + set -l rbenv_commands (rbenv commands) + complete -f -c rbenv -n "not __fish_seen_subcommand_from $rbenv_commands" -a update -d 'Update rbenv and rbenv plugins' + rbenv $argv + end end diff --git a/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl index 91db53b..27ebf0f 100644 --- a/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl @@ -2,5 +2,9 @@ if type -q op function op-signin -d "Sign in to 1Password CLI" eval (op signin --account {{ onepasswordRead "op://Private/1Password CLI Account Name/notesPlain" }}) end - op completion fish | source + set -l _op_completion ~/.config/fish/completions/op.fish + set -l _op_bin (command -v op) + if not test -f $_op_completion; or test $_op_bin -nt $_op_completion + op completion fish > $_op_completion + end end From a09956b0cca4bcfa40c23a9ba9f0eb970917728a Mon Sep 17 00:00:00 2001 From: Chip Warden Date: Sat, 30 May 2026 23:41:45 -0500 Subject: [PATCH 2/6] Specify shell for Z shell Homebrew initialization. --- private_dot_zprofile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/private_dot_zprofile b/private_dot_zprofile index fb49bc6..0557d24 100644 --- a/private_dot_zprofile +++ b/private_dot_zprofile @@ -1,3 +1,3 @@ # Set PATH, MANPATH, etc., for Homebrew. -eval "$(/opt/homebrew/bin/brew shellenv)" +eval "$(/opt/homebrew/bin/brew shellenv zsh)" export HOMEBREW_CASK_OPTS="--appdir=~/Applications" From 8dfa05e899e5e659b2006c69dee5f2d3e327def4 Mon Sep 17 00:00:00 2001 From: Chip Warden Date: Sat, 30 May 2026 23:48:17 -0500 Subject: [PATCH 3/6] fix(shell): write op completion to temp file before replacing cache Avoid truncating the cached op.fish before generation succeeds. Write to a mktemp file and mv into place only on success; clean up the temp file on failure. Co-Authored-By: Claude Sonnet 4.6 --- .../private_conf.d/private_20-config-op.fish.tmpl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl index 27ebf0f..e918b37 100644 --- a/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_20-config-op.fish.tmpl @@ -5,6 +5,11 @@ if type -q op set -l _op_completion ~/.config/fish/completions/op.fish set -l _op_bin (command -v op) if not test -f $_op_completion; or test $_op_bin -nt $_op_completion - op completion fish > $_op_completion + set -l _op_tmp (mktemp) + if op completion fish > $_op_tmp + mv $_op_tmp $_op_completion + else + rm -f $_op_tmp + end end end From 2ff75ffc1771bfc7a5ebd8aaf78f9912c5085031 Mon Sep 17 00:00:00 2001 From: Chip Warden Date: Sat, 30 May 2026 23:52:21 -0500 Subject: [PATCH 4/6] fix(shell): guard shim path add when *ENV_ROOT is unset or shims absent When a version manager is installed via Homebrew without a user root directory, *ENV_ROOT may be unset, causing "$NODENV_ROOT/shims" etc. to expand to "/shims" and prepend a bogus entry to PATH. Guard the fish_add_path/path_prepend call in all three version managers (bash and fish) so shims are only added when the variable is set and the directory exists. Co-Authored-By: Claude Sonnet 4.6 --- private_dot_bashrc.d/private_tools/private_golang.bash.tmpl | 4 +++- private_dot_bashrc.d/private_tools/private_node.bash.tmpl | 4 +++- private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl | 4 +++- .../private_conf.d/private_00-path-golang.fish.tmpl | 4 +++- .../private_conf.d/private_00-path-node.fish.tmpl | 4 +++- .../private_conf.d/private_00-path-ruby.fish.tmpl | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl index 1236d96..3365e96 100644 --- a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl @@ -11,7 +11,9 @@ fi {{- end }} if command -v goenv >/dev/null 2>&1; then - path_prepend "$GOENV_ROOT/shims" + if [[ -n "$GOENV_ROOT" ]] && [[ -d "$GOENV_ROOT/shims" ]]; then + path_prepend "$GOENV_ROOT/shims" + fi goenv() { unset -f goenv eval "$(command goenv init -)" diff --git a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl index 400877a..34010f5 100644 --- a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl @@ -15,7 +15,9 @@ fi {{- end }} if command -v nodenv >/dev/null 2>&1; then - path_prepend "$NODENV_ROOT/shims" + if [[ -n "$NODENV_ROOT" ]] && [[ -d "$NODENV_ROOT/shims" ]]; then + path_prepend "$NODENV_ROOT/shims" + fi nodenv() { unset -f nodenv eval "$(command nodenv init -)" diff --git a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl index b2f4f28..2c6f91b 100644 --- a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl @@ -11,7 +11,9 @@ fi {{- end }} if command -v rbenv >/dev/null 2>&1; then - path_prepend "$RBENV_ROOT/shims" + if [[ -n "$RBENV_ROOT" ]] && [[ -d "$RBENV_ROOT/shims" ]]; then + path_prepend "$RBENV_ROOT/shims" + fi rbenv() { unset -f rbenv eval "$(command rbenv init -)" diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl index 5f8bf33..c463525 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl @@ -10,7 +10,9 @@ end if type -q goenv && status --is-interactive set -x GOENV_PATH_ORDER front - fish_add_path -mpP $GOENV_ROOT/shims + if test -n "$GOENV_ROOT" -a -d "$GOENV_ROOT/shims" + fish_add_path -mpP $GOENV_ROOT/shims + end function goenv functions -e goenv goenv init - fish | source diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl index 7a10d02..aed76ec 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl @@ -15,7 +15,9 @@ end {{- end }} if type -q nodenv && status --is-interactive - fish_add_path -mpP $NODENV_ROOT/shims + if test -n "$NODENV_ROOT" -a -d "$NODENV_ROOT/shims" + fish_add_path -mpP $NODENV_ROOT/shims + end {{- if eq .chezmoi.os "darwin" }} set -x NODE_BUILD_DEFINITIONS "$HOMEBREW_PREFIX/opt/node-build-update-defs/share/node-build" {{- end }} diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl index 6a7d3c4..63f3e20 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl @@ -9,7 +9,9 @@ end {{- end }} if type -q rbenv && status --is-interactive - fish_add_path -mpP $RBENV_ROOT/shims + if test -n "$RBENV_ROOT" -a -d "$RBENV_ROOT/shims" + fish_add_path -mpP $RBENV_ROOT/shims + end function rbenv functions -e rbenv rbenv init - fish | source From 3de044faf522c9f714398d012dfdcc9b22420f72 Mon Sep 17 00:00:00 2001 From: Chip Warden Date: Sun, 31 May 2026 00:05:57 -0500 Subject: [PATCH 5/6] fix(shell): use default value expansion to guarantee *ENV_ROOT is set Replace the directory-existence check with an unconditional default: export RBENV_ROOT="${RBENV_ROOT:-$HOME/.rbenv}" # bash set -q RBENV_ROOT; or set -x RBENV_ROOT $HOME/.rbenv # fish *ENV_ROOT is now always set to a well-formed path before the shims entry is added to PATH, so the tool being Homebrew-installed without an explicit root directory can no longer produce a bogus /shims entry. The directory-existence guard introduced in the previous commit is removed as it is no longer necessary. Co-Authored-By: Claude Sonnet 4.6 --- .../private_tools/private_golang.bash.tmpl | 8 ++------ private_dot_bashrc.d/private_tools/private_node.bash.tmpl | 8 ++------ private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl | 8 ++------ .../private_conf.d/private_00-path-golang.fish.tmpl | 8 ++------ .../private_conf.d/private_00-path-node.fish.tmpl | 8 ++------ .../private_conf.d/private_00-path-ruby.fish.tmpl | 8 ++------ 6 files changed, 12 insertions(+), 36 deletions(-) diff --git a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl index 3365e96..9de6b4e 100644 --- a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl @@ -1,8 +1,6 @@ # shellcheck shell=bash # shellcheck disable=SC2103,SC2155,SC2164 -if [[ -d "$HOME/.goenv" ]]; then - export GOENV_ROOT="$HOME/.goenv" -fi +export GOENV_ROOT="${GOENV_ROOT:-$HOME/.goenv}" {{- if (and (eq .chezmoi.os "linux") (or (eq .chezmoi.osRelease.id "debian") (eq .chezmoi.osRelease.id "ubuntu"))) }} if [[ -n "$GOENV_ROOT" ]] && [[ -f "$GOENV_ROOT/bin/goenv" ]]; then @@ -11,9 +9,7 @@ fi {{- end }} if command -v goenv >/dev/null 2>&1; then - if [[ -n "$GOENV_ROOT" ]] && [[ -d "$GOENV_ROOT/shims" ]]; then - path_prepend "$GOENV_ROOT/shims" - fi + path_prepend "$GOENV_ROOT/shims" goenv() { unset -f goenv eval "$(command goenv init -)" diff --git a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl index 34010f5..9704285 100644 --- a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl @@ -4,9 +4,7 @@ if [[ -d "$HOMEBREW_PREFIX/share/npm/bin" ]]; then path_append "$HOMEBREW_PREFIX/share/npm/bin" fi -if [[ -d "$HOME/.nodenv" ]]; then - export NODENV_ROOT="$HOME/.nodenv" -fi +export NODENV_ROOT="${NODENV_ROOT:-$HOME/.nodenv}" {{- if (and (eq .chezmoi.os "linux") (or (eq .chezmoi.osRelease.id "debian") (eq .chezmoi.osRelease.id "ubuntu"))) }} if [[ -n "$NODENV_ROOT" ]] && [[ -f "$NODENV_ROOT/bin/nodenv" ]]; then @@ -15,9 +13,7 @@ fi {{- end }} if command -v nodenv >/dev/null 2>&1; then - if [[ -n "$NODENV_ROOT" ]] && [[ -d "$NODENV_ROOT/shims" ]]; then - path_prepend "$NODENV_ROOT/shims" - fi + path_prepend "$NODENV_ROOT/shims" nodenv() { unset -f nodenv eval "$(command nodenv init -)" diff --git a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl index 2c6f91b..5d00463 100644 --- a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl @@ -1,8 +1,6 @@ # shellcheck shell=bash # shellcheck disable=SC2103,SC2155,SC2164 -if [[ -d "$HOME/.rbenv" ]]; then - export RBENV_ROOT="$HOME/.rbenv" -fi +export RBENV_ROOT="${RBENV_ROOT:-$HOME/.rbenv}" {{- if (and (eq .chezmoi.os "linux") (or (eq .chezmoi.osRelease.id "debian") (eq .chezmoi.osRelease.id "ubuntu"))) }} if [[ -n "$RBENV_ROOT" ]] && [[ -f "$RBENV_ROOT/bin/rbenv" ]]; then @@ -11,9 +9,7 @@ fi {{- end }} if command -v rbenv >/dev/null 2>&1; then - if [[ -n "$RBENV_ROOT" ]] && [[ -d "$RBENV_ROOT/shims" ]]; then - path_prepend "$RBENV_ROOT/shims" - fi + path_prepend "$RBENV_ROOT/shims" rbenv() { unset -f rbenv eval "$(command rbenv init -)" diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl index c463525..86cb092 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl @@ -1,6 +1,4 @@ -if test -d "$HOME/.goenv" - set -x GOENV_ROOT $HOME/.goenv -end +set -q GOENV_ROOT; or set -x GOENV_ROOT $HOME/.goenv {{- if (and (eq .chezmoi.os "linux") (or (eq .chezmoi.osRelease.id "debian") (eq .chezmoi.osRelease.id "ubuntu"))) }} if test -n "$GOENV_ROOT" -a -f "$GOENV_ROOT/bin/goenv" @@ -10,9 +8,7 @@ end if type -q goenv && status --is-interactive set -x GOENV_PATH_ORDER front - if test -n "$GOENV_ROOT" -a -d "$GOENV_ROOT/shims" - fish_add_path -mpP $GOENV_ROOT/shims - end + fish_add_path -mpP $GOENV_ROOT/shims function goenv functions -e goenv goenv init - fish | source diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl index aed76ec..d5c2cf8 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl @@ -4,9 +4,7 @@ if test -d "$HOMEBREW_PREFIX/share/npm/bin" end {{- end }} -if test -d "$HOME/.nodenv" - set -x NODENV_ROOT $HOME/.nodenv -end +set -q NODENV_ROOT; or set -x NODENV_ROOT $HOME/.nodenv {{- if (and (eq .chezmoi.os "linux") (or (eq .chezmoi.osRelease.id "debian") (eq .chezmoi.osRelease.id "ubuntu"))) }} if test -n "$NODENV_ROOT" -a -f "$NODENV_ROOT/bin/nodenv" @@ -15,9 +13,7 @@ end {{- end }} if type -q nodenv && status --is-interactive - if test -n "$NODENV_ROOT" -a -d "$NODENV_ROOT/shims" - fish_add_path -mpP $NODENV_ROOT/shims - end + fish_add_path -mpP $NODENV_ROOT/shims {{- if eq .chezmoi.os "darwin" }} set -x NODE_BUILD_DEFINITIONS "$HOMEBREW_PREFIX/opt/node-build-update-defs/share/node-build" {{- end }} diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl index 63f3e20..d262104 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl @@ -1,6 +1,4 @@ -if test -d "$HOME/.rbenv" - set -x RBENV_ROOT $HOME/.rbenv -end +set -q RBENV_ROOT; or set -x RBENV_ROOT $HOME/.rbenv {{- if (and (eq .chezmoi.os "linux") (or (eq .chezmoi.osRelease.id "debian") (eq .chezmoi.osRelease.id "ubuntu"))) }} if test -n "$RBENV_ROOT" -a -f "$RBENV_ROOT/bin/rbenv" @@ -9,9 +7,7 @@ end {{- end }} if type -q rbenv && status --is-interactive - if test -n "$RBENV_ROOT" -a -d "$RBENV_ROOT/shims" - fish_add_path -mpP $RBENV_ROOT/shims - end + fish_add_path -mpP $RBENV_ROOT/shims function rbenv functions -e rbenv rbenv init - fish | source From 417328631d71447c05785f953ad9ea8cc08e3107 Mon Sep 17 00:00:00 2001 From: Chip Warden Date: Sun, 31 May 2026 00:14:17 -0500 Subject: [PATCH 6/6] fix(shell): guard shim path_prepend with directory existence check *ENV_ROOT now always expands to a well-formed path, but the shims directory itself may not exist when the tool is installed but no versions have been installed yet. Add -d guards to path_prepend/ fish_add_path calls in all three version managers (bash and fish) to match the pattern used for other conditional path entries. Co-Authored-By: Claude Sonnet 4.6 --- private_dot_bashrc.d/private_tools/private_golang.bash.tmpl | 4 +++- private_dot_bashrc.d/private_tools/private_node.bash.tmpl | 4 +++- private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl | 4 +++- .../private_conf.d/private_00-path-golang.fish.tmpl | 4 +++- .../private_conf.d/private_00-path-node.fish.tmpl | 4 +++- .../private_conf.d/private_00-path-ruby.fish.tmpl | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl index 9de6b4e..f9429b1 100644 --- a/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_golang.bash.tmpl @@ -9,7 +9,9 @@ fi {{- end }} if command -v goenv >/dev/null 2>&1; then - path_prepend "$GOENV_ROOT/shims" + if [[ -d "$GOENV_ROOT/shims" ]]; then + path_prepend "$GOENV_ROOT/shims" + fi goenv() { unset -f goenv eval "$(command goenv init -)" diff --git a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl index 9704285..ab9478e 100644 --- a/private_dot_bashrc.d/private_tools/private_node.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_node.bash.tmpl @@ -13,7 +13,9 @@ fi {{- end }} if command -v nodenv >/dev/null 2>&1; then - path_prepend "$NODENV_ROOT/shims" + if [[ -d "$NODENV_ROOT/shims" ]]; then + path_prepend "$NODENV_ROOT/shims" + fi nodenv() { unset -f nodenv eval "$(command nodenv init -)" diff --git a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl index 5d00463..5aa8f9b 100644 --- a/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl +++ b/private_dot_bashrc.d/private_tools/private_ruby.bash.tmpl @@ -9,7 +9,9 @@ fi {{- end }} if command -v rbenv >/dev/null 2>&1; then - path_prepend "$RBENV_ROOT/shims" + if [[ -d "$RBENV_ROOT/shims" ]]; then + path_prepend "$RBENV_ROOT/shims" + fi rbenv() { unset -f rbenv eval "$(command rbenv init -)" diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl index 86cb092..baefc0d 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-golang.fish.tmpl @@ -8,7 +8,9 @@ end if type -q goenv && status --is-interactive set -x GOENV_PATH_ORDER front - fish_add_path -mpP $GOENV_ROOT/shims + if test -d "$GOENV_ROOT/shims" + fish_add_path -mpP $GOENV_ROOT/shims + end function goenv functions -e goenv goenv init - fish | source diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl index d5c2cf8..b556423 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-node.fish.tmpl @@ -13,7 +13,9 @@ end {{- end }} if type -q nodenv && status --is-interactive - fish_add_path -mpP $NODENV_ROOT/shims + if test -d "$NODENV_ROOT/shims" + fish_add_path -mpP $NODENV_ROOT/shims + end {{- if eq .chezmoi.os "darwin" }} set -x NODE_BUILD_DEFINITIONS "$HOMEBREW_PREFIX/opt/node-build-update-defs/share/node-build" {{- end }} diff --git a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl index d262104..82a0268 100644 --- a/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl +++ b/private_dot_config/private_fish/private_conf.d/private_00-path-ruby.fish.tmpl @@ -7,7 +7,9 @@ end {{- end }} if type -q rbenv && status --is-interactive - fish_add_path -mpP $RBENV_ROOT/shims + if test -d "$RBENV_ROOT/shims" + fish_add_path -mpP $RBENV_ROOT/shims + end function rbenv functions -e rbenv rbenv init - fish | source