Compare commits

..

10 Commits

12 changed files with 1243 additions and 0 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
.DS_Store
*.log
node_modules/
.env
.env.local
.env.*

View File

@ -0,0 +1,12 @@
{
"mcpServers": {
"222a-seo-audit": {
"type": "http",
"url": "https://222a.ru/api/mcp",
"headers": {
"Authorization": "Bearer ${MCP_222A_TOKEN}",
"X-Plugin-Version": "1.0.0"
}
}
}
}

View File

@ -0,0 +1,71 @@
# 222A SEO Audit — плагин для Claude Code
Доступ к SEO-аудитам, анализу технических проблем и client reports от 222A.ru прямо из Claude Code.
## Установка
```bash
/plugin marketplace add https://git.222a.ru/222a/claude-marketplace.git
/plugin install 222a-seo-audit@222a
```
## Получение токена
1. Откройте [https://222a.ru/lk/ai-tokens](https://222a.ru/lk/ai-tokens)
2. Войдите или зарегистрируйтесь
3. Создайте токен с правами **`mcp.read`** и **`mcp.write`**
4. Скопируйте токен
## Настройка переменной окружения
**macOS / Linux (zsh):**
```bash
echo 'export MCP_222A_TOKEN="вставьте-сюда-токен"' >> ~/.zshrc
source ~/.zshrc
```
**Linux (bash):**
```bash
echo 'export MCP_222A_TOKEN="вставьте-сюда-токен"' >> ~/.bashrc
source ~/.bashrc
```
**Windows PowerShell:**
```powershell
[Environment]::SetEnvironmentVariable("MCP_222A_TOKEN", "вставьте-сюда-токен", "User")
```
После настройки **перезапустите Claude Code**.
## Команды
| Команда | Описание |
|---|---|
| `/222a-audit <url\|project_id>` | Запустить аудит сайта и получить executive summary |
| `/222a-status [audit_run_id]` | Статус текущего или указанного аудита |
| `/222a-issue <issue_code> [audit_run_id]` | Разбор одной проблемы: затронутые URL + рекомендации |
| `/222a-report [audit_run_id]` | Собрать client report из готовых артефактов |
| `/222a-progress [audit_run_id]` | Сравнение с предыдущим аудитом |
Помимо команд, можно просто описать задачу естественным языком — Claude использует подключённый MCP-сервер и встроенные workflow.
## Обновление
```bash
/plugin marketplace update
/plugin update 222a-seo-audit
```
## Безопасность
- **Не коммитьте токен** в репозитории и не отправляйте в чаты
- Если токен утёк — отзовите его на [https://222a.ru/lk/ai-tokens](https://222a.ru/lk/ai-tokens) и создайте новый
- Токен хранится только в переменной окружения, не пишется в файлы плагина
## Поддержка
Issues и обратная связь: [https://git.222a.ru/222a/claude-marketplace/issues](https://git.222a.ru/222a/claude-marketplace/issues)
## Лицензия
Плагин распространяется свободно. Использование 222A.ru API — по условиям сервиса.

View File

@ -0,0 +1,40 @@
---
description: Запустить SEO-аудит сайта и показать executive summary
argument-hint: <url или project_id>
---
Пользователь хочет провести полный SEO-аудит. Аргумент: `$ARGUMENTS`
## Шаги
1. **Определить project_id:**
- Если аргумент похож на URL — вызови `list_projects` и найди проект, у которого `url` или `domain` совпадает с аргументом.
- Если нашёл — используй его `project_id`.
- Если не нашёл — спроси пользователя подтверждение и вызови `create_project` с этим URL.
- Если аргумент — число/uuid — используй как `project_id` напрямую.
- Если аргумент пустой — вызови `list_projects` и попроси пользователя выбрать проект.
2. **Запустить аудит:**
- Вызови `start_audit` с найденным `project_id`.
- Сохрани `audit_run_id` из ответа — он понадобится для следующих шагов и должен оставаться видимым пользователю.
3. **Polling статуса:**
- Вызывай `get_audit_status` с возрастающим интервалом: 10s → 30s → 60s → 60s...
- Не делай tight loop. На каждой итерации показывай пользователю короткий статус (прогресс/этап).
- Останавливайся когда `status` = `completed` (успех) или `failed`/`cancelled` (показать причину).
4. **Executive summary:**
- При успехе вызови `get_executive_summary` для этого `audit_run_id`.
- Покажи пользователю результат: краткое резюме, топ-проблемы, ключевые метрики.
5. **Сохранить артефакт:**
- Если есть `mcp.write` (если scope позволяет) — вызови `save_audit_artifact` с типом `executive_summary`, `source="claude-code"`, телом полученного summary.
- Если `mcp.write` нет — пропусти этот шаг молча.
6. **Финальный вывод:**
- Покажи `audit_run_id` и подскажи следующие команды: `/222a-issue <code>` для разбора проблемы, `/222a-report` для client report, `/222a-progress` для сравнения с предыдущим аудитом.
## Замечания
- При ошибках `mcp.write` (scope error) — сообщи пользователю «токен без `mcp.write` — артефакт не сохранён», но не прерывай вывод executive summary.
- Если `start_audit` падает с «project not in current team» — попроси пользователя проверить, что токен от того же аккаунта, в котором создан проект.

View File

@ -0,0 +1,41 @@
---
description: Разбор одной проблемы из аудита (URL + рекомендации + evidence)
argument-hint: "<issue_code> [audit_run_id]"
---
Пользователь хочет разобрать конкретную проблему. Аргументы: `$ARGUMENTS` (первый — issue_code, опциональный второй — audit_run_id).
## Шаги
1. **Распарсить аргументы:**
- Первое слово — `issue_code` (например `seo.duplicate_title`, `tech.internal_broken_link`, `perf.no_compression`).
- Второе слово (если есть) — `audit_run_id`.
- Если `issue_code` пустой — попроси пользователя указать.
- Если `audit_run_id` пустой — возьми последний completed аудит через `list_audits`.
2. **Получить страницы с проблемой:**
- Вызови `get_issue_pages` с `audit_run_id` и `issue_code`.
- Покажи список URL с их статусом (HTTP code, title если есть).
3. **Получить рекомендации:**
- Вызови `get_issue_remediation` с `audit_run_id` и `issue_code`.
- Покажи рекомендации.
4. **Разобрать evidence:**
- В ответах `get_issue_pages` инспектируй `evidence_type` и `evidence[]`:
- GSC CTR issues → `gsc_page_metrics`
- Yandex position drops → `yandex_webmaster_queries`
- Site-level sitemap → `sitemap_discovery`
- duplicate_h1 → `duplicate_h1_groups`
- near_duplicate → `near_duplicate_groups`
- URL issues → `url_samples` / `mixed_case_groups`
- hreflang → `hreflang_*`
- Page-level checks (schema, og, viewport, redirect_chain, perf.*, viewport_bad, js_errors, content.missing_*, tap_targets_small, font_too_small, heading_hierarchy_broken) → per-page `data` с конкретной находкой.
- Покажи пользователю самые важные эвиденсы.
5. **Особый случай `tech.internal_broken_link` vs `tech.target_not_crawled`:**
- Если код `tech.target_not_crawled`НЕ называй это «битыми ссылками». Это страницы, обнаруженные но не закраленные (по `max_pages_cap` или `robots_disallowed`).
- Рекомендация: увеличить `max_pages` (особенно если `top_uncrawled_targets[].incoming_count` высокий — это популярные URL в навигации/футере) или поправить robots.txt.
6. **Сохранить артефакт:**
- Если есть `mcp.write` — вызови `save_audit_artifact` с типом `seo_recommendations` или `developer_tasks` (зависит от природы проблемы), `source="claude-code"`.

View File

@ -0,0 +1,38 @@
---
description: Сравнение текущего аудита с предыдущим (что починили, что появилось)
argument-hint: "[audit_run_id]"
---
Пользователь хочет понять прогресс между аудитами. Аргумент: `$ARGUMENTS`
## Шаги
1. **Определить audit_run_id:**
- Если аргумент задан — используй его.
- Если пустой — возьми последний completed аудит через `list_audits`.
2. **Прочитать контекст:**
- Вызови `get_audit_context` для `audit_run_id`.
- Посмотри секцию `progress_since_previous` в ответе.
3. **Если `progress_since_previous` доступна (быстрый путь):**
- Используй её для краткой сводки «что починили / что органически появилось».
- Покажи `top_resolved_pages` и `top_appeared_pages` если есть.
- **ВАЖНО — data-source disambiguation:**
- `appeared_issues_count` — органические (реальные новые проблемы)
- `appeared_due_to_new_data_source_count` / `top_appeared_due_to_new_data_source` — это **не деградация сайта**, это новый источник данных (например, подключили GSC и появились старые CTR-проблемы)
- `resolved_issues_count` — органические починки
- `resolved_due_to_data_source_unavailable_count` / `top_resolved_due_to_data_source_unavailable` — это **не реальные починки**, это отвалившийся источник данных. НЕ показывай как progress.
- **ВАЖНО — флэйковость perf:**
- Perf-issues (cls/inp/page_weight) у границ lab-thresholds могут мигать. Они помечены `is_flaky=true` и попадают в отдельные счётчики `appeared_flaky_count`, `resolved_flaky_count`, `changed_flaky_count`, `top_flaky_issues`.
- Не показывай их как progress/regression — это измерительный шум.
- **Site-level issues:**
- ya.*, seo.duplicate_*, tech.crawled_not_in_sitemap, seo.url_*, content.near_duplicate, seo.hreflang_*, seo.indexed_not_crawled — живут в отдельных счётчиках `site_appeared_issues_count`/`site_resolved_issues_count`/`site_changed_issues_count` с теми же data-source оговорками.
- Подавай их как audit-wide изменения, не per-URL.
4. **Если нужен drill-down:**
- Вызови `compare_audits` для детального сравнения.
- Issue `changed` bucket = изменения severity. `unchanged` = persistent проблемы с тем же severity.
5. **Сохранить артефакт:**
- Если есть `mcp.write` и сравнение полезное — вызови `save_audit_artifact` с типом `progress_comparison`, `source="claude-code"`.

View File

@ -0,0 +1,29 @@
---
description: Собрать client report из готовых артефактов аудита
argument-hint: "[audit_run_id]"
---
Пользователь хочет собрать отчёт для клиента. Аргумент: `$ARGUMENTS`
## Шаги
1. **Определить audit_run_id:**
- Если аргумент задан — используй его.
- Если пустой — возьми последний completed аудит через `list_audits`.
2. **Проверить состояние workspace:**
- Вызови `get_audit_workspace_summary` с этим `audit_run_id`.
- Посмотри `client_ready_count` и список `client_ready` артефактов.
- Если `client_ready_count` = 0 — сообщи «нет готовых для клиента артефактов. Сначала запустите `/222a-audit` и сохраните executive_summary, или попросите менеджера подготовить материалы». Не продолжай.
3. **Инспектировать артефакты:**
- Вызови `list_audit_artifacts` для просмотра доступных артефактов.
- Если есть только executive_summary без специалистских материалов (recommendations, work_plan, progress_comparison) — спроси пользователя, делать ли отчёт только из executive_summary или подождать остальное.
4. **Создать client report:**
- Вызови `create_client_report` с `audit_run_id`.
- Покажи пользователю получившийся client_report.
5. **Сохранить артефакт:**
- Если есть `mcp.write` — вызови `save_audit_artifact` с типом `client_report`, `source="claude-code"`, телом отчёта.
- Не перезаписывай существующий client_report — если он уже есть, передай `parent_artifact_id` для версии.

View File

@ -0,0 +1,25 @@
---
description: Статус последнего или указанного аудита
argument-hint: "[audit_run_id]"
---
Пользователь хочет посмотреть статус аудита. Аргумент: `$ARGUMENTS`
## Шаги
1. **Определить audit_run_id:**
- Если аргумент задан — используй его.
- Если пустой — вызови `list_audits` и возьми последний (самый свежий) аудит. Если их нет — сообщи «нет аудитов, запустите `/222a-audit <url>`».
2. **Получить статус:**
- Вызови `get_audit_status` с этим `audit_run_id`.
3. **Показать пользователю:**
- `status` (running/completed/failed/cancelled)
- Если running — текущий этап и прогресс (если поле есть в ответе)
- Если completed — дата завершения, краткие метрики (issue counts из `get_audit_context.summary` если нужно — отдельным вызовом)
- Если failed/cancelled — причина
4. **Подсказки:**
- Если completed — предложи `/222a-issue <code>`, `/222a-report`, `/222a-progress`
- Если running — предложи перезапустить `/222a-status` через минуту

View File

@ -0,0 +1,112 @@
---
name: "222a-seo-audit"
description: "Use when working with 222A SEO audit data: running audits, analyzing technical issues, GSC/Yandex metrics, generating client reports. Triggers: SEO audit, technical SEO, аудит сайта, GSC, Yandex Webmaster, core web vitals."
---
# 222A MCP Audit
Use the 222A MCP server for SEO audit context instead of scraping local database tables or asking for raw exports. The MCP contract intentionally exposes safe, manager-level audit data and hides raw HTML, headers, screenshots, logs, and low-level check payloads.
## Quick Start
1. The 222A MCP server is preconfigured by this plugin (`.mcp.json`). It connects to `https://222a.ru/api/mcp` using a Bearer token from `MCP_222A_TOKEN` env variable.
2. The user creates the token at `https://222a.ru/lk/ai-tokens` (see plugin README).
3. Use `mcp.read` for context and existing analyses; use `mcp.write` when saving durable audit work back to 222A.
4. Read `references/mcp-contract.md` for the MCP tool contract before debugging tool calls or saving analyses.
5. Treat `https://222a.ru/ai/capabilities.json` as the shared capability manifest.
## Common Workflow
- When the user asks what 222A can do, call `get_available_actions`, read `222a://capabilities`, or use REST `GET /api/v1/ai-audit-workspace/actions`, then present the returned action menu.
- For the full manager workflow, use `run_project_audit_and_save_summary` from the shared manifest: `list_projects`, choose an existing project or create one with `create_project` when missing, `start_audit`, `get_audit_status`, `get_audit_context`, then `save_audit_artifact`.
- For recurring monitoring, use `schedule_project_audit`: `list_projects`, then `schedule_audit` with a real `project_id`, cron expression, and timezone. Use `list_audit_schedules`, `update_audit_schedule`, and `delete_audit_schedule` to inspect or change periodic runs.
- For recommendation work, use `analyze_audit_and_save_recommendations`: `get_audit_workspace_summary`, `get_audit_context`, `list_audit_artifacts`, then save as `seo_recommendations` when write access exists.
- For role-based specialist tasks, use `prepare_specialist_tasks`: split the work into SEO, content, and development tasks, then save useful outputs as `seo_recommendations`, `content_tasks`, and `developer_tasks`.
- For client-facing reports, use `create_client_report_from_ready_artifacts`: check workspace state, inspect artifacts, then use `create_client_report` for `client_ready` work and save as `client_report`.
- To inspect affected URLs for one issue, take `issue_code` from `get_audit_context` and call `get_issue_pages` instead of asking for raw page checks. This also covers supported aggregate-only duplicate issues such as `seo.duplicate_title`, `seo.duplicate_meta_description`, `seo.duplicate_h1`. Always inspect `evidence_type` and `evidence[]`: Google CTR issues can include `gsc_page_metrics`, Yandex position drops can include `yandex_webmaster_queries`, site-level sitemap misses can include `sitemap_discovery`, duplicate H1 returns `duplicate_h1_groups`, near-duplicate text returns `near_duplicate_groups`, URL structure issues return `url_samples` or `mixed_case_groups`, and hreflang issues return `hreflang_*` evidence types. Page-level checks (schema, og, viewport, redirect_chain, perf.dom_too_large, perf.no_compression, viewport_bad, js_errors, content.missing_author/date/stale, tap_targets_small, font_too_small, heading_hierarchy_broken) include per-page `data` with the specific finding (problems list, missing tags, hop chain, metric values, samples).
- To inspect all problems for one URL, take `page_id` from `get_issue_pages` and call `get_page_audit` instead of asking for raw page checks.
- Distinguish `tech.internal_broken_link` (high — REAL broken: target is 4xx/5xx or genuinely missing) from `tech.target_not_crawled` (info — target was discovered but skipped by crawl policy: max_pages_cap, robots_disallowed). For target_not_crawled NEVER call these «broken links» — recommend increasing `max_pages` (especially when `top_uncrawled_targets[].incoming_count` is high — those URLs appear in nav/footer of many pages and are likely important categories like /articles, /sitemap) or adjusting robots.txt.
- To find near-duplicates of a page across the team's other completed audits (e.g. the same content appearing on two projects, or content stolen between sites), call `find_similar_pages_across_audits` with `audit_run_id` + `page_id`/`url`. Default similarity threshold is 0.85; lower it (e.g. 0.7) to widen the search. Returns matches sorted by similarity with project/audit context. Pages without sufficient text return `reason=no_simhash`.
- When reading `get_audit_context`, inspect `progress_since_previous` first. If it is available, use it for the quick "what was fixed / what organically appeared" manager summary, including `top_resolved_pages` and `top_appeared_pages` when present, then call `compare_audits` only when the user needs drill-down. `appeared_issues_count` is organic; treat `appeared_due_to_new_data_source_count` and `top_appeared_due_to_new_data_source` as new evidence from a newly connected source, not as site degradation. `resolved_issues_count` is organic; treat `resolved_due_to_data_source_unavailable_count` and `top_resolved_due_to_data_source_unavailable` as false-positive resolutions caused by a previously connected source going offline — do NOT report them as real fixes. Perf issues (cls/inp/page_weight) that toggle severity around lab thresholds across runs are flagged is_flaky=true and isolated into `appeared_flaky_count`, `resolved_flaky_count`, `changed_flaky_count`, and `top_flaky_issues` — treat them as measurement noise, do NOT highlight them as progress or regression. Site-level (audit-wide) issues such as ya.*, seo.duplicate_*, tech.crawled_not_in_sitemap, seo.url_*, content.near_duplicate, seo.hreflang_*, seo.indexed_not_crawled live in a separate set of counts (site_appeared_issues_count/site_resolved_issues_count/site_changed_issues_count and top_site_appeared_issues/top_site_resolved_issues/top_site_changed_issues), with the same data-source disambiguation (site_appeared_due_to_new_data_source / site_resolved_due_to_data_source_unavailable). Report them as audit-wide changes (affecting many URLs at once) distinct from per-URL page issues.
- To explain progress between two completed audits, call `compare_audits` and save useful conclusions as `progress_comparison` when write access exists. Treat the issue `changed` bucket as severity changes; same-severity persistent issues are in `unchanged`.
- When monitoring an audit, poll politely, avoid tight loops, and always keep `audit_run_id` visible so the user can resume later.
- List resources to discover available audits: `resources/list`.
- Read `audit://{audit_run_id}/context` or call `get_audit_context` before analysis.
- Read `audit://{audit_run_id}/workspace-summary` or call `get_audit_workspace_summary` when deciding whether to create/update a manager synthesis or client report. Use `workspace.progress_since_previous` for a quick progress note when available.
- Read `audit://{audit_run_id}/analyses` before writing, to avoid duplicating prior conclusions.
- Save durable, manager-facing output with `save_audit_artifact` unless the user explicitly says not to save it.
- Set `source` to `"claude-code"`.
## AI Artifacts
When the user asks for an analysis, plan, comparison, client text, or recommendations, save the result back to 222A as an append-only artifact unless they explicitly say not to save it. This keeps a durable history of work by different AI clients and specialists.
Use:
- `list_projects` to find existing projects before starting audits.
- `create_project` to create a new current-team project only after confirming it is not already in `list_projects`.
- `start_audit` to start a new audit for an existing current-team project.
- `get_audit_status` to monitor safe progress metadata.
- `schedule_audit` to create a periodic audit schedule for an existing current-team project.
- `list_audit_schedules`, `update_audit_schedule`, and `delete_audit_schedule` to manage periodic audit schedules.
- `get_issue_pages` to list safe page URLs, titles, and HTTP statuses for a specific issue code.
- `get_page_audit` to list all safe issue summaries for one specific page.
- `compare_audits` to compare two completed audits and summarize progress.
- `get_audit_workspace_summary` to understand saved AI work, latest synthesis, client-ready count, channels, progress since previous audit, and recommended next actions.
- `list_audits` before choosing an audit.
- `get_audit_context` to read safe audit data.
- `list_audit_artifacts` to inspect existing work.
- `synthesize_audit_artifacts` to combine saved specialist/AI work into a manager synthesis.
- `create_client_report` to build a client-facing report from `client_ready` artifacts.
- `save_audit_artifact` to create a new artifact.
Never overwrite existing artifacts. If you revise previous work, pass `parent_artifact_id` and create a new artifact.
Preferred artifact types:
- `executive_summary`
- `work_plan`
- `progress_comparison`
- `client_report`
## Prompt templates
The shared capability manifest at `https://222a.ru/ai/capabilities.json` publishes `prompt_templates` for user-facing audit workflows:
- `list_projects`
- `create_project`
- `start_project_audit`
- `schedule_project_audit`
- `check_audit_status`
- `get_issue_pages`
- `get_page_audit`
- `compare_audits`
- `run_audit_then_save_summary` (`run_project_audit_and_save_summary`)
- `analyze_audit_and_save_recommendations`
- `prepare_specialist_tasks`
- `list_audits`
- `latest_audit_summary`
- `save_executive_summary`
- `save_work_plan`
- `manager_synthesis`
- `create_client_report`
- `do_not_save`
When durable work uses `mcp.write`, save it append-only unless the user explicitly says not to save it.
## Slash Commands
This plugin provides 5 slash commands for common workflows. When a user's request matches one of these, suggest the corresponding command:
- `/222a-audit <url|project_id>` — full audit cycle: project → start → poll → executive summary → save artifact
- `/222a-status [audit_run_id]` — current/specified audit status; defaults to latest from `list_audits`
- `/222a-issue <issue_code> [audit_run_id]` — unpack one issue: pages + remediation + evidence
- `/222a-report [audit_run_id]` — build client report from `client_ready` artifacts via `create_client_report`
- `/222a-progress [audit_run_id]` — compare with previous audit via `progress_since_previous` or `compare_audits`
The commands trigger the same workflows described above with standardized output and automatic artifact saving.
## Analysis Rules
- Treat MCP context as the source of truth for what is safe to show to the model.
- Do not request raw HTML, screenshots, headers, cookies, console logs, or full crawler payloads.
- If `save_audit_artifact` or `save_audit_analysis` fails with an MCP scope error, report that the token needs `mcp.write`.
- If a read tool returns an empty result with `visible=false` or a `hint`, follow the hint: usually call `list_audits`, choose a visible audit, or ask the user for the right audit.

View File

@ -0,0 +1,722 @@
# 222A MCP Contract
## Endpoint
- Production URL: `https://222a.ru/api/mcp`
- Local URL: use `APP_URL` plus `/api/mcp`
- Transport: Streamable HTTP
- Protocol: JSON-RPC 2.0 over POST
- MCP protocol version returned by `initialize`: `2025-06-18`
- Auth: `Authorization: Bearer <token>`
Create tokens in the 222A LK page `/lk/ai-tokens`.
Shared machine-readable capability manifest:
- Production URL: `https://222a.ru/ai/capabilities.json`
- Repository source: `backend/resources/ai/222a-ai-capabilities.json`
Manifest v2 fields:
- `contract_version`: version identifier for the published AI workspace contract.
- `scopes`: token scopes and what each one authorizes.
- `source_clients`: allowed client identifiers for saved artifacts and analyses.
- `links`: canonical URLs for MCP, skill archives, token management, and related resources.
- `mcp_tools`: MCP tool descriptions, scopes, input schemas, and output expectations.
- `mcp_resources`: resource URIs/templates exposed to MCP clients.
- `rest_api`: REST mirror metadata and endpoint contracts.
- `recommended_workflows`: named multi-step workflows clients should compose from existing tools/endpoints.
- `prompt_templates`: user-facing prompt templates for common audit workflows.
Shared REST API for future clients:
- Production base path: `https://222a.ru/api/v1/ai-audit-workspace`
- Auth: the same user-owned Sanctum Bearer token and `mcp.read` / `mcp.write` scopes.
- Purpose: expose the same audit workspace operations to non-MCP clients without creating a separate domain contract.
- Action menu: `GET /actions` mirrors `get_available_actions` and accepts optional `audit_run_id`.
- Schedule endpoints mirror MCP schedule tools: `POST /projects/{project_id}/audit-schedules`, `GET /audit-schedules`, `PATCH /audit-schedules/{schedule_id}`, and `DELETE /audit-schedules/{schedule_id}`.
## Scopes
- `mcp.read`: list/read audit resources and call read tools.
- `mcp.write`: includes read access and allows saving append-only AI artifacts.
Tokens can also have `ai-tasks.*` scopes, but those are for pull-mode AI workers, not audit MCP analysis.
## Resources
`resources/list` returns resources for the current token user's current or first accessible team.
Resource templates:
- `audit://{audit_run_id}/context`
- `audit://{audit_run_id}/analyses`
- `audit://{audit_run_id}/workspace-summary`
Static resources:
- `222a://capabilities`: available user-facing actions, workflows, prompt templates, artifact types, links, and save-back behavior.
`audit://.../context` includes safe audit summary data such as project identity, run stats, issue index, page samples, saved AI analyses, and AI summary status. It does not include raw HTML bodies, raw check data, console logs, headers, cookies, or screenshots.
`audit://.../analyses` returns saved AI analyses/artifacts for the audit run, including author metadata.
`audit://.../workspace-summary` returns the same manager-friendly AI workspace state as `get_audit_workspace_summary`: artifact counts, latest manager synthesis, client-ready count, channels, progress since previous audit, next actions, and the save-back rule.
`222a://capabilities` mirrors `get_available_actions` for clients that prefer MCP resources over tools.
## Save-Back Rule
222A is an append-only AI workspace for SEO audits. When an AI client produces durable audit work for a user, it should save the result back to 222A with `save_audit_artifact` whenever `mcp.write` is available, unless the user explicitly asks not to save.
Durable audit work includes executive summaries, work plans, progress comparisons, client reports, technical notes, SEO recommendations, content tasks, developer tasks, and manager syntheses.
Before saving, inspect existing work with `list_audit_artifacts` when an `audit_run_id` is known. Never overwrite previous work. If revising a previous artifact, create a new artifact and pass `parent_artifact_id`.
## Tools
### `get_available_actions`
Requires `mcp.read`.
Input:
```json
{
"audit_run_id": 123
}
```
Output includes the user-facing action menu from the shared manifest: prompt templates, recommended workflows, artifact types, save-back rule, and links. Use this when the user asks what 222A can do, what to do next, or which audit actions are available. `audit_run_id` is optional and substitutes `<audit_run_id>` placeholders in returned prompts.
### `list_projects`
Requires `mcp.read`.
Input:
```json
{
"limit": 10
}
```
Output includes current-team projects and latest audit hints in `structuredContent.projects`. Use this before starting audits. Do not invent `project_id` values.
### `create_project`
Requires `mcp.write`.
Input:
```json
{
"name": "Example project",
"root_url": "https://example.com"
}
```
Creates a current-team project for a new audit target and returns the created project payload. Call `list_projects` first and use this only when the needed site is not already present.
### `start_audit`
Requires `mcp.write`.
Input:
```json
{
"project_id": 45
}
```
Starts an audit for an existing current-team project. Only call this after the project id came from `list_projects` or an equivalent REST project list.
### `get_audit_status`
Requires `mcp.read`.
Input:
```json
{
"audit_run_id": 123
}
```
Returns safe status and progress metadata. Poll politely and expose `audit_run_id` so the user can resume the workflow later.
### `schedule_audit`
Requires `mcp.write`.
Input:
```json
{
"project_id": 45,
"cron_expression": "0 3 * * *",
"timezone": "Europe/Moscow",
"audit_options": {
"max_pages": 500
}
}
```
Creates one enabled periodic audit schedule for an existing current-team project. Cron expressions must not run more often than once per hour, and each project can have only one active schedule. Output includes `schedule_id`, `next_run_at`, `cron_expression`, `timezone`, `is_enabled`, `last_run_at`, `last_audit_run_id`, and `audit_options`.
### `list_audit_schedules`
Requires `mcp.read`.
Input:
```json
{
"project_id": 45
}
```
Returns current-team audit schedules in `structuredContent.schedules`. `project_id` is optional.
### `update_audit_schedule`
Requires `mcp.write`.
Input:
```json
{
"schedule_id": 12,
"cron_expression": "0 4 * * *",
"timezone": "Europe/Moscow",
"audit_options": {
"max_pages": 1000
},
"is_enabled": true
}
```
Updates schedule settings and recalculates `next_run_at`. Set `is_enabled=false` to pause the schedule without deleting it.
### `delete_audit_schedule`
Requires `mcp.write`.
Input:
```json
{
"schedule_id": 12
}
```
Deletes one current-team audit schedule and returns `{ "deleted": true }`.
### `list_audits`
Requires `mcp.read`.
Input:
```json
{
"limit": 10
}
```
Output includes current-team audits newest first in `structuredContent.audit_runs`. Use this before choosing an audit when the user asks for projects, audits, recent audits, latest audits, or audit history.
### `get_audit_context`
Requires `mcp.read`.
Input:
```json
{
"audit_run_id": 123
}
```
Output includes the same safe context as `audit://123/context` in `structuredContent`. When a previous completed audit exists for the same project, `progress_since_previous` summarizes the adjacent diff: previous/current audit ids and finish times, resolved and organically appeared issue counts, issues attributed to newly connected data sources, issues attributed to data sources that became unavailable, improved/worsened severity counts, flaky perf counts (`appeared_flaky_count`, `resolved_flaky_count`, `changed_flaky_count`, `top_flaky_issues`), site-level issue counts (`site_appeared_issues_count`, `site_resolved_issues_count`, `site_changed_issues_count`, `top_site_appeared_issues`, `top_site_resolved_issues`, `top_site_changed_issues`, plus parallel `site_appeared_due_to_new_data_source_count` / `site_resolved_due_to_data_source_unavailable_count` and `top_site_*` variants), page deltas, `top_resolved_pages`, `top_appeared_pages`, HTTP status recovery/regression counts, score/page-crawl deltas, and top safe issue samples. `appeared_issues_count` is organic; explain `appeared_due_to_new_data_source_count` and `top_appeared_due_to_new_data_source` separately as new evidence, not automatic site degradation. `resolved_issues_count` is organic; explain `resolved_due_to_data_source_unavailable_count` and `top_resolved_due_to_data_source_unavailable` separately as false-positive resolutions caused by a previously connected source going offline, not real fixes. Flaky perf issues are kept out of `appeared`/`resolved`/`changed` buckets and routed to `appeared_flaky`/`resolved_flaky`/`changed_flaky` instead — these are measurement noise around lab thresholds, not real progress or regression. Site-level issues (ya.*, seo.duplicate_*, tech.crawled_not_in_sitemap, seo.url_*, content.near_duplicate, seo.hreflang_*, seo.indexed_not_crawled) are tracked separately in the `site_issues` bucket — they affect many URLs at once, not single pages. Use this for a quick manager answer about what was fixed since the last audit; call `compare_audits` for full drill-down (`compare_audits` payload includes both `issues` and `site_issues` buckets).
### `get_issue_pages`
Requires `mcp.read`.
Input:
```json
{
"audit_run_id": 123,
"issue_code": "seo.missing_h1",
"limit": 25
}
```
Output includes safe page-level findings in `structuredContent`: audit/project identity, issue metadata, `pages_count`, `total_pages_count`, `has_more`, and a `pages` list with `page_id`, `url`, `title`, and `http_status`. It supports normal page-check issues and supported aggregate-only duplicate issues such as `seo.duplicate_title` and `seo.duplicate_meta_description`. It can also return `evidence_type` and `evidence` for non-page signals: `evidence_type=gsc_page_metrics` for Google Search Console CTR issues, `evidence_type=yandex_webmaster_queries` for Yandex query issues such as `ya.position_dropped`, and `evidence_type=sitemap_discovery` for site-level `tech.sitemap_missing`. It does not include raw HTML, headers, screenshots, or raw check payloads.
Use this after `get_audit_context` when the user asks which URLs are affected by a specific issue. For `seo.high_impressions_low_ctr`, include clicks, impressions, CTR, and position from `pages[].gsc` or `evidence[]`. For `seo.indexed_not_crawled`, `page_id` can be null and fragment URLs are collapsed to the canonical URL with source samples. For `ya.position_dropped`, show `query_text`, `position_before`, `position_after`, and `delta_positions` from `evidence[]`. For `tech.sitemap_missing`, show `checked_paths`, robots Sitemap directives, and probe statuses. If both `pages` and `evidence` are empty, use the returned hint and suggest checking `issue_code` from the context.
### `get_page_audit`
Requires `mcp.read`.
Input:
```json
{
"audit_run_id": 123,
"page_id": 456
}
```
`url` may be used instead of `page_id` when the exact audit page URL is known. Output includes safe page metadata and all issue summaries for that page: code, severity, category, Russian title, and Russian description. It does not include raw HTML, headers, screenshots, console logs, network failures, or raw check payloads.
Use this after `get_issue_pages` when the user asks what exactly is wrong on a specific URL.
### `compare_audits`
Requires `mcp.read`.
Input:
```json
{
"base_audit_run_id": 123,
"compare_audit_run_id": 124,
"limit": 10
}
```
Output includes safe progress buckets for two completed current-team audits of the same project: `metrics`, issue buckets (`appeared`, `resolved`, `changed`, `unchanged`), and page buckets (`appeared`, `resolved`, `content_changed`, `robots_changed`, `unchanged`). Issue `changed` means severity changed; persistent same-severity issues are in `unchanged`. Bucket items include safe URLs, issue codes, severities, HTTP statuses, and robots statuses. They do not include raw check payloads, raw HTML, headers, screenshots, or content hashes.
Use this when the user asks for progress between audits. If the result is useful and `mcp.write` is available, save the conclusion append-only as `artifact_type=progress_comparison`.
### `get_audit_workspace_summary`
Requires `mcp.read`.
Input:
```json
{
"audit_run_id": 123
}
```
Output includes manager-friendly AI workspace state in `structuredContent.workspace`: artifact counts, human revisions, client-ready count, channels used by AI/LK/API clients, latest manager synthesis metadata, new artifact count after that synthesis, `progress_since_previous`, recommended next actions, and the save-back rule.
Use this before deciding what to do next on an audit. If it recommends `update_manager_synthesis`, call `synthesize_audit_artifacts`. If it recommends `create_client_report`, call `create_client_report`.
### `list_audit_artifacts`
Requires `mcp.read`.
Input:
```json
{
"audit_run_id": 123,
"limit": 10
}
```
Output includes already saved AI work for the audit in `structuredContent.artifacts`.
### `synthesize_audit_artifacts`
Requires `mcp.read`. Requires `mcp.write` only when `save` is `true`.
Input:
```json
{
"audit_run_id": 123,
"limit": 10,
"save": true,
"title": "Manager synthesis",
"source_client": "codex_skill"
}
```
Output includes a manager-facing synthesis draft in `structuredContent.summary_markdown`, the source artifacts used, and `saved_artifact` when `save=true`.
Use this when a manager wants a combined conclusion from several saved AI/specialist artifacts. If the synthesis is useful and `mcp.write` is available, save it as `manager_synthesis`.
### `create_client_report`
Requires `mcp.read`. Requires `mcp.write` only when `save` is `true`.
Input:
```json
{
"audit_run_id": 123,
"limit": 10,
"save": true,
"title": "Client report",
"source_client": "codex_skill"
}
```
Output includes a client-facing report draft in `structuredContent.summary_markdown`, only `client_ready` source artifacts, and `saved_artifact` when `save=true`.
Use this when a manager wants a client report from already approved AI/specialist work. It saves append-only as `client_report`.
### `save_audit_artifact`
Requires `mcp.write`.
Input:
```json
{
"audit_run_id": 123,
"artifact_type": "executive_summary",
"title": "Executive summary",
"summary_markdown": "## Summary\n...",
"structured_blocks": [],
"recommendations": [
{
"title": "Fix missing H1",
"priority": "high"
}
],
"metadata": {
"model": "codex",
"prompt_version": "manual/v1"
},
"status": "draft",
"source_client": "codex_skill",
"source_actor_type": "ai",
"source": "mcp-codex",
"ai_model": "gpt",
"prompt_version": "audit-artifact/v1"
}
```
Required fields: `audit_run_id`, `artifact_type`, `title`, `summary_markdown`.
Optional fields: `structured_blocks`, `recommendations`, `metadata`, `status`, `visibility`, `parent_artifact_id`, `source_client`, `source_actor_type`, `source`, `ai_model`, `prompt_version`.
The saved artifact is attached to the audit run, team, current token user, and current access token. Saving is append-only: the server creates a new record and never overwrites previous work.
Artifact types:
- `executive_summary`
- `work_plan`
- `progress_comparison`
- `client_report`
- `technical_notes`
- `seo_recommendations`
- `content_tasks`
- `developer_tasks`
- `manager_synthesis`
### `save_audit_analysis`
Requires `mcp.write`.
Compatibility tool for older analysis clients. Prefer `save_audit_artifact` for new MCP, skill, and ChatGPT App integrations.
## REST API Mirror
Future API, Actions, bot, or custom client integrations should use the same artifact language and save-back rule. The REST API mirrors the core MCP workspace operations:
- `GET /api/v1/ai-audit-workspace/audits`
- `GET /api/v1/ai-audit-workspace/audits/latest/context`
- `GET /api/v1/ai-audit-workspace/projects`
- `POST /api/v1/ai-audit-workspace/projects`
- `GET /api/v1/ai-audit-workspace/audits/{audit_run_id}/context`
- `GET /api/v1/ai-audit-workspace/audits/{audit_run_id}/issues/{issue_code}/pages`
- `GET /api/v1/ai-audit-workspace/audits/{base_audit_run_id}/compare/{compare_audit_run_id}`
- `GET /api/v1/ai-audit-workspace/audits/{audit_run_id}/pages/{page_id}/audit`
- `GET /api/v1/ai-audit-workspace/audits/{audit_run_id}/workspace-summary`
- `GET /api/v1/ai-audit-workspace/audits/{audit_run_id}/artifacts`
- `POST /api/v1/ai-audit-workspace/audits/{audit_run_id}/artifacts`
- `POST /api/v1/ai-audit-workspace/audits/{audit_run_id}/artifact-synthesis`
- `POST /api/v1/ai-audit-workspace/audits/{audit_run_id}/client-report`
Use `source_client: "future_client"` for REST clients that are not ChatGPT App, Codex skill, Claude skill, internal AI, or manual LK actions.
## Recommended Workflows
The manifest publishes `recommended_workflows` so MCP, skills, ChatGPT Apps, and future clients perform the same manager workflows without adding long-running server-side jobs.
### `run_project_audit_and_save_summary`
Purpose: start a fresh audit for an existing project, monitor completion, read safe audit context, and save a durable executive summary back to 222A.
Tool chain:
`list_projects → start_audit → get_audit_status → get_audit_context → list_audit_artifacts → save_audit_artifact`
Rules:
- Use only projects returned by `list_projects` or `GET /api/v1/ai-audit-workspace/projects`.
- Ask the user to choose if several projects are plausible.
- Do not invent `project_id` or `audit_run_id`.
- Do not claim completion until `get_audit_status` returns a terminal completed state.
- Poll politely; if the client session may time out, return `audit_run_id` and ask the user to continue later.
- If the audit fails or is cancelled, report the final status and safe error text; do not invent an analysis.
- If `mcp.write` is available and the user did not ask not to save, save the manager-facing result append-only as `artifact_type=executive_summary`.
### `analyze_audit_and_save_recommendations`
Purpose: turn safe audit data and existing AI work into prioritized SEO recommendations for a manager.
Tool/resource chain:
`get_audit_workspace_summary → get_audit_context → list_audit_artifacts → save_audit_artifact`
Resource-capable clients can use:
`audit://{audit_run_id}/workspace-summary → audit://{audit_run_id}/context → audit://{audit_run_id}/analyses`
Rules:
- Start with workspace summary when `audit_run_id` is known so you understand existing work, latest synthesis, client-ready count, and next actions.
- Read safe audit context before making recommendations.
- Inspect existing artifacts before saving to avoid duplicating prior conclusions.
- Do not request or expose raw HTML, headers, screenshots, cookies, console logs, or raw check payloads.
- If `mcp.write` is available and the user did not ask not to save, save append-only as `artifact_type=seo_recommendations`.
- If write scope is missing, still provide useful recommendations and clearly say they were not saved.
### `prepare_specialist_tasks`
Purpose: split audit findings and saved AI work into role-specific tasks for SEO, content, and development specialists.
Tool/resource chain:
`get_audit_workspace_summary → get_audit_context → list_audit_artifacts → save_audit_artifact`
Save targets:
- `seo_recommendations` for SEO specialist recommendations.
- `content_tasks` for copy, content structure, metadata, and editorial tasks.
- `developer_tasks` for redirects, canonicals, templates, rendering, performance, security, and implementation tasks.
Rules:
- Start with workspace summary and existing artifacts to avoid duplicating previous specialist work.
- Make each task actionable and testable: priority, reason from audit data, expected result, and verification step.
- Save separate append-only artifacts for each useful role output when `mcp.write` is available.
- If a role has no meaningful work, say so instead of inventing tasks.
- If write scope is missing, provide the role-specific tasks and clearly say they were not saved.
### `create_client_report_from_ready_artifacts`
Purpose: turn approved AI/specialist work into a client-facing report.
Tool/resource chain:
`get_audit_workspace_summary → list_audit_artifacts → create_client_report`
Resource-capable clients can use:
`audit://{audit_run_id}/workspace-summary → audit://{audit_run_id}/analyses`
Rules:
- Start with workspace summary to check `client_ready_count`, latest manager synthesis, and next actions.
- Inspect saved artifacts and include only material that is ready for the client.
- Prefer `create_client_report` over hand-writing this artifact because it uses the shared 222A client report builder.
- If `mcp.write` is available and the user did not ask not to save, call `create_client_report` with `save=true` and save append-only as `artifact_type=client_report`.
- If there are no `client_ready` artifacts, say which internal artifacts should be reviewed or marked ready first.
## REST Endpoint Contracts
Each endpoint in `rest_api.endpoints` describes the same contract shape:
- `method`: HTTP verb.
- `path`: path relative to `/api/v1/ai-audit-workspace`.
- `scope`: required token scope, usually `mcp.read` or `mcp.write`.
- `purpose`: human-readable reason to call the endpoint.
- `request_example`: example query parameters or JSON body.
- `response_shape`: high-level response fields clients should expect.
- `mcp_equivalent`: matching MCP tool or resource for clients that use JSON-RPC.
These endpoint contracts keep REST clients aligned with MCP clients and the same append-only save-back behavior.
## Prompt Template IDs
The manifest publishes these `prompt_templates` IDs:
- `list_projects`
- `create_project`
- `start_project_audit`
- `check_audit_status`
- `get_issue_pages`
- `get_page_audit`
- `compare_audits`
- `run_audit_then_save_summary`
- `analyze_audit_and_save_recommendations`
- `prepare_specialist_tasks`
- `list_audits`
- `latest_audit_summary`
- `save_executive_summary`
- `save_work_plan`
- `manager_synthesis`
- `create_client_report`
- `do_not_save`
These are user-facing prompts for clients and UI actions, not secret system prompts.
## JSON-RPC Examples
Initialize:
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize"
}
```
List tools:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}
```
Read audit context resource:
```json
{
"jsonrpc": "2.0",
"id": 3,
"method": "resources/read",
"params": {
"uri": "audit://123/context"
}
}
```
Call context tool:
```json
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "get_audit_context",
"arguments": {
"audit_run_id": 123
}
}
}
```
Get pages affected by one issue:
```json
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "get_issue_pages",
"arguments": {
"audit_run_id": 123,
"issue_code": "seo.missing_h1",
"limit": 25
}
}
}
```
List audits:
```json
{
"jsonrpc": "2.0",
"id": 6,
"method": "tools/call",
"params": {
"name": "list_audits",
"arguments": {
"limit": 10
}
}
}
```
Save artifact:
```json
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "save_audit_artifact",
"arguments": {
"audit_run_id": 123,
"artifact_type": "executive_summary",
"title": "SEO audit executive summary",
"summary_markdown": "## Summary\nThe audit shows...",
"recommendations": [],
"status": "draft",
"source_client": "codex_skill",
"source_actor_type": "ai",
"metadata": {
"model": "codex"
},
"source": "mcp-codex"
}
}
}
```
Synthesize artifacts and save the result:
```json
{
"jsonrpc": "2.0",
"id": 8,
"method": "tools/call",
"params": {
"name": "synthesize_audit_artifacts",
"arguments": {
"audit_run_id": 123,
"save": true,
"title": "Manager synthesis",
"source_client": "codex_skill"
}
}
}
```
```json
{
"jsonrpc": "2.0",
"id": 9,
"method": "tools/call",
"params": {
"name": "create_client_report",
"arguments": {
"audit_run_id": 123,
"save": true,
"title": "Client report",
"source_client": "codex_skill"
}
}
}
```
## Error Handling
- HTTP 401: missing or invalid Bearer token.
- HTTP 403: token is valid but lacks any `mcp.*` scope.
- JSON-RPC error `-32003`: required MCP scope is missing, usually `mcp.write`.
- JSON-RPC error `-32004`: a write operation could not find the target project, audit run, or parent artifact, so the write did not happen.
- Read-only audit tools avoid `-32004` for missing/invisible audits. They return `isError=false`, empty arrays such as `issues`, `artifacts`, `pages`, or `source_artifacts`, and a `hint` telling the client to use `list_audits` or save the missing prerequisite work first.
- JSON-RPC error `-32602`: unsupported URI, unknown tool, or invalid arguments.

129
scripts/release.sh Executable file
View File

@ -0,0 +1,129 @@
#!/usr/bin/env bash
# Release script для 222a-seo-audit plugin.
# Использование: ./scripts/release.sh <semver> [--message "changelog text"] [--dry-run]
set -euo pipefail
VERSION="${1:-}"
DRY_RUN=0
MESSAGE=""
shift || true
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=1 ;;
--message)
if [[ $# -lt 2 || -z "${2:-}" ]]; then
echo "ERROR: --message требует непустой аргумент"
exit 1
fi
MESSAGE="$2"
shift
;;
*) echo "Unknown arg: $1"; exit 1 ;;
esac
shift
done
# 1. Валидация semver
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ERROR: версия должна быть в формате MAJOR.MINOR.PATCH (например, 1.0.0)"
echo "Получено: '$VERSION'"
exit 1
fi
TAG="v${VERSION}"
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$REPO_ROOT"
# 2. Проверка чистоты и ветки
if [[ "$DRY_RUN" -eq 0 ]]; then
if [[ -n "$(git status --porcelain)" ]]; then
echo "ERROR: рабочая копия не чистая. Закоммитьте или стэшните изменения."
exit 1
fi
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
if [[ "$CURRENT_BRANCH" != "main" ]]; then
echo "ERROR: релиз только из ветки main. Текущая: $CURRENT_BRANCH"
exit 1
fi
fi
# 3. Проверка, что тег ещё не существует
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "ERROR: тег $TAG уже существует"
exit 1
fi
if [[ "$DRY_RUN" -eq 1 ]]; then
echo "Would release $VERSION (dry-run)"
exit 0
fi
# 4. Подменить версию в 3 json-файлах (sed inline)
PLUGIN_JSON="plugins/222a-seo-audit/.claude-plugin/plugin.json"
MCP_JSON="plugins/222a-seo-audit/.mcp.json"
MARKETPLACE_JSON=".claude-plugin/marketplace.json"
# Используем python для безопасной правки JSON
python3 - "$VERSION" "$PLUGIN_JSON" "$MCP_JSON" "$MARKETPLACE_JSON" <<'PY'
import json, sys
version = sys.argv[1]
plugin_json, mcp_json, marketplace_json = sys.argv[2], sys.argv[3], sys.argv[4]
# Phase 1: load all files (fail fast if anything is broken)
with open(plugin_json) as f: p = json.load(f)
with open(mcp_json) as f: m = json.load(f)
with open(marketplace_json) as f: mk = json.load(f)
# Phase 2: mutate in memory
p["version"] = version
m["mcpServers"]["222a-seo-audit"]["headers"]["X-Plugin-Version"] = version
mk["plugins"][0]["version"] = version
# Phase 3: write all files (still not fully atomic across files, but all loads succeeded
# so each individual write is a clean replace of a parsed structure)
for path, data in [(plugin_json, p), (mcp_json, m), (marketplace_json, mk)]:
with open(path, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
print(f"Updated version to {version} in 3 files")
PY
# 5. Обновить CHANGELOG.md
CHANGELOG="plugins/222a-seo-audit/CHANGELOG.md"
TODAY="$(date +%Y-%m-%d)"
# Проверка, что в CHANGELOG есть якорь [Unreleased]
if ! grep -q '^## \[Unreleased\]' "$CHANGELOG"; then
echo "ERROR: в $CHANGELOG нет секции '## [Unreleased]' — релиз остановлен"
echo "Восстановите якорь и запустите снова."
exit 1
fi
if [[ -n "$MESSAGE" ]]; then
# Вставить новую секцию после "## [Unreleased]"
TMP="$(mktemp)"
awk -v v="$VERSION" -v d="$TODAY" -v m="$MESSAGE" '
/^## \[Unreleased\]/ { print; print ""; print "## [" v "] - " d; print ""; print m; print ""; next }
{ print }
' "$CHANGELOG" > "$TMP"
mv "$TMP" "$CHANGELOG"
else
# Открыть редактор для ручного ввода
echo "Откройте $CHANGELOG, добавьте секцию для $VERSION в начало, сохраните и закройте."
${EDITOR:-nano} "$CHANGELOG"
fi
# 6. Коммит, тег, push
git add "$PLUGIN_JSON" "$MCP_JSON" "$MARKETPLACE_JSON" "$CHANGELOG"
git commit -m "release: v$VERSION"
git tag -a "$TAG" -m "Release $VERSION"
git push origin main
git push origin "$TAG"
echo ""
echo "Released $VERSION (tag $TAG)."
echo "Клиенты обновятся через:"
echo " /plugin marketplace update"
echo " /plugin update 222a-seo-audit"

21
scripts/test-release.sh Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Smoke-тесты для release.sh. Запускать вручную перед коммитом изменений в release.sh.
set -euo pipefail
cd "$(dirname "$0")/.."
# Тест 1: невалидный semver должен фейлиться
if ./scripts/release.sh "1.0" 2>/dev/null; then
echo "FAIL: невалидный semver принят"
exit 1
fi
echo "OK: невалидный semver отклонён"
# Тест 2: dry-run на корректном semver должен пройти валидацию
if ! ./scripts/release.sh "9.9.9" --dry-run 2>&1 | grep -q "Would release"; then
echo "FAIL: dry-run на 9.9.9 не сработал"
exit 1
fi
echo "OK: dry-run работает"
echo "All smoke tests passed"