* feat(spec): add project-template skill init and check flow * refactor(spec): remove repo-init migrate references to project-template * test(spec): structural tests for project-template skill and command * fix(test): wrap long lines and use non_templated var in project template tests * fix(ci): reformat test_project_template_skill.py for ruff format --------- Co-authored-by: opencode-agent <agent@opencode.local>
340 lines
No EOL
17 KiB
Markdown
340 lines
No EOL
17 KiB
Markdown
---
|
||
name: project-template
|
||
description: Init new project from cookiecutter template by type + GitHub remote + branch protection, or audit existing project via project-status. Replaces repo-init. Also when user says "новый проект", "инициализируй репо", "проверь проект", "create project", "project template".
|
||
---
|
||
|
||
# Project Template
|
||
|
||
Два flow: **init** (новый проект: cookiecutter по типу + GitHub remote) и
|
||
**check** (существующий проект: project-status аудит с рекомендациями).
|
||
|
||
Замена монолитному `repo-init`: Phase A (GitHub remote + branch protection)
|
||
мигрирована без изменений, Phase B (ручное scaffolding) заменена на cookiecutter
|
||
шаблоны из `.opencode/templates/<type>/` (issue #229 / PR #235). Проверка
|
||
архитектуры — через `project-status` tool (issue #228 / PR #233).
|
||
|
||
## ПРОТОКОЛ (ЖЁСТКО)
|
||
|
||
1. Определи flow (вопрос юзеру, см. ниже).
|
||
2. init flow → шаги 1-6 (см. ниже).
|
||
3. check flow → шаги 1-3 (см. ниже).
|
||
4. После каждого шага → 1 строка прогресса юзеру (формат: `✅ <step> — <done>`).
|
||
|
||
### ЗАПРЕЩЕНО
|
||
|
||
- Запускать cookiecutter / git / gh напрямую из main agent — делегируй subagent
|
||
(Template INIT, Template GITHUB). Main agent = оркестратор: вопросы юзеру +
|
||
`project-status` tool (read-only oracle) + делегирование.
|
||
- `gh repo create` БЕЗ предварительного git init + initial commit (bare-repo →
|
||
empty push → main branch не появляется → branch protection падает).
|
||
- Импровизировать тип проекта вне `VALID_TYPES` из `spec-status.py` (см. ниже).
|
||
- Запускать `/run-pipeline` автоматически — стоп после init/check, дальше юзер
|
||
сам.
|
||
|
||
### Остановы
|
||
|
||
- Subagent error → 1 retry, потом STOP + report пользователю.
|
||
- cookiecutter не установлен → WARN + инструкция, STOP init flow.
|
||
- Template для типа не найден → WARN, STOP init flow (предложи check flow или
|
||
тип из доступных).
|
||
- `project-status` tool вернул `⚠️ ...failed` → WARN, сообщи пользователю,
|
||
продолжай без отчёта (не блокирующий).
|
||
|
||
## Определение flow
|
||
|
||
Вопрос юзеру (один вопрос, multiple choice):
|
||
|
||
```
|
||
Это новый проект или проверка существующего?
|
||
[1] init — новый проект: cookiecutter по типу + GitHub remote + branch protection
|
||
[2] check — аудит существующего: project-status (структура, роуты, качество, README, infra)
|
||
```
|
||
|
||
Если юзер выбрал init, но cwd уже git-репо с коммитами и файлами → предложи
|
||
check flow (см. Граничные случаи). Если cwd пустой или юзер подтвердил init →
|
||
init flow.
|
||
|
||
## init flow
|
||
|
||
### Шаг 1: Вопрос — тип проекта
|
||
|
||
```
|
||
Выбери тип проекта (из spec-status VALID_TYPES):
|
||
[1] backend — FastAPI + Tortoise, REST API (cookiecutter template)
|
||
[2] fullstack — backend + SvelteKit frontend (cookiecutter template)
|
||
[3] cli — Python CLI tool, Typer (cookiecutter template)
|
||
[4] mcp-server — MCP + REST сервер (нет cookiecutter template — ручная инициализация)
|
||
[5] bot — Telegram bot, aiogram 3 (нет cookiecutter template — ручная инициализация)
|
||
[6] worker — Prefect flows (нет cookiecutter template — ручная инициализация)
|
||
```
|
||
|
||
Cookiecutter templates доступны для типов: `backend`, `fullstack`, `cli`
|
||
(директории в `.opencode/templates/`). Для `mcp-server`, `bot`, `worker`
|
||
шаблонов нет → WARN: "cookiecutter template not found for type `<type>`.
|
||
Доступные: backend, fullstack, cli. Для остальных типов используй check flow
|
||
или создай issue на добавление template." → STOP init flow.
|
||
|
||
### Шаг 2: Вопрос — имя, описание, опции
|
||
|
||
```
|
||
Имя проекта (kebab-case, станет package name и GitHub repo name): ___
|
||
Описание (1 строка): ___
|
||
GitHub owner: ___
|
||
use_auth: [1] no (default) / [2] yes
|
||
use_db: [1] yes (default) / [2] no
|
||
```
|
||
|
||
Опции `use_auth` / `use_db` — переменные cookiecutter (см. `cookiecutter.json`).
|
||
Значения: `"no"` или `"yes"` (строки, lowercase).
|
||
|
||
### Шаг 3: Делегирование — cookiecutter + git init + initial commit
|
||
|
||
Subagent (general) — Template INIT ниже. Cookiecutter рендерит проект в
|
||
`./<project_name>/`, post_gen_project hook удаляет файлы условные на
|
||
`use_auth`/`use_db`. Затем git init + initial commit внутри `./<project_name>/`.
|
||
|
||
### Шаг 4: Делегирование — GitHub remote + branch protection
|
||
|
||
Subagent (general) — Template GITHUB ниже. Мигрировано из repo-init Phase A
|
||
(steps 1-3) БЕЗ изменений: `gh repo create`, squash-only merge settings, branch
|
||
protection на main. Требует локальный git-репо с initial commit (из шага 3).
|
||
|
||
### Шаг 5: Оркестратор — project-status
|
||
|
||
Вызови `project-status` tool напрямую (read-only oracle, ALLOWED для
|
||
оркестратора — как `pipeline-status` / `spec-status`):
|
||
|
||
```
|
||
project-status({})
|
||
```
|
||
|
||
Tool вернёт отчёт: `Project: <type>`, 7 групп `[OK]/[WARN]/[FAIL]`, `Итог:`,
|
||
`Рекомендации:`. Покажи отчёт юзеру. Если tool вернул `⚠️ ...failed` → WARN,
|
||
продолжай без отчёта.
|
||
|
||
### Шаг 6: Финальный репорт
|
||
|
||
```
|
||
Project <project_name> created at ./<project_name>/.
|
||
GitHub: https://github.com/<owner>/<project_name>
|
||
Branch protection: main (PR + required_status_checks + linear history)
|
||
Project-status: <summary из шага 5>
|
||
Дальше: /run-pipeline для реализации фич, или /spec для генерации spec.
|
||
```
|
||
|
||
## check flow
|
||
|
||
### Шаг 1: Оркестратор — project-status
|
||
|
||
```
|
||
project-status({})
|
||
```
|
||
|
||
Для строгого режима (exit 1 на FAIL) — `project-status({ check: true })`.
|
||
Для пропуска медленных remote-проверок (branch protection via gh) —
|
||
`project-status({ fast: true })`. По умолчанию — non-blocking (exit 0).
|
||
|
||
### Шаг 2: Оркестратор — отчёт + рекомендации
|
||
|
||
Покажи полный отчёт юзеру. В разделе `Рекомендации:` — список FAIL-чеков с
|
||
путями. Сгруппируй по категориям (Структура / Качество кода / Тесты / README /
|
||
Infra / Coverage).
|
||
|
||
### Шаг 3: Вопрос — чинить?
|
||
|
||
```
|
||
Найдены проблемы: <N FAIL, M WARN>.
|
||
Запустить fix-subagents для рекомендаций?
|
||
[1] да — делегируй subagent(ов) для каждого FAIL
|
||
[2] нет — только отчёт, я починю сам
|
||
```
|
||
|
||
Если `да` → для каждого FAIL из `Рекомендации:` создай subagent (general) с
|
||
Template FIX (ниже), передав путь и описание проблемы. Subagent чинит, коммитит
|
||
через `commit` tool, push. Один FAIL = один subagent (последовательно, не
|
||
параллельно — см. AGENTS.md Linear Execution). После всех фиксов → re-run
|
||
`project-status` для верификации.
|
||
|
||
Если `нет` → STOP, отчёт у юзера.
|
||
|
||
## Граничные случаи
|
||
|
||
- **Существующий репо (не пустой)** → init flow: предложи check flow. Если юзер
|
||
настаивает на init → cookiecutter создаст `./<project_name>/` рядом (не
|
||
перезапишет текущий репо). Уточни: "cwd уже git-репо с файлами. Init создаст
|
||
новый проект в подкаталоге `./<project_name>/`. Продолжить? [1] да / [2] нет,
|
||
лучше check flow".
|
||
- **GitHub repo уже существует** → skip `gh repo create`, только branch
|
||
protection (если ещё не настроена). Subagent проверяет: `gh repo view
|
||
<owner>/<name>` — если существует, пропускает create, переходит к settings +
|
||
branch protection.
|
||
- **cookiecutter не установлен** → WARN: "cookiecutter не найден. Установи:
|
||
`uv tool install cookiecutter` (или `pipx install cookiecutter`). После
|
||
установки повтори init." → STOP init flow.
|
||
- **project-status не найден** → WARN: "project-status tool не доступен (issue
|
||
#228 / PR #233 не завершён или tool не зарегистрирован). Пропускаю
|
||
project-status проверку." → продолжай без отчёта (не блокирующий).
|
||
- **Template для типа не найден** (mcp-server/bot/worker) → WARN (см. Шаг 1).
|
||
- **gh auth не настроен** → subagent упадёт на `gh repo create`. Сообщи юзеру:
|
||
"запусти `gh auth login` и повтори".
|
||
|
||
## Prompt templates
|
||
|
||
### Template INIT (cookiecutter + git init + initial commit)
|
||
|
||
```
|
||
Создай новый проект типа <type> с именем <project_name>.
|
||
Контекст: init flow project-template skill, cwd = <cwd>.
|
||
|
||
1. Проверь cookiecutter: `cookiecutter --version`. Если не установлен → STOP,
|
||
верни: "cookiecutter не установлен. Установи: `uv tool install cookiecutter`".
|
||
2. Запусти cookiecutter (no-input, переменные из ответов юзера):
|
||
`cookiecutter .opencode/templates/<type>/ --no-input \
|
||
project_name=<project_name> \
|
||
project_type=<type> \
|
||
description="<description>" \
|
||
use_auth=<auth> \
|
||
use_db=<db> \
|
||
python_version=3.13`
|
||
Cookiecutter создаст каталог `./<project_name>/` с рендеренным проектом.
|
||
post_gen_project hook удалит файлы условные на use_auth/use_db.
|
||
3. `cd <project_name>` (все дальнейшие команды — внутри этого каталога).
|
||
4. `git init`
|
||
5. `git add .` затем `git status` — проверь staged set (только файлы проекта,
|
||
без лишнего). Если лишнее — `git restore --staged <file>`.
|
||
6. `commit({ message: "chore: initial commit" })` tool (НЕ raw `git commit` —
|
||
заблокирован deny).
|
||
7. Верни: "done: project created at ./<project_name>/, git init + initial commit".
|
||
|
||
Если найдёшь баг вне scope — загрузи skill `bug-discovery` через
|
||
`skill("bug-discovery")` и следуй протоколу. НЕ чини баг сам.
|
||
```
|
||
|
||
### Template GITHUB (gh repo create + settings + branch protection)
|
||
|
||
> Мигрировано из repo-init Phase A (steps 1-3) БЕЗ изменений. Требует локальный
|
||
> git-репо с initial commit (из Template INIT).
|
||
|
||
```
|
||
Настрой GitHub remote для проекта <project_name> (cwd = <cwd>/<project_name>).
|
||
owner = <owner>, visibility = public (или private если internal).
|
||
|
||
0. Проверь: GitHub repo уже существует?
|
||
`gh repo view <owner>/<project_name>` — если exit 0, skip step 1 (create),
|
||
переходи к step 2 (settings) и step 3 (branch protection).
|
||
|
||
1. Создание репозитория:
|
||
`gh repo create <owner>/<project_name> --public --source=. --remote=origin --push`
|
||
(или --private если internal)
|
||
После создания: `gh auth setup-git`
|
||
|
||
2. Настройки репозитория (squash-only merge, auto-delete branch):
|
||
`gh api repos/<owner>/<project_name> \
|
||
--method PATCH \
|
||
-f allow_squash_merge=true \
|
||
-f allow_merge_commit=false \
|
||
-f allow_rebase_merge=false \
|
||
-f delete_branch_on_merge=true \
|
||
-f squash_merge_commit_title=COMMIT_OR_PR_TITLE \
|
||
-f squash_merge_commit_message=COMMIT_MESSAGES`
|
||
|
||
3. Защита ветки main (требовать PR, required_status_checks, linear history):
|
||
`gh api repos/<owner>/<project_name>/rules/branches/main \
|
||
--method POST \
|
||
-F target=branch \
|
||
-f enforcement=active \
|
||
--input - <<'EOF'
|
||
{
|
||
"conditions": {
|
||
"ref_name": {
|
||
"include": ["refs/heads/main"],
|
||
"exclude": []
|
||
}
|
||
},
|
||
"rules": [
|
||
{
|
||
"type": "pull_request",
|
||
"parameters": {
|
||
"required_approving_review_count": 0,
|
||
"dismiss_stale_reviews_on_push": false,
|
||
"require_code_owner_review": false,
|
||
"require_last_push_approval": false,
|
||
"required_review_thread_resolution": false
|
||
}
|
||
},
|
||
{
|
||
"type": "required_status_checks",
|
||
"parameters": {
|
||
"strict_required_status_checks": true,
|
||
"do_not_enforce_on_create": false,
|
||
"required_status_checks": []
|
||
}
|
||
},
|
||
{
|
||
"type": "deletion"
|
||
},
|
||
{
|
||
"type": "non_fast_forward"
|
||
}
|
||
]
|
||
}
|
||
EOF`
|
||
|
||
`required_status_checks` заполняется именами CI-джобов после первого пуша
|
||
(имена из cookiecutter CI: `lint`, `typecheck`, `test`, `complexity` для
|
||
Python; `check` для JS/TS). На этом этапе оставь пустой массив — обновится
|
||
после первого CI-прогона.
|
||
|
||
4. Верни: "done: GitHub remote created/verified, squash-only merge, branch
|
||
protection on main".
|
||
|
||
Если найдёшь баг вне scope — загрузи skill `bug-discovery` через
|
||
`skill("bug-discovery")` и следуй протоколу. НЕ чини баг сам.
|
||
```
|
||
|
||
### Template FIX (check flow — починить FAIL из project-status)
|
||
|
||
```
|
||
Почини проблему из project-status отчёта.
|
||
Категория: <category> (Структура / Качество кода / Тесты / README / Infra / Coverage)
|
||
Проблема: <name>: <detail>
|
||
Путь: <path из рекомендации>
|
||
|
||
1. Прочитай контекст проблемы (файл по пути из рекомендации).
|
||
2. Минимальный фикс: добавь/исправь только то, что указано в рекомендации.
|
||
Не рефактори unrelated код.
|
||
3. Перед коммитом — `git status` для проверки staged set (`commit` tool НЕ
|
||
делает `git add` — коммитит только staged; используй
|
||
`git add <конкретные-пути>`, НЕ `git add -A`).
|
||
4. `commit({ message: "fix(<scope>): <description>" })` tool (НЕ raw
|
||
`git commit`), push.
|
||
5. Верни: "done: fixed <name>, commit <hash>".
|
||
|
||
Если найдёшь баг вне scope — загрузи skill `bug-discovery` через
|
||
`skill("bug-discovery")` и следуй протоколу. НЕ чини баг сам.
|
||
```
|
||
|
||
## VALID_TYPES (из spec-status.py)
|
||
|
||
```
|
||
backend, fullstack, mcp-server, cli, bot, worker
|
||
```
|
||
|
||
Cookiecutter templates доступны для: `backend`, `fullstack`, `cli`
|
||
(директории `.opencode/templates/<type>/`).
|
||
|
||
## Rules
|
||
|
||
- Main agent = оркестратор: вопросы юзеру + `project-status` tool (read-only) +
|
||
делегирование subagent'ам (Template INIT / GITHUB / FIX). Не делает
|
||
cookiecutter/git/gh напрямую.
|
||
- `project-status` tool — read-only oracle, ALLOWED для оркестратора (как
|
||
`pipeline-status` / `spec-status`).
|
||
- init flow порядок: cookiecutter → git init/commit → gh repo create → branch
|
||
protection → project-status. Не меняй порядок.
|
||
- check flow: project-status → отчёт → рекомендации → subagents (последовательно).
|
||
- Subagent error → 1 retry, потом STOP + report.
|
||
- Совместим с spec-pipeline: Phase 8 EXECUTE (spec/SKILL.md Template I) может
|
||
вызывать project-template init для scaffolding issue.
|
||
- `commit` tool НЕ делает `git add` — коммитит только staged. Используй
|
||
`git add <конкретные-пути>`, НЕ `git add -A`. |