@gian-tiaga/eda 0.6.2 → 0.7.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 +35 -12
- 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 +147 -0
- package/skills/eda-review.md +28 -108
- package/skills/eda-roadmap.md +3 -23
- package/skills/eda-send-review.md +2 -10
- 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,6 +21,14 @@ 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
|
## 🛠️ Скилы
|
|
@@ -32,14 +40,16 @@ eda init
|
|
|
32
40
|
| `eda-plan` | Пишет план реализации через стандартный Plan Mode хост-агента. `docs/rules.md` и `docs/arch.md` использует как обязательную рамку, а не справочный контекст: план должен строго следовать правилам и архитектуре. В плане явно фиксирует контракты БД/API, если задача их затрагивает. Затем три параллельных субагента/модели (слабая, средняя, мощная) проверяют план на реалистичность, пропущенные шаги и нарушения правил — главный планировщик сам решает, что применить | `docs/plans/` |
|
|
33
41
|
| `eda-execute` | Выполняет план. Спрашивает, где работать (текущая ветка, новая ветка, отдельный worktree). Перед правками читает план, `docs/rules.md` и `docs/arch.md`; правила и архитектура обязательны к исполнению. Если шаг плана им противоречит, останавливается и спрашивает. Тесты пишет внутри каждого шага. В конце — полный прогон тестов и линтеров | `docs/executions/` |
|
|
34
42
|
| `eda-fix` | Делает обычные фиксы по короткому контексту, баг-репорту или файлу плана. Перед правками читает правила и архитектуру, добавляет нужные тесты, прогоняет проверки и сохраняет историю правок | `docs/fixes/` |
|
|
35
|
-
| `eda-review` | Делает код-ревью с оценкой 0–100 и сверкой с планом работ, но в файл пишет только проблемы: ошибки, недоделки, неточности, нарушения правил/архитектуры, риски и недостающие тесты. Не перечисляет выполненную работу.
|
|
43
|
+
| `eda-review` | Делает код-ревью с оценкой 0–100 и сверкой с планом работ, но в файл пишет только проблемы: ошибки, недоделки, неточности, нарушения правил/архитектуры, риски и недостающие тесты. Не перечисляет выполненную работу. В обычном режиме после черновика передаёт файл в `eda-review-check`; с флагом `draft` сохраняет только первичное ревью без субагентов | `docs/reviews/` |
|
|
44
|
+
| `eda-review-check` | Проверяет готовое ревью из `docs/reviews/` специализированными субагентами: выполнение плана, архитектуру, правила и при включённой настройке качество кода. В строгом режиме добавляет кросс-ревью между Claude и Codex. Сам применяет подтверждённые замечания к файлу ревью, но не правит код | `docs/reviews/` |
|
|
36
45
|
| `eda-fix-by-review` | Применяет замечания из ревью. Обязательные — сразу. Спорные — спрашивает. В конце ссылается на отчёт прямо в файле ревью | `docs/review-fixes/` |
|
|
46
|
+
| `eda-polish` | Оркестрирует доводку изменений: запускает `eda-review draft`, затем `eda-review-check`, затем `eda-fix-by-review apply-optional` и повторяет цикл до оценки 95/100 или лимита 5 итераций. Каждый шаг идёт в изолированном субагенте или отдельном CLI-процессе. Не коммитит | `docs/reviews/`, `docs/review-fixes/` |
|
|
37
47
|
| `eda-send-review` | Отправляет ревью на GitHub PR через `gh` — как комментарий, review, approve или request-changes. Сам определяет PR по текущей ветке | (комментарий в PR) |
|
|
38
48
|
| `eda-commit` | Делает один аккуратный коммит в стиле проекта. В конце спрашивает: push, merge в main + удалить ветку, или ничего | (git) |
|
|
39
49
|
| `eda-worktree` | Создаёт git worktree рядом с основным проектом в папке `{name}-work-{n}` и одноимённую ветку. Базу берёт из аргумента или спрашивает | соседняя папка `{name}-work-{n}` |
|
|
40
50
|
| `eda-merge-worktree` | Мержит ветку из соседнего worktree в текущую ветку. Принимает номер `1`, короткое имя `work-1` или полное имя `{name}-work-1`. Worktree и ветку после merge не удаляет | (git) |
|
|
41
51
|
| `eda-docs` | Создаёт или обновляет `docs/rules.md` (максимально строгие правила для твоего стека), `docs/arch.md` (архитектура проекта) и шапку `AGENTS.md`. Может предлагать инструменты, которых ещё нет в проекте | `docs/rules.md`, `docs/arch.md`, `AGENTS.md` |
|
|
42
|
-
| `eda-automate` | Анализирует историю ревью и фиксов. Если
|
|
52
|
+
| `eda-automate` | Анализирует историю ревью и фиксов. Если ошибка повторяется — предлагает автоматизации на уровне языка и тулчейна: линтеры, статанализаторы, typecheck, тесты, pre-commit/CI-проверки. Если кодовая проверка не подходит, может предложить MCP-сервер, агентную проверку, новый скил или уточнение правил/архитектуры | `docs/automations/` |
|
|
43
53
|
|
|
44
54
|
---
|
|
45
55
|
|
|
@@ -53,7 +63,10 @@ eda init
|
|
|
53
63
|
|---|---|---|---|
|
|
54
64
|
| `eda-explore` | `strict` | После сохранения отчёта отдаёт его соседнему CLI (Claude → Codex или наоборот) на критическое ревью конкретности, фактов, развилок, рисков и версий; затем доправляет отчёт по замечаниям | Серьёзные исследования, которые лягут в основу больших решений; когда хочется второго мнения от другой модели/среды |
|
|
55
65
|
| `eda-plan` | `strict` | После обычного мета-ревью трёх субагентов/моделей отдаёт план соседнему CLI на дополнительный круг проверки; доправляет план | Большие или ответственные планы, особенно затрагивающие смежные системы |
|
|
56
|
-
| `eda-review` | `
|
|
66
|
+
| `eda-review` | `draft` | Сохраняет первичное ревью со статусом `draft` и не запускает `eda-review-check`, субагентов и кросс-CLI | Когда ревью нужно как черновик для внешней оркестрации, например `eda-polish` |
|
|
67
|
+
| `eda-review` | `strict` | После draft-ревью запускает `eda-review-check strict`: специализированные субагенты плюс соседний CLI; доправляет ревью по подтверждённым замечаниям | Ревью важных PR; когда нужен максимальный охват |
|
|
68
|
+
| `eda-review-check` | `strict` | Проверяет уже готовое ревью специализированными субагентами и затем отдаёт его соседнему CLI на дополнительный круг проверки | Когда черновик ревью уже есть и нужно усилить только проверку ревью |
|
|
69
|
+
| `eda-fix-by-review` | `apply-optional` | Применяет не только обязательные, но и пункты «на усмотрение автора» без дополнительного вопроса | Для заранее согласованной автоматической доводки, прежде всего внутри `eda-polish` |
|
|
57
70
|
|
|
58
71
|
---
|
|
59
72
|
|
|
@@ -67,7 +80,7 @@ eda init
|
|
|
67
80
|
version: 1
|
|
68
81
|
|
|
69
82
|
defaults:
|
|
70
|
-
# Включает strict-режим по умолчанию для eda-explore, eda-plan и eda-review.
|
|
83
|
+
# Включает strict-режим по умолчанию для eda-explore, eda-plan, eda-review и eda-review-check.
|
|
71
84
|
# true | false
|
|
72
85
|
strict: false
|
|
73
86
|
# Задаёт размер плана по умолчанию для eda-plan.
|
|
@@ -89,21 +102,21 @@ automate:
|
|
|
89
102
|
include_plans: false
|
|
90
103
|
|
|
91
104
|
review:
|
|
92
|
-
# Добавляет в eda-review проверку качества кода и meta-reviewer quality-check.
|
|
105
|
+
# Добавляет в eda-review / eda-review-check проверку качества кода и meta-reviewer quality-check.
|
|
93
106
|
# true | false
|
|
94
107
|
include_code_quality: true
|
|
95
108
|
```
|
|
96
109
|
|
|
97
110
|
Что означают настройки:
|
|
98
|
-
- `defaults.strict` — включает strict-режим по умолчанию для `eda-explore`, `eda-plan` и `eda-review`.
|
|
111
|
+
- `defaults.strict` — включает strict-режим по умолчанию для `eda-explore`, `eda-plan`, `eda-review` и `eda-review-check`.
|
|
99
112
|
- `defaults.plan_size` — размер плана для `eda-plan`: `normal`, `short` или `ask_each_time`.
|
|
100
113
|
- `defaults.decision_mode` — как `eda-explore` ведёт исследовательские развилки, а `eda-plan` принимает существенные решения: `autonomous` выбирает сам, `recommend_and_ask` рекомендует и спрашивает по значимым развилкам, `ask_each_time` спрашивает по каждой развилке, которая влияет на ход работы или итоговый выбор.
|
|
101
114
|
- `defaults.test_strategy` — стратегия тестов для `eda-plan`: `after_each_phase`, `tdd_each_phase`, `end_of_plan` или `ask_each_time`.
|
|
102
115
|
- `defaults.logging_strategy` — стратегия логирования для `eda-plan`: `debug_precise`, `standard` или `ask_each_time`.
|
|
103
116
|
- `automate.include_plans` — добавляет `docs/plans/` в обычный запуск `eda-automate`.
|
|
104
|
-
- `review.include_code_quality` — добавляет в `eda-review` проверку качества кода и отдельного мета-ревьюера `quality-check`.
|
|
117
|
+
- `review.include_code_quality` — добавляет в `eda-review` / `eda-review-check` проверку качества кода и отдельного мета-ревьюера `quality-check`.
|
|
105
118
|
|
|
106
|
-
`eda init` и `eda update` создают `docs/settings.yaml`, только если файла ещё нет. Существующий файл не перезаписывается.
|
|
119
|
+
`eda init` и `eda update` создают `docs/settings.yaml`, только если файла ещё нет. Существующий файл не перезаписывается. `eda update-all` настройки не создаёт и не меняет.
|
|
107
120
|
|
|
108
121
|
---
|
|
109
122
|
|
|
@@ -113,11 +126,13 @@ review:
|
|
|
113
126
|
docs ───────────────┬───────────────┐
|
|
114
127
|
│ │
|
|
115
128
|
v v
|
|
116
|
-
roadmap ────────> explore ─────> plan ───> execute ───┬──> review ───> fix-by-review ───┬──> send-review
|
|
129
|
+
roadmap ────────> explore ─────> plan ───> execute ───┬──> review ───> review-check ───> fix-by-review ───┬──> send-review
|
|
117
130
|
│ │ │
|
|
118
131
|
└──────────────> plan v └──> commit
|
|
119
132
|
fix ─────────────> review
|
|
120
133
|
|
|
134
|
+
polish = review draft ─> review-check ─> fix-by-review apply-optional ─> повтор до нужной оценки
|
|
135
|
+
|
|
121
136
|
automate может запускаться от review, fix-by-review или fix.
|
|
122
137
|
```
|
|
123
138
|
|
|
@@ -129,7 +144,7 @@ automate может запускаться от review, fix-by-review или fix
|
|
|
129
144
|
|
|
130
145
|
- **Простой язык.** Скилы общаются с тобой так, чтобы понял человек без глубоких знаний предмета. Термины — только когда без них нельзя.
|
|
131
146
|
- **Все вопросы — интерактивно.** В Claude Code — через `AskUserQuestion`; в интерактивном Codex — через `request_user_input` или блокирующий вопрос в чат. В `codex exec` и других неинтерактивных запусках скил не имитирует диалог: если без ответа нельзя безопасно продолжать, он завершает работу со статусом `blocked: нужен ответ пользователя`.
|
|
132
|
-
- **Мета-проверки — через субагентов.** В интерактивном Codex обычные проверки планов и ревью запускаются через `spawn_agent` или аналогичный инструмент субагентов. Отдельный `codex exec` остаётся fallback для неинтерактивного режима и механизмом strict-кросс-проверки соседним CLI.
|
|
147
|
+
- **Мета-проверки — через субагентов.** В интерактивном Codex обычные проверки планов и ревью запускаются через `spawn_agent` или аналогичный инструмент субагентов. Проверки готового ревью собраны в `eda-review-check`. Отдельный `codex exec` остаётся fallback для неинтерактивного режима и механизмом strict-кросс-проверки соседним CLI.
|
|
133
148
|
- **Артефакты по папкам.** Исследования отдельно, планы отдельно, ревью отдельно. Между файлами — ссылки. Через месяц легко найти, кто что когда решал.
|
|
134
149
|
- **Границы между скилами жёсткие.** `execute` не коммитит — это работа `commit`. `review` не правит код — это `fix-by-review`. Никаких размытых ответственностей.
|
|
135
150
|
- **Доверие модели.** Скилы короткие. Они говорят «что» и «почему», а «как именно» — модель разбирается сама.
|
|
@@ -141,6 +156,7 @@ automate может запускаться от review, fix-by-review или fix
|
|
|
141
156
|
```bash
|
|
142
157
|
eda init # выбрать Claude Code / Codex / обе среды и установить скилы
|
|
143
158
|
eda update # обновить скилы, показать реально изменившиеся и создать docs/settings.yaml, если его ещё нет
|
|
159
|
+
eda update-all [dir] # обновить скилы во всех найденных проектах внутри dir на глубине 2
|
|
144
160
|
eda --version # показать версию установленного пакета
|
|
145
161
|
eda --help # справка
|
|
146
162
|
```
|
|
@@ -152,6 +168,13 @@ npm update -g @gian-tiaga/eda # подтянуть новый код
|
|
|
152
168
|
eda update # синхронизировать скилы в текущем проекте
|
|
153
169
|
```
|
|
154
170
|
|
|
171
|
+
Для папки с несколькими проектами:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm update -g @gian-tiaga/eda
|
|
175
|
+
eda update-all ~/Code
|
|
176
|
+
```
|
|
177
|
+
|
|
155
178
|
---
|
|
156
179
|
|
|
157
180
|
## 📁 Куда устанавливаются скилы
|
|
@@ -163,7 +186,7 @@ eda update # синхронизировать скилы в текущ
|
|
|
163
186
|
| **Claude Code** | `<project>/.claude/skills/<skill>/SKILL.md` — отдельная папка на каждый скил |
|
|
164
187
|
| **Codex CLI** | `<project>/.codex/skills/<skill>/SKILL.md` — отдельная папка на каждый скил |
|
|
165
188
|
|
|
166
|
-
`eda update` идемпотентно перезаписывает файлы в обеих папках и в конце пишет только те скилы, содержимое которых реально изменилось относительно установленной копии. При обновлении старые файлы Codex-формата `<project>/.codex/skills/<skill>.md`, созданные версиями `eda` до этой структуры, удаляются. Если ты хочешь подправить скил локально — лучше копию сделай рядом, а не прямо в `.claude/skills/` или `.codex/skills/`, иначе при следующем `update` твои правки потеряются.
|
|
189
|
+
`eda update` идемпотентно перезаписывает файлы в обеих папках и в конце пишет только те скилы, содержимое которых реально изменилось относительно установленной копии. `eda update-all [dir]` делает то же самое для каждого найденного проекта внутри `dir`, но не создаёт `docs/settings.yaml`. При обновлении старые файлы Codex-формата `<project>/.codex/skills/<skill>.md`, созданные версиями `eda` до этой структуры, удаляются. Если ты хочешь подправить скил локально — лучше копию сделай рядом, а не прямо в `.claude/skills/` или `.codex/skills/`, иначе при следующем `update` твои правки потеряются.
|
|
167
190
|
|
|
168
191
|
`AGENTS.md` (как и любые другие файлы в корне проекта) установщик **не трогает**. Если хочешь, чтобы Codex автоматически подгружал скилы, дай ему знать сам — например, одной строкой в `AGENTS.md`: «следуй инструкциям из `.codex/skills/`».
|
|
169
192
|
|
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.7.0",
|
|
4
|
+
"description": "Набор скилов eda-* для Claude Code и Codex CLI: 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"
|