#!/usr/bin/env bash # claude-harness: симлинки из /.claude/ в репозитории направлений (роли и агенты; память агентов симлинком не работает, спека раздел 11). # Запуск: bash link-roles.sh [workspace] [--map = ...] # Источник пар «каталог → роль»: таблица | Каталог | Репозиторий | Роль | в /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 требует =" >&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