Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions setup-modules/shell-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,13 @@ add_local_bin_to_path() {
# in every ShellCheck invocation, causing exponential memory growth (11 GB+)
# when source chains span 463+ scripts. The wrapper intercepts this.
#
# Uses launchctl setenv (macOS) for GUI-launched apps + shell rc for terminals.
# This ensures all processes — regardless of shell — see the wrapper.
# Three layers ensure all processes see the wrapper:
# 1. launchctl setenv (macOS) — GUI-launched apps (current boot only)
# 2. .zshenv — ALL zsh processes including non-interactive (persists)
# 3. Shell rc files (.zshrc, .bash_profile) — interactive terminals
# Layer 2 is critical: opencode spawns bash-language-server as a non-interactive
# child process. .zshrc is NOT sourced for non-interactive shells, so without
# .zshenv the wrapper is invisible to the LSP and shellcheck runs unbounded.
setup_shellcheck_wrapper() {
local wrapper_path="$HOME/.aidevops/agents/scripts/shellcheck-wrapper.sh"

Expand Down Expand Up @@ -497,7 +502,24 @@ setup_shellcheck_wrapper() {
fi
fi

# Layer 2: Shell rc files — affects terminal sessions
# Layer 2: .zshenv — affects ALL zsh processes (interactive AND non-interactive)
# This is critical because opencode spawns bash-language-server as a
# non-interactive child process. .zshrc is NOT sourced for non-interactive
# shells, so SHELLCHECK_PATH set only in .zshrc is invisible to the LSP.
local zshenv="$HOME/.zshenv"
if [[ -f "$zshenv" ]] || command -v zsh >/dev/null 2>&1; then
if grep -q 'SHELLCHECK_PATH' "$zshenv" 2>/dev/null; then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While this logic is clever, using 2>/dev/null with grep can mask underlying issues like file permission errors, causing the script to fail on a later line with a less informative error message. A more robust approach is to explicitly check for the file's existence before calling grep. This avoids suppressing potentially important errors and aligns with the project's general rules against blanket error suppression.

Suggested change
if grep -q 'SHELLCHECK_PATH' "$zshenv" 2>/dev/null; then
if [[ -f "$zshenv" ]] && grep -q 'SHELLCHECK_PATH' "$zshenv"; then
References
  1. Avoid using 2>/dev/null to suppress errors on file operations if the file's existence has already been verified by a preceding check (e.g., [[ -f "$file" ]] or an early return). This practice is redundant for 'file not found' errors and can mask other important issues like permissions problems.
  2. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.

already_in="${already_in:+$already_in, }$zshenv"
else
touch "$zshenv"
echo "" >>"$zshenv"
echo "# Added by aidevops setup (GH#2915: prevent ShellCheck memory explosion)" >>"$zshenv"
echo "$env_line" >>"$zshenv"
added_to="${added_to:+$added_to, }$zshenv"
fi
fi

# Layer 3: Shell rc files — affects interactive terminal sessions
local rc_file
while IFS= read -r rc_file; do
[[ -z "$rc_file" ]] && continue
Expand Down
Loading