@gian-tiaga/eda 3.13.0 → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -13
- package/agents/eda-review-tests/prompt.md +1 -1
- package/agents/eda-skill-runner/agent.json +14 -0
- package/agents/eda-skill-runner/prompt.md +11 -0
- package/bin/cli.js +3 -3
- package/lib/catalog.js +4 -0
- package/lib/install.js +52 -28
- package/lib/renderers/opencode-agent.js +23 -0
- package/lib/renderers/opencode-skill.js +24 -0
- package/package.json +3 -2
- package/skills/eda-review/SKILL.md +10 -3
- package/skills/eda-review/references/review-matrix.md +3 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 🌊 eda
|
|
2
2
|
|
|
3
3
|
> Поточная разработка с AI-агентами — на русском языке.
|
|
4
|
-
> Пакет готовых скилов и специализированных агентов для **Claude Code** и **
|
|
4
|
+
> Пакет готовых скилов и специализированных агентов для **Claude Code**, **Codex CLI** и **OpenCode V2**, которые ведут тебя через весь цикл: от исследования до коммита.
|
|
5
5
|
|
|
6
6
|
`eda` — это двадцать три скила и пакетные агенты для повторяемых ролей. Скил отвечает за пользовательский workflow и оркестрацию, агент — за изолированную работу с закреплённой моделью и ограничениями. Вместо того чтобы каждый раз объяснять модели, как делать ревью или как исполнять план, ты говоришь одно слово — и она следует чёткой инструкции на русском, со всеми правилами, проверками и артефактами в нужных папках.
|
|
7
7
|
|
|
@@ -21,9 +21,11 @@ npm install -g @gian-tiaga/eda
|
|
|
21
21
|
eda init
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Установщик покажет чекбоксы: стрелками выбираешь среду, пробелом отмечаешь, Enter продолжает. Можно
|
|
24
|
+
Установщик покажет чекбоксы: стрелками выбираешь среду, пробелом отмечаешь, Enter продолжает. Можно выбрать любую комбинацию Claude Code, Codex CLI и OpenCode. Устанавливаются и скилы, и агенты. Если `docs/settings.yaml` ещё нет, установщик предложит настройки скилов и проверок review, включая модели Claude/Codex. Без интерактивного терминала устанавливаются все три среды и записывается сбалансированный профиль. В конце `eda init` отдельно пишет, какие скилы и агенты реально установлены или изменились.
|
|
25
25
|
|
|
26
|
-
`eda update
|
|
26
|
+
Чтобы добавить OpenCode или другую платформу в проект с уже установленным EDA, запусти `eda update`. В интерактивном терминале команда при каждом запуске показывает все платформы: установленные уже отмечены, остальные можно добавить. Установленные снимать нельзя — `update` их обновляет, а не удаляет. Enter без изменений обновляет текущий набор. Выбор фиксируется установленными каталогами и manifest каждой платформы, поэтому при следующем запуске она уже отмечена; отдельный список в `docs/settings.yaml` не нужен. Без TTY новые платформы не добавляются. Если ни одной среды ещё нет, сначала нужен `eda init`. У `update-all` выбор платформ не меняется: он обновляет только уже найденные среды.
|
|
27
|
+
|
|
28
|
+
После выбора платформ `eda update` переносит старые рабочие каталоги из `docs/<тип>/` в `docs/artifacts/<тип>/`, затем обновляет настройки, скилы и агентов. Содержимое файлов при переносе не меняется. Если один относительный путь уже существует в новой структуре, новый файл сохраняется, а старый удаляется.
|
|
27
29
|
|
|
28
30
|
Полный валидный v3-конфиг сохраняется, пока совпадает с актуальным шаблоном; если в пакете появились новые значения или подсказки, файл молча перерисовывается с сохранением ваших значений. Старый, неизвестный или неполный файл разбирается как YAML: известные значения переносятся, в TTY спрашиваются только отсутствующие, затем профиль целиком атомарно записывается как v3. Без TTY используются перенесённые значения и defaults.
|
|
29
31
|
|
|
@@ -33,7 +35,7 @@ eda init
|
|
|
33
35
|
eda update-all ~/Code
|
|
34
36
|
```
|
|
35
37
|
|
|
36
|
-
`eda update-all` ищет проекты в указанной директории, её прямых подпапках и подпапках второго уровня. Проект считается найденным, если в нём уже есть установленный скил, агент или manifest `eda` для Claude/Codex. В каждом проекте команда переносит рабочие артефакты, затем предлагает настроить один общий профиль для всех проектов или выбрать `skip`. В режиме `skip` актуальный полный v3 сохраняется, устаревший по шаблону перерисовывается, старые и неполные конфиги индивидуально переносятся, отсутствующие создаются с defaults. Без TTY автоматически используется `skip`. Ошибка одного проекта не останавливает остальные.
|
|
38
|
+
`eda update-all` ищет проекты в указанной директории, её прямых подпапках и подпапках второго уровня. Проект считается найденным, если в нём уже есть установленный скил, агент или manifest `eda` для Claude/Codex/OpenCode. Служебные каталоги, включая `.opencode`, и symlink-директории не обходятся. В каждом проекте команда переносит рабочие артефакты, затем предлагает настроить один общий профиль для всех проектов или выбрать `skip`. В режиме `skip` актуальный полный v3 сохраняется, устаревший по шаблону перерисовывается, старые и неполные конфиги индивидуально переносятся, отсутствующие создаются с defaults. Без TTY автоматически используется `skip`. Ошибка одного проекта не останавливает остальные.
|
|
37
39
|
|
|
38
40
|
---
|
|
39
41
|
|
|
@@ -54,7 +56,7 @@ eda update-all ~/Code
|
|
|
54
56
|
| `eda-plan-execute` | Управляет выполнением плана по фазам в режиме `subagents`, `main` или `auto`. В `subagents` каждую фазу целиком выполняет отдельный изолированный субагент: он читает план, правила, архитектуру и только business/reference-карточки затронутого поведения и компонентов. Фазы проходят строго последовательно и принимаются независимыми проверяющими. В `main` весь план по тем же правилам выполняет и проверяет основной агент в одном контексте, а `auto` выбирает режим по плану. Отметки подтверждённых задач и журнал ведёт основной агент | `docs/artifacts/executions/` |
|
|
55
57
|
| `eda-just-do-it` | Сразу выполняет задачу из текста рядом с вызовом: определяет scope, загружает только необходимые проектные инструкции, business/reference-карточки, код и тесты, вносит нужные изменения и проверяет результат. Не подменяет выполнение планом и не делает git- или внешние действия без прямого указания | `docs/artifacts/just-do-it/` |
|
|
56
58
|
| `eda-fix` | Делает обычные фиксы по короткому контексту, баг-репорту или плану. Перед правками читает правила, архитектуру и только применимые карточки, добавляет нужные тесты, прогоняет проверки и сохраняет историю правок | `docs/artifacts/fixes/` |
|
|
57
|
-
| `eda-review` | Оркестрирует отдельные read-only проверки корректности, архитектуры, правил, references, business-правил, плана, качества, тестов, безопасности, производительности, frontend/UI/UX, API, БД, документации и предыдущих ревью. Сохраняет только доказанные дефекты, которые обязательно исправить; косметические и спекулятивные предложения отбрасывает. Любая находка даёт `changes-required`, а чистое ревью — `clean` и 100/100. Без аргументов ревьюит `git diff HEAD` | `docs/artifacts/reviews/` |
|
|
59
|
+
| `eda-review` | Оркестрирует отдельные read-only проверки корректности, архитектуры, правил, references, business-правил, плана, качества, тестов, безопасности, производительности, frontend/UI/UX, API, БД, документации и предыдущих ревью. Для PR/MR переиспользует результаты CI текущего head и не запускает локально уже завершённые там тесты, линтеры, typecheck, сборку и аналогичные проверки; смысловое ревью diff при этом выполняется полностью. Сохраняет только доказанные дефекты, которые обязательно исправить; косметические и спекулятивные предложения отбрасывает. Любая находка даёт `changes-required`, а чистое ревью — `clean` и 100/100. Без аргументов ревьюит `git diff HEAD` | `docs/artifacts/reviews/` |
|
|
58
60
|
| `eda-fix-by-review` | Применяет все находки из ревью с учётом правил, архитектуры и применимых карточек. Спрашивает только при неоднозначности, конфликте, расширении scope или рискованном действии. В конце ссылается на отчёт прямо в файле ревью | `docs/artifacts/review-fixes/` |
|
|
59
61
|
| `eda-manual-test` | Делает ручную проверку после изменений. По умолчанию проверка полная: разбирает план или другой артефакт по разделам, дополняет его фактическим `git diff HEAD` и закрывает матрицу областей — API, база данных, консольные команды, интерфейс, алгоритмы, фон и интеграции, права и роли, конфигурация, логи, регрессии рядом. Область нельзя закрыть чтением кода или зелёными автотестами; незакрытая область даёт `blocked`. Быстрый smoke включается настройкой `manual-test.depth` или словом в запросе. Применимая business-карточка может добавить только относящийся к задаче инвариант или сценарий. Не правит код, не пишет автотесты и не коммитит | `docs/artifacts/manual-tests/` |
|
|
60
62
|
| `eda-polish` | Оркестрирует доводку изменений: запускает полное `eda-review`, затем `eda-fix-by-review` и повторяет цикл до `clean` и отсутствия находок либо до лимита 5 итераций. Режим цикла задаёт `polish.execution`: в `main` оба контракта выполняет основной агент без субагентов, в `subagents` каждый шаг получает отдельный изолированный контекст. Все находки исправляются, score остаётся справочным. Не коммитит | `docs/artifacts/reviews/`, `docs/artifacts/review-fixes/` |
|
|
@@ -96,6 +98,7 @@ eda update-all ~/Code
|
|
|
96
98
|
| `eda-aim-planner` | `sonnet`, workspace-write | `gpt-5.6-terra`, workspace-write | Задаёт вопросы, формулирует простой проверяемый список и создаёт файл только после подтверждения человека |
|
|
97
99
|
| `eda-aim-executor` | `opus`, workspace-write | `gpt-5.6-sol`, workspace-write | Выполняет назначенные пункты, при необходимости запрашивает установленные скилы для запуска в изолированных субагентах и дополняет общий журнал |
|
|
98
100
|
| `eda-aim-verifier` | `opus`, workspace-write | `gpt-5.6-sol`, workspace-write | Независимо проверяет каждый критерий, отмечает подтверждённые цели и возвращает пробелы на новый круг выполнения |
|
|
101
|
+
| `eda-skill-runner` | `opus`, workspace-write | `gpt-5.6-sol`, workspace-write | Выполняет один установленный скил в изолированной сессии; в OpenCode сохраняет возможность вложенных субагентов |
|
|
99
102
|
| `eda-commit-executor` | `sonnet` | `gpt-5.6-terra` | Одним вызовом собирает git-контекст, пишет сообщения коммитов и PR по запросу, артефактам и фактическим изменениям, коммитит состав одним коммитом или по группам при `split` и выполняет явно разрешённые push/PR/merge-действия |
|
|
100
103
|
| `eda-worktree-executor` | `haiku` | `gpt-5.6-luna` | Создаёт соседний worktree и одноимённую ветку, не изменяя файлы проекта |
|
|
101
104
|
| `eda-merge-worktree-executor` | `haiku` | `gpt-5.6-luna` | Мержит ветку из соседнего worktree в текущую без cleanup и ручного разрешения конфликтов |
|
|
@@ -119,6 +122,16 @@ eda update-all ~/Code
|
|
|
119
122
|
|
|
120
123
|
Для Claude Code установленный `eda-commit` получает `model: sonnet`, а `eda-worktree` и `eda-merge-worktree` — `model: haiku`. В Codex у скилов пока нет отдельного per-skill model override: основной поток остаётся на выбранной пользователем модели, но он выполняет только лёгкую оркестрацию; содержательная работа `eda-commit` закреплена за `gpt-5.6-terra`, а worktree-операции — за `gpt-5.6-luna`.
|
|
121
124
|
|
|
125
|
+
### OpenCode V2
|
|
126
|
+
|
|
127
|
+
Вызывай скилы через `@eda-plan`, `@eda-review` и другие точные ID. OpenCode-копии содержат платформенный адаптер: вложенные скилы загружаются через `skill`, агенты запускаются через `subagent`, вопросы задаются через `question`. Изолированные шаги оркестраторов выполняет `eda-skill-runner`, а не встроенный general, у которого запрещены вложенные субагенты. Режимы `main` / `subagents` сохраняют обычные границы.
|
|
128
|
+
|
|
129
|
+
Все OpenCode-агенты по умолчанию наследуют модель сессии: колонки Claude/Codex в таблице выше и соответствующие поля моделей в `docs/settings.yaml` к OpenCode не применяются. В каноническом `agent.json` можно задать необязательное `models.opencode` в формате `provider/model#variant`; variant необязателен. Модель можно настроить средствами OpenCode. Per-skill модель не назначается. При явном runtime override, который хост не поддерживает, скил возвращает `blocked`, а не молча заменяет модель.
|
|
130
|
+
|
|
131
|
+
Read-only роли используют V2 `permissions`: разрешены чтение, поиск и web-инструменты, запрещены shell, редакторы, MCP и субагенты. Оркестратор передаёт им diff и git/CI-контекст; такие агенты сами не запускают тесты. Git-write роли не получают редакторов, но shell наследует разрешения пользователя; workspace-write также не переопределяет пользовательские разрешения. Это правила инструментов, не отдельный OS sandbox.
|
|
132
|
+
|
|
133
|
+
Установщик не меняет `opencode.json(c)` и не требует перезапуска OpenCode. Скилы `.opencode/skills` имеют приоритет над совместимыми копиями `.claude/skills` и `.agents/skills` с тем же ID. Если нет обязательного инструмента, разрешения или нативного Plan Mode, workflow сообщает конкретный блокер. В strict из OpenCode нужно явно выбрать внешний Claude Code или Codex CLI либо ответить на вопрос скила.
|
|
134
|
+
|
|
122
135
|
---
|
|
123
136
|
|
|
124
137
|
## 🚩 Флаги скилов
|
|
@@ -498,8 +511,8 @@ discover-automations может запускаться от review, fix-by-revie
|
|
|
498
511
|
## 💻 Команды
|
|
499
512
|
|
|
500
513
|
```bash
|
|
501
|
-
eda init # выбрать Claude Code / Codex /
|
|
502
|
-
eda update #
|
|
514
|
+
eda init # выбрать Claude Code / Codex / OpenCode и установить пакет
|
|
515
|
+
eda update # предложить добавить платформы, обновить настройки, скилы и агентов
|
|
503
516
|
eda update-all [dir] # сохранить конфиги или настроить общий и обновить проекты на глубине 2
|
|
504
517
|
eda --version # показать версию установленного пакета
|
|
505
518
|
eda --help # справка
|
|
@@ -527,15 +540,15 @@ eda update-all ~/Code
|
|
|
527
540
|
|
|
528
541
|
Исходники агентов лежат в `agents/<agent>/agent.json` и `prompt.md`. Установщик рендерит единый агентный контракт в нативный формат выбранной среды.
|
|
529
542
|
|
|
530
|
-
| Компонент | Claude Code | Codex CLI |
|
|
531
|
-
|
|
532
|
-
| Скил | `.claude/skills/<skill>/SKILL.md` | `.agents/skills/<skill>/SKILL.md` |
|
|
533
|
-
| Агент | `.claude/agents/<agent>.md` | `.codex/agents/<agent>.toml` |
|
|
534
|
-
| Manifest владения | `.claude/eda-manifest.json` | `.codex/eda-manifest.json` |
|
|
543
|
+
| Компонент | Claude Code | Codex CLI | OpenCode V2 |
|
|
544
|
+
|---|---|---|---|
|
|
545
|
+
| Скил | `.claude/skills/<skill>/SKILL.md` | `.agents/skills/<skill>/SKILL.md` | `.opencode/skills/<skill>/SKILL.md` |
|
|
546
|
+
| Агент | `.claude/agents/<agent>.md` | `.codex/agents/<agent>.toml` | `.opencode/agents/<agent>.md` |
|
|
547
|
+
| Manifest владения | `.claude/eda-manifest.json` | `.codex/eda-manifest.json` | `.opencode/eda-manifest.json` |
|
|
535
548
|
|
|
536
549
|
`eda update` переносит известные старые каталоги артефактов, сохраняет актуальный полный v3-конфиг как есть, устаревший по шаблону перерисовывает с сохранением значений, а старый или неполный умно переносит и целиком нормализует; затем идемпотентно синхронизирует обе группы компонентов и отдельно показывает реально изменившиеся скилы и агенты. Manifest хранит только идентификаторы компонентов, которыми владеет `eda`: retired-компоненты удаляются, а чужие скилы и агенты остаются нетронутыми. `eda update-all [dir]` выполняет тот же перенос артефактов в каждом проекте, затем либо записывает общий профиль, либо в `skip` сохраняет актуальный полный v3, перерисовывает устаревший по шаблону и переносит остальные настройки. При миграции Codex установщик переносит актуальные скилы в `.agents/skills/` и удаляет принадлежащие `eda` старые копии `.codex/skills/<skill>/` и `.codex/skills/<skill>.md`, не затрагивая чужие компоненты.
|
|
537
550
|
|
|
538
|
-
Установленные копии не являются источником правды. Локальные изменения внутри `.claude/skills/eda-*`, `.agents/skills/eda-*`, `.claude/agents/eda-*` или `.
|
|
551
|
+
Установленные копии не являются источником правды. Локальные изменения внутри `.claude/skills/eda-*`, `.agents/skills/eda-*`, `.opencode/skills/eda-*`, `.claude/agents/eda-*`, `.codex/agents/eda-*` или `.opencode/agents/eda-*` будут заменены следующим обновлением.
|
|
539
552
|
|
|
540
553
|
`AGENTS.md` (как и любые другие файлы в корне проекта) установщик **не трогает**. Codex автоматически обнаруживает проектные скилы в `.agents/skills/`.
|
|
541
554
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Вход и работа
|
|
6
6
|
|
|
7
|
-
В task-сообщении получи рабочую директорию, `TARGET`, `PLAN_FILE`, `REFERENCE_FILES`, `MODEL` и
|
|
7
|
+
В task-сообщении получи рабочую директорию, `TARGET`, `PLAN_FILE`, `REFERENCE_FILES`, `MODEL`, краткий `REVIEW_CONTEXT` и `CI_CONTEXT`. Прочитай diff, изменённое поведение, существующие тесты и проектные команды тестирования. Запускай только безопасные read-only проверки, если это нужно для подтверждения; не меняй snapshots и другие tracked-файлы. Для PR/MR не повторяй тест, линтер, typecheck, сборку или другую автоматическую команду, уже завершённую в CI на текущем head: используй переданный результат и лог CI как доказательство. Это не отменяет анализ полноты и корректности самих тестов.
|
|
8
8
|
|
|
9
9
|
Не требуй тест на каждую строку. Находка должна описывать конкретную регрессию, которую текущие тесты не поймают, либо ошибку в самих тестах. Не дублируй функциональную проблему, если можешь сформулировать только тестовый пробел. Не правь файлы.
|
|
10
10
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "eda-skill-runner",
|
|
4
|
+
"description": "Выполняет один установленный eda-скил в изолированной сессии с сохранением его режима и границ ответственности.",
|
|
5
|
+
"models": {
|
|
6
|
+
"claude": "opus",
|
|
7
|
+
"codex": "gpt-5.6-sol"
|
|
8
|
+
},
|
|
9
|
+
"reasoning": {
|
|
10
|
+
"claude": "high",
|
|
11
|
+
"codex": "high"
|
|
12
|
+
},
|
|
13
|
+
"access": "workspace-write"
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Роль
|
|
2
|
+
|
|
3
|
+
Выполни один установленный eda-скил в изолированной сессии. Получи от оркестратора рабочую директорию, точный ID скила, исходный запрос, аргументы, применимые overrides, пути входных артефактов и требуемый результат.
|
|
4
|
+
|
|
5
|
+
Загрузи указанный скил нативным инструментом хоста и следуй его инструкции целиком. Не заменяй его своей процедурой. Режим исполнения и границы ответственности обязательны; запускай вложенных агентов только когда это предписывает выбранный скил. Не делай git/publish-действий без прямого разрешения пользователя, переданного оркестратором.
|
|
6
|
+
|
|
7
|
+
Если вход или возможности хоста недостаточны, верни `status: blocked` с одним конкретным вопросом или техническим блокером. Не обходи разрешения и не меняй режим исполнения.
|
|
8
|
+
|
|
9
|
+
## Результат
|
|
10
|
+
|
|
11
|
+
Верни результат по контракту вызванного скила, пути созданных артефактов и фактически выполненные проверки. Если скил не задаёт машинный формат, верни YAML с `status: completed | blocked`, `summary`, `artifacts`, `checks`, `question`. Не выдавай непроведённые проверки за успешные.
|
package/bin/cli.js
CHANGED
|
@@ -6,11 +6,11 @@ const require = createRequire(import.meta.url);
|
|
|
6
6
|
const { version } = require('../package.json');
|
|
7
7
|
const cmd = process.argv[2];
|
|
8
8
|
|
|
9
|
-
const HELP = `eda — установка и обновление скилов и агентов eda-* для Claude Code
|
|
9
|
+
const HELP = `eda — установка и обновление скилов и агентов eda-* для Claude Code, Codex CLI и OpenCode.
|
|
10
10
|
|
|
11
11
|
Использование:
|
|
12
|
-
eda init — выбрать целевые среды (Claude / Codex /
|
|
13
|
-
eda update —
|
|
12
|
+
eda init — выбрать целевые среды (Claude / Codex / OpenCode) и установить пакет
|
|
13
|
+
eda update — предложить добавить платформы и обновить текущий проект
|
|
14
14
|
eda update-all [dir] — перенести артефакты и настройки найденных проектов
|
|
15
15
|
eda --version — показать версию
|
|
16
16
|
eda --help — показать эту справку
|
package/lib/catalog.js
CHANGED
|
@@ -89,6 +89,10 @@ function validateAgent(directoryName, agent, prompt) {
|
|
|
89
89
|
if (!agent.models?.claude || !agent.models?.codex) {
|
|
90
90
|
throw new Error(`Агент ${directoryName}: нужны модели Claude и Codex.`);
|
|
91
91
|
}
|
|
92
|
+
if (agent.models.opencode !== undefined
|
|
93
|
+
&& (typeof agent.models.opencode !== 'string' || !/^[^\s/#]+\/[^\s/#]+(?:#[^\s#]+)?$/.test(agent.models.opencode))) {
|
|
94
|
+
throw new Error(`Агент ${directoryName}: models.opencode должен иметь формат provider/model#variant.`);
|
|
95
|
+
}
|
|
92
96
|
if (!['read-only', 'workspace-write', 'git-write'].includes(agent.access)) {
|
|
93
97
|
throw new Error(`Агент ${directoryName}: access должен быть read-only, workspace-write или git-write.`);
|
|
94
98
|
}
|
package/lib/install.js
CHANGED
|
@@ -11,6 +11,8 @@ import { renderClaudeAgent } from './renderers/claude-agent.js';
|
|
|
11
11
|
import { renderClaudeSkill } from './renderers/claude-skill.js';
|
|
12
12
|
import { renderCodexAgent } from './renderers/codex-agent.js';
|
|
13
13
|
import { renderCodexSkill } from './renderers/codex-skill.js';
|
|
14
|
+
import { renderOpenCodeAgent } from './renderers/opencode-agent.js';
|
|
15
|
+
import { renderOpenCodeSkill } from './renderers/opencode-skill.js';
|
|
14
16
|
|
|
15
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
16
18
|
const __dirname = path.dirname(__filename);
|
|
@@ -37,10 +39,11 @@ const ARTIFACT_DIRECTORY_NAMES = [
|
|
|
37
39
|
];
|
|
38
40
|
const TARGET_CHOICES = [
|
|
39
41
|
{ value: 'claude', label: 'Claude Code', dir: '.claude/skills/' },
|
|
40
|
-
{ value: 'codex', label: 'Codex CLI', dir: '.agents/skills/' }
|
|
42
|
+
{ value: 'codex', label: 'Codex CLI', dir: '.agents/skills/' },
|
|
43
|
+
{ value: 'opencode', label: 'OpenCode', dir: '.opencode/skills/' }
|
|
41
44
|
];
|
|
42
45
|
const UPDATE_ALL_MAX_DEPTH = 2;
|
|
43
|
-
const UPDATE_ALL_SKIP_DIRS = new Set(['.git', '.agents', '.claude', '.codex', 'node_modules']);
|
|
46
|
+
const UPDATE_ALL_SKIP_DIRS = new Set(['.git', '.agents', '.claude', '.codex', '.opencode', 'node_modules']);
|
|
44
47
|
const RETIRED_SKILLS = [
|
|
45
48
|
'eda-research',
|
|
46
49
|
'eda-review-check',
|
|
@@ -540,13 +543,14 @@ export async function init({ cwd, input = process.stdin, output = process.stdout
|
|
|
540
543
|
await syncPackage(cwd, targets, output, { action: 'install' });
|
|
541
544
|
}
|
|
542
545
|
|
|
543
|
-
export async function update({ cwd, input = process.stdin, output = process.stdout }) {
|
|
544
|
-
const
|
|
545
|
-
if (
|
|
546
|
+
export async function update({ cwd, input = process.stdin, output = process.stdout, checkboxPrompt = checkbox }) {
|
|
547
|
+
const installedTargets = await detectTargets(cwd);
|
|
548
|
+
if (installedTargets.length === 0) {
|
|
546
549
|
output.write('Не нашёл установленного пакета eda в этом проекте. Запусти `eda init`.\n');
|
|
547
550
|
return;
|
|
548
551
|
}
|
|
549
|
-
output.write(`Найдены установленные среды: ${
|
|
552
|
+
output.write(`Найдены установленные среды: ${installedTargets.join(', ')}\n`);
|
|
553
|
+
const targets = await askUpdateTargets({ installedTargets, input, output, checkboxPrompt });
|
|
550
554
|
await migrateArtifactDirectories(cwd, output);
|
|
551
555
|
await configureSettings(cwd, { input, output });
|
|
552
556
|
await syncPackage(cwd, targets, output, { action: 'update' });
|
|
@@ -677,7 +681,7 @@ export async function updateAll({
|
|
|
677
681
|
|
|
678
682
|
export async function askTargets({ input = process.stdin, output = process.stdout } = {}) {
|
|
679
683
|
if (!input.isTTY || !output.isTTY) {
|
|
680
|
-
output.write('Нет интерактивного терминала — устанавливаю Claude Code
|
|
684
|
+
output.write('Нет интерактивного терминала — устанавливаю Claude Code, Codex CLI и OpenCode.\n');
|
|
681
685
|
return TARGET_CHOICES.map(choice => choice.value);
|
|
682
686
|
}
|
|
683
687
|
|
|
@@ -695,6 +699,30 @@ export async function askTargets({ input = process.stdin, output = process.stdou
|
|
|
695
699
|
});
|
|
696
700
|
}
|
|
697
701
|
|
|
702
|
+
export async function askUpdateTargets({
|
|
703
|
+
installedTargets,
|
|
704
|
+
input = process.stdin,
|
|
705
|
+
output = process.stdout,
|
|
706
|
+
checkboxPrompt = checkbox
|
|
707
|
+
}) {
|
|
708
|
+
if (!input.isTTY || !output.isTTY) return [...installedTargets];
|
|
709
|
+
|
|
710
|
+
const selected = await checkboxPrompt({
|
|
711
|
+
message: 'Какие платформы добавить? Установленные уже отмечены и будут обновлены.',
|
|
712
|
+
instructions: 'Space — добавить платформу, Enter — обновить выбранные; установленные снимать нельзя',
|
|
713
|
+
choices: TARGET_CHOICES.map(choice => ({
|
|
714
|
+
name: `${choice.label} (${choice.dir})${installedTargets.includes(choice.value) ? ' — установлена' : ''}`,
|
|
715
|
+
value: choice.value,
|
|
716
|
+
checked: installedTargets.includes(choice.value)
|
|
717
|
+
})),
|
|
718
|
+
validate: choices => installedTargets.every(target => choices.some(choice => choice.value === target))
|
|
719
|
+
|| 'Установленные платформы нужно оставить отмеченными: update их не удаляет.'
|
|
720
|
+
}, { input, output });
|
|
721
|
+
|
|
722
|
+
return TARGET_CHOICES.map(choice => choice.value)
|
|
723
|
+
.filter(target => installedTargets.includes(target) || selected.includes(target));
|
|
724
|
+
}
|
|
725
|
+
|
|
698
726
|
export async function askUpdateAllSettingsMode({
|
|
699
727
|
input = process.stdin,
|
|
700
728
|
output = process.stdout,
|
|
@@ -884,8 +912,9 @@ async function askAgentSettings({ input, output, selectPrompt, definitions, seed
|
|
|
884
912
|
|
|
885
913
|
async function detectTargets(cwd) {
|
|
886
914
|
const targets = [];
|
|
887
|
-
|
|
888
|
-
|
|
915
|
+
for (const { value } of TARGET_CHOICES) {
|
|
916
|
+
if (await targetStructureExists(cwd, value)) targets.push(value);
|
|
917
|
+
}
|
|
889
918
|
return targets;
|
|
890
919
|
}
|
|
891
920
|
|
|
@@ -893,8 +922,9 @@ async function detectTargets(cwd) {
|
|
|
893
922
|
// или manifest владения. Одних пустых/чужих каталогов skills и agents недостаточно.
|
|
894
923
|
async function detectInstalledTargets(cwd) {
|
|
895
924
|
const targets = [];
|
|
896
|
-
|
|
897
|
-
|
|
925
|
+
for (const { value } of TARGET_CHOICES) {
|
|
926
|
+
if (await hasInstalledPackage(cwd, value)) targets.push(value);
|
|
927
|
+
}
|
|
898
928
|
return targets;
|
|
899
929
|
}
|
|
900
930
|
|
|
@@ -908,7 +938,7 @@ async function targetStructureExists(cwd, target) {
|
|
|
908
938
|
|
|
909
939
|
async function hasInstalledPackage(cwd, target) {
|
|
910
940
|
const { skillsDir, agentsDir, manifestPath, legacySkillsDir } = getTargetPaths(cwd, target);
|
|
911
|
-
const agentExtension = target === '
|
|
941
|
+
const agentExtension = target === 'codex' ? '.toml' : '.md';
|
|
912
942
|
return await fileExists(manifestPath)
|
|
913
943
|
|| await hasInstalledSkill(skillsDir)
|
|
914
944
|
|| (legacySkillsDir !== null && await hasInstalledSkill(legacySkillsDir))
|
|
@@ -952,13 +982,9 @@ async function syncPackage(cwd, targets, output = process.stdout, { action = 'up
|
|
|
952
982
|
|
|
953
983
|
const changedSkills = new Set();
|
|
954
984
|
const changedAgents = new Set();
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
for (const agentName of result.changedAgents) changedAgents.add(agentName);
|
|
959
|
-
}
|
|
960
|
-
if (targets.includes('codex')) {
|
|
961
|
-
const result = await installTarget(cwd, 'codex', skills, agents, packageVersion, output);
|
|
985
|
+
for (const { value } of TARGET_CHOICES) {
|
|
986
|
+
if (!targets.includes(value)) continue;
|
|
987
|
+
const result = await installTarget(cwd, value, skills, agents, packageVersion, output);
|
|
962
988
|
for (const skillName of result.changedSkills) changedSkills.add(skillName);
|
|
963
989
|
for (const agentName of result.changedAgents) changedAgents.add(agentName);
|
|
964
990
|
}
|
|
@@ -1592,10 +1618,9 @@ async function installTarget(cwd, target, skills, agents, packageVersion, output
|
|
|
1592
1618
|
|
|
1593
1619
|
if (agents.length > 0) await fs.mkdir(agentsDir, { recursive: true });
|
|
1594
1620
|
for (const agent of agents) {
|
|
1595
|
-
const extension = target === '
|
|
1596
|
-
const
|
|
1597
|
-
|
|
1598
|
-
: renderCodexAgent(agent, agent.prompt);
|
|
1621
|
+
const extension = target === 'codex' ? '.toml' : '.md';
|
|
1622
|
+
const renderAgent = { claude: renderClaudeAgent, codex: renderCodexAgent, opencode: renderOpenCodeAgent }[target];
|
|
1623
|
+
const rendered = renderAgent(agent, agent.prompt);
|
|
1599
1624
|
const changed = await writeManagedFile(path.join(agentsDir, `${agent.name}${extension}`), rendered);
|
|
1600
1625
|
if (changed) changedAgents.push(agent.name);
|
|
1601
1626
|
}
|
|
@@ -1611,7 +1636,7 @@ async function installTarget(cwd, target, skills, agents, packageVersion, output
|
|
|
1611
1636
|
agents: agents.map(agent => agent.name)
|
|
1612
1637
|
});
|
|
1613
1638
|
|
|
1614
|
-
const label =
|
|
1639
|
+
const label = TARGET_CHOICES.find(choice => choice.value === target).label;
|
|
1615
1640
|
const location = skillsDir === path.join(targetRoot, 'skills')
|
|
1616
1641
|
? targetRoot
|
|
1617
1642
|
: `${skillsDir}; ${agentsDir}`;
|
|
@@ -1638,9 +1663,8 @@ async function buildSkillFiles(skill, target) {
|
|
|
1638
1663
|
if (!entrypoint) throw new Error(`У скила ${skill.name} нет SKILL.md.`);
|
|
1639
1664
|
|
|
1640
1665
|
const content = entrypoint.toString('utf8');
|
|
1641
|
-
const
|
|
1642
|
-
|
|
1643
|
-
: renderCodexSkill(content, skill.config);
|
|
1666
|
+
const renderSkill = { claude: renderClaudeSkill, codex: renderCodexSkill, opencode: renderOpenCodeSkill }[target];
|
|
1667
|
+
const rendered = renderSkill(content, skill.config);
|
|
1644
1668
|
files.set('SKILL.md', Buffer.from(rendered));
|
|
1645
1669
|
return files;
|
|
1646
1670
|
}
|
|
@@ -1828,7 +1852,7 @@ async function removeRetiredComponents(skillsDir, agentsDir, target, previousMan
|
|
|
1828
1852
|
await fs.rm(path.join(skillsDir, `${skillName}.md`), { force: true });
|
|
1829
1853
|
}
|
|
1830
1854
|
|
|
1831
|
-
const extension = target === '
|
|
1855
|
+
const extension = target === 'codex' ? '.toml' : '.md';
|
|
1832
1856
|
for (const agentName of staleAgents) {
|
|
1833
1857
|
await fs.rm(path.join(agentsDir, `${agentName}${extension}`), { force: true });
|
|
1834
1858
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { stringify } from 'yaml';
|
|
2
|
+
|
|
3
|
+
export function renderOpenCodeAgent(agent, prompt) {
|
|
4
|
+
const metadata = {
|
|
5
|
+
description: agent.description,
|
|
6
|
+
mode: 'subagent'
|
|
7
|
+
};
|
|
8
|
+
// Без явного provider/model OpenCode наследует модель родительской сессии.
|
|
9
|
+
if (agent.models?.opencode) metadata.model = agent.models.opencode;
|
|
10
|
+
if (agent.access === 'read-only') {
|
|
11
|
+
metadata.permissions = [
|
|
12
|
+
{ action: '*', resource: '*', effect: 'deny' },
|
|
13
|
+
...['read', 'glob', 'grep', 'webfetch', 'websearch'].map(action => ({
|
|
14
|
+
action, resource: '*', effect: 'allow'
|
|
15
|
+
})),
|
|
16
|
+
{ action: 'read', resource: '*.env', effect: 'ask' },
|
|
17
|
+
{ action: 'read', resource: '*.env.*', effect: 'ask' }
|
|
18
|
+
];
|
|
19
|
+
} else if (agent.access === 'git-write') {
|
|
20
|
+
metadata.permissions = [{ action: 'edit', resource: '*', effect: 'deny' }];
|
|
21
|
+
}
|
|
22
|
+
return `---\n${stringify(metadata)}---\n\n${prompt.trimEnd()}\n`;
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const OPEN_CODE_INSTRUCTIONS = `## Среда исполнения: OpenCode V2
|
|
2
|
+
|
|
3
|
+
Этот раздел адаптирует только платформенные механизмы инструкции ниже; её scope, режимы исполнения, подтверждения, лимиты и контракты результатов сохраняются. В OpenCode применяй следующие правила вместо веток Claude Code/Codex:
|
|
4
|
+
|
|
5
|
+
- Загружай вложенный скил через инструмент \`skill\` по точному ID; его ресурсы читай относительно выданной базовой директории. Установленные скилы находятся в \`.opencode/skills/\`, агенты — в \`.opencode/agents/\`.
|
|
6
|
+
- Установленного агента запускай через \`subagent\` с \`agent: <имя>\` и \`prompt: <вход>\`. Для изолированного выполнения скила используй установленного \`eda-skill-runner\` с указанием загрузить нужный скил. Дочерние сессии получают свежий контекст: передавай весь необходимый вход явно. Не передавай Codex-параметр \`fork_turns\`.
|
|
7
|
+
- Для параллельных проверок отправь независимые вызовы одновременно, используй background только при независимой работе; ожидай уведомления, не опрашивай shell или файлы. Для продолжения передай \`sessionID\` того же агента.
|
|
8
|
+
- Не заменяй \`eda-skill-runner\` встроенным general: general не может запускать субагентов. При недоступности нужной роли, вложенного запуска или инструмента верни конкретный \`blocked\`, не меняй режим и не подменяй работу отдельным CLI или основным агентом.
|
|
9
|
+
- Вместо \`AskUserQuestion\` / \`request_user_input\` используй \`question\`; если интерактивный инструмент недоступен, задай короткий вопрос и остановись. В неинтерактивном запуске не читай stdin, верни \`blocked: нужен ответ пользователя\`.
|
|
10
|
+
- Модели из колонок Claude/Codex и \`review.agents.*.model.claude/codex\` не относятся к OpenCode. По умолчанию используй модель установленного агента или наследуемую модель сессии; в поле MODEL передавай фактическую модель, иначе \`current\`. Явный runtime override должен иметь формат \`provider/model#variant\` (variant необязателен); если хост не может его применить, верни \`blocked\`. Не выдумывай provider ID и не переписывай настройки проекта.
|
|
11
|
+
- Read-only агенты не имеют shell, редакторов, MCP и субагентов. Оркестратор заранее получает diff и нужные git/CI-данные разрешёнными read-only командами и передаёт их вместе с исходным target в prompt. Агент может дочитывать исходники; отсутствие shell не означает, что тесты были выполнены. Если доказательств недостаточно, сообщи блокер.
|
|
12
|
+
- Если инструкция требует Plan Mode, используй доступный нативный режим планирования без изменения кода. Если его нет либо он запрещает сохранение подтверждённого плана в требуемый каталог, остановись с конкретным блокером, не обходи permissions.
|
|
13
|
+
- Для strict кросс-CLI ревью из OpenCode попроси выбрать Claude Code или Codex CLI, если CLI не указан явно. Не считай OpenCode автоматически одной из двух сторон и не пропускай включённый strict.
|
|
14
|
+
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export function renderOpenCodeSkill(content) {
|
|
18
|
+
const closingMarker = content.indexOf('\n---', 4);
|
|
19
|
+
if (!content.startsWith('---\n') || closingMarker === -1) {
|
|
20
|
+
throw new Error('Не удалось добавить настройки OpenCode: некорректный front matter скила.');
|
|
21
|
+
}
|
|
22
|
+
const bodyStart = closingMarker + '\n---'.length;
|
|
23
|
+
return `${content.slice(0, bodyStart)}\n\n${OPEN_CODE_INSTRUCTIONS}${content.slice(bodyStart).trimStart()}`;
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gian-tiaga/eda",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Пакет скилов и специализированных агентов eda-* для Claude Code
|
|
3
|
+
"version": "3.14.0",
|
|
4
|
+
"description": "Пакет скилов и специализированных агентов eda-* для Claude Code, Codex CLI и OpenCode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"eda": "bin/cli.js"
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"claude-code",
|
|
26
26
|
"codex",
|
|
27
27
|
"codex-cli",
|
|
28
|
+
"opencode",
|
|
28
29
|
"skills",
|
|
29
30
|
"agents"
|
|
30
31
|
],
|
|
@@ -70,12 +70,15 @@ Default — `subagents`. При неизвестном или отсутству
|
|
|
70
70
|
|
|
71
71
|
## Подготовить контекст
|
|
72
72
|
|
|
73
|
-
1. Определи `$TARGET`: явный файл, папка, URL PR/MR, ветка, коммит, указанный diff или `git diff HEAD` без аргументов. Для GitHub/GitLab URL получи metadata и
|
|
73
|
+
1. Определи `$TARGET`: явный файл, папка, URL PR/MR, ветка, коммит, указанный diff или `git diff HEAD` без аргументов. Для GitHub/GitLab URL получи metadata, diff, SHA текущего head и статусы CI read-only командами `gh`/`glab`; для другого сервиса используй доступное read-only средство. Если основной diff недоступен, остановись: warning разрешён для недоступных CI-результатов и прошлых обсуждений, но не для самого target.
|
|
74
74
|
2. Прочитай `AGENTS.md`, `CLAUDE.md`, `docs/rules.md`, `docs/arch.md` и сам target настолько, чтобы выбрать проверки и сформировать точный контекст. В `subagents` на этом шаге не делай собственное code review; в `main` эти документы и target станут общей основой всех проходов и не должны загружаться заново для каждой проверки.
|
|
75
75
|
3. Определи `$PLAN_FILE`. Если его нет, используй `none` и не пытайся восстановить последний план наугад.
|
|
76
76
|
4. Определи `$REFERENCE_FILES`: если план содержит `sources.references`, используй их; иначе через `docs/references.md` выбери только применимые карточки для компонентов target. Если карточек нет, используй `none`.
|
|
77
77
|
5. Определи `$BUSINESS_FILES`: сначала установи исходную задачу и фактически затронутое пользовательское или доменное поведение по текущему сообщению, плану и target. Если план содержит `sources.business`, используй только относящиеся к этому поведению пути; иначе прочитай `docs/business.md` и по описаниям выбери только применимые карточки. Если индекс отсутствует, подходящих карточек нет или изменения не затрагивают бизнес-поведение, используй `none`. Не загружай все карточки только потому, что индекс существует.
|
|
78
78
|
6. Сформируй краткий `$REVIEW_CONTEXT`: тип target, base, исходную задачу из текущего сообщения, плана, PR/MR title/body или явно связанного issue/артефакта, изменённые области, применимые документы и явные решения пользователя. Если надёжного описания задачи нет, явно напиши `task: unknown`, а не восстанавливай намерение по догадке. Не включай в контекст domain-инструкции агентов.
|
|
79
|
+
7. Для PR/MR сформируй `$CI_CONTEXT`: SHA head, названия, статусы, определимые команды и ссылки на автоматические CI-проверки; для failure добавь только значимый фрагмент лога, не передавай полные логи всех jobs. Учитывай только результаты для текущего head. Завершённую в CI проверку со статусом success или failure не запускай локально повторно: используй её результат и лог как доказательство. Локальный запуск допустим только для отсутствующей, отменённой, пропущенной, устаревшей или не сопоставимой с CI проверки либо по прямому указанию пользователя. Недоступный CI отметь warning и выполняй нужные проверки обычным способом. Для не-PR/MR target используй `CI_CONTEXT: none`.
|
|
80
|
+
|
|
81
|
+
CI переиспользуется только как результат автоматических команд — тестов, линтеров, typecheck, сборки и аналогичных jobs. Он не заменяет выбранные смысловые проходы `correctness`, `architecture`, `tests` и другие: они по-прежнему анализируют diff и качество покрытия, но не дублируют уже завершённые CI-команды.
|
|
79
82
|
|
|
80
83
|
Текущая задача задаёт область и намерение изменений. Применимые business-карточки проверяют затронутое поведение, но не расширяют target. Если задача явно меняет правило карточки, это возможная рассинхронизация business-документации, которую должен классифицировать `eda-review-business`, а не основание молча объявить реализацию неверной.
|
|
81
84
|
|
|
@@ -106,10 +109,10 @@ Default — `subagents`. При неизвестном или отсутству
|
|
|
106
109
|
|
|
107
110
|
Прочитай [references/review-matrix.md](references/review-matrix.md) целиком. Это обязательный контракт всех специализированных проходов в `main`; не читай packaged prompts из `agents/eda-review-*` и не пытайся вызвать их как скилы.
|
|
108
111
|
|
|
109
|
-
1. Прочитай target и общий код вокруг изменений один раз. Применимые инструкции, `$PLAN_FILE`, `$REFERENCE_FILES` и `$BUSINESS_FILES` также загрузи один раз и только когда соответствующая проверка выбрана.
|
|
112
|
+
1. Прочитай target и общий код вокруг изменений один раз. Применимые инструкции, `$PLAN_FILE`, `$REFERENCE_FILES` и `$BUSINESS_FILES` также загрузи один раз и только когда соответствующая проверка выбрана. Соблюдай `$CI_CONTEXT`: не перезапускай автоматическую команду, уже завершённую в CI на текущем head.
|
|
110
113
|
2. Последовательно выполни отдельный проход по каждой выбранной проверке из матрицы. Не смешивай области и не пропускай проход из-за того, что соседняя проверка уже изучала тот же код.
|
|
111
114
|
3. Для каждого прохода сохрани внутренний результат: `check`, `status`, `summary` и кандидаты в находки с `severity`, `explanation`, `evidence`, `repro`, `fix` и `tests`. YAML между проходами не нужен.
|
|
112
|
-
4. Если проверка оказалась неприменима, перенеси её в skipped с конкретной причиной. Если обязательную проверку невозможно выполнить из-за недоступного target или контекста, остановись без итогового файла. Недоступные предыдущие удалённые обсуждения преврати в warning и продолжай.
|
|
115
|
+
4. Если проверка оказалась неприменима, перенеси её в skipped с конкретной причиной. Если обязательную проверку невозможно выполнить из-за недоступного target или контекста, остановись без итогового файла. Недоступные CI-результаты и предыдущие удалённые обсуждения преврати в warning и продолжай.
|
|
113
116
|
5. После всех проходов проверь доказательства, дедуплицируй кандидатов, выставь score и сохрани итог по общим правилам ниже. Не запускай отдельный редакторский или подтверждающий проход.
|
|
114
117
|
|
|
115
118
|
### Режим subagents
|
|
@@ -150,6 +153,9 @@ REFERENCE_FILES: <paths | none>
|
|
|
150
153
|
BUSINESS_FILES: <paths | none>
|
|
151
154
|
MODEL: <фактически выбранная модель>
|
|
152
155
|
REVIEW_CONTEXT: <краткий общий контекст>
|
|
156
|
+
CI_CONTEXT: <head SHA, CI-проверки со статусами, командами, ссылками и значимыми failure-логами | none>
|
|
157
|
+
|
|
158
|
+
Для PR/MR не запускай локально автоматическую команду, если CI_CONTEXT подтверждает, что эквивалентная проверка уже завершилась в CI на текущем head. Используй результат и лог CI как доказательство; смысловой review-проход выполни полностью.
|
|
153
159
|
|
|
154
160
|
Верни результат строго по YAML-контракту установленного агента.
|
|
155
161
|
```
|
|
@@ -214,6 +220,7 @@ checks:
|
|
|
214
220
|
- **Completed:** <проверки и модели>
|
|
215
221
|
- **Skipped:** <проверки и причины>
|
|
216
222
|
- **Warnings:** <предупреждения или «нет»>
|
|
223
|
+
- **CI:** <переиспользованные результаты текущего head, локально запущенные отсутствующие проверки и недоступные данные>
|
|
217
224
|
- **Frontend:** <если запускался: «UI/UX проверены по коду; браузерная проверка не выполнялась»>
|
|
218
225
|
- **Previous reviews:** <актуальные / исправленные, но открытые / недоступны>
|
|
219
226
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Этот файл используется только при `review.execution: main`. Выполни отдельный проход по каждой выбранной проверке, но читай общий target и проектные инструкции один раз. Не смешивай области: одна проблема должна остаться в наиболее точной проверке.
|
|
4
4
|
|
|
5
|
+
Для PR/MR соблюдай переданный `CI_CONTEXT`: не запускай локально тесты, линтеры, typecheck, сборку или другую автоматическую команду, если эквивалентная проверка уже завершилась в CI на текущем head. Используй CI-результат и доступный лог как доказательство. Это не отменяет смысловые проходы матрицы: анализируй diff и полноту тестов как обычно.
|
|
6
|
+
|
|
5
7
|
Для любой находки обязательны точное место, достижимый на текущем коде сценарий, практический ущерб, доказательство, `repro`, способ исправления и нужный тест. Не принимай вкусовой рефакторинг, косметику, спекулятивное усиление, необязательный тест или проблему, которая появится только после гипотетического будущего изменения. Не перечисляй удачные решения и выполненные пункты.
|
|
6
8
|
|
|
7
9
|
## correctness
|
|
@@ -39,7 +41,7 @@
|
|
|
39
41
|
|
|
40
42
|
## tests
|
|
41
43
|
|
|
42
|
-
Ищи пропущенные регрессии, неверные ожидания, неподходящий уровень теста, хрупкие проверки и изменённое поведение без защиты. Не требуй тест на каждую строку. Находка должна назвать конкретную регрессию, которую текущие тесты не поймают, либо ошибку в самих тестах. Для подтверждения разрешены только безопасные проверки, не меняющие tracked
|
|
44
|
+
Ищи пропущенные регрессии, неверные ожидания, неподходящий уровень теста, хрупкие проверки и изменённое поведение без защиты. Не требуй тест на каждую строку. Находка должна назвать конкретную регрессию, которую текущие тесты не поймают, либо ошибку в самих тестах. Для подтверждения разрешены только безопасные проверки, не меняющие tracked-файлы и не дублирующие завершённые CI-проверки текущего head.
|
|
43
45
|
|
|
44
46
|
## security
|
|
45
47
|
|