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:
2026-09-13 17:20:57 -04:00
parent a53a5a26a8
commit f3919b6ace
7 changed files with 82 additions and 24 deletions
+14 -10
View File
@@ -102,17 +102,21 @@ esac
_passive_t=0
detect_superpowers 2>/dev/null && _passive_t=$((_passive_t + 800))
# Token costs for toggle plugins — map display name to cost
declare -A _plugin_costs=(
[gstack]=2750
[ui-ux-pro-max]=400
[plugin-dev]=100
[context7]=200
[graphify]=300
)
# Token cost per toggle plugin, by display name. A `case`, not an associative
# array: macOS ships bash 3.2 as /bin/bash, where `declare -A` is rejected —
# every cost then read as 0 and the budget warning below never fired.
_plugin_cost() {
case "$1" in
gstack) echo 2750 ;;
ui-ux-pro-max) echo 400 ;;
plugin-dev) echo 100 ;;
context7) echo 200 ;;
graphify) echo 300 ;;
*) echo 0 ;;
esac
}
for _p in "${TOGGLE_ACTIVE[@]}"; do
_cost="${_plugin_costs[$_p]:-0}"
_passive_t=$((_passive_t + _cost))
_passive_t=$((_passive_t + $(_plugin_cost "$_p")))
done
_budget_pct=$((_passive_t * 100 / _budget))
if [ "$_budget_pct" -gt 50 ]; then