С Claude Code 2.1.206 вход в worktree вне .claude/worktrees/ спрашивает подтверждение при любых allow-правилах. EnterWorktree с именем создаёт worktree в <repo>/.claude/worktrees/<slug> на ветке worktree-<slug> от origin/main и входит без вопроса; ветка переименовывается в feat/<id>-<slug>. - roles/dev.md: «Исполнение» — EnterWorktree с именем; п. 1 закрытия — archive-<id>; п. 4 — ExitWorktree (keep) снимает блокировку сессии, затем git worktree remove и branch -D. - .claude/worktrees/ в .gitignore: adopt-project.sh, project-template, этот репозиторий; doctor.sh — WARN, если не игнорируется. - Спека hook-guards: сценарии «worktree внутри репозитория» для guard-main и require-plan; тесты закрепляют уже верное поведение. - HARNESS.md (шаг 4, п. 4, подтверждения), SKILL.md, CHANGELOG 0.5.1, CLAUDE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
5.1 KiB
Bash
Executable File
81 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# claude-harness: подключение обвязки к СУЩЕСТВУЮЩЕМУ репозиторию.
|
||
# Запуск из терминала (не из Claude Code): bash adopt-project.sh [папка] [--no-merge] [--push]
|
||
# Делает всё на ветке chore/harness-init и по умолчанию вливает её в main fast-forward.
|
||
set -euo pipefail
|
||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||
# Режим workspace (каталог не git, рядом репозитории направлений): bash adopt-project.sh --workspace [папка]
|
||
if [ "${1:-}" = "--workspace" ]; then
|
||
cd "${2:-.}"; NAME="$(basename "$(pwd)")"
|
||
if [ -f CLAUDE.md ]; then echo "CLAUDE.md: есть, не трогаю"
|
||
else sed "s/{{PROJECT_NAME}}/$NAME/g" "$HERE/project-template/workspace/CLAUDE.md" > CLAUDE.md; echo "CLAUDE.md: создан из шаблона workspace — заполни {{...}} и таблицу репозиториев"; fi
|
||
mkdir -p .claude/roles
|
||
if [ -e .claude/roles/dev.md ]; then echo ".claude/roles/dev.md: есть, не трогаю"
|
||
else sed "s/{{PROJECT_NAME}}/$NAME/g" "$HERE/project-template/workspace/roles/dev.md" > .claude/roles/dev.md; echo ".claude/roles/dev.md: заготовка"; fi
|
||
bash "$HERE/link-roles.sh" "$(pwd)"
|
||
cat <<MSG
|
||
|
||
Workspace $NAME подключён. Дальше:
|
||
1. Заполни таблицу репозиториев в CLAUDE.md и перезапусти: bash $HERE/link-roles.sh $(pwd)
|
||
2. Если обвязка ставилась с --no-permissions: разреши агенту удалять ветки на сервере (чеклист закрытия, п. 4) — строка в .claude/settings.json → permissions.allow:
|
||
"Bash(git push origin --delete:*)"
|
||
3. Сессии: claude -n "dev …" | "admin …" | "qa …" | "analyst …" из этого каталога.
|
||
MSG
|
||
exit 0
|
||
fi
|
||
DIR="."; MERGE=1; PUSH=0
|
||
for a in "$@"; do case "$a" in --no-merge) MERGE=0;; --push) PUSH=1;; *) DIR="$a";; esac; done
|
||
cd "$DIR"
|
||
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "ERR: $DIR — не git-репозиторий"; exit 1; }
|
||
[ -z "$(git status --porcelain)" ] || { echo "ERR: рабочее дерево не чистое — закоммить или спрячь изменения"; exit 1; }
|
||
NAME="$(basename "$(git rev-parse --show-toplevel)")"
|
||
BASE="$(git branch --show-current)"
|
||
[ -n "$BASE" ] || { echo "ERR: detached HEAD"; exit 1; }
|
||
BR=chore/harness-init
|
||
git switch -c "$BR" >/dev/null
|
||
|
||
# CLAUDE.md: свой — дописать секцию харнеса; нет — из шаблона
|
||
if [ -f CLAUDE.md ]; then
|
||
grep -q '^## OpenSpec и superpowers' CLAUDE.md || { printf '\n' >> CLAUDE.md; cat "$HERE/project-template/CLAUDE.harness-section.md" >> CLAUDE.md; echo "CLAUDE.md: добавлена секция «OpenSpec и superpowers»"; }
|
||
else
|
||
sed "s/{{PROJECT_NAME}}/$NAME/" "$HERE/project-template/CLAUDE.md" > CLAUDE.md
|
||
echo "CLAUDE.md: создан из шаблона — заполни {{...}} (или попроси агента описать проект по коду на отдельной ветке)"
|
||
fi
|
||
[ -f ARCHITECTURE.md ] || { cp "$HERE/project-template/ARCHITECTURE.md" ARCHITECTURE.md; echo "ARCHITECTURE.md: заготовка"; }
|
||
|
||
# .gitignore: только строки обвязки
|
||
touch .gitignore
|
||
for line in '.superpowers/' '.bounded' '.claude/worktrees/' '.DS_Store'; do
|
||
grep -qxF "$line" .gitignore || echo "$line" >> .gitignore
|
||
done
|
||
mkdir -p docs/superpowers/plans && touch docs/superpowers/plans/.gitkeep
|
||
|
||
if command -v openspec >/dev/null 2>&1; then
|
||
[ -d openspec ] || openspec init --tools claude 2>/dev/null || openspec init
|
||
else echo "WARN: openspec не установлен (npm i -g @fission-ai/openspec)"; fi
|
||
if command -v codegraph >/dev/null 2>&1; then
|
||
[ -d .codegraph ] || codegraph init >/dev/null 2>&1 || echo "WARN: codegraph init не удался"
|
||
else echo "WARN: codegraph не установлен"; fi
|
||
|
||
git add -A
|
||
if git diff --cached --quiet; then
|
||
echo "Нечего менять: обвязка уже подключена"; git switch "$BASE" >/dev/null; git branch -d "$BR" >/dev/null; exit 0
|
||
fi
|
||
git commit -qm "chore: claude harness bootstrap"
|
||
if [ "$MERGE" = 1 ]; then
|
||
git switch "$BASE" >/dev/null && git merge --ff-only "$BR" >/dev/null && git branch -d "$BR" >/dev/null
|
||
echo "Влито в $BASE fast-forward."
|
||
[ "$PUSH" = 1 ] && git push origin "$BASE"
|
||
else
|
||
echo "Ветка $BR оставлена, в $BASE не влита."
|
||
[ "$PUSH" = 1 ] && git push -u origin "$BR"
|
||
fi
|
||
cat <<MSG
|
||
|
||
Проект $NAME подключён к обвязке. Дальше:
|
||
1. Если обвязка ставилась с --no-permissions: разреши агенту удалять ветки на сервере (чеклист закрытия, п. 4) — строка в .claude/settings.json → permissions.allow:
|
||
"Bash(git push origin --delete:*)"
|
||
2. cd $(pwd) && claude
|
||
«Опиши проект в CLAUDE.md по коду: разделы «Что это», «Стек», «Архитектура», «Команды». Bounded-задача.»
|
||
MSG
|