feat(install): роли, skill /role, briefing, role-hint, link-roles; --check видит их

Refs #2

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzkPQWjfA7RpqYWkjnqJwt
This commit is contained in:
Andrey Epifancev 2026-10-12 00:37:08 +04:00
parent 0e984a096e
commit 24b8333bf5
2 changed files with 41 additions and 4 deletions

View File

@ -24,6 +24,12 @@ check() {
if [ -f "$CC/settings.json" ] && grep -q 'codegraph prompt-hook' "$CC/settings.json"; then
echo " WARN codegraph prompt-hook в settings.json — рекомендуется отключить на время пилота"
fi
echo "== Установленная часть обвязки ($CC)"
for f in CLAUDE.md hooks/guard-main.sh hooks/require-plan.sh hooks/harness-check.sh hooks/role-hint.sh \
roles/dev.md roles/admin.md roles/analyst.md roles/qa.md skills/role/SKILL.md agents/briefing.md \
harness/adopt-project.sh harness/new-project.sh harness/link-roles.sh skills/harness-doctor/SKILL.md; do
[ -f "$CC/$f" ] && echo " ok $f" || { echo " MISS $f (bash install.sh)"; ok=1; }
done
return $ok
}
@ -39,15 +45,21 @@ fi
cp "$HERE/global/CLAUDE.md" "$CC/CLAUDE.md"
# 2. Хуки
cp "$HERE/hooks/guard-main.sh" "$HERE/hooks/require-plan.sh" "$HERE/hooks/harness-check.sh" "$CC/hooks/"
cp "$HERE/hooks/guard-main.sh" "$HERE/hooks/require-plan.sh" "$HERE/hooks/harness-check.sh" "$HERE/hooks/role-hint.sh" "$CC/hooks/"
# 2a. Скрипты бутстрапа проекта — агент запускает их из сессии
mkdir -p "$CC/harness"
cp -R "$HERE/adopt-project.sh" "$HERE/new-project.sh" "$HERE/project-template" "$CC/harness/"
rm -rf "$CC/harness/project-template"
cp -R "$HERE/adopt-project.sh" "$HERE/new-project.sh" "$HERE/link-roles.sh" "$HERE/project-template" "$CC/harness/"
chmod +x "$CC/harness/"*.sh
# 2b. Skill диагностики
mkdir -p "$CC/skills"
rm -rf "$CC/skills/harness-doctor" && cp -R "$HERE/skills/harness-doctor" "$CC/skills/harness-doctor"
chmod +x "$CC/skills/harness-doctor/scripts/"*.sh
# 2c. Роли, skill /role, агент briefing
mkdir -p "$CC/roles" "$CC/skills/role" "$CC/agents"
cp "$HERE/roles/"*.md "$CC/roles/"
cp "$HERE/skills/role/SKILL.md" "$CC/skills/role/SKILL.md"
cp "$HERE/agents/briefing.md" "$CC/agents/briefing.md"
chmod +x "$CC/hooks/"*.sh
# 3. caveman off by default
@ -68,7 +80,8 @@ def ours(entry):
pre[:] = [e for e in pre if not ours(e)]
pre.extend(h["hooks"]["PreToolUse"])
ss = hooks.setdefault("SessionStart", [])
ss[:] = [e for e in ss if not any("harness-check.sh" in x.get("command","") for x in e.get("hooks",[]))]
ours_ss = ("harness-check.sh", "role-hint.sh")
ss[:] = [e for e in ss if not any(any(n in x.get("command","") for n in ours_ss) for x in e.get("hooks",[]))]
ss.extend(h["hooks"]["SessionStart"])
for ev in ("SessionStart","PreCompact"):
if ev in hooks:
@ -80,6 +93,6 @@ json.dump(s, open(sp,"w"), ensure_ascii=False, indent=2)
print("settings.json: hooks merged")
PY
echo "done: $CC/CLAUDE.md, $CC/skills/harness-doctor, $CC/hooks/{guard-main,require-plan,harness-check}.sh, $CC/harness/, ~/.config/caveman/config.json"
echo "done: $CC/CLAUDE.md, $CC/skills/harness-doctor, $CC/hooks/{guard-main,require-plan,harness-check,role-hint}.sh, $CC/roles/, $CC/skills/role, $CC/agents/briefing.md, $CC/harness/, ~/.config/caveman/config.json"
echo "Плагины Claude Code ставятся вручную: /plugin install superpowers@claude-plugins-official"
check || true

24
tests/test-install.sh Normal file
View File

@ -0,0 +1,24 @@
# install.sh: новые файлы ставятся, повторный запуск не дублирует хуки, --check их видит.
export HOME="$TMP/home"; export CLAUDE_CONFIG_DIR="$TMP/home/.claude"; mkdir -p "$CLAUDE_CONFIG_DIR"
echo '{"hooks":{"SessionStart":[{"matcher":"startup","hooks":[{"type":"command","command":"\"$HOME/.claude/hooks/harness-check.sh\""}]}]}}' > "$CLAUDE_CONFIG_DIR/settings.json"
bash "$ROOT/install.sh" >/dev/null 2>&1; bash "$ROOT/install.sh" >/dev/null 2>&1
CC="$CLAUDE_CONFIG_DIR"
for r in dev admin analyst qa; do assert_file "roles/$r.md установлен" "$CC/roles/$r.md"; done
assert_file "skills/role/SKILL.md установлен" "$CC/skills/role/SKILL.md"
assert_file "agents/briefing.md установлен" "$CC/agents/briefing.md"
assert_file "hooks/role-hint.sh установлен" "$CC/hooks/role-hint.sh"
assert_eq "hooks/role-hint.sh исполняемый" "$([ -x "$CC/hooks/role-hint.sh" ] && echo x)" "x"
assert_file "harness/link-roles.sh установлен" "$CC/harness/link-roles.sh"
assert_file "harness/project-template/workspace" "$CC/harness/project-template/workspace/CLAUDE.md"
assert_file "harness/project-template/role-repo" "$CC/harness/project-template/role-repo/ROLE.md"
cnt=$(python3 -c "import json,sys; s=json.load(open(sys.argv[1])); print(sum(1 for e in s['hooks']['SessionStart'] for h in e.get('hooks',[]) if 'role-hint.sh' in h['command']))" "$CC/settings.json")
assert_eq "role-hint.sh в settings.json один раз после двух установок" "$cnt" "1"
cnt=$(python3 -c "import json,sys; s=json.load(open(sys.argv[1])); print(sum(1 for e in s['hooks']['SessionStart'] for h in e.get('hooks',[]) if 'harness-check.sh' in h['command']))" "$CC/settings.json")
assert_eq "harness-check.sh в settings.json один раз" "$cnt" "1"
out=$(bash "$ROOT/install.sh" --check 2>&1)
assert_grep "--check: roles" 'roles/' <(printf '%s' "$out")
assert_grep "--check: skill role" 'skills/role' <(printf '%s' "$out")
assert_grep "--check: agent briefing" 'agents/briefing' <(printf '%s' "$out")
rm "$CC/agents/briefing.md"
out=$(bash "$ROOT/install.sh" --check 2>&1)
assert_grep "--check: MISS briefing" 'MISS +.*briefing' <(printf '%s' "$out")