скиллы: doc-canon стал canon, версия раскладки поднята до 2
- каталог скилла и все вызовы переименованы: префикс `doc-` называл материал, а скилл занят формой — раскладкой всех частей проекта и общим повышением версии, включая каталог задач; - README перестроен: `canon` вынесен из семейства документов отдельным блоком и отдельным узлом графа, правило префиксов переформулировано, у документов уточнено владение — содержимым, а не раскладкой; - заведена запись 2 журнала версий: в проекте ничего не переехало, но путь к `docs.py` и имя вызова живут в гейте и в `CLAUDE.md` проекта и сломаются молча; - прежние адреса в записи 1 и в журнале решений оставлены как есть: журнал описывает состояния, которые были, и задним числом не переписывается.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: doc-canon
|
||||
description: Привести проект к канону документов av-dev и держать его в соответствии — три операции одной машиной сравнения. check — что разошлось с текущей версией канона; adopt — перевод проекта из любой прежней раскладки (docs/specs, drafts, backlog, BRIEF.md, review-brief) в канон с переносом файлов; upgrade — повышение проекта с версии канона N до текущей по журналу версий. Использовать, когда просят проверить документацию проекта, перевести проект на канон, обновить его под новую версию канона или когда пришли в старый проект и надо понять, что в нём не так. Заведение нового проекта с нуля — скилл av-dev:doc-init.
|
||||
name: canon
|
||||
description: Форма раскладки проекта под av-dev и её обновление — три операции одной машиной сравнения. check — что разошлось с текущей версией раскладки; adopt — перевод проекта из любой прежней раскладки (docs/specs, drafts, backlog, BRIEF.md, review-brief) в канон с переносом файлов и вызовом владельцев каталога задач и openspec/; upgrade — повышение проекта с версии N до текущей по журналу версий, и повышается им вся раскладка, включая каталог задач. Использовать, когда просят проверить документацию проекта, перевести проект на канон, обновить его под новую версию раскладки или когда пришли в старый проект и надо понять, что в нём не так. Имя без префикса намеренно — скилл держит форму всех артефактов проекта, а не один их вид. Содержимое документов ведёт av-dev:doc-sync, форму записей задач — av-dev:task-track, заведение проекта с нуля — av-dev:doc-init.
|
||||
---
|
||||
|
||||
# Приведение проекта к канону
|
||||
# Форма раскладки проекта
|
||||
|
||||
Три операции, одна машина сравнения с разными исходами:
|
||||
|
||||
@@ -13,6 +13,14 @@ description: Привести проект к канону документов
|
||||
| `adopt` | проект в чужой раскладке | перенос в канон |
|
||||
| `upgrade` | канон вырос, проект отстал | по журналу версий |
|
||||
|
||||
**Имя без префикса, и это не случайность.** Остальные скиллы названы по
|
||||
материалу, с которым работают, — `doc-`, `task-`, `code-`; этот работает не с
|
||||
материалом, а с **формой**, и она у всех частей проекта одна. `check` сверяет
|
||||
раскладку документов, `adopt` заводит все части сразу и зовёт владельцев каталога
|
||||
задач и `openspec/`, `upgrade` повышает **всю** раскладку одним журналом версий —
|
||||
и документы, и каталог задач. Содержимое при этом не его: документы ведёт
|
||||
`av-dev:doc-sync`, записи задач — `av-dev:task-track`.
|
||||
|
||||
**Определение канона — [references/canon.md](references/canon.md).** Здесь оно не
|
||||
пересказывается: два описания одной раскладки разъедутся, и работать будет то,
|
||||
которое прочитали последним. Прочитай его **до** первой правки.
|
||||
@@ -45,7 +53,7 @@ description: Привести проект к канону документов
|
||||
## Инструмент
|
||||
|
||||
```
|
||||
ds="$CLAUDE_PLUGIN_ROOT/skills/doc-canon/scripts/docs.py"
|
||||
ds="$CLAUDE_PLUGIN_ROOT/skills/canon/scripts/docs.py"
|
||||
|
||||
python3 $ds check --dir <корень> [--base <rev>] # раскладка, ссылки, версия, сверки
|
||||
python3 $ds version --dir <корень> # версия раскладки: скрипта и проекта
|
||||
@@ -128,7 +136,7 @@ capability: незаполненный канон это переходное с
|
||||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||||
|
||||
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
|
||||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||||
поведении.
|
||||
+3
-3
@@ -6,7 +6,7 @@
|
||||
[журнала](changelog.md). Литерал в шапке был третьим и отстал на первом же
|
||||
повышении — версию 13 он пережил, объявляя канон двенадцатым.
|
||||
|
||||
Это **единственный дом определения канона**. Скиллы `doc-init`, `doc-canon` и `doc-sync`
|
||||
Это **единственный дом определения канона**. Скиллы `doc-init`, `canon` и `doc-sync`
|
||||
читают его, а не пересказывают: три описания одной раскладки разъедутся, и
|
||||
работать будет то, которое прочитали последним. Меняется канон — меняется этот
|
||||
файл и появляется запись в [changelog.md](changelog.md).
|
||||
@@ -19,7 +19,7 @@
|
||||
Рядом лежит OpenSpec, у которого структура тоже строгая.
|
||||
|
||||
Цена принята сознательно: плагин не переносится на чужой репозиторий как есть —
|
||||
чужой репозиторий **приводится** к канону скиллом `doc-canon`.
|
||||
чужой репозиторий **приводится** к канону скиллом `canon`.
|
||||
|
||||
Раскладка отвечает, **где** текст лежит и на какой вопрос отвечает. Каким он
|
||||
должен быть **словами** — общий для всех документов канона файл
|
||||
@@ -527,7 +527,7 @@ kebab-case.** Причина не эстетическая: имя файла с
|
||||
разрез, что между `task-form` и `task-wording`.
|
||||
|
||||
**Зовутся оба одинаково и одним скиллом — `av-dev:doc-healthcheck`, на весь
|
||||
канон разом; шагом `adopt` и шагом `upgrade` его зовёт `doc-canon`.** Не на синке
|
||||
канон разом; шагом `adopt` и шагом `upgrade` его зовёт `canon`.** Не на синке
|
||||
документации: `doc-consistency` на
|
||||
`opus` по каждой сделанной задаче не окупается, а расхождение между двумя документами по
|
||||
определению требует двух, и на большинстве задач синк правит один. Пачка,
|
||||
+32
-1
@@ -1,7 +1,7 @@
|
||||
# Журнал версий раскладки
|
||||
|
||||
Одна запись на версию. Проект знает свою версию из ключа `version` в
|
||||
`.av-dev.toml`; операция `upgrade` скилла `av-dev:doc-canon` идёт по записям
|
||||
`.av-dev.toml`; операция `upgrade` скилла `av-dev:canon` идёт по записям
|
||||
снизу вверх от версии проекта до текущей и делает то, что в них названо.
|
||||
|
||||
Правило записи: **что добавилось, что переехало, что удалено, что сделать
|
||||
@@ -22,6 +22,37 @@
|
||||
|
||||
---
|
||||
|
||||
## Версия 2 — 2026-08-13
|
||||
|
||||
Скилл `doc-canon` стал `canon`: префикс называл материал (`doc-`), а скилл
|
||||
занят не материалом, а **формой** — раскладкой всех частей проекта и общим
|
||||
повышением версии. Ни один файл проекта от этого не переехал; сменились **путь к
|
||||
скрипту** и **имя вызова**, а оба живут в проекте: первый — строкой гейта, второй
|
||||
— в `CLAUDE.md` и в записях задач.
|
||||
|
||||
**Что переехало в вызовах.** `av-dev:doc-canon` → `av-dev:canon`. Прочие имена не
|
||||
тронуты.
|
||||
|
||||
**Что сделать проекту.**
|
||||
|
||||
1. **Поправить шаг гейта.** Путь к `docs.py` сменился вместе с именем каталога
|
||||
скилла: `skills/doc-canon/scripts/docs.py` →
|
||||
`skills/canon/scripts/docs.py`. Шаг, который не нашёл скрипт, обязан
|
||||
краснеть, а не пропускаться, — проверь, что он краснеет.
|
||||
2. **Поправить свои вызовы скилла** — `grep -rn "doc-canon" --exclude-dir=.git .`
|
||||
по проекту целиком: имя встречается в `CLAUDE.md`, в `Taskfile`, в записях
|
||||
задач и в документах канона. Прежнее полное имя не разрешится вовсе.
|
||||
3. **Поднять версию** — `docs.py bump`. Последним шагом.
|
||||
4. `docs.py check` и `tasks.py check --dir <каталог задач>` — до отсутствия
|
||||
дрейфа.
|
||||
|
||||
**Проект, не прошедший запись 1, переименовывает дважды подряд** — `skills/canon/`
|
||||
→ `skills/doc-canon/` записью 1 и обратно этой. Порядок записей от этого не
|
||||
меняется: каждая исполняется на том состоянии, которое оставила предыдущая, и
|
||||
прошлая запись под новое имя не переписывается.
|
||||
|
||||
---
|
||||
|
||||
## Версия 1 — 2026-08-13
|
||||
|
||||
Три плагина — `av-dev-docs`, `av-dev-tasks` и `av-dev-code` — слились в один,
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# Скелеты документов канона
|
||||
|
||||
Что кладут `init` и `doc-canon adopt` в незаполненный слот. Правило одно:
|
||||
Что кладут `init` и `canon adopt` в незаполненный слот. Правило одно:
|
||||
**честная информативная строка вместо заглушки**. Проход читает строку как факт;
|
||||
`<!-- заполнить: … -->` он читает как пробел, и `docs.py check` о таком
|
||||
плейсхолдере напоминает.
|
||||
@@ -209,7 +209,7 @@
|
||||
|
||||
Верно одно из трёх:
|
||||
|
||||
<!-- копия: adr-когда-заводить из av-dev/skills/doc-canon/references/canon.md -->
|
||||
<!-- копия: adr-когда-заводить из av-dev/skills/canon/references/canon.md -->
|
||||
- **дорогой откат** — переделка стоит дороже переписывания одного файла;
|
||||
- **намеренный отказ** от очевидного подхода;
|
||||
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус
|
||||
@@ -316,7 +316,7 @@ def check_version(root: Path, cfg: dict, rep: Report) -> None:
|
||||
if got < LAYOUT_VERSION:
|
||||
rep.error(
|
||||
f"проект приведён к раскладке версии {got}, текущая — {LAYOUT_VERSION}:"
|
||||
f" нужно повышение (скилл av-dev:doc-canon, операция upgrade)"
|
||||
f" нужно повышение (скилл av-dev:canon, операция upgrade)"
|
||||
)
|
||||
elif got > LAYOUT_VERSION:
|
||||
rep.error(
|
||||
@@ -373,7 +373,7 @@ def check_legacy(root: Path, rep: Report) -> None:
|
||||
f"нет {CONFIG}, а настройки лежат по прежней раскладке"
|
||||
f" ({', '.join(legacy)}) — она осталась от трёх плагинов, которые"
|
||||
f" слились в один: перенеси значения и удали старые файлы операцией"
|
||||
f" upgrade скилла av-dev:doc-canon (журнал, версия 1). Прежние имена не"
|
||||
f" upgrade скилла av-dev:canon (журнал, версия 1). Прежние имена не"
|
||||
f" читаются, поэтому в этом прогоне всё остальное проверено так, будто"
|
||||
f" настроек нет вовсе"
|
||||
)
|
||||
@@ -138,7 +138,7 @@ python3 $os form # слепок формы против жив
|
||||
## Кто зовёт этот скилл
|
||||
|
||||
- `av-dev:doc-init` — шагом заведения нового проекта, до первого документа;
|
||||
- `av-dev:doc-canon` в режиме `adopt` — если на переводимом проекте каталога нет
|
||||
- `av-dev:canon` в режиме `adopt` — если на переводимом проекте каталога нет
|
||||
или `config.yaml` остался примером;
|
||||
- `av-dev:code-resolve` и `av-dev:code-review` — не вызовом по ходу, а отсылкой:
|
||||
OpenSpec у обоих жёсткая предпосылка, и на проекте без каталога оба посылают
|
||||
@@ -160,7 +160,7 @@ python3 $os form # слепок формы против жив
|
||||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||||
|
||||
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
|
||||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||||
поведении.
|
||||
@@ -188,7 +188,7 @@ python3 $os form # слепок формы против жив
|
||||
## Чего этот скилл не делает
|
||||
|
||||
- **Не пишет спеки и предложения.** Это `opsx:propose` и конвейер задачи.
|
||||
- **Не ведёт документы канона** — их дом скилл `av-dev:doc-canon`, и адреса в
|
||||
- **Не ведёт документы канона** — их дом скилл `av-dev:canon`, и адреса в
|
||||
`context` только на них ссылаются.
|
||||
- **Не чинит расхождение формы с версией OpenSpec в проекте.** Оно чинится в
|
||||
плагине: константы скрипта, образец здесь, запись в журнал версий канона.
|
||||
|
||||
@@ -216,7 +216,7 @@ def check_form(root: Path, rep: Report) -> None:
|
||||
rep.skip(
|
||||
f"{where} в проекте нет — ссылка на него в context не "
|
||||
f"требуется. Документы канона проект не завёл, и без них "
|
||||
f"конвейер работает вслепую: заводит их av-dev:doc-canon"
|
||||
f"конвейер работает вслепую: заводит их av-dev:canon"
|
||||
)
|
||||
continue
|
||||
if pointer not in live:
|
||||
|
||||
@@ -66,7 +66,7 @@ description: "Взять одну задачу и довести её до за
|
||||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||||
|
||||
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
|
||||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||||
поведении.
|
||||
@@ -97,7 +97,7 @@ description: "Взять одну задачу и довести её до за
|
||||
карта «что где» — `references/project-facts.md` конвейера ревью.
|
||||
|
||||
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и
|
||||
предложи скилл `av-dev:doc-canon`: одна операция на проект против поразрядной
|
||||
предложи скилл `av-dev:canon`: одна операция на проект против поразрядной
|
||||
деградации на каждой задаче. Работу при этом не останавливай.
|
||||
|
||||
## Вход
|
||||
|
||||
@@ -333,7 +333,7 @@ Change ты не передаёшь — его нет.
|
||||
Список документов и их триггеров здесь не дублируется — он в чек-листе скилла
|
||||
`av-dev:doc-sync`; копия уже однажды разошлась с оригиналом. Документов канона в
|
||||
проекте нет — синка нет вовсе: скажи это исходом и предложи завести канон
|
||||
скиллом `av-dev:doc-canon`.
|
||||
скиллом `av-dev:canon`.
|
||||
|
||||
### 6. Коммит
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
**Отсутствие канона бьёт по разведке сильнее, чем по решению**, и сказать об этом
|
||||
строкой мало: без документов у ответа нет дома, и знание осядет в переписке.
|
||||
Назови исход и предложи `av-dev:doc-canon`; работу не останавливай, но адрес
|
||||
Назови исход и предложи `av-dev:canon`; работу не останавливай, но адрес
|
||||
ответа тогда выбираешь сам и говоришь об этом вслух.
|
||||
|
||||
## Что этот сценарий требует от входа
|
||||
@@ -267,7 +267,7 @@ git и читается диффом, а второй стоп на каждой
|
||||
перечня адресов неотличим от доклада о ненаписанном.
|
||||
|
||||
**Документов канона в проекте нет** — писать ответ некуда: назови это исходом,
|
||||
предложи завести канон скиллом `av-dev:doc-canon` и оставь ответ в докладе
|
||||
предложи завести канон скиллом `av-dev:canon` и оставь ответ в докладе
|
||||
целиком, чтобы работа не пропала. Заводить `docs/` мимо канона нельзя.
|
||||
|
||||
### 5. Задачи: завести и уточнить
|
||||
|
||||
@@ -333,7 +333,7 @@ flowchart TD
|
||||
триггера.
|
||||
|
||||
**Документов канона в проекте нет** — синка нет вовсе: назови это исходом и
|
||||
предложи завести канон скиллом `av-dev:doc-canon`. Придумывать раскладку под
|
||||
предложи завести канон скиллом `av-dev:canon`. Придумывать раскладку под
|
||||
задачу нельзя: документ, заведённый мимо канона, окажется вторым домом ровно
|
||||
тому, что канон потом заведёт своим.
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ description: "Конвейер ревью изменения, устроенны
|
||||
непроверенная ветка деградации хуже честного отказа. Заводить руками не надо:
|
||||
этим владеет скилл `av-dev:code-openspec` — он заводит каталог и заменяет
|
||||
пример в `config.yaml` настройкой. Его же зовут `av-dev:doc-init` на новом
|
||||
проекте и `av-dev:doc-canon` в режиме `adopt` — на переводимом.
|
||||
проекте и `av-dev:canon` в режиме `adopt` — на переводимом.
|
||||
**Предпосылка эта — про изменение поведения, а не про всякий прогон:**
|
||||
сценарий обслуживания зовёт конвейер без change и без дельта-спек, и ни один
|
||||
проход его плана на них не завязан. См. «Прогон без change».
|
||||
@@ -83,7 +83,7 @@ description: "Конвейер ревью изменения, устроенны
|
||||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||||
|
||||
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
|
||||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||||
поведении.
|
||||
@@ -132,7 +132,7 @@ description: "Конвейер ревью изменения, устроенны
|
||||
критерий, по которому судит изменение. `adr.*`, `research.*` и `tasks/` не
|
||||
открывает никто.
|
||||
|
||||
Дом канона этой раскладки — скилл `av-dev:doc-canon`, раздел «Три категории
|
||||
Дом канона этой раскладки — скилл `av-dev:canon`, раздел «Три категории
|
||||
документов». Конвейер её **читатель**: категории и имена тем он берёт
|
||||
оттуда и своих не заводит.
|
||||
|
||||
@@ -191,7 +191,7 @@ description: "Конвейер ревью изменения, устроенны
|
||||
дом для тех же фактов разошёлся бы и выглядел актуальным.
|
||||
|
||||
**Документов канона нет вовсе** — проект не приведён к канону. Скажи это строкой
|
||||
и предложи скилл `av-dev:doc-canon`: одна операция на проект против деградации на
|
||||
и предложи скилл `av-dev:canon`: одна операция на проект против деградации на
|
||||
каждой задаче. Прогон при этом не останавливается.
|
||||
|
||||
## Что получает каждый проход
|
||||
@@ -1142,7 +1142,7 @@ flowchart TD
|
||||
и где это лежит в документах проекта; таблица поразрядной деградации.
|
||||
- [references/review-levels.md](references/review-levels.md) — дом правила выбора
|
||||
метки: две оси, спорное вниз, чем `small` дешевле, доли как проверка правила.
|
||||
- Skill `av-dev:doc-canon` — приведение проекта к канону документов.
|
||||
- Skill `av-dev:canon` — приведение проекта к канону документов.
|
||||
- [references/finding-contract.md](references/finding-contract.md) — контракт находок.
|
||||
- [references/promote.md](references/promote.md) — промоут находка → конвенция → правило → удаление.
|
||||
- [references/calibration.md](references/calibration.md) — калибровка инъекцией, вердикты keep/retune/drop.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
и проход читает их напрямую: пути жёсткие, посредник не нужен, а
|
||||
второй дом для тех же фактов разошёлся бы и выглядел актуальным.
|
||||
|
||||
Определение канона держит скилл `av-dev:doc-canon`. Здесь только карта «тема →
|
||||
Определение канона держит скилл `av-dev:canon`. Здесь только карта «тема →
|
||||
её дом → что оттуда берётся».
|
||||
|
||||
## Карта тем
|
||||
@@ -118,7 +118,7 @@
|
||||
строка неотличима от «мы просто не стали» и перестаёт читаться на третьей задаче.
|
||||
|
||||
**Документов канона нет вовсе** — проект не приведён к канону. Это не повод
|
||||
работать вслепую: скажи об этом строкой и предложи `av-dev:doc-canon`. Одна
|
||||
работать вслепую: скажи об этом строкой и предложи `av-dev:canon`. Одна
|
||||
операция на проект против деградации на каждой задаче.
|
||||
|
||||
## Правило чтения
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
## Форма записи
|
||||
|
||||
**Это дом формы, и у него есть копия.** Скелет `docs/review.md`, который кладёт
|
||||
в проект `av-dev:doc-canon`, повторяет её дословно — он уезжает в репозиторий и обязан там что-то говорить. Правка формы
|
||||
в проект `av-dev:canon`, повторяет её дословно — он уезжает в репозиторий и обязан там что-то говорить. Правка формы
|
||||
здесь **обязана** тянуть правку скелета и запись в журнал версий канона; иначе
|
||||
проекты продолжат писать по старой форме, а конвейер — ждать поля, которого нет.
|
||||
Дословность сверяет `scripts/copies.py` маркетплейса по маркерам ниже — но
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: doc-healthcheck
|
||||
description: "Проверка здоровья документации проекта судом, а не машиной: не разошлись ли документы между собой и с кодом. Зовёт двух агентов на весь канон разом — doc-consistency (один факт в двух домах, прямое противоречие, поведение в architecture.md вместо спек, ADR без парного статуса, число без провенанса) и doc-code-drift (протухший факт: имя ветки, команды, пути, зависимости поимённо, настройки с числом, единые точки, capability). Разбирает урожай порциями: строка на замену идёт в документ сразу, работа больше абзаца становится задачей. Использовать, когда с прошлой сверки сделан десяток задач, когда вернулись к проекту после перерыва, перед тем как опереться на документ в решении, а также шагом adopt и upgrade. Дорого — не на каждой задаче. Раскладку и версию раскладки проверяет скилл av-dev:doc-canon, язык документов — агент doc-wording."
|
||||
description: "Проверка здоровья документации проекта судом, а не машиной: не разошлись ли документы между собой и с кодом. Зовёт двух агентов на весь канон разом — doc-consistency (один факт в двух домах, прямое противоречие, поведение в architecture.md вместо спек, ADR без парного статуса, число без провенанса) и doc-code-drift (протухший факт: имя ветки, команды, пути, зависимости поимённо, настройки с числом, единые точки, capability). Разбирает урожай порциями: строка на замену идёт в документ сразу, работа больше абзаца становится задачей. Использовать, когда с прошлой сверки сделан десяток задач, когда вернулись к проекту после перерыва, перед тем как опереться на документ в решении, а также шагом adopt и upgrade. Дорого — не на каждой задаче. Раскладку и версию раскладки проверяет скилл av-dev:canon, язык документов — агент doc-wording."
|
||||
---
|
||||
|
||||
# Здоровье документации
|
||||
@@ -23,7 +23,7 @@ check` и его скрипт; здесь начинается там, где к
|
||||
`architecture.md` и уже живущий в `CLAUDE.md`;
|
||||
- **вернулись к проекту после перерыва** — прежде чем опираться на написанное;
|
||||
- **перед тем как опереться на документ в решении**, если оно дорогое;
|
||||
- шагом `adopt` и шагом `upgrade` — их зовёт скилл `doc-canon` сам.
|
||||
- шагом `adopt` и шагом `upgrade` — их зовёт скилл `canon` сам.
|
||||
|
||||
**Не на каждой задаче и не на каждом синке документации.** Цена реальная:
|
||||
`doc-consistency` идёт на `opus`, потому что сличение утверждений — суждение;
|
||||
@@ -52,7 +52,7 @@ check` и его скрипт; здесь начинается там, где к
|
||||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||||
|
||||
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
|
||||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||||
поведении.
|
||||
@@ -132,15 +132,15 @@ check` и его скрипт; здесь начинается там, где к
|
||||
идёт из его собственного отчёта — перечень фактов у него закрытый, и он
|
||||
называет, какие из них проверить было нечем.
|
||||
- Канона в проекте нет вовсе — это исход, а не пустой прогон: скажи строкой и
|
||||
предложи `av-dev:doc-canon`.
|
||||
предложи `av-dev:canon`.
|
||||
|
||||
## Чего этот скилл не делает
|
||||
|
||||
- **Не проверяет раскладку, версию и ссылки** — это `doc-canon check`, там машина.
|
||||
- **Не проверяет раскладку, версию и ссылки** — это `canon check`, там машина.
|
||||
- **Не судит язык** документов: залог, англицизмы, жаргон, термин без дома — это
|
||||
агент `doc-wording`, и зовут его отдельно, по пачке правленных документов.
|
||||
Звонящие у него названные — последний шаг синка в `av-dev:doc-sync`, шаг 9
|
||||
`av-dev:doc-init` и шаг вычитки в обоих режимах `doc-canon`, — просто ни один из
|
||||
`av-dev:doc-init` и шаг вычитки в обоих режимах `canon`, — просто ни один из
|
||||
них не здесь. У него другой ритм: он нужен там, где текст только что писали, а
|
||||
не там, где он год лежал. Оркестровать его нечем — он один и работает по
|
||||
названному списку.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: doc-init
|
||||
description: "Завести новый проект — сессия вопросов и ответов по свободному описанию замысла, из которой рождается первичная документация по канону av-dev: паспорт, CLAUDE.md с инвариантами и командами, модель угроз с периметром и скелет остальных документов; первые цели собирает интервью, а записывает их вызовом скилла av-dev:task-track — роадмап принадлежит учёту работ. OpenSpec заводит не сам, а вызовом скилла av-dev:code-openspec — каталог принадлежит конвейеру. Использовать, когда начинают новый проект с нуля, когда есть только текст «что мне нужно и почему» и надо превратить его в рабочую документацию, когда просят провести стартовое интервью по брифу. Проект, где документация уже как-то ведётся, переводит скилл doc-canon."
|
||||
description: "Завести новый проект — сессия вопросов и ответов по свободному описанию замысла, из которой рождается первичная документация по канону av-dev: паспорт, CLAUDE.md с инвариантами и командами, модель угроз с периметром и скелет остальных документов; первые цели собирает интервью, а записывает их вызовом скилла av-dev:task-track — роадмап принадлежит учёту работ. OpenSpec заводит не сам, а вызовом скилла av-dev:code-openspec — каталог принадлежит конвейеру. Использовать, когда начинают новый проект с нуля, когда есть только текст «что мне нужно и почему» и надо превратить его в рабочую документацию, когда просят провести стартовое интервью по брифу. Проект, где документация уже как-то ведётся, переводит скилл canon."
|
||||
---
|
||||
|
||||
# Заведение нового проекта
|
||||
@@ -8,9 +8,9 @@ description: "Завести новый проект — сессия вопро
|
||||
Вход — свободный текст «что мне нужно и почему». Выход — канон документов, с
|
||||
которого дальше работают все остальные скиллы.
|
||||
|
||||
**Определение канона — [канон](../doc-canon/references/canon.md).** Прочитай его до
|
||||
**Определение канона — [канон](../canon/references/canon.md).** Прочитай его до
|
||||
первого вопроса: интервью идёт по слотам канона, а не по вкусу. Что класть в
|
||||
каждый файл — [скелеты](../doc-canon/references/skeletons.md); не выдумывай заглушки
|
||||
каждый файл — [скелеты](../canon/references/skeletons.md); не выдумывай заглушки
|
||||
своей формы, `docs.py` узнаёт только плейсхолдер оттуда.
|
||||
|
||||
## Что `init` физически не может произвести
|
||||
@@ -90,7 +90,7 @@ description: "Завести новый проект — сессия вопро
|
||||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||||
|
||||
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
|
||||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||||
поведении.
|
||||
@@ -133,12 +133,12 @@ description: "Завести новый проект — сессия вопро
|
||||
5. Напиши заполняемые документы. **Бриф переезжает в `passport.md`** и
|
||||
отдельным файлом не остаётся: два дома для одного замысла разойдутся на
|
||||
первом же уточнении.
|
||||
6. Заведи скелет остальных по [скелетам](../doc-canon/references/skeletons.md) —
|
||||
6. Заведи скелет остальных по [скелетам](../canon/references/skeletons.md) —
|
||||
каждый с честной строкой.
|
||||
7. Каталог задач и первые цели — **вызови скилл `av-dev:task-track`**: он владеет
|
||||
форматом целей и задач. Не разрешился — учёт задач остаётся владельцу, и это
|
||||
тоже строка доклада.
|
||||
8. `docs.py check` из скилла `doc-canon` — до отсутствия дрейфа. Замечания о
|
||||
8. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о
|
||||
незаполненных плейсхолдерах остаются: их закрывает не `init`, а работа.
|
||||
9. **Вычитай написанное — агент `doc-wording`**, по пачке заполненных документов
|
||||
(`passport.md`, `CLAUDE.md`, `security.md`). Здесь он нужен сильнее, чем где
|
||||
@@ -152,7 +152,7 @@ description: "Завести новый проект — сессия вопро
|
||||
## Что дальше
|
||||
|
||||
- Содержимое канона по ходу разработки ведёт скилл `doc-sync`.
|
||||
- Раскладку проверяет `doc-canon check`.
|
||||
- Раскладку проверяет `canon check`.
|
||||
- Первую задачу берёт конвейер проекта; `architecture.md` и `conventions/`
|
||||
наполняются его шагом синка, а не заранее.
|
||||
|
||||
@@ -160,6 +160,6 @@ description: "Завести новый проект — сессия вопро
|
||||
|
||||
- **Не проектирует систему.** Архитектура выводится из кода, а не наоборот.
|
||||
- **Не пишет код** и не заводит сборку.
|
||||
- **Не переводит существующий проект** — это `doc-canon adopt`. Признак: в
|
||||
- **Не переводит существующий проект** — это `canon adopt`. Признак: в
|
||||
репозитории уже есть документация или беклог в какой-то раскладке.
|
||||
- **Не решает за человека**, что важно: цель, границы и периметр — его ответы.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
name: doc-sync
|
||||
description: Вести содержимое документов канона по ходу разработки — синк после сделанной задачи с построчным отчётом по каждому документу, заведение ADR промоутом из архивного design.md или из записки разведки, запись наблюдения в research, запись дефекта и настройки конвейера в review.md, чистка architecture.md от поведения с маркерами долга. Использовать, когда задача сделана и надо обновить документацию, когда просят завести ADR или записать решение, занести находку о внешних данных, записать проскочивший дефект, разгрузить разросшуюся архитектуру. Раскладку и соответствие канону проверяет скилл av-dev:doc-canon.
|
||||
description: Вести содержимое документов канона по ходу разработки — синк после сделанной задачи с построчным отчётом по каждому документу, заведение ADR промоутом из архивного design.md или из записки разведки, запись наблюдения в research, запись дефекта и настройки конвейера в review.md, чистка architecture.md от поведения с маркерами долга. Использовать, когда задача сделана и надо обновить документацию, когда просят завести ADR или записать решение, занести находку о внешних данных, записать проскочивший дефект, разгрузить разросшуюся архитектуру. Раскладку и соответствие канону проверяет скилл av-dev:canon.
|
||||
---
|
||||
|
||||
# Ведение содержимого канона
|
||||
|
||||
Скилл владеет **содержимым** документов канона; раскладкой владеет `doc-canon`.
|
||||
Определение канона и роли документов — [канон](../doc-canon/references/canon.md),
|
||||
Скилл владеет **содержимым** документов канона; раскладкой владеет `canon`.
|
||||
Определение канона и роли документов — [канон](../canon/references/canon.md),
|
||||
здесь не пересказывается.
|
||||
|
||||
Главный вызывающий — **шаг синка документации в конвейере задачи**: скилл
|
||||
@@ -106,11 +106,11 @@ description: Вести содержимое документов канона
|
||||
`av-dev:code-resolve`, сценарий разведки: решение, принятое разведкой (намеренный отказ, выбор
|
||||
подхода, «проверили и не делаем»), `design.md` не имеет по построению — change по
|
||||
нему не будет никогда. Промоут при этом тот же: цитата и ссылка, но на записку.
|
||||
Перечень источников закрыт и живёт в [каноне](../doc-canon/references/canon.md),
|
||||
Перечень источников закрыт и живёт в [каноне](../canon/references/canon.md),
|
||||
раздел `adr/`.
|
||||
|
||||
**Триггер заведения, форма имени и правило замены — в
|
||||
[каноне](../doc-canon/references/canon.md), раздел `adr/`.** Здесь они не
|
||||
[каноне](../canon/references/canon.md), раздел `adr/`.** Здесь они не
|
||||
повторяются: копия правила расходится с оригиналом на первой же смене версии
|
||||
канона, а расходится незаметно.
|
||||
|
||||
@@ -126,7 +126,7 @@ description: Вести содержимое документов канона
|
||||
|
||||
Обзор не держит поведение — его нормативный дом `openspec/specs/`. **Форма
|
||||
маркера долга и правило «гейт от них не краснеет» — в
|
||||
[каноне](../doc-canon/references/canon.md), раздел `architecture.md`.**
|
||||
[каноне](../canon/references/canon.md), раздел `architecture.md`.**
|
||||
|
||||
Разбирается порциями: раздел вычищает та задача, которая его касается.
|
||||
Содержимое не выбрасывается, а переезжает — требования в дельта-спеку change,
|
||||
@@ -136,7 +136,7 @@ description: Вести содержимое документов канона
|
||||
|
||||
Наблюдение о внешнем мире: что реально шлёт источник, чем документация формата
|
||||
расходится с практикой. **Требование провенанса и правило про расходящееся
|
||||
число — в [каноне](../doc-canon/references/canon.md), раздел `research/`.**
|
||||
число — в [каноне](../canon/references/canon.md), раздел `research/`.**
|
||||
|
||||
Твоя часть — заметить, что по ходу задачи узналось новое о внешних данных, и не
|
||||
дать этому остаться в контексте. Признак: ты правил разбор, опираясь на то, чего
|
||||
@@ -163,7 +163,7 @@ description: Вести содержимое документов канона
|
||||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||||
|
||||
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
|
||||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||||
поведении.
|
||||
@@ -191,7 +191,7 @@ description: Вести содержимое документов канона
|
||||
|
||||
Файл держит два раздела с разными сроками жизни — журнал дефектов и настройку
|
||||
конвейера. **Что в каком и в какой форме — в
|
||||
[каноне](../doc-canon/references/canon.md), раздел `review.md`**; подробности формы
|
||||
[каноне](../canon/references/canon.md), раздел `review.md`**; подробности формы
|
||||
записи и выбор адреса, куда она ведёт, — у конвейера ревью: `Skill
|
||||
av-dev:code-review`, его `references/review-journal.md`.
|
||||
|
||||
@@ -205,7 +205,7 @@ av-dev:code-review`, его `references/review-journal.md`.
|
||||
Находка → конвенция → правило линтера → **удаление из прозы**. Процедура целиком
|
||||
принадлежит конвейеру ревью — его `references/promote.md`, читается через
|
||||
`Skill av-dev:code-review`; роль каталога конвенций — в
|
||||
[каноне](../doc-canon/references/canon.md). **Прогон идёт вне конвейера**
|
||||
[каноне](../canon/references/canon.md). **Прогон идёт вне конвейера**
|
||||
(находку принесли руками) — три шага всё равно твои, просто без его процедуры:
|
||||
сформулируй правило,
|
||||
поищи, чем оно механизируется, и вычеркни прозу, если механизировалось.
|
||||
@@ -217,8 +217,8 @@ av-dev:code-review`, его `references/review-journal.md`.
|
||||
|
||||
## Чего этот скилл не делает
|
||||
|
||||
- **Не проверяет раскладку** — это `doc-canon`.
|
||||
- **Не заводит недостающие документы** — их скелет кладёт `doc-canon adopt` или
|
||||
- **Не проверяет раскладку** — это `canon`.
|
||||
- **Не заводит недостающие документы** — их скелет кладёт `canon adopt` или
|
||||
`doc-init`.
|
||||
- **Не сочиняет содержание.** Нечего записать — так и пишется, честной строкой.
|
||||
- **Не переоформляет документы «заодно»**: правится то, чего коснулась работа.
|
||||
|
||||
@@ -244,4 +244,4 @@ flowchart TD
|
||||
себе — формат и содержимое ведёт `task-track` (груминг зовёт его операции). Не решает
|
||||
за человека, что важно: он готовит развилки и рекомендует. Не принимает
|
||||
закрытые задачи отдельным ритуалом — `reopen` есть, момента у него нет. Не судит
|
||||
документы проекта — это скиллы `av-dev:doc-canon` и `av-dev:doc-healthcheck`.
|
||||
документы проекта — это скиллы `av-dev:canon` и `av-dev:doc-healthcheck`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: task-track
|
||||
description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). У каждой записи есть тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Каталог отстал от версии раскладки — это скажет tasks.py check, а повышает проект скилл av-dev:doc-canon по общему журналу версий. Расстановка приоритетов и разбор накопившегося — скилл av-dev:task-groom. Не реализует задачи — этим занимается скилл решения задачи.
|
||||
description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). У каждой записи есть тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Каталог отстал от версии раскладки — это скажет tasks.py check, а повышает проект скилл av-dev:canon по общему журналу версий. Расстановка приоритетов и разбор накопившегося — скилл av-dev:task-groom. Не реализует задачи — этим занимается скилл решения задачи.
|
||||
---
|
||||
|
||||
# Задачи
|
||||
@@ -511,7 +511,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
|
||||
Формат каталога задач меняется, и проект должен знать, к какой версии он
|
||||
приведён. Число живёт ключом `version` в `.av-dev.toml` в корне репозитория,
|
||||
журнал версий — [журнал скилла `doc-canon`](../doc-canon/references/changelog.md),
|
||||
журнал версий — [журнал скилла `canon`](../canon/references/changelog.md),
|
||||
сверяет их `tasks.py check`: отстало — строка расхождения, ушло вперёд — устарел
|
||||
плагин. Обратной совместимости нет: есть «приведён» и «не приведён».
|
||||
|
||||
@@ -521,7 +521,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
половины проектов нет. Плагин один — довод ушёл, а два числа оставляли бы
|
||||
вопрос, по какому журналу повышать.
|
||||
|
||||
**Повышает проект скилл `av-dev:doc-canon`, операция `upgrade`** — он идёт по
|
||||
**Повышает проект скилл `av-dev:canon`, операция `upgrade`** — он идёт по
|
||||
журналу, двигает число и зовёт этот скилл там, где запись касается задач. Здесь
|
||||
повышения нет намеренно: две операции, двигающие одно число, разъезжаются на
|
||||
первом же проекте, где прошла только одна из них.
|
||||
@@ -580,7 +580,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
**одним проходом вместе с починкой перекрёстных ссылок**, а не по одному слагу.
|
||||
|
||||
Если переводить надо не только задачи, а весь `docs/` — это скилл
|
||||
`av-dev:doc-canon`, и он зовёт этот сценарий сам на своём шаге.
|
||||
`av-dev:canon`, и он зовёт этот сценарий сам на своём шаге.
|
||||
|
||||
### Декомпозиция и штурм сырья
|
||||
|
||||
@@ -685,7 +685,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
- **Каталог задач — `tasks/` в корне, жёстко**, и `--dir` передаётся явно всегда:
|
||||
раскладка канона одинакова во всех проектах, и искать больше нечего. Каталога
|
||||
нет — код 3 и вопрос человеку; `init` заводит его **только** когда проект
|
||||
действительно новый, а перевод чужой раскладки делает `av-dev:doc-canon`.
|
||||
действительно новый, а перевод чужой раскладки делает `av-dev:canon`.
|
||||
У скрипта поиск вверх по дереву ещё жив — он для непереведённых проектов, и
|
||||
полагаться на него скилл не должен: молча найденный чужой каталог это дрейф.
|
||||
- **Версия и настройки живут в `.av-dev.toml` в корне репозитория** — версия
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
после неё проект живёт скиллами `task-track` и `task-groom`.
|
||||
|
||||
**Это часть приведения проекта к канону.** Раскладку `docs/` целиком ведёт скилл
|
||||
`av-dev:doc-canon`; он же зовёт этот сценарий на шаге «каталог задач», потому что
|
||||
форматом задач владеет `task-track`, а не `doc-canon`. Отдельно сценарий вызывается,
|
||||
`av-dev:canon`; он же зовёт этот сценарий на шаге «каталог задач», потому что
|
||||
форматом задач владеет `task-track`, а не `canon`. Отдельно сценарий вызывается,
|
||||
когда переводить надо **только** задачи.
|
||||
|
||||
Вход какой угодно: старая раскладка `av-dev-backlog` (индекс `README.md`,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
называется ключом `[tasks] dir`. Каталог принадлежит этому скиллу, а не канону
|
||||
документов: учёт работ ведут и в проекте, который к канону не приведён. Имена
|
||||
частей и **версия раскладки** живут в `.av-dev.toml` в корне; журнал версий —
|
||||
references/changelog.md скилла doc-canon.
|
||||
references/changelog.md скилла canon.
|
||||
|
||||
tasks/
|
||||
items/ задачи и цели файлами, <slug>.md
|
||||
@@ -503,7 +503,7 @@ def _validate_config(data: dict, path: Path) -> dict:
|
||||
if "plan" in unknown:
|
||||
raise Env(f"{path}: ключ «plan» переименован в «roadmap»,"
|
||||
f" а PLAN.md — в ROADMAP.md. Повысь проект скиллом"
|
||||
f" av-dev:doc-canon (upgrade), а не правь ключ в одиночку:"
|
||||
f" av-dev:canon (upgrade), а не правь ключ в одиночку:"
|
||||
f" файл и ссылки на него переезжают вместе с ним")
|
||||
if unknown:
|
||||
known = sorted({*DEFAULTS, DIR_KEY})
|
||||
@@ -582,10 +582,10 @@ def version_problems(lay: Layout) -> list[str]:
|
||||
if legacy:
|
||||
return [f"нет {path}, а прежняя раскладка на месте"
|
||||
f" ({', '.join(legacy)}): перенеси настройки и удали старые"
|
||||
f" файлы операцией upgrade скилла av-dev:doc-canon"]
|
||||
f" файлы операцией upgrade скилла av-dev:canon"]
|
||||
return [f"нет {path} — версия раскладки не объявлена."
|
||||
f" Заведи файл с «{VERSION_KEY} = {LAYOUT_VERSION}» (журнал"
|
||||
f" версий — references/changelog.md скилла av-dev:doc-canon)"]
|
||||
f" версий — references/changelog.md скилла av-dev:canon)"]
|
||||
# Что число целое, уже проверил общий читатель — иначе сюда не дошли бы
|
||||
# вовсе (код 3). Здесь `isinstance` значит ровно «ключ есть».
|
||||
got = conf.version(lay.full)
|
||||
@@ -595,7 +595,7 @@ def version_problems(lay: Layout) -> list[str]:
|
||||
elif got < LAYOUT_VERSION:
|
||||
out.append(f"проект приведён к раскладке версии {got}, текущая —"
|
||||
f" {LAYOUT_VERSION}: нужно повышение по журналу"
|
||||
f" (скилл av-dev:doc-canon, операция upgrade)")
|
||||
f" (скилл av-dev:canon, операция upgrade)")
|
||||
elif got > LAYOUT_VERSION:
|
||||
out.append(f"проект приведён к раскладке версии {got}, а скрипт знает"
|
||||
f" {LAYOUT_VERSION}: устарел плагин, обнови маркетплейс")
|
||||
|
||||
Reference in New Issue
Block a user