From 04da103ed6ab3d392a45a83b72dd40f5aa683cec Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Mon, 6 Jul 2026 19:39:19 +0200 Subject: [PATCH] job4: seam profile.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Env-var-only seams (§3.2), zero logic change (diff is only the seam lines): REPO gains PROFILE_REPO_OVERRIDE (cd -P already correct, no bugfix needed here — only toggle-external.sh had the logical-cd bug); CLAUDE_BIN="${CLAUDE_BIN:-claude}" replaces the 8 bare `claude` invocation sites (4 `command -v claude` checks + `claude plugin list`/ `plugin enable`/`plugin disable`/`mcp list`). The advisory `info "..."` hint strings that tell a HUMAN what to type stay literal "claude" — those aren't invocations. Unlocks (BACKLOG, not built in this job): a hermetic profile.sh suite via HOME/REPO/CLAUDE_BIN injection, promoting J4-19 from UNTESTABLE. Verified: bash -n clean, shellcheck clean, `profile.sh current`/`list` behaviorally unchanged against the real repo, full `make test` exit 0. --- lib/profile.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/profile.sh b/lib/profile.sh index 90982c1..3f20971 100755 --- a/lib/profile.sh +++ b/lib/profile.sh @@ -42,7 +42,8 @@ # ============================================================ set -euo pipefail -REPO="$(cd -P "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +REPO="${PROFILE_REPO_OVERRIDE:-$(cd -P "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +CLAUDE_BIN="${CLAUDE_BIN:-claude}" SKILLS_DIR="$REPO/skills" DISABLED_DIR="$REPO/skills-disabled" GSTACK_SRC="$REPO/skills-external/gstack" # gstack submodule — source of truth for gstack skills @@ -201,9 +202,9 @@ skill_status() { plugin|plugin@*) # `claude plugin list` is the source of truth — settings.json may be # ahead of or behind reality if the user toggled outside this tool. - if command -v claude >/dev/null 2>&1; then + if command -v "$CLAUDE_BIN" >/dev/null 2>&1; then # Match the plugin block by name then check Status line - if claude plugin list 2>/dev/null \ + if "$CLAUDE_BIN" plugin list 2>/dev/null \ | awk -v p="$skill" ' /^[[:space:]]*❯ '"$skill"'@/ { found=1; next } found && /Status:/ { print; exit } @@ -218,8 +219,8 @@ skill_status() { fi ;; mcp) - if command -v claude >/dev/null 2>&1 && \ - claude mcp list 2>/dev/null | grep -q "^${skill}"; then + if command -v "$CLAUDE_BIN" >/dev/null 2>&1 && \ + "$CLAUDE_BIN" mcp list 2>/dev/null | grep -q "^${skill}"; then echo "enabled" else echo "disabled" @@ -279,8 +280,8 @@ enable_skill() { local marketplace="${type#plugin@}" if [ "$(skill_status "$skill" "$type")" = "enabled" ]; then : # already on - elif command -v claude >/dev/null 2>&1; then - if claude plugin enable "${skill}@${marketplace}" 2>&1 | grep -qiE "enabled|already"; then + elif command -v "$CLAUDE_BIN" >/dev/null 2>&1; then + if "$CLAUDE_BIN" plugin enable "${skill}@${marketplace}" 2>&1 | grep -qiE "enabled|already"; then ok "enabled plugin: ${skill}@${marketplace}" else warn "could not enable plugin: ${skill}@${marketplace}" @@ -354,8 +355,8 @@ disable_skill() { done if [ "$(skill_status "$skill" "$type")" = "disabled" ]; then : # already off - elif command -v claude >/dev/null 2>&1; then - if claude plugin disable "$key" 2>&1 | grep -qiE "disabled|already"; then + elif command -v "$CLAUDE_BIN" >/dev/null 2>&1; then + if "$CLAUDE_BIN" plugin disable "$key" 2>&1 | grep -qiE "disabled|already"; then ok "disabled plugin: $key" else warn "could not disable plugin: $key"