fix(b3): eliminate command -v herdr bash function false positive in preflight checks (100% PASS)

This commit is contained in:
2026-08-06 21:59:58 +09:00
parent cdeb9e2c8f
commit 0f6dd8ba8b
9 changed files with 818 additions and 14 deletions
+43 -1
View File
@@ -50,9 +50,51 @@ _HERDR_SKILLS_BIN_PATTERN="${_HERDR_SKILLS_BIN_PATTERN:-/.agents/skills/.bin}"
HERDR_SESSION_NAME="${HERDR_SESSION_NAME:-default}"
_canonical_file() {
local p="$1" t d b i=0
while [ -L "$p" ] && [ "$i" -lt 40 ]; do
t="$(readlink "$p" 2>/dev/null)" || break
case "$t" in
/*) p="$t" ;;
*) p="$(dirname "$p")/$t" ;;
esac
i=$((i + 1))
done
d="$(cd -P "$(dirname "$p")" 2>/dev/null && pwd -P)" || return 1
b="$(basename "$p")"
printf '%s/%s\n' "$d" "$b"
}
_is_shim_path() {
case "/$1/" in
*"/.mam/shim/"*|*-shim/*|*"$_HERDR_SHIM_DIR_PATTERN"*|*"$_HERDR_SKILLS_BIN_PATTERN"/*)
return 0 ;;
esac
return 1
}
_resolve_real_herdr_path() {
_REAL_HERDR_PATH="herdr"
local dir cand save_ifs="$IFS" real_path=""
IFS=:
for dir in $PATH; do
[ -n "$dir" ] || continue
_is_shim_path "$dir" && continue
[ -x "$dir/herdr" ] || continue
cand="$(_canonical_file "$dir/herdr" 2>/dev/null)" || cand="$dir/herdr"
[ -n "$cand" ] || cand="$dir/herdr"
_is_shim_path "$cand" && continue
real_path="$dir/herdr"
break
done
IFS="$save_ifs"
[ -n "$real_path" ] || return 1
_REAL_HERDR_PATH="$real_path"
export _REAL_HERDR_PATH
printf '%s\n' "$real_path"
}
has_real_herdr() {
_resolve_real_herdr_path >/dev/null 2>&1
}
_init_herdr_isolation() {
@@ -34,7 +34,10 @@ Before doing anything, verify the environment:
```bash
# 1) herdr available and isolated server status
command -v herdr || { echo "ERROR: herdr not installed"; exit 1; }
# Use lib.sh's has_real_herdr, NOT `command -v herdr` / `type -P herdr`: once
# lib.sh is sourced the former matches its herdr() function and the latter
# matches the .mam/shim wrapper, so both pass on a host with no herdr (B-3).
has_real_herdr || { echo "ERROR: herdr not installed"; exit 1; }
echo "Herdr session name: ${HERDR_SESSION_NAME:-default}"
# 2) claude / agy available
@@ -81,7 +81,9 @@ fi
[ -n "$AGENT" ] || { echo "ERROR: --agent required" >&2; usage; exit 2; }
[ -n "$ROLE" ] || { echo "ERROR: --role required" >&2; usage; exit 2; }
[ -d "$WORKSPACE" ] || { echo "ERROR: workspace $WORKSPACE not a directory" >&2; exit 1; }
command -v herdr >/dev/null || type -P herdr >/dev/null || { echo "ERROR: herdr not installed" >&2; exit 1; }
# B-3: `command -v herdr` matches lib.sh's herdr() function and `type -P herdr`
# matches the .mam/shim wrapper, so both pass with no herdr installed.
has_real_herdr || { echo "ERROR: herdr not installed" >&2; exit 1; }
command -v "$AGENT" >/dev/null || { echo "ERROR: $AGENT CLI not in PATH" >&2; exit 1; }
# Auth Check (OAuth check for agy, loggedIn check for claude, status for hermes)
@@ -445,7 +445,8 @@ run_agent() {
return
fi
if ! command -v herdr >/dev/null 2>&1; then
# B-3: must probe for the real binary, not the herdr() function / shim wrapper.
if ! has_real_herdr; then
echo "ERROR: this skill requires herdr (interactive agent sessions)." >&2
echo " Ensure herdr is installed and executable." >&2
return 1
@@ -28,11 +28,15 @@ This is the "what's running right now?" answer — faster than dispatching `mult
## Pre-flight
```bash
command -v herdr
has_real_herdr || { echo "ERROR: herdr not installed"; exit 1; } # lib.sh helper (B-3)
command -v python3
test -f .mam/agent-sessions.yaml
```
> `command -v herdr` and `type -P herdr` both report success even when herdr is
> not installed — they match lib.sh's `herdr()` function and the `.mam/shim`
> wrapper respectively. Always use `has_real_herdr`.
If `agent-sessions.yaml` doesn't exist or is malformed → print clear error, exit 1. **Do not create it.** (Use `multi-agent-mux-create` first.)
## Workflow