claude-harness/new-project.sh
andrey.epifantsev 897fa0f3a7 feat: install.sh ставит allow-правила цикла фичи, --no-permissions для отказа (#24, 0.5.0)
Пересмотр решения владельца 2: allow-правила (git worktree, git branch
-m/-D, push фичевых и chore-веток, push --delete, tea issues/pulls
create/list/edit/comments) ставит install.sh в ~/.claude/settings.json,
а не владелец руками. Список — global/permissions.json; merge и push в
main в нём нет. Правила только дописываются, чужие не трогаются; копия
списка — ~/.claude/harness/permissions.json для doctor.sh.

- install.sh: шаг 5 — слияние permissions.allow; --no-permissions;
  неизвестный аргумент — ошибка; --check показывает permissions N/M.
- doctor.sh, «Машина»: ok / WARN со списком недостающих / MISS.
- adopt/new-project: строка push --delete — для --no-permissions.
- harness-doctor: агент чинит install.sh --no-permissions, права ставит
  владелец (иначе обход отказа классификатора auto mode).
- EnterWorktree не входит: вход в worktree вне .claude/worktrees/
  спрашивает подтверждение при любых правилах (#25).
- README, HARNESS.md, roles/dev.md, CLAUDE.md, ретро (пометка о
  пересмотре решения 2), CHANGELOG 0.5.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 00:01:57 +04:00

78 lines
4.5 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# claude-harness: каркас нового проекта под обвязку.
# Запуск: bash new-project.sh <папка> [ssh-url репозитория в Gitea]
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
# Режим workspace: bash new-project.sh --workspace <папка> [--role admin] [--role qa] [--role analyst]
if [ "${1:-}" = "--workspace" ]; then
DIR="${2:?usage: new-project.sh --workspace <dir> [--role <r> ...]}"; shift 2
ROLES=()
while [ $# -gt 0 ]; do case "$1" in --role) ROLES+=("$2"); shift 2 ;; *) echo "ERR: неизвестный аргумент $1"; exit 1 ;; esac; done
mkdir -p "$DIR" && cd "$DIR"; NAME="$(basename "$(pwd)")"
[ -f CLAUDE.md ] || sed "s/{{PROJECT_NAME}}/$NAME/g" "$HERE/project-template/workspace/CLAUDE.md" > CLAUDE.md
mkdir -p .claude/roles
[ -e .claude/roles/dev.md ] || sed "s/{{PROJECT_NAME}}/$NAME/g" "$HERE/project-template/workspace/roles/dev.md" > .claude/roles/dev.md
for r in "${ROLES[@]+"${ROLES[@]}"}"; do
case "$r" in admin|analyst|qa) ;; *) echo "ERR: роль $r не из admin|analyst|qa"; exit 1 ;; esac
d="$r"; [ "$r" = analyst ] && d="analysis"
if [ -d "$d/.git" ]; then echo "$d/: уже git, не трогаю"; continue; fi
mkdir -p "$d/.claude/roles" "$d/notes"
sed -e "s/{{PROJECT_NAME}}/$NAME/g" -e "s/{{ROLE}}/$r/g" -e "s#{{DIR}}#$d#g" "$HERE/project-template/role-repo/CLAUDE.md" > "$d/CLAUDE.md"
sed -e "s/{{PROJECT_NAME}}/$NAME/g" -e "s/{{ROLE}}/$r/g" -e "s#{{DIR}}#$d#g" "$HERE/project-template/role-repo/ROLE.md" > "$d/.claude/roles/$r.md"
cp "$HERE/project-template/role-repo/notes/README.md" "$d/notes/README.md"
echo "$r" > "$d/.claude/role"
git -C "$d" init -q -b main && git -C "$d" add -A && git -C "$d" commit -qm "chore: репозиторий направления $r (claude-harness)"
# строка таблицы: заменить заготовку {{owner/repo-<r>}} на имя каталога, если заготовка есть
sed -i.bak "s#| $d/ | {{owner/repo-[a-z]*}} | $r |#| $d/ | <owner>/$NAME-$d | $r |#" CLAUDE.md && rm -f CLAUDE.md.bak
echo "$d/: репозиторий направления $r создан"
done
bash "$HERE/link-roles.sh" "$(pwd)"
cat <<MSG
Workspace $NAME готов. Дальше:
1. Заполни {{...}} в CLAUDE.md и в .claude/roles/dev.md; в репозиториях направлений — .claude/roles/<r>.md.
2. Заведи репозитории направлений в Gitea и добавь remote (tea repos create …; git remote add origin …).
3. Если обвязка ставилась с --no-permissions: разреши агенту удалять ветки на сервере (чеклист закрытия, п. 4) — строка в .claude/settings.json → permissions.allow:
"Bash(git push origin --delete:*)"
4. cd $(pwd) && claude -n "dev …"
MSG
exit 0
fi
DIR="${1:?usage: new-project.sh <dir> [git-remote-url]}"
REMOTE="${2:-}"
NAME="$(basename "$DIR")"
mkdir -p "$DIR" && cd "$DIR"
[ -d .git ] || git init -b main
sed "s/{{PROJECT_NAME}}/$NAME/" "$HERE/project-template/CLAUDE.md" > CLAUDE.md
cp "$HERE/project-template/ARCHITECTURE.md" ARCHITECTURE.md
cp "$HERE/project-template/gitignore" .gitignore
mkdir -p tests/fixtures docs/superpowers/plans
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 не удался"
fi
git add -A
git commit -qm "chore: bootstrap project skeleton (claude-harness)" || true
if [ -n "$REMOTE" ]; then
git remote get-url origin >/dev/null 2>&1 || git remote add origin "$REMOTE"
git push -u origin main
fi
cat <<MSG
Проект $NAME готов. Дальше:
1. Заполните {{...}} в CLAUDE.md и ARCHITECTURE.md.
2. Положите первые фикстуры в tests/fixtures/.
3. Если обвязка ставилась с --no-permissions: разрешите агенту удалять ветки на сервере (чеклист закрытия, п. 4) — строка в .claude/settings.json → permissions.allow:
"Bash(git push origin --delete:*)"
4. cd $DIR && claude
«Хочу сделать ... Описание и ограничения в CLAUDE.md. Давай начнём.»
MSG