legitAgent
by kiruxich
README.md


# legitAgent
Проверка сайта на типичные риски **152-ФЗ**, **38-ФЗ** и **ЗоЗПП** прямо в Cursor, Claude, Kimi и в терминале.
Сайт: [kiruxich.github.io/legitAgent](https://kiruxich.github.io/legitAgent/). Каталог правил: [docs/RULES.md](docs/RULES.md).
Подключите MCP — агент локально просканирует HTML/JS/TS/JSX/TSX/Vue/Svelte/Astro, покажет находки со статьёй закона, confidence, evidence и подскажет, как исправить. В Cursor после установки плагина те же действия доступны через `/check`, `/scan`, `/scan-url`. Либо одна команда в CI, GitHub Action с выгрузкой SARIF, либо `scan-url` для живой страницы: тот же каталог по DOM плюс cookie/storage/network до и после Reject и Accept.
```bash
npx @legit-agent/cli scan
```
**Это эвристическая проверка кода, а не юридическое заключение.** legitAgent не заменяет юриста и не гарантирует соответствие закону. Решение принимает человек.
---
🛡 **Нужен Enterprise-аудит?** Разрабатываем кастомные высоконагруженные системы и проводим юридический и технический аудит кода. Получите бесплатный отчет по нагрузке и соответствию 152-ФЗ для вашей инфраструктуры: Свяжитесь со мной в Telegram: [@kirillsklemin](https://t.me/kirillsklemin)
---
## Быстрый старт
Нужен Node.js 20+. Пакеты ставить не обязательно — достаточно `npx`.
### MCP (Cursor, Claude, Kimi и другие)
Один и тот же сервер. `@latest` и `--prefer-online`: при каждом запуске Cursor, Claude, Kimi и других IDE npx берёт текущий релиз с npm, а не кэш. Уже открытый чат сам не обновится — нужен перезапуск окна / MCP.
В Cursor одной кнопкой: [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=legitagent&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIi0tcHJlZmVyLW9ubGluZSIsIkBsZWdpdC1hZ2VudC9tY3BAbGF0ZXN0Il19).
```json
{
"mcpServers": {
"legitagent": {
"command": "npx",
"args": ["-y", "--prefer-online", "@legit-agent/mcp@latest"]
}
}
}
```
| Клиент | Куда вставить |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Cursor** | **User** (все проекты): `~/.cursor/mcp.json` — туда же пишет [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=legitagent&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIi0tcHJlZmVyLW9ubGluZSIsIkBsZWdpdC1hZ2VudC9tY3BAbGF0ZXN0Il19). **Проект** (только этот репозиторий): `.cursor/mcp.json`. Скиллы `/check` … — Marketplace или `~/.cursor/plugins/local` |
| **Claude Code** | `claude mcp add --transport stdio legitagent -- npx -y --prefer-online @legit-agent/mcp@latest` |
| **Claude Desktop** | тот же JSON в `claude_desktop_config.json`. Инструменты: `scan`, `review`, `autofix`, `create_baseline`, `scan_url`, `list_rules`, `explain_rule`, `generate_policy`, `get_law`. Слэша `/check` нет — пишете «проверь проект». |
| **Kimi Code** | `~/.kimi-code/mcp.json` или `.kimi-code/mcp.json` |
| **Kimi CLI** | `kimi mcp add --transport stdio legitagent -- npx -y --prefer-online @legit-agent/mcp@latest` или `~/.kimi/mcp.json` |
| **Windsurf, Cline, Continue, Copilot** | тот же `mcpServers`; если спрашивают транспорт — `stdio` |
После подключения: «проверь этот репозиторий на 152-ФЗ», «покажи каталог правил», «объясни PDN.FORM.NO_CONSENT».
В Cursor те же действия вызываются через `/` (скиллы плагина, карточка при наведении берётся из `description`). Локально: `~/.cursor/plugins/local/legitagent`. В каталоге у всех — после публикации на Marketplace. В ChatGPT и Kimi слэша Cursor нет: там работают MCP-инструменты, не `/check`.
| Команда | MCP |
| ----------------------------------- | -------------------------------------------------- |
| `/check` | `scan` + локальный offline-review; LLM только при явной настройке |
| `/fix` | `scan` + `review`, preview safe-рецептов, запись только по явному подтверждению, перескан |
| `/scan` | `scan` |
| `/scan-url https://example.com` | `scan_url` |
| `/list-rules` | `list_rules` |
| `/explain-rule PDN.FORM.NO_CONSENT` | `explain_rule` |
| `/generate-policy ООО Пример` | `generate_policy` |
| `/get-law 152-fz 9` | `get_law` |
Slash-команда не заменяет MCP: она говорит агенту вызвать инструмент. Без включённого сервера `legitagent` скана не будет.
### CLI
```bash
npx @legit-agent/cli scan
npx @legit-agent/cli scan ./my-site
npx @legit-agent/cli scan ./my-site --json
npx @legit-agent/cli scan ./my-site --sarif
npx @legit-agent/cli scan ./my-site --sarif findings.sarif
npx @legit-agent/cli scan ./my-site --lang en
npx @legit-agent/cli scan ./my-site --review --json
npx @legit-agent/cli scan ./my-site --changed-files src/Form.tsx,src/Cookie.tsx
npx @legit-agent/cli scan ./my-site --write-baseline
npx @legit-agent/cli scan ./my-site --baseline .legitagent-baseline.json
npx @legit-agent/cli scan ./my-site --fail-on-confidence medium
npx @legit-agent/cli scan ./my-site --cache
npx @legit-agent/cli fix ./my-site --json
npx @legit-agent/cli fix ./my-site --write
npx @legit-agent/cli scan-url https://example.com --json
npx @legit-agent/cli scan-url https://example.com --review --evidence legitagent-evidence
npx @legit-agent/cli scan-url https://example.com --review --evidence --notify-telegram
npx @legit-agent/cli scan-url https://example.com --sarif legitagent.sarif
npx @legit-agent/cli init-policy --operator "ООО Ромашка" --inn 123 --email privacy@site.ru --out privacy.md
```
`--review` добавляет второй проход. По умолчанию он **не вызывает LLM и не отправляет данные в сеть**: обычные находки получают `not_reviewed`, а неоднозначные проверки — `ask_human`. Код выхода и SARIF считаются по детерминированным findings, поэтому результат CI не зависит от LLM.
`scan-url --evidence [dir]` пишет evidence pack: скриншоты баннера, раздельные состояния до/после Reject и Accept, метаданные cookie без значений, имена ключей local/session storage, network resource type и инициатор без query string, `evidence.json`, `evidence.sarif`, `evidence.pdf`. **Скриншоты могут визуально содержать персональные, секретные или иные чувствительные данные** — храните и передавайте evidence pack с соответствующими ограничениями доступа и не публикуйте его без проверки. В пачку попадают все находки, кроме отклонённых LLM (`reject`). Локальные/private URL по умолчанию запрещены; для доверенной внутренней цели нужен явный `--allow-private-network`.
Telegram (опционально): `LEGITAGENT_TELEGRAM_BOT_TOKEN`, `LEGITAGENT_TELEGRAM_CHAT_ID` + флаг `--notify-telegram`. Без credentials — код выхода `2`.
#### Review, OpenRouter и приватность
У legitAgent нет собственного облака. Source scan, live scan, baseline, suppressions, SARIF и evidence pack выполняются на машине пользователя или runner-е CI. LLM необязателен:
| Режим | Настройка | Куда уходят данные |
| --- | --- | --- |
| `offline` | режим по умолчанию | Никуда; LLM не вызывается |
| `local` | `LEGITAGENT_REVIEW_MODE=local`, `LEGITAGENT_LOCAL_LLM_BASE_URL=http://127.0.0.1:11434/v1`, `LEGITAGENT_LLM_MODEL=...` | На loopback endpoint с `/chat/completions`; удалённый host отклоняется |
| `openrouter` | `LEGITAGENT_REVIEW_MODE=openrouter`, `LEGITAGENT_OPENROUTER_API_KEY=...` | В OpenRouter и к выбранному им/model-провайдеру |
Для OpenRouter модель по умолчанию — `openrouter/auto`; её можно зафиксировать через `LEGITAGENT_LLM_MODEL`. Если ключ `LEGITAGENT_OPENROUTER_API_KEY` задан, а режим не указан, выбирается `openrouter`; иначе — `offline`. Явно заданный неизвестный или пустой `LEGITAGENT_REVIEW_MODE` вызывает ошибку конфигурации: опечатка не включает внешнюю отправку. Режим `local` принимает только HTTP(S) loopback endpoint и запрещает redirects. Старое имя `LEGITAGENT_LLM_API_KEY` временно поддерживается как alias ключа OpenRouter.
OpenRouter review использует строгий JSON Schema, batches, timeout/retry и process-local cache по fingerprint+snippet. Защитные лимиты: `LEGITAGENT_LLM_BATCH_SIZE` (10), `LEGITAGENT_LLM_MAX_FINDINGS` (100), `LEGITAGENT_LLM_MAX_PROMPT_CHARS` (48000), `LEGITAGENT_LLM_MAX_OUTPUT_TOKENS` (2000), `LEGITAGENT_LLM_MAX_COST_USD` (0.25), `LEGITAGENT_LLM_TIMEOUT_MS` (30000), `LEGITAGENT_LLM_RETRIES` (1). `LEGITAGENT_LLM_MAX_COST_USD` — это post-response budget для batch review: после достижения суммарного `usage.cost` новые batches не отправляются, но последний уже отправленный batch может превысить порог. Это не hard provider spend cap. Ответ показывает фактически выбранную модель в `reviewModel`.
По умолчанию запрос просит маршрутизатор OpenRouter выбирать провайдера с Zero Data Retention и запрещённым provider data collection; это preference маршрутизации, а не абсолютная гарантия хранения. Ограничить маршрутизацию можно через `LEGITAGENT_OPENROUTER_ONLY_PROVIDERS`, исключить провайдеров — через `LEGITAGENT_OPENROUTER_IGNORE_PROVIDERS`; списки разделяются запятыми. Ценовые ограничения провайдера задаются `LEGITAGENT_OPENROUTER_MAX_PROMPT_PRICE` и `LEGITAGENT_OPENROUTER_MAX_COMPLETION_PRICE`. Отключение ZDR требует явного `LEGITAGENT_OPENROUTER_ZDR=false`.
При `openrouter` отправляются только поля находок, выдержки норм и связанные фрагменты исходников — не весь репозиторий. Очевидные значения `key`/`token`/`secret`/`password`/`authorization` маскируются, фрагменты ограничиваются по размеру. Это best-effort защита: перед включением внешнего review проверьте политику обработки данных OpenRouter и выбранного model-провайдера.
User rule для Cursor always-on: скопируйте текст из `[docs/cursor-user-rule.md](docs/cursor-user-rule.md)` в User rules.
### Конфиг
В корне проекта можно положить `legitagent.config.json`:
```json
{
"$schema": "https://raw.githubusercontent.com/kiruxich/legitAgent/main/packages/core/config.schema.json",
"ignore": ["**/vendor/**"],
"disabled": ["PDN.COOKIE.NO_REJECT"],
"severity": { "PDN.TRANSFER.FOREIGN_TRACKER": "low" },
"baseline": ".legitagent-baseline.json",
"cache": true,
"suppress": [
{
"ruleId": "PDN.COOKIE.NO_REJECT",
"file": "src/legacy/**",
"reason": "Принято владельцем риска до миграции CMP",
"expires": "2026-12-31"
}
]
}
```
Подавление требует причину и может быть ограничено rule/file/fingerprint и сроком. Для точечного исключения рядом с кодом: `legitagent-ignore-next-line RULE_ID -- причина`. Создать baseline текущих находок: `--write-baseline`; в последующих запусках передать `--baseline` или указать файл в конфиге. Baseline и suppressions не удаляют находки из модели данных — они переходят в `suppressedFindings` вместе с источником и причиной подавления.
Нет файла — используются безопасные значения по умолчанию. Невалидный JSON: код выхода `2`.
`cache: true` сохраняет только hash, диапазоны строк и структурные сигналы в `.legitagent/cache-v1.json`; фрагменты исходного кода в cache не записываются. Cache можно включить CLI-флагом `--cache` или задать путь через `--cache-file`. Неизвестные поля конфига попадают в warnings; JSON Schema поставляется с `@legit-agent/core`.
`legitagent fix` всегда работает как dry-run. Только `--write` применяет allowlist безопасных механических рецептов ко всем соответствующим находкам свежего scan; сейчас автоматически снимается статическое prechecked-состояние consent checkbox. Это не LLM-gated patching: перед `--write` проверьте preview. Добавление юридического текста, URL политики и consent-flow остаётся manual recipe.
Вывод по-русски по умолчанию; `--lang en` — английские сообщения. Каждая находка содержит стабильный `fingerprint`, диапазон строк, `kind` (`violation`, `risk`, `manual_check`), `confidence`, наблюдаемые сигналы, правовое основание и способ исправления.
`init-policy` печатает **черновик** политики обработки ПДн (не юридический документ). Корпус 152-ФЗ / 38-ФЗ / ЗоЗПП лежит в `packages/core/legal/corpus/`; обновить с pravo.gov.ru: `pnpm fetch-law`.
`--sarif` без пути пишет `legitagent.sarif` (SARIF 2.1.0). `scan-url` открывает страницу в Chromium в изолированных контекстах: ждёт гидрацию SPA, отдельно проверяет состояния до/после Reject и Accept, сравнивает cookie/storage/network и прогоняет тот же каталог правил по HTML страницы. `scan_url` в MCP при `evidenceDir` сохраняет только скриншоты; полный evidence pack (JSON/SARIF/PDF) создаёт CLI.
Автоматические клики выполняются только в распознанном cookie-интерфейсе; обычный диалог с кнопкой Accept не считается баннером согласия. HTTP 4xx/5xx при загрузке страницы или повторном заходе для Accept завершают проверку технической ошибкой. Изображения в PDF встраиваются в документ и проверяются перед сохранением.
| Код выхода | Значение |
| ---------- | ------------------------------------------------------------------------------------------------------------ |
| `0` | Нет серьёзных находок (в том числе нечего сканировать) |
| `1` | Есть хотя бы одна находка `high` с confidence не ниже `--fail-on-confidence` |
| `2` | Ошибка команды или конфигурации, включая невалидный режим review и отсутствующие обязательные credentials |
| `3` | Технический сбой: загрузка страницы, браузер, LLM API или запись отчёта |
В GitHub Action `fail-on-high=false` допускает только код `1` после успешного создания SARIF. Ошибки конфигурации, выполнения и отсутствующий отчёт продолжают блокировать job.
В CI достаточно `npx @legit-agent/cli@1.1.1 scan --json`: ненулевой код — стоп пайплайна. Source-scan без `--review` не запускает второй проход; даже с `--review` сеть не используется в режиме `offline`. Для code scanning скопируйте `[examples/github-scan.yml](examples/github-scan.yml)` в `.github/workflows/legitagent.yml` — он вызывает композитное действие `[.github/actions/legitagent-scan](.github/actions/legitagent-scan/action.yml)` с пином `@v1.1.1`: пишет SARIF, загружает его в GitHub, поддерживает baseline/changed-files/confidence threshold, комментирует PR и создаёт issue при новых находках `high`. Для мониторинга живого сайта после деплоя — `[examples/github-watch.yml](examples/github-watch.yml)` (`scan-url --review --evidence`, опционально Telegram и OpenRouter).
---
## Возможности
Один движок `[@legit-agent/core](https://www.npmjs.com/package/@legit-agent/core)`, живой сканер `[@legit-agent/live](https://www.npmjs.com/package/@legit-agent/live)`, оболочки `[@legit-agent/mcp](https://www.npmjs.com/package/@legit-agent/mcp)` и `[@legit-agent/cli](https://www.npmjs.com/package/@legit-agent/cli)`.
### Инструменты MCP
| Инструмент | Что делает |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scan` | Сканирует проект. Необязательные `root` и `lang` (`ru` / `en`). |
| `review` | Второй проход по findings. Offline по умолчанию; локальная LLM или OpenRouter включаются только пользовательской env-настройкой (для OpenRouter достаточно ключа, если режим не переопределён). Необязательные `root` и `lang`. |
| `create_baseline` | Создаёт baseline текущих fingerprints внутри `root`. Операция записи. |
| `autofix` | Возвращает safe/manual fix-рецепты; dry-run по умолчанию, запись только при `write: true`. |
| `scan_url` | Проверяет живой URL: cookie, баннер, формы, политика, ERID, витрина, иностранные трекеры; ждёт гидрацию SPA и отдельно проверяет Reject/Accept внутри баннера. Опционально `evidenceDir`; private network запрещена по умолчанию. |
| `list_rules` | Полный каталог правил. |
| `explain_rule` | Правило, выдержка статьи, как исправить, дисклеймер. Нужен `ruleId`. |
| `generate_policy` | Черновик политики обработки ПДн. Нужен `operator`. Не юридическое заключение. |
| `get_law` | Текст из корпуса (`152-fz`, `38-fz`, `zozpp`), опционально номер статьи. |
`scan` и `review` принимают `changedFiles`, `baseline`, `cache` и `minimumConfidence`; ответ содержит единый confidence gate. При changed-files весь проект остаётся контекстом для project-wide правил, но локальные findings фильтруются по изменённым файлам. `autofix` принимает отдельный `write` и по умолчанию ничего не меняет.
Ответ `scan`: `findings`, `suppressedFindings`, `warnings`, `scannedFileCount`. У находки есть fingerprint, файл и диапазон строк, severity, confidence, kind, evidence, legalBasis, сообщение и фикс. Если путь нечитаем: `Укажите корень проекта`.
### Что проверяется в коде
Сканер читает `.html`, `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.vue`, `.svelte`, `.astro`. Пропускает `node_modules`, `.next`, `dist`, `build`, `coverage`, `.git`. Для JS/TS анализируется путь от consent-condition/event handler до функции запуска tracker. Синтаксически сломанный файл не роняет проверку — он уходит в предупреждение.
| id | Что находит | Норма |
| ------------------------------ | -------------------------------------------------------------------------- | --------------- |
| `PDN.FORM.NO_CONSENT` | Форма с именем, email или телефоном без чекбокса согласия | 152-ФЗ ст. 9 |
| `PDN.FORM.PRECHECKED_CONSENT` | Предзаполненный чекбокс согласия | 152-ФЗ ст. 9 |
| `PDN.FORM.NO_POLICY_LINK` | Согласие без ссылки на политику | 152-ФЗ ст. 9 |
| `PDN.POLICY.NO_LINK` | В проекте нет ссылки на политику обработки ПДн | 152-ФЗ ст. 18.1 |
| `PDN.POLICY.INCOMPLETE` | Политика без оператора, целей, сроков или порядка отзыва | 152-ФЗ ст. 18.1 |
| `PDN.TRACKER.NO_CONSENT` | Яндекс.Метрика, gtag, GA, Meta Pixel, VK.Retargeting без проверки согласия | 152-ФЗ ст. 6 |
| `PDN.COOKIE.NO_REJECT` | Cookie-баннер без возможности отказа | 152-ФЗ ст. 9 |
| `PDN.TRANSFER.FOREIGN_TRACKER` | Иностранный трекер / возможная трансграничная передача | 152-ФЗ ст. 12 |
| `PDN.LOCALIZATION.UNCLEAR` | Форма с ПДн и иностранный трекер без указания локализации баз в РФ (`low`) | 152-ФЗ ст. 18 |
| `PDN.ORG.RKN_NOTICE` | Форма с ПДн без следов уведомления РКН (`low`) | 152-ФЗ ст. 22 |
| `ADV.ERID.MISSING` | Пометка «Реклама» без erid | 38-ФЗ ст. 18.1 |
| `CONSUMER.OFFER.MISSING` | Витрина без доступных условий дистанционной продажи | ЗоЗПП ст. 26.1 |
| `CONSUMER.REQUISITES.MISSING` | Витрина без реквизитов продавца | ЗоЗПП ст. 9 |
| `CONSUMER.RETURN.MISSING` | Витрина без условий возврата | ЗоЗПП ст. 26.1 |
### Полный чек-лист
Помимо автопоиска агент знает весь каталог и по `explain_rule` разбирает каждый пункт: зачем правило, какая статья, что сделать.
**Формы и согласие** — `PDN.FORM.NO_CONSENT`, предзаполненный чекбокс (`PDN.FORM.PRECHECKED_CONSENT`), ссылка на политику рядом с согласием (`PDN.FORM.NO_POLICY_LINK`).
**Политика ПДн** — ссылка в проекте (`PDN.POLICY.NO_LINK`), состав документа: оператор, цели, сроки, отзыв (`PDN.POLICY.INCOMPLETE`).
**Метрики и cookie** — трекер без opt-in (`PDN.TRACKER.NO_CONSENT`), cookie до согласия (`PDN.COOKIE.BEFORE_CONSENT`, живой `scan-url`), баннер без отказа (`PDN.COOKIE.NO_REJECT`), иностранный трекер / трансграничная передача (`PDN.TRANSFER.FOREIGN_TRACKER`).
**Организация** — локализация баз в РФ (`PDN.LOCALIZATION.UNCLEAR`) и уведомление Роскомнадзора (`PDN.ORG.RKN_NOTICE`): только если есть форма с ПДн, серьёзность `low`. CMP вроде Cookiebot не считается «метрикой без согласия».
**Реклама** — пометка «Реклама» без идентификатора (`ADV.ERID.MISSING`).
**Витрина** — условия дистанционной продажи, реквизиты продавца, возврат (`CONSUMER.`*). Отдельный документ с названием «оферта» не считается безусловно обязательным автоматически — правило просит проверить доступность обязательной информации до заказа.
У каждого правила в репозитории есть короткая выдержка статьи. Без выдержки правило в каталог не попадает.
Полный каталог с выдержками закона: [docs/RULES.md](docs/RULES.md). На сайте — [страница правил](https://kiruxich.github.io/legitAgent/rules.html).
---
## Разработка
```bash
git clone https://github.com/kiruxich/legitAgent.git
cd legitAgent
pnpm install
pnpm test
pnpm build
pnpm benchmark
pnpm legal:check
pnpm release:check
```
Монорепозиторий pnpm:
- `packages/core` — каталог YAML, выдержки закона, парсеры, детекторы, `scanProject`
- `packages/cli` — команды `legitagent scan`, `scan-url`, `init-policy`, вывод `--json` / `--sarif` / `--lang`
- `packages/live` — Playwright-сканер живой страницы
- `packages/mcp` — stdio-сервер для агентов
Правила: `packages/core/rules/*.yaml`. Выдержки: `packages/core/legal/*.yaml`. Корпус законов: `packages/core/legal/corpus/` (`pnpm fetch-law`). Каталог для людей: `pnpm catalog` → `docs/RULES.md` и `website/rules.html`.
`pnpm benchmark` проверяет 140 исходных случаев: 40 synthetic regression seeds и 100 закреплённых source groups из открытых проектов. Пять форматных вариантов дают 700 parser-stability сценариев; повторные представления одного источника не увеличивают независимый счётчик. Отчёт отдельно считает TP/FP/FN/TN и precision/recall по исходным кейсам (`seedRules`, `seedFrameworks`) и всем вариантам (`rules`, `frameworks`). Реальные случаи дополнительно проверяются строго: любая ошибка ожидаемого правила или технического признака завершает прогон с ошибкой. Источники, SHA, лицензии и обоснования разметки сохранены в [benchmarks/real-world](benchmarks/real-world); [разбор покрытия](benchmarks/real-world-cases.md) указывает границы статической проверки. Порог v1 в 100 независимых групп источников закрыт; покрытие отдельных правил и отложенная оценка всё ещё требуют ревью.
`pnpm legal:check` проверяет integrity hash локальных snapshot-ов и свежесть `verifiedAt`. Еженедельный workflow `legal-drift.yml` сравнивает snapshot с источником; изменение закона блокирует задачу до ручной ревизии и обновления hash.
---
## Релиз
Пакеты живут на [npmjs.com/org/legit-agent](https://www.npmjs.com/org/legit-agent), не в GitHub Packages.
Новая версия: одинаковый `version` в `packages/*/package.json` (core, cli, live, mcp), `pnpm release:check`, коммит в `main`, тег `vX.Y.Z`, `git push origin vX.Y.Z`. Workflow использует commit-SHA pins для сторонних Actions, npm Trusted Publishing с provenance, генерирует SPDX SBOM, создаёт build attestation и прикладывает tarballs/SBOM к GitHub Release.
Для `1.x` release-check дополнительно требует минимум `100` entries с `provenance: "independent-real-world"` в `benchmarks/corpus.json`. Synthetic seeds и их пять мутаций в этот gate не засчитываются. Сейчас в корпусе ровно 100 независимых групп, поэтому количественный gate закрыт; перед публикацией `v1.1.1` остаются полный CI и ручная проверка release-артефактов.
---
## Лицензия
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues