feat(readme): switch support link to /contacts (#270)

* feat(tool): switch create-readme support link to /contacts

* feat(scripts): warn on deprecated support link in readme check

* feat(templates): switch cookiecutter readme support links to contacts

* docs(skill): drop removed validate mode from repo-readme docs

* test(status): cover contacts link warn/fail/ok cases

* fix(ci): shorten lines to satisfy ruff

* fix(ci): apply ruff format

---------

Co-authored-by: opencode-agent <agent@opencode.local>
This commit is contained in:
Sergey 2026-08-05 03:54:59 +03:00 committed by GitHub
parent c0e8ec816a
commit 70b8203704
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 70 additions and 33 deletions

View file

@ -1,5 +1,5 @@
---
description: Standardize repo README + cover image (create/validate)
description: Standardize repo README + cover image (create)
agent: build
---
Load the `repo-readme` skill via `skill({name: "repo-readme"})` and follow its ПРОТОКОЛ strictly. Workflow: create-readme (generate) → draw-image (cover) → validate → fix cycle. One command = full README + cover standardization.
Load the `repo-readme` skill via `skill({name: "repo-readme"})` and follow its ПРОТОКОЛ strictly. Workflow: create-readme (create) → draw-image (cover) → проверка через project-status check_readme. One command = full README + cover standardization.

View file

@ -1013,12 +1013,21 @@ def _readme_required_sections(content: str) -> list[CheckResult]:
)
else:
results.append(CheckResult(CheckStatus.OK, "[Русский](#-русский)", "присутствует"))
if "slaid098.dev/support" not in content:
if "slaid098.dev/contacts" in content:
results.append(CheckResult(CheckStatus.OK, "slaid098.dev/contacts", "присутствует"))
elif "slaid098.dev/support" in content:
results.append(
CheckResult(CheckStatus.FAIL, "slaid098.dev/support", "отсутствует support link")
CheckResult(
CheckStatus.WARN,
"slaid098.dev/contacts",
"deprecated: найдена старая ссылка slaid098.dev/support, "
"перегенерируй README через create-readme",
)
)
else:
results.append(CheckResult(CheckStatus.OK, "slaid098.dev/support", "присутствует"))
results.append(
CheckResult(CheckStatus.FAIL, "slaid098.dev/contacts", "отсутствует support link")
)
if "Quick Start" not in content:
results.append(
CheckResult(CheckStatus.FAIL, "Quick Start", "отсутствует EN секция Quick Start")

View file

@ -14,11 +14,11 @@ Support block, Quick Start, language switcher). Скилл даёт контек
- **Новый репо**`create-readme` (mode: `create`) — генерирует
стандартизированный двуязычный README с нуля.
- **Проверка существующего README**`create-readme` (mode: `validate`) —
проверяет, что структура соответствует стандарту витрины.
- **После ручных правок README** → всегда `validate`. Любая правка руками
- **Проверка существующего README**`.opencode/scripts/project-status.py`
(`check_readme`) — проверяет, что структура соответствует стандарту витрины.
- **После ручных правок README** → всегда проверка через `check_readme`. Любая правка руками
агента (через Edit/Write) может нарушить разделители — после правок
обязательна валидация.
обязательна проверка.
Не генерируй README вручную через Write — структура критична для парсинга
витриной. Только через тулзу `create-readme`.
@ -44,9 +44,10 @@ Support block, Quick Start, language switcher). Скилл даёт контек
`"./assets/cover.png"` — можно не передавать.
3. Ручные правки если нужно (агент редактирует файл напрямую через Edit) —
например, расширить `custom_sections`, поправить формулировки.
4. `create-readme` (mode: `validate`) → проверяет, что структура не нарушена
(теперь в т.ч. наличие `assets/cover.png` reference).
5. Если `validate` fails → фикс нарушения → re-`validate`. Цикл пока не
4. Проверка через `.opencode/scripts/project-status.py` (`check_readme`) →
структура соответствует стандарту витрины (в т.ч. наличие
`assets/cover.png` reference).
5. Если проверка fails → фикс нарушения → повторная проверка. Цикл пока не
пройдёт.
Локальный режим (по умолчанию): тулза пишет в `file_path` (default
@ -95,7 +96,7 @@ README ссылается именно на этот путь через `![Cove
Поэтому структура README **должна быть гарантирована тулзой**, а не агентом.
Агент может менять текст *внутри* разделителей, но не должен удалять/двигать
сами разделители. `validate` ловит такие нарушения.
сами разделители. `check_readme` ловит такие нарушения.
## 5. Шаблон README (reference)
@ -181,17 +182,18 @@ README ссылается именно на этот путь через `![Cove
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**
```
`validate` проверяет: наличие всех 6 пар EN/RU разделителей (tagline + summary +
features), непустой контент между ними, H1 title prefix `# 🚀 `, **cover image
`check_readme` (project-status.py) проверяет: наличие всех 6 пар EN/RU
разделителей (tagline + summary + features), непустой контент между ними, H1
title prefix `# 🚀 `, **cover image
reference `assets/cover.png`** (substring-чек, без проверки существования
файла), ссылку
`slaid098.dev/support`, секции Quick Start (EN) и Быстрый старт (RU), language
`slaid098.dev/contacts`, секции Quick Start (EN) и Быстрый старт (RU), language
switcher `[English]` / `[Русский]`, заголовок `## 🇷🇺 Русский` (не "Русская
версия"), anchor `[Русский](#-русский)` (не `#-русская-версия`). Флагирует
ручной заголовок `## License` / `## LICENSE` / `## Лицензия` как ERROR
ручной заголовок `## License` / `## LICENSE` / `## Лицензия` как FAIL
дубликат GitHub sidebar (GitHub рендерит license из LICENSE-файла). Шаги
`quick_start_steps_*` не влияют на валидацию — они рендерятся вне delimiter-пар
(summary/features).
@ -209,7 +211,7 @@ switcher `[English]` / `[Русский]`, заголовок `## 🇷🇺 Ру
`create-readme`:
- `mode``"create"` | `"validate"` (обязательный).
- `mode``"create"` (обязательный).
- `repo_name`, `tagline_en`, `tagline_ru`, `why_en`, `what_en`, `why_ru`,
`what_ru`, `quick_start`, `features_en`, `features_ru` — обязательны для
`create`.
@ -315,6 +317,6 @@ Access at [http://localhost:4096](http://localhost:4096)
`❌ tagline_en is required for create mode`.
**Существующие README** (без tagline delimiter-тегов) станут invalid при
`validate` — `Missing <!-- tagline-en:start --> delimiter` и
проверке `check_readme` — `Missing <!-- tagline-en:start --> delimiter` и
`Missing <!-- tagline-ru:start --> delimiter`. Регенерация README через
`create` (с новыми параметрами) делается отдельным шагом после merge.

View file

@ -32,7 +32,7 @@ uv run uvicorn main:app --reload
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**
---
@ -64,4 +64,4 @@ uv run uvicorn main:app --reload
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**

View file

@ -31,7 +31,7 @@ uv sync --extra dev
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**
---
@ -62,4 +62,4 @@ uv sync --extra dev
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**

View file

@ -32,7 +32,7 @@ cd frontend && npm install && npm run dev
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**
---
@ -64,4 +64,4 @@ cd frontend && npm install && npm run dev
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**

View file

@ -126,7 +126,7 @@ ${bashBlockRu}${stepsRu}${accessLineRu}${developmentBlockRu}
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**
`
}

View file

@ -125,7 +125,7 @@ pip install -r requirements.txt
## 💬 Support and contacts / Поддержка и контакты
👉 **[slaid098.dev/support](https://slaid098.dev/support)**
👉 **[slaid098.dev/contacts](https://slaid098.dev/contacts)**
"""
DELIMITERS = [

View file

@ -860,7 +860,7 @@ def _write_valid_readme(tmp_path: Path) -> None:
content = (
"# 🚀 Title\n[English](#-english) [Русский](#-русский)\n"
"## 🇺🇸 English\n## 🇷🇺 Русский\nassets/cover.png\n"
"Quick Start\nБыстрый старт\nslaid098.dev/support\n"
"Quick Start\nБыстрый старт\nslaid098.dev/contacts\n"
)
for d in ps.README_DELIMITERS:
content += f"<!-- {d} -->\n"
@ -887,7 +887,7 @@ def test_readme_missing(tmp_path, ctx):
def test_readme_missing_delimiters(tmp_path, ctx):
(tmp_path / "README.md").write_text(
"# 🚀 Title\n## 🇺🇸 English\n## 🇷🇺 Русский\n[English](#-english)\n"
"[Русский](#-русский)\nQuick Start\nБыстрый старт\nslaid098.dev/support\n"
"[Русский](#-русский)\nQuick Start\nБыстрый старт\nslaid098.dev/contacts\n"
)
group = ps.check_readme(ps.ProjectType.BACKEND, ctx)
assert any("delimiter" in c.name and c.status == ps.CheckStatus.FAIL for c in group.checks)
@ -905,13 +905,39 @@ def test_readme_missing_ru_switcher_fail(tmp_path, ctx):
def test_readme_missing_support_link_fail(tmp_path, ctx):
"""README без ``slaid098.dev/support`` → FAIL."""
"""README без обеих ссылок (contacts/support) → FAIL."""
_write_valid_readme(tmp_path)
content = (tmp_path / "README.md").read_text().replace("slaid098.dev/support", "")
content = (tmp_path / "README.md").read_text().replace("slaid098.dev/contacts", "")
(tmp_path / "README.md").write_text(content)
group = ps.check_readme(ps.ProjectType.BACKEND, ctx)
assert any(
c.name == "slaid098.dev/support" and c.status == ps.CheckStatus.FAIL for c in group.checks
c.name == "slaid098.dev/contacts" and c.status == ps.CheckStatus.FAIL for c in group.checks
)
assert group.overall() == ps.CheckStatus.FAIL
def test_readme_deprecated_support_link_warn(tmp_path, ctx):
"""README только со старой ссылкой ``slaid098.dev/support`` → WARN (не FAIL)."""
_write_valid_readme(tmp_path)
content = (
(tmp_path / "README.md")
.read_text()
.replace("slaid098.dev/contacts", "slaid098.dev/support")
)
(tmp_path / "README.md").write_text(content)
group = ps.check_readme(ps.ProjectType.BACKEND, ctx)
assert any(
c.name == "slaid098.dev/contacts" and c.status == ps.CheckStatus.WARN for c in group.checks
)
assert group.overall() == ps.CheckStatus.WARN
def test_readme_contacts_link_ok(tmp_path, ctx):
"""README со ссылкой ``slaid098.dev/contacts`` → OK."""
_write_valid_readme(tmp_path)
group = ps.check_readme(ps.ProjectType.BACKEND, ctx)
assert any(
c.name == "slaid098.dev/contacts" and c.status == ps.CheckStatus.OK for c in group.checks
)