From 1f5a1368adbad9d3bbfb0b5ea39401e01d19e914 Mon Sep 17 00:00:00 2001 From: Gorakh Nath Yadav Date: Thu, 30 Jul 2026 16:58:19 +0530 Subject: [PATCH] fix(installers): correct exit status on macOS bash 3.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS /bin/bash (3.2), the exit status of the last command in an EXIT trap becomes the script's exit status. cleanup_on_exit ends with a '[ -f ... ] && rm' test that legitimately fails when TEMP_FILES is empty, so every installer exited 1 even on success — breaking any set -e wrapper or CI that checks the curl|bash exit code. Linux bash 4/5 preserves the original status, which is why this went unnoticed. Capture $? on trap entry and re-exit with it, preserving both success (0) and real failure codes. Verified on macOS bash 3.2 across the codex, claude-code, and github-copilot installers. --- ai/lib/common.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ai/lib/common.sh b/ai/lib/common.sh index 2464625..d8c0707 100644 --- a/ai/lib/common.sh +++ b/ai/lib/common.sh @@ -127,6 +127,11 @@ cleanup_on_error() { # but install_error_trap below replaces the EXIT trap — so we re-do the # bootstrap cleanup here. macOS mktemp writes to /var/folders/, Linux to /tmp/. cleanup_on_exit() { + # Capture the script's real exit status and re-exit with it below. On + # bash 3.2 (macOS /bin/bash) the status of the LAST command in an EXIT + # trap silently becomes the script's exit status — without this, the + # trailing `[ -f ... ]` test made every installer exit 1 even on success. + local exit_code=$? if [ -n "${COMMON_SH:-}" ] && [ -f "$COMMON_SH" ]; then case "$COMMON_SH" in /tmp/*|/var/folders/*) rm -f "$COMMON_SH" ;; @@ -135,6 +140,7 @@ cleanup_on_exit() { for f in "${TEMP_FILES[@]:-}"; do [ -f "$f" ] && rm -f "$f" done + exit "$exit_code" } # Caller installs the trap via: install_error_trap