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:
parent
0e984a096e
commit
24b8333bf5
21
install.sh
21
install.sh
@ -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
24
tests/test-install.sh
Normal 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")
|
||||
Loading…
x
Reference in New Issue
Block a user