diff --git a/CHANGELOG.md b/CHANGELOG.md index 68f2507..7f1e710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `.github/dependabot.yml` — monthly GitHub Actions updates - README badges, attribution line, and Contributing/Security/License/Citation sections +### Fixed +- `ralph-loop.sh` no longer crashes on macOS (bash 3.2) with + `mem_limit_prefix[@]: unbound variable`. Empty-array expansions now use the + `${arr[@]:+"${arr[@]}"}` idiom, which is safe under `set -u` on bash < 4.4 + (macOS default) and expands identically to `"${arr[@]}"` when the RAM-limit + prefix is populated on Linux. + ### Changed - `NOTICE`, source headers and `CITATION.cff` declare **César Gallego Rodríguez** as the original author and copyright holder, with a link to the original diff --git a/ralph-loop.sh b/ralph-loop.sh index f588c20..596d602 100755 --- a/ralph-loop.sh +++ b/ralph-loop.sh @@ -305,7 +305,7 @@ run_tool() { if [ "$ralph_thinking" = false ]; then extra_flags=(-c 'model_reasoning_summary="none"' -c hide_agent_reasoning=true) fi - "${mem_limit_prefix[@]}" "$tool_command" exec "${tool_flags[@]}" \ + ${mem_limit_prefix[@]:+"${mem_limit_prefix[@]}"} "$tool_command" exec "${tool_flags[@]}" \ -m "$tool_model" \ -o "$current_console_output" \ -c "model_reasoning_effort=\"$tool_reasoning_effort\"" \ @@ -319,7 +319,7 @@ run_tool() { else env_prefix=(env -u CLAUDE_CODE_DISABLE_THINKING "CLAUDE_CODE_EFFORT_LEVEL=$tool_reasoning_effort") fi - "${mem_limit_prefix[@]}" "${env_prefix[@]}" "$tool_command" "${tool_flags[@]}" --model "$tool_model" --effort "$tool_reasoning_effort" -p <"$prompt_path" + ${mem_limit_prefix[@]:+"${mem_limit_prefix[@]}"} "${env_prefix[@]}" "$tool_command" "${tool_flags[@]}" --model "$tool_model" --effort "$tool_reasoning_effort" -p <"$prompt_path" ;; gemini) gemini_settings_dir=$(mktemp -d "$RALPH_LOCAL_DIR/gemini-settings.XXXXXX") || return 1 @@ -343,7 +343,7 @@ run_tool() { printf '}\n' } >"$gemini_settings_file" - "${mem_limit_prefix[@]}" \ + ${mem_limit_prefix[@]:+"${mem_limit_prefix[@]}"} \ env GEMINI_CLI_SYSTEM_SETTINGS_PATH="$gemini_settings_file" \ "$tool_command" "${tool_flags[@]}" --model ralph-selected <"$prompt_path" run_exit_code=$? @@ -354,7 +354,7 @@ run_tool() { # Devin reads the prompt from --prompt-file, not stdin (piping the prompt # makes it drop into REPL mode and panic). It has no reasoning/thinking # knob, so the capability tier only selects the model. -p is print mode. - "${mem_limit_prefix[@]}" "$tool_command" "${tool_flags[@]}" \ + ${mem_limit_prefix[@]:+"${mem_limit_prefix[@]}"} "$tool_command" "${tool_flags[@]}" \ --model "$tool_model" --prompt-file "$prompt_path" -p ;; esac diff --git a/tests/ralph-loop.bats b/tests/ralph-loop.bats index 1343125..a306b7e 100644 --- a/tests/ralph-loop.bats +++ b/tests/ralph-loop.bats @@ -52,6 +52,16 @@ teardown() { [[ "$output" == *"PROMPT_FILE must exist"* ]] } +@test "mem_limit_prefix expansions are safe under set -u (bash 3.2)" { + # Regression for the macOS bash 3.2 crash: expanding an empty array with + # "${arr[@]}" under set -u raises "unbound variable" on bash < 4.4. Every + # mem_limit_prefix expansion must use the ${arr[@]:+"${arr[@]}"} idiom. + # An unsafe expansion is a bare "${mem_limit_prefix[@]}" (quote preceded by + # whitespace); the safe idiom has the quote preceded by ':+'. + run grep -nE '[[:space:]]"\$\{mem_limit_prefix\[@\]\}"' "$SCRIPT" + [ "$status" -ne 0 ] +} + @test "stop.md present at startup: exits 0 without running an agent" { echo "do something" > prompt.md echo "stop" > stop.md