forked from bchanot/claude
fix(portability): replace bash 4 builtins absent from macOS bash 3.2
macOS ships bash 3.2 as /bin/bash, which `#!/usr/bin/env bash` resolves to when no newer bash is on PATH. Two builtins the repo relies on do not exist there, and both failed SILENTLY: - `mapfile` in the three surgical-commit helpers left every array empty, so the scope guards passed on nothing (fail-OPEN) and the commits degraded to "nothing pending — no-op" while reporting success. deploy-commit.test.sh went 4/16; memory and doc commits simply never happened. - `declare -A` in the session-start hook errored on every session and left each plugin cost at 0, so the passive-budget warning could never fire. `_read_lines_into` is the portable equivalent of `mapfile`, space-safe and resetting its target first — expanding a never-assigned array trips `set -u` on bash < 4.4, which is how the empty arrays surfaced as "unbound variable". Plugin costs move to a `case`. source-scope.sh's header prescribed `mapfile` to its callers; it now shows the read loop, and its own test plus run-reconcile.sh stop using the builtin. deploy-commit 16/16, source-scope 34/34, run-reconcile 25 GREEN / 0 RED, session-start stderr empty.
This commit is contained in:
+22
-4
@@ -15,6 +15,19 @@
|
||||
# not just stderr, so it can't share rc 1's "nothing to do" (J4-22).
|
||||
set -uo pipefail
|
||||
|
||||
# bash 3.2 (macOS /bin/bash) predates the `mapfile` builtin; this is the portable
|
||||
# equivalent. Reads stdin's lines into the array named by $1, space-safe
|
||||
# (IFS= read -r). The array is reset first, so empty input yields an empty array
|
||||
# rather than a stale or unset one — `set -u` on bash < 4.4 trips on expanding
|
||||
# an array that was never assigned.
|
||||
_read_lines_into() {
|
||||
local _name="$1" _line
|
||||
eval "$_name=()"
|
||||
while IFS= read -r _line; do
|
||||
eval "$_name+=(\"\$_line\")"
|
||||
done
|
||||
}
|
||||
|
||||
_in_git_repo() { git rev-parse --git-dir >/dev/null 2>&1; }
|
||||
|
||||
_unsafe_state() { # 0 = unsafe
|
||||
@@ -48,7 +61,8 @@ _in_git_repo || { echo "deploy-commit: not a git repo" >&2; exit 2; }
|
||||
case "$cmd" in
|
||||
pending)
|
||||
[ "$#" -gt 0 ] || { echo "deploy-commit: pending needs file args" >&2; exit 2; }
|
||||
mapfile -t violations < <(_scope_violations "$@")
|
||||
violations=()
|
||||
_read_lines_into violations < <(_scope_violations "$@")
|
||||
if [ "${#violations[@]}" -gt 0 ]; then
|
||||
{ echo "deploy-commit: REFUSED — path(s) outside .claude/deploy/ allowlist:";
|
||||
printf ' - %s\n' "${violations[@]}";
|
||||
@@ -59,21 +73,25 @@ case "$cmd" in
|
||||
commit)
|
||||
msg="${1:-}"; shift || true
|
||||
[ -n "$msg" ] && [ "$#" -gt 0 ] || { echo "deploy-commit: commit needs <msg> <file>..." >&2; exit 2; }
|
||||
mapfile -t violations < <(_scope_violations "$@")
|
||||
violations=()
|
||||
_read_lines_into violations < <(_scope_violations "$@")
|
||||
if [ "${#violations[@]}" -gt 0 ]; then
|
||||
{ echo "deploy-commit: REFUSED — path(s) outside .claude/deploy/ allowlist:";
|
||||
printf ' - %s\n' "${violations[@]}";
|
||||
echo "deploy-commit: NOTHING committed. Caller must pass only .claude/deploy/ files."; } >&2
|
||||
exit 4
|
||||
fi
|
||||
mapfile -t ignored_paths < <(for p in "$@"; do _ignored "$p" && printf '%s\n' "$p"; done)
|
||||
ignored_paths=()
|
||||
_read_lines_into ignored_paths \
|
||||
< <(for p in "$@"; do _ignored "$p" && printf '%s\n' "$p"; done)
|
||||
if [ "${#ignored_paths[@]}" -gt 0 ]; then
|
||||
{ echo "deploy-commit: REFUSED — path(s) are git-ignored and will NOT persist; \`.claude/deploy/\` must be committable in this project:";
|
||||
printf ' - %s\n' "${ignored_paths[@]}"; } >&2
|
||||
exit 5
|
||||
fi
|
||||
_unsafe_state && { echo "deploy-commit: unsafe git state (detached/merge/rebase) — not committing" >&2; exit 3; }
|
||||
mapfile -t changed < <(_changed_only "$@")
|
||||
changed=()
|
||||
_read_lines_into changed < <(_changed_only "$@")
|
||||
[ "${#changed[@]}" -gt 0 ] || exit 1
|
||||
git add -- "${changed[@]}"
|
||||
if git diff --cached --quiet -- "${changed[@]}"; then
|
||||
|
||||
Reference in New Issue
Block a user