link-roles.sh больше не создаёт симлинки agent-memory (спека, раздел 11: симлинк делает память read-only), doctor не проверяет их; шаблоны workspace и role-repo описывают запасной вариант 6.5 (notes/agent-memory.md). В спеке разделы 2, 6.5, 8 получили указатель на раздел 11. Заодно --map без значения даёт русскую ошибку и exit 2. Refs #2 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzkPQWjfA7RpqYWkjnqJwt
60 lines
2.6 KiB
Bash
Executable File
60 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# claude-harness: симлинки из <workspace>/.claude/ в репозитории направлений (роли и агенты; память агентов симлинком не работает, спека раздел 11).
|
||
# Запуск: bash link-roles.sh [workspace] [--map <dir>=<role> ...]
|
||
# Источник пар «каталог → роль»: таблица | Каталог | Репозиторий | Роль | в <workspace>/CLAUDE.md (роли admin|analyst|qa)
|
||
# и/или пары --map. Идемпотентно. Обычные файлы на месте ссылок не трогает (ПРОПУЩЕН).
|
||
set -euo pipefail
|
||
WS="."; MAPS=()
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--map) [ $# -ge 2 ] || { echo "link-roles: --map требует <dir>=<role>" >&2; exit 2; }; MAPS+=("$2"); shift 2 ;;
|
||
*) WS="$1"; shift ;;
|
||
esac
|
||
done
|
||
cd "$WS"; WS="$(pwd)"
|
||
pairs=()
|
||
if [ -f CLAUDE.md ]; then
|
||
while IFS= read -r line; do pairs+=("$line"); done < <(
|
||
python3 - CLAUDE.md <<'PY'
|
||
import sys
|
||
for line in open(sys.argv[1], encoding="utf-8"):
|
||
if not line.startswith("|"): continue
|
||
cells = [c.strip() for c in line.strip().strip("|").split("|")]
|
||
if len(cells) < 3: continue
|
||
d, role = cells[0].rstrip("/"), cells[2]
|
||
if role in ("admin", "analyst", "qa") and d and not d.startswith("-"):
|
||
print(f"{d}={role}")
|
||
PY
|
||
)
|
||
fi
|
||
pairs+=("${MAPS[@]+"${MAPS[@]}"}")
|
||
[ ${#pairs[@]} -gt 0 ] || { echo "link-roles: нет пар каталог=роль (таблица в CLAUDE.md или --map)"; exit 0; }
|
||
mkdir -p .claude/roles .claude/agents
|
||
|
||
link() { # $1 = путь ссылки (относительно WS), $2 = цель (относительно каталога ссылки)
|
||
local l="$1" t="$2"
|
||
if [ -L "$l" ]; then
|
||
if [ "$(readlink "$l")" = "$t" ]; then echo " есть $l"; return 0; fi
|
||
rm "$l"
|
||
elif [ -e "$l" ]; then
|
||
echo " ПРОПУЩЕН $l — обычный файл/каталог, не симлинк; убери его вручную, если нужна ссылка"; return 0
|
||
fi
|
||
ln -s "$t" "$l"; echo " создан $l → $t"
|
||
}
|
||
|
||
for p in "${pairs[@]}"; do
|
||
d=${p%%=*}; r=${p#*=}; d=${d%/}
|
||
echo "$d ($r)"
|
||
[ -d "$d" ] || { echo " WARN каталог $d не найден"; continue; }
|
||
if [ -f "$d/.claude/roles/$r.md" ]; then
|
||
link ".claude/roles/$r.md" "../../$d/.claude/roles/$r.md"
|
||
else
|
||
echo " WARN нет $d/.claude/roles/$r.md — проектный файл роли не слинкован"
|
||
fi
|
||
for a in "$d"/.claude/agents/*.md; do
|
||
[ -f "$a" ] || continue
|
||
n=$(basename "$a" .md)
|
||
link ".claude/agents/$n.md" "../../$d/.claude/agents/$n.md"
|
||
done
|
||
done
|