@gian-tiaga/eda 0.6.2 → 0.8.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 +49 -13
- package/bin/cli.js +5 -1
- package/lib/install.js +158 -6
- package/package.json +2 -2
- package/skills/eda-automate.md +61 -52
- package/skills/eda-commit.md +2 -9
- package/skills/eda-docs.md +7 -18
- package/skills/eda-execute.md +10 -11
- package/skills/eda-explore.md +17 -49
- package/skills/eda-fix-by-review.md +12 -14
- package/skills/eda-fix.md +1 -12
- package/skills/eda-merge-worktree.md +2 -17
- package/skills/eda-plan.md +120 -338
- package/skills/eda-polish.md +113 -0
- package/skills/eda-review-check.md +149 -0
- package/skills/eda-review.md +36 -114
- package/skills/eda-roadmap.md +3 -23
- package/skills/eda-send-review.md +2 -10
- package/skills/eda-start.md +226 -0
- package/skills/eda-worktree.md +2 -15
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Поточная разработка с AI-агентами — на русском языке.
|
|
4
4
|
> Набор готовых скилов для **Claude Code** и **Codex CLI**, которые ведут тебя через весь цикл: от исследования до коммита.
|
|
5
5
|
|
|
6
|
-
`eda` — это
|
|
6
|
+
`eda` — это шестнадцать скилов, каждый отвечает за свой кусок работы. Вместо того чтобы каждый раз объяснять модели, как делать ревью или как исполнять план, ты говоришь одно слово — и она следует чёткой инструкции на русском, со всеми правилами, проверками и артефактами в нужных папках.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -21,25 +21,36 @@ eda init
|
|
|
21
21
|
|
|
22
22
|
Установщик покажет чекбоксы: стрелками выбираешь среду, пробелом отмечаешь, Enter продолжает. Можно поставить Claude Code, Codex CLI или обе среды сразу. Если `docs/settings.yaml` ещё нет, установщик также предложит выбрать настройки скилов и создаст этот файл. В конце `eda init` пишет, какие скилы реально установлены или изменились.
|
|
23
23
|
|
|
24
|
+
Если скилы уже стоят во многих проектах, можно обновить их одной командой:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
eda update-all ~/Code
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`eda update-all` ищет проекты в указанной директории, её прямых подпапках и подпапках второго уровня. Проект считается найденным, если в нём уже есть `.claude/skills` или `.codex/skills`. Команда обновляет только найденные среды и не создаёт `docs/settings.yaml`, чтобы массовый запуск не добавлял новые файлы в проекты.
|
|
31
|
+
|
|
24
32
|
---
|
|
25
33
|
|
|
26
34
|
## 🛠️ Скилы
|
|
27
35
|
|
|
28
36
|
| Скил | Что делает | Куда складывает |
|
|
29
37
|
|---|---|---|
|
|
38
|
+
| `eda-start` | Помогает стартовать новый проект: собирает требования, вместе с пользователем выбирает стек, архитектуру, инструменты качества кода, AI-скилы, агентные инструкции, MCP-серверы и правила проекта. Не пишет код и не ставит зависимости; сохраняет согласованные стартовые решения и по подтверждению создаёт черновики правил/архитектуры/AGENTS | `docs/project-starts/`, опционально `docs/rules.md`, `docs/arch.md`, `AGENTS.md` |
|
|
30
39
|
| `eda-roadmap` | Создаёт roadmap-файл: список будущих задач с короткими, понятными и недвусмысленными описаниями без деталей реализации, файлов, библиотек, API и пошагового плана | `docs/roadmaps/` |
|
|
31
40
|
| `eda-explore` | Исследует тему до конкретного результата: описание проблемы, релевантная архитектура, закрытые развилки, риски внутри решений и короткий выбранный вариант решения без плана. В дефолтном режиме ведёт исследование как диалог: факты собирает сам, а значимые развилки выносит тебе с рекомендацией. Если нужны пакеты или ПО — проверяет актуальные стабильные версии через context7 или web search | `docs/researches/` |
|
|
32
41
|
| `eda-plan` | Пишет план реализации через стандартный Plan Mode хост-агента. `docs/rules.md` и `docs/arch.md` использует как обязательную рамку, а не справочный контекст: план должен строго следовать правилам и архитектуре. В плане явно фиксирует контракты БД/API, если задача их затрагивает. Затем три параллельных субагента/модели (слабая, средняя, мощная) проверяют план на реалистичность, пропущенные шаги и нарушения правил — главный планировщик сам решает, что применить | `docs/plans/` |
|
|
33
42
|
| `eda-execute` | Выполняет план. Спрашивает, где работать (текущая ветка, новая ветка, отдельный worktree). Перед правками читает план, `docs/rules.md` и `docs/arch.md`; правила и архитектура обязательны к исполнению. Если шаг плана им противоречит, останавливается и спрашивает. Тесты пишет внутри каждого шага. В конце — полный прогон тестов и линтеров | `docs/executions/` |
|
|
34
43
|
| `eda-fix` | Делает обычные фиксы по короткому контексту, баг-репорту или файлу плана. Перед правками читает правила и архитектуру, добавляет нужные тесты, прогоняет проверки и сохраняет историю правок | `docs/fixes/` |
|
|
35
|
-
| `eda-review` | Делает код-ревью с оценкой 0–100 и сверкой с планом работ, но в файл пишет только проблемы: ошибки, недоделки, неточности, нарушения правил/архитектуры, риски и недостающие тесты.
|
|
44
|
+
| `eda-review` | Делает код-ревью с оценкой 0–100 и сверкой с планом работ, но в файл пишет только проблемы: ошибки, недоделки, неточности, нарушения правил/архитектуры, риски и недостающие тесты. Если запущен без аргументов, ревьюит незакоммиченный `git diff HEAD` без проверки плана. Не перечисляет выполненную работу. В обычном режиме после черновика передаёт файл в `eda-review-check`; с флагом `draft` сохраняет только первичное ревью без субагентов | `docs/reviews/` |
|
|
45
|
+
| `eda-review-check` | Проверяет готовое ревью из `docs/reviews/` специализированными субагентами: архитектуру, правила, выполнение плана при указанном plan-файле и при включённой настройке качество кода. В строгом режиме добавляет кросс-ревью между Claude и Codex. Сам применяет подтверждённые замечания к файлу ревью, но не правит код | `docs/reviews/` |
|
|
36
46
|
| `eda-fix-by-review` | Применяет замечания из ревью. Обязательные — сразу. Спорные — спрашивает. В конце ссылается на отчёт прямо в файле ревью | `docs/review-fixes/` |
|
|
47
|
+
| `eda-polish` | Оркестрирует доводку изменений: запускает `eda-review draft`, затем `eda-review-check`, затем `eda-fix-by-review apply-optional` и повторяет цикл до оценки 95/100 или лимита 5 итераций. Каждый шаг идёт в изолированном субагенте или отдельном CLI-процессе. Не коммитит | `docs/reviews/`, `docs/review-fixes/` |
|
|
37
48
|
| `eda-send-review` | Отправляет ревью на GitHub PR через `gh` — как комментарий, review, approve или request-changes. Сам определяет PR по текущей ветке | (комментарий в PR) |
|
|
38
49
|
| `eda-commit` | Делает один аккуратный коммит в стиле проекта. В конце спрашивает: push, merge в main + удалить ветку, или ничего | (git) |
|
|
39
50
|
| `eda-worktree` | Создаёт git worktree рядом с основным проектом в папке `{name}-work-{n}` и одноимённую ветку. Базу берёт из аргумента или спрашивает | соседняя папка `{name}-work-{n}` |
|
|
40
51
|
| `eda-merge-worktree` | Мержит ветку из соседнего worktree в текущую ветку. Принимает номер `1`, короткое имя `work-1` или полное имя `{name}-work-1`. Worktree и ветку после merge не удаляет | (git) |
|
|
41
52
|
| `eda-docs` | Создаёт или обновляет `docs/rules.md` (максимально строгие правила для твоего стека), `docs/arch.md` (архитектура проекта) и шапку `AGENTS.md`. Может предлагать инструменты, которых ещё нет в проекте | `docs/rules.md`, `docs/arch.md`, `AGENTS.md` |
|
|
42
|
-
| `eda-automate` | Анализирует историю ревью и фиксов. Если
|
|
53
|
+
| `eda-automate` | Анализирует историю ревью и фиксов. Если ошибка повторяется — предлагает автоматизации на уровне языка и тулчейна: линтеры, статанализаторы, typecheck, тесты, pre-commit/CI-проверки. Если кодовая проверка не подходит, может предложить MCP-сервер, агентную проверку, новый скил или уточнение правил/архитектуры | `docs/automations/` |
|
|
43
54
|
|
|
44
55
|
---
|
|
45
56
|
|
|
@@ -53,7 +64,10 @@ eda init
|
|
|
53
64
|
|---|---|---|---|
|
|
54
65
|
| `eda-explore` | `strict` | После сохранения отчёта отдаёт его соседнему CLI (Claude → Codex или наоборот) на критическое ревью конкретности, фактов, развилок, рисков и версий; затем доправляет отчёт по замечаниям | Серьёзные исследования, которые лягут в основу больших решений; когда хочется второго мнения от другой модели/среды |
|
|
55
66
|
| `eda-plan` | `strict` | После обычного мета-ревью трёх субагентов/моделей отдаёт план соседнему CLI на дополнительный круг проверки; доправляет план | Большие или ответственные планы, особенно затрагивающие смежные системы |
|
|
56
|
-
| `eda-review` | `
|
|
67
|
+
| `eda-review` | `draft` | Сохраняет первичное ревью со статусом `draft` и не запускает `eda-review-check`, субагентов и кросс-CLI | Когда ревью нужно как черновик для внешней оркестрации, например `eda-polish` |
|
|
68
|
+
| `eda-review` | `strict` | После draft-ревью запускает `eda-review-check strict`: специализированные субагенты плюс соседний CLI; доправляет ревью по подтверждённым замечаниям | Ревью важных PR; когда нужен максимальный охват |
|
|
69
|
+
| `eda-review-check` | `strict` | Проверяет уже готовое ревью специализированными субагентами и затем отдаёт его соседнему CLI на дополнительный круг проверки | Когда черновик ревью уже есть и нужно усилить только проверку ревью |
|
|
70
|
+
| `eda-fix-by-review` | `apply-optional` | Применяет не только обязательные, но и пункты «на усмотрение автора» без дополнительного вопроса | Для заранее согласованной автоматической доводки, прежде всего внутри `eda-polish` |
|
|
57
71
|
|
|
58
72
|
---
|
|
59
73
|
|
|
@@ -67,7 +81,7 @@ eda init
|
|
|
67
81
|
version: 1
|
|
68
82
|
|
|
69
83
|
defaults:
|
|
70
|
-
# Включает strict-режим по умолчанию для eda-explore, eda-plan и eda-review.
|
|
84
|
+
# Включает strict-режим по умолчанию для eda-explore, eda-plan, eda-review и eda-review-check.
|
|
71
85
|
# true | false
|
|
72
86
|
strict: false
|
|
73
87
|
# Задаёт размер плана по умолчанию для eda-plan.
|
|
@@ -89,39 +103,53 @@ automate:
|
|
|
89
103
|
include_plans: false
|
|
90
104
|
|
|
91
105
|
review:
|
|
92
|
-
# Добавляет в eda-review проверку качества кода и meta-reviewer quality-check.
|
|
106
|
+
# Добавляет в eda-review / eda-review-check проверку качества кода и meta-reviewer quality-check.
|
|
93
107
|
# true | false
|
|
94
108
|
include_code_quality: true
|
|
95
109
|
```
|
|
96
110
|
|
|
97
111
|
Что означают настройки:
|
|
98
|
-
- `defaults.strict` — включает strict-режим по умолчанию для `eda-explore`, `eda-plan` и `eda-review`.
|
|
112
|
+
- `defaults.strict` — включает strict-режим по умолчанию для `eda-explore`, `eda-plan`, `eda-review` и `eda-review-check`.
|
|
99
113
|
- `defaults.plan_size` — размер плана для `eda-plan`: `normal`, `short` или `ask_each_time`.
|
|
100
114
|
- `defaults.decision_mode` — как `eda-explore` ведёт исследовательские развилки, а `eda-plan` принимает существенные решения: `autonomous` выбирает сам, `recommend_and_ask` рекомендует и спрашивает по значимым развилкам, `ask_each_time` спрашивает по каждой развилке, которая влияет на ход работы или итоговый выбор.
|
|
101
115
|
- `defaults.test_strategy` — стратегия тестов для `eda-plan`: `after_each_phase`, `tdd_each_phase`, `end_of_plan` или `ask_each_time`.
|
|
102
116
|
- `defaults.logging_strategy` — стратегия логирования для `eda-plan`: `debug_precise`, `standard` или `ask_each_time`.
|
|
103
117
|
- `automate.include_plans` — добавляет `docs/plans/` в обычный запуск `eda-automate`.
|
|
104
|
-
- `review.include_code_quality` — добавляет в `eda-review` проверку качества кода и отдельного мета-ревьюера `quality-check`.
|
|
118
|
+
- `review.include_code_quality` — добавляет в `eda-review` / `eda-review-check` проверку качества кода и отдельного мета-ревьюера `quality-check`.
|
|
105
119
|
|
|
106
|
-
`eda init` и `eda update` создают `docs/settings.yaml`, только если файла ещё нет. Существующий файл не перезаписывается.
|
|
120
|
+
`eda init` и `eda update` создают `docs/settings.yaml`, только если файла ещё нет. Существующий файл не перезаписывается. `eda update-all` настройки не создаёт и не меняет.
|
|
107
121
|
|
|
108
122
|
---
|
|
109
123
|
|
|
110
124
|
## 🔄 Воркфлоу
|
|
111
125
|
|
|
126
|
+
```text
|
|
127
|
+
start ─────────────> docs ───────────────┬───────────────┐
|
|
128
|
+
│ │ │
|
|
129
|
+
v v v
|
|
130
|
+
roadmap ────────> explore ─────> plan ───> execute ───┬──> review ───> review-check ───> fix-by-review ───┬──> send-review
|
|
131
|
+
│ │ │
|
|
132
|
+
└────────────> plan v └──> commit
|
|
133
|
+
fix ─────────────> review
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Если проект уже существует, можно начинать без `eda-start`:
|
|
137
|
+
|
|
112
138
|
```text
|
|
113
139
|
docs ───────────────┬───────────────┐
|
|
114
140
|
│ │
|
|
115
141
|
v v
|
|
116
|
-
roadmap ────────> explore ─────> plan ───> execute ───┬──> review ───> fix-by-review ───┬──> send-review
|
|
142
|
+
roadmap ────────> explore ─────> plan ───> execute ───┬──> review ───> review-check ───> fix-by-review ───┬──> send-review
|
|
117
143
|
│ │ │
|
|
118
144
|
└──────────────> plan v └──> commit
|
|
119
145
|
fix ─────────────> review
|
|
120
146
|
|
|
147
|
+
polish = review draft ─> review-check ─> fix-by-review apply-optional ─> повтор до нужной оценки
|
|
148
|
+
|
|
121
149
|
automate может запускаться от review, fix-by-review или fix.
|
|
122
150
|
```
|
|
123
151
|
|
|
124
|
-
Использовать всю цепочку не обязательно — каждый скил самодостаточен.
|
|
152
|
+
Использовать всю цепочку не обязательно — каждый скил самодостаточен. Новый проект можно начать с `eda-start`; существующий — с `eda-roadmap`, `eda-explore`, или сразу с `eda-execute` на готовом плане, или просто `eda-commit`, когда правки уже сделаны. Для параллельной работы есть `eda-worktree`, а для возврата ветки из worktree в текущую ветку — `eda-merge-worktree`.
|
|
125
153
|
|
|
126
154
|
---
|
|
127
155
|
|
|
@@ -129,7 +157,7 @@ automate может запускаться от review, fix-by-review или fix
|
|
|
129
157
|
|
|
130
158
|
- **Простой язык.** Скилы общаются с тобой так, чтобы понял человек без глубоких знаний предмета. Термины — только когда без них нельзя.
|
|
131
159
|
- **Все вопросы — интерактивно.** В Claude Code — через `AskUserQuestion`; в интерактивном Codex — через `request_user_input` или блокирующий вопрос в чат. В `codex exec` и других неинтерактивных запусках скил не имитирует диалог: если без ответа нельзя безопасно продолжать, он завершает работу со статусом `blocked: нужен ответ пользователя`.
|
|
132
|
-
- **Мета-проверки — через субагентов.** В интерактивном Codex обычные проверки планов и ревью запускаются через `spawn_agent` или аналогичный инструмент субагентов. Отдельный `codex exec` остаётся fallback для неинтерактивного режима и механизмом strict-кросс-проверки соседним CLI.
|
|
160
|
+
- **Мета-проверки — через субагентов.** В интерактивном Codex обычные проверки планов и ревью запускаются через `spawn_agent` или аналогичный инструмент субагентов. Проверки готового ревью собраны в `eda-review-check`. Отдельный `codex exec` остаётся fallback для неинтерактивного режима и механизмом strict-кросс-проверки соседним CLI.
|
|
133
161
|
- **Артефакты по папкам.** Исследования отдельно, планы отдельно, ревью отдельно. Между файлами — ссылки. Через месяц легко найти, кто что когда решал.
|
|
134
162
|
- **Границы между скилами жёсткие.** `execute` не коммитит — это работа `commit`. `review` не правит код — это `fix-by-review`. Никаких размытых ответственностей.
|
|
135
163
|
- **Доверие модели.** Скилы короткие. Они говорят «что» и «почему», а «как именно» — модель разбирается сама.
|
|
@@ -141,6 +169,7 @@ automate может запускаться от review, fix-by-review или fix
|
|
|
141
169
|
```bash
|
|
142
170
|
eda init # выбрать Claude Code / Codex / обе среды и установить скилы
|
|
143
171
|
eda update # обновить скилы, показать реально изменившиеся и создать docs/settings.yaml, если его ещё нет
|
|
172
|
+
eda update-all [dir] # обновить скилы во всех найденных проектах внутри dir на глубине 2
|
|
144
173
|
eda --version # показать версию установленного пакета
|
|
145
174
|
eda --help # справка
|
|
146
175
|
```
|
|
@@ -152,6 +181,13 @@ npm update -g @gian-tiaga/eda # подтянуть новый код
|
|
|
152
181
|
eda update # синхронизировать скилы в текущем проекте
|
|
153
182
|
```
|
|
154
183
|
|
|
184
|
+
Для папки с несколькими проектами:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm update -g @gian-tiaga/eda
|
|
188
|
+
eda update-all ~/Code
|
|
189
|
+
```
|
|
190
|
+
|
|
155
191
|
---
|
|
156
192
|
|
|
157
193
|
## 📁 Куда устанавливаются скилы
|
|
@@ -163,7 +199,7 @@ eda update # синхронизировать скилы в текущ
|
|
|
163
199
|
| **Claude Code** | `<project>/.claude/skills/<skill>/SKILL.md` — отдельная папка на каждый скил |
|
|
164
200
|
| **Codex CLI** | `<project>/.codex/skills/<skill>/SKILL.md` — отдельная папка на каждый скил |
|
|
165
201
|
|
|
166
|
-
`eda update` идемпотентно перезаписывает файлы в обеих папках и в конце пишет только те скилы, содержимое которых реально изменилось относительно установленной копии. При обновлении старые файлы Codex-формата `<project>/.codex/skills/<skill>.md`, созданные версиями `eda` до этой структуры, удаляются. Если ты хочешь подправить скил локально — лучше копию сделай рядом, а не прямо в `.claude/skills/` или `.codex/skills/`, иначе при следующем `update` твои правки потеряются.
|
|
202
|
+
`eda update` идемпотентно перезаписывает файлы в обеих папках и в конце пишет только те скилы, содержимое которых реально изменилось относительно установленной копии. `eda update-all [dir]` делает то же самое для каждого найденного проекта внутри `dir`, но не создаёт `docs/settings.yaml`. При обновлении старые файлы Codex-формата `<project>/.codex/skills/<skill>.md`, созданные версиями `eda` до этой структуры, удаляются. Если ты хочешь подправить скил локально — лучше копию сделай рядом, а не прямо в `.claude/skills/` или `.codex/skills/`, иначе при следующем `update` твои правки потеряются.
|
|
167
203
|
|
|
168
204
|
`AGENTS.md` (как и любые другие файлы в корне проекта) установщик **не трогает**. Если хочешь, чтобы Codex автоматически подгружал скилы, дай ему знать сам — например, одной строкой в `AGENTS.md`: «следуй инструкциям из `.codex/skills/`».
|
|
169
205
|
|
package/bin/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { init, update } from '../lib/install.js';
|
|
3
|
+
import { init, update, updateAll } from '../lib/install.js';
|
|
4
4
|
|
|
5
5
|
const require = createRequire(import.meta.url);
|
|
6
6
|
const { version } = require('../package.json');
|
|
@@ -11,6 +11,7 @@ const HELP = `eda — установка и обновление скилов ed
|
|
|
11
11
|
Использование:
|
|
12
12
|
eda init — выбрать целевые среды (Claude / Codex / обе) и установить скилы
|
|
13
13
|
eda update — обновить уже установленные скилы в текущем проекте
|
|
14
|
+
eda update-all [dir] — обновить уже установленные скилы во всех проектах внутри dir
|
|
14
15
|
eda --version — показать версию
|
|
15
16
|
eda --help — показать эту справку
|
|
16
17
|
`;
|
|
@@ -23,6 +24,9 @@ try {
|
|
|
23
24
|
case 'update':
|
|
24
25
|
await update({ cwd: process.cwd() });
|
|
25
26
|
break;
|
|
27
|
+
case 'update-all':
|
|
28
|
+
await updateAll({ root: process.argv[3] ?? process.cwd() });
|
|
29
|
+
break;
|
|
26
30
|
case '-v':
|
|
27
31
|
case '--version':
|
|
28
32
|
process.stdout.write(`${version}\n`);
|
package/lib/install.js
CHANGED
|
@@ -13,6 +13,8 @@ const TARGET_CHOICES = [
|
|
|
13
13
|
{ value: 'claude', label: 'Claude Code', dir: '.claude/skills/' },
|
|
14
14
|
{ value: 'codex', label: 'Codex CLI', dir: '.codex/skills/' }
|
|
15
15
|
];
|
|
16
|
+
const UPDATE_ALL_MAX_DEPTH = 2;
|
|
17
|
+
const UPDATE_ALL_SKIP_DIRS = new Set(['.git', '.claude', '.codex', 'node_modules']);
|
|
16
18
|
const RETIRED_SKILLS = ['eda-research'];
|
|
17
19
|
const DEFAULT_SETTINGS = {
|
|
18
20
|
strict: false,
|
|
@@ -26,7 +28,7 @@ const DEFAULT_SETTINGS = {
|
|
|
26
28
|
const SETTINGS_CHOICES = [
|
|
27
29
|
{
|
|
28
30
|
value: 'strict',
|
|
29
|
-
name: 'Strict по умолчанию для explore / plan / review',
|
|
31
|
+
name: 'Strict по умолчанию для explore / plan / review / review-check',
|
|
30
32
|
checked: DEFAULT_SETTINGS.strict
|
|
31
33
|
},
|
|
32
34
|
{
|
|
@@ -36,7 +38,7 @@ const SETTINGS_CHOICES = [
|
|
|
36
38
|
},
|
|
37
39
|
{
|
|
38
40
|
value: 'includeCodeQuality',
|
|
39
|
-
name: 'Проверять качество кода в eda-review',
|
|
41
|
+
name: 'Проверять качество кода в eda-review / eda-review-check',
|
|
40
42
|
checked: DEFAULT_SETTINGS.includeCodeQuality
|
|
41
43
|
}
|
|
42
44
|
];
|
|
@@ -122,6 +124,88 @@ export async function update({ cwd, input = process.stdin, output = process.stdo
|
|
|
122
124
|
await syncSkills(cwd, targets, output, { action: 'update' });
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
export async function updateAll({
|
|
128
|
+
root = process.cwd(),
|
|
129
|
+
output = process.stdout,
|
|
130
|
+
maxDepth = UPDATE_ALL_MAX_DEPTH
|
|
131
|
+
} = {}) {
|
|
132
|
+
if (!Number.isInteger(maxDepth) || maxDepth < 0) {
|
|
133
|
+
throw new Error('Глубина поиска должна быть неотрицательным целым числом.');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const rootDir = path.resolve(root);
|
|
137
|
+
const rootStat = await statIfExists(rootDir);
|
|
138
|
+
if (!rootStat?.isDirectory()) {
|
|
139
|
+
throw new Error(`Директория не найдена: ${rootDir}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
output.write(`Ищу проекты с установленными скилами в ${rootDir} (глубина ${maxDepth}).\n`);
|
|
143
|
+
|
|
144
|
+
const projects = await findInstalledProjects(rootDir, maxDepth);
|
|
145
|
+
if (projects.length === 0) {
|
|
146
|
+
output.write('Не нашёл проектов с установленными скилами.\n');
|
|
147
|
+
return {
|
|
148
|
+
root: rootDir,
|
|
149
|
+
maxDepth,
|
|
150
|
+
projects,
|
|
151
|
+
updatedProjects: [],
|
|
152
|
+
skippedProjects: [],
|
|
153
|
+
failedProjects: []
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
output.write(`Найдено ${formatProjectCount(projects.length)}: ${projects.map(project => formatProjectPath(rootDir, project)).join(', ')}\n`);
|
|
158
|
+
|
|
159
|
+
const updatedProjects = [];
|
|
160
|
+
const skippedProjects = [];
|
|
161
|
+
const failedProjects = [];
|
|
162
|
+
|
|
163
|
+
for (const projectDir of projects) {
|
|
164
|
+
const projectLabel = formatProjectPath(rootDir, projectDir);
|
|
165
|
+
output.write(`\n=== ${projectLabel} ===\n`);
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const targets = await detectTargets(projectDir);
|
|
169
|
+
if (targets.length === 0) {
|
|
170
|
+
output.write('Пропускаю: установленные среды исчезли во время обхода.\n');
|
|
171
|
+
skippedProjects.push(projectDir);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
output.write(`Найдены установленные среды: ${targets.join(', ')}\n`);
|
|
176
|
+
const result = await syncSkills(projectDir, targets, output, {
|
|
177
|
+
action: 'update',
|
|
178
|
+
writeDone: false
|
|
179
|
+
});
|
|
180
|
+
updatedProjects.push({
|
|
181
|
+
path: projectDir,
|
|
182
|
+
targets,
|
|
183
|
+
changedSkills: result.changedSkills
|
|
184
|
+
});
|
|
185
|
+
} catch (err) {
|
|
186
|
+
failedProjects.push({ path: projectDir, error: err });
|
|
187
|
+
output.write(`Ошибка: ${err.message}\n`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
output.write(`\nСводка: обновлено ${formatProjectCount(updatedProjects.length)}, пропущено ${formatProjectCount(skippedProjects.length)}, ошибки: ${formatErrorCount(failedProjects.length)}.\n`);
|
|
192
|
+
if (failedProjects.length > 0) {
|
|
193
|
+
output.write('Ошибки по проектам:\n');
|
|
194
|
+
for (const failedProject of failedProjects) {
|
|
195
|
+
output.write(` - ${formatProjectPath(rootDir, failedProject.path)}: ${failedProject.error.message}\n`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
root: rootDir,
|
|
201
|
+
maxDepth,
|
|
202
|
+
projects,
|
|
203
|
+
updatedProjects,
|
|
204
|
+
skippedProjects,
|
|
205
|
+
failedProjects
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
125
209
|
export async function askTargets({ input = process.stdin, output = process.stdout } = {}) {
|
|
126
210
|
if (!input.isTTY || !output.isTTY) {
|
|
127
211
|
output.write('Нет интерактивного терминала — устанавливаю Claude Code и Codex CLI.\n');
|
|
@@ -211,7 +295,7 @@ async function detectTargets(cwd) {
|
|
|
211
295
|
return targets;
|
|
212
296
|
}
|
|
213
297
|
|
|
214
|
-
async function syncSkills(cwd, targets, output = process.stdout, { action = 'update' } = {}) {
|
|
298
|
+
async function syncSkills(cwd, targets, output = process.stdout, { action = 'update', writeDone = true } = {}) {
|
|
215
299
|
const skills = await listSkills();
|
|
216
300
|
if (skills.length === 0) {
|
|
217
301
|
throw new Error(`В пакете нет скилов (искал в ${SKILLS_SRC}).`);
|
|
@@ -234,7 +318,37 @@ async function syncSkills(cwd, targets, output = process.stdout, { action = 'upd
|
|
|
234
318
|
.map(skill => skill.name)
|
|
235
319
|
.filter(skillName => changedSkills.has(skillName));
|
|
236
320
|
output.write(formatChangedSkills(actionLabel, changedSkillNames));
|
|
237
|
-
output.write('\nГотово.\n');
|
|
321
|
+
if (writeDone) output.write('\nГотово.\n');
|
|
322
|
+
return { changedSkills: changedSkillNames };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function findInstalledProjects(rootDir, maxDepth) {
|
|
326
|
+
const projects = [];
|
|
327
|
+
|
|
328
|
+
async function walk(dir, depth) {
|
|
329
|
+
const targets = await detectTargets(dir);
|
|
330
|
+
if (targets.length > 0) projects.push(dir);
|
|
331
|
+
if (depth >= maxDepth) return;
|
|
332
|
+
|
|
333
|
+
let entries;
|
|
334
|
+
try {
|
|
335
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
336
|
+
} catch (err) {
|
|
337
|
+
if (err?.code === 'EACCES' || err?.code === 'EPERM') return;
|
|
338
|
+
throw err;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const childDirs = entries
|
|
342
|
+
.filter(entry => !entry.isSymbolicLink() && entry.isDirectory() && !UPDATE_ALL_SKIP_DIRS.has(entry.name))
|
|
343
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
344
|
+
|
|
345
|
+
for (const entry of childDirs) {
|
|
346
|
+
await walk(path.join(dir, entry.name), depth + 1);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
await walk(rootDir, 0);
|
|
351
|
+
return projects;
|
|
238
352
|
}
|
|
239
353
|
|
|
240
354
|
async function listSkills() {
|
|
@@ -264,7 +378,7 @@ function formatSettings(settings) {
|
|
|
264
378
|
return `version: 1
|
|
265
379
|
|
|
266
380
|
defaults:
|
|
267
|
-
# Включает strict-режим по умолчанию для eda-explore, eda-plan и eda-review.
|
|
381
|
+
# Включает strict-режим по умолчанию для eda-explore, eda-plan, eda-review и eda-review-check.
|
|
268
382
|
# true | false
|
|
269
383
|
strict: ${settings.strict ? 'true' : 'false'}
|
|
270
384
|
# Задаёт размер плана по умолчанию для eda-plan.
|
|
@@ -286,7 +400,7 @@ automate:
|
|
|
286
400
|
include_plans: ${settings.includePlans ? 'true' : 'false'}
|
|
287
401
|
|
|
288
402
|
review:
|
|
289
|
-
# Добавляет в eda-review проверку качества кода и meta-reviewer quality-check.
|
|
403
|
+
# Добавляет в eda-review / eda-review-check проверку качества кода и meta-reviewer quality-check.
|
|
290
404
|
# true | false
|
|
291
405
|
include_code_quality: ${settings.includeCodeQuality ? 'true' : 'false'}
|
|
292
406
|
`;
|
|
@@ -347,6 +461,35 @@ function formatSkillCount(count) {
|
|
|
347
461
|
return `${count} ${pluralizeSkill(count)}`;
|
|
348
462
|
}
|
|
349
463
|
|
|
464
|
+
function formatProjectPath(rootDir, projectDir) {
|
|
465
|
+
const relative = path.relative(rootDir, projectDir);
|
|
466
|
+
return relative === '' ? '.' : relative;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function formatProjectCount(count) {
|
|
470
|
+
return `${count} ${pluralizeProject(count)}`;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function pluralizeProject(count) {
|
|
474
|
+
const mod10 = count % 10;
|
|
475
|
+
const mod100 = count % 100;
|
|
476
|
+
if (mod10 === 1 && mod100 !== 11) return 'проект';
|
|
477
|
+
if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) return 'проекта';
|
|
478
|
+
return 'проектов';
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function formatErrorCount(count) {
|
|
482
|
+
return `${count} ${pluralizeError(count)}`;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function pluralizeError(count) {
|
|
486
|
+
const mod10 = count % 10;
|
|
487
|
+
const mod100 = count % 100;
|
|
488
|
+
if (mod10 === 1 && mod100 !== 11) return 'ошибка';
|
|
489
|
+
if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) return 'ошибки';
|
|
490
|
+
return 'ошибок';
|
|
491
|
+
}
|
|
492
|
+
|
|
350
493
|
function pluralizeSkill(count) {
|
|
351
494
|
const mod10 = count % 10;
|
|
352
495
|
const mod100 = count % 100;
|
|
@@ -397,3 +540,12 @@ async function fileExists(p) {
|
|
|
397
540
|
return false;
|
|
398
541
|
}
|
|
399
542
|
}
|
|
543
|
+
|
|
544
|
+
async function statIfExists(p) {
|
|
545
|
+
try {
|
|
546
|
+
return await fs.stat(p);
|
|
547
|
+
} catch (err) {
|
|
548
|
+
if (err?.code !== 'ENOENT') throw err;
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
551
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gian-tiaga/eda",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Набор скилов eda-* для Claude Code и Codex CLI: roadmap, explore, plan, execute, fix, review, fix-by-review, send-review, commit, worktree, merge-worktree, docs, automate",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Набор скилов eda-* для Claude Code и Codex CLI: start, roadmap, explore, plan, execute, fix, review, review-check, fix-by-review, polish, send-review, commit, worktree, merge-worktree, docs, automate",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"eda": "bin/cli.js"
|