@gian-tiaga/eda 0.5.1 → 0.5.2
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 +3 -3
- package/lib/install.js +43 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ npm install -g @gian-tiaga/eda
|
|
|
19
19
|
eda init
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Установщик покажет чекбоксы: стрелками выбираешь среду, пробелом отмечаешь, Enter продолжает. Можно поставить Claude Code, Codex CLI или обе среды сразу. Если `docs/settings.yaml` ещё нет, установщик также предложит выбрать настройки скилов и создаст этот файл. В конце `eda init` пишет,
|
|
22
|
+
Установщик покажет чекбоксы: стрелками выбираешь среду, пробелом отмечаешь, Enter продолжает. Можно поставить Claude Code, Codex CLI или обе среды сразу. Если `docs/settings.yaml` ещё нет, установщик также предложит выбрать настройки скилов и создаст этот файл. В конце `eda init` пишет, какие скилы реально установлены или изменились.
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -137,7 +137,7 @@ automate может запускаться от review, fix-by-review или fix
|
|
|
137
137
|
|
|
138
138
|
```bash
|
|
139
139
|
eda init # выбрать Claude Code / Codex / обе среды и установить скилы
|
|
140
|
-
eda update # обновить скилы, показать
|
|
140
|
+
eda update # обновить скилы, показать реально изменившиеся и создать docs/settings.yaml, если его ещё нет
|
|
141
141
|
eda --version # показать версию установленного пакета
|
|
142
142
|
eda --help # справка
|
|
143
143
|
```
|
|
@@ -160,7 +160,7 @@ eda update # синхронизировать скилы в текущ
|
|
|
160
160
|
| **Claude Code** | `<project>/.claude/skills/<skill>/SKILL.md` — отдельная папка на каждый скил |
|
|
161
161
|
| **Codex CLI** | `<project>/.codex/skills/<skill>/SKILL.md` — отдельная папка на каждый скил |
|
|
162
162
|
|
|
163
|
-
`eda update` идемпотентно перезаписывает файлы в обеих папках и в конце
|
|
163
|
+
`eda update` идемпотентно перезаписывает файлы в обеих папках и в конце пишет только те скилы, содержимое которых реально изменилось относительно установленной копии. При обновлении старые файлы Codex-формата `<project>/.codex/skills/<skill>.md`, созданные версиями `eda` до этой структуры, удаляются. Если ты хочешь подправить скил локально — лучше копию сделай рядом, а не прямо в `.claude/skills/` или `.codex/skills/`, иначе при следующем `update` твои правки потеряются.
|
|
164
164
|
|
|
165
165
|
`AGENTS.md` (как и любые другие файлы в корне проекта) установщик **не трогает**. Если хочешь, чтобы Codex автоматически подгружал скилы, дай ему знать сам — например, одной строкой в `AGENTS.md`: «следуй инструкциям из `.codex/skills/`».
|
|
166
166
|
|
package/lib/install.js
CHANGED
|
@@ -218,12 +218,22 @@ async function syncSkills(cwd, targets, output = process.stdout, { action = 'upd
|
|
|
218
218
|
}
|
|
219
219
|
output.write(`Скилы для установки: ${skills.map(s => s.name).join(', ')}\n`);
|
|
220
220
|
|
|
221
|
-
|
|
222
|
-
if (targets.includes('
|
|
221
|
+
const changedSkills = new Set();
|
|
222
|
+
if (targets.includes('claude')) {
|
|
223
|
+
const result = await installToClaude(cwd, skills, output);
|
|
224
|
+
for (const skillName of result.changedSkills) changedSkills.add(skillName);
|
|
225
|
+
}
|
|
226
|
+
if (targets.includes('codex')) {
|
|
227
|
+
const result = await installToCodex(cwd, skills, output);
|
|
228
|
+
for (const skillName of result.changedSkills) changedSkills.add(skillName);
|
|
229
|
+
}
|
|
223
230
|
await removeRetiredSkills(cwd, targets);
|
|
224
231
|
|
|
225
232
|
const actionLabel = action === 'install' ? 'Установлено' : 'Обновлено';
|
|
226
|
-
|
|
233
|
+
const changedSkillNames = skills
|
|
234
|
+
.map(skill => skill.name)
|
|
235
|
+
.filter(skillName => changedSkills.has(skillName));
|
|
236
|
+
output.write(formatChangedSkills(actionLabel, changedSkillNames));
|
|
227
237
|
output.write('\nГотово.\n');
|
|
228
238
|
}
|
|
229
239
|
|
|
@@ -285,26 +295,52 @@ review:
|
|
|
285
295
|
async function installToClaude(cwd, skills, output = process.stdout) {
|
|
286
296
|
const dst = path.join(cwd, '.claude/skills');
|
|
287
297
|
await fs.mkdir(dst, { recursive: true });
|
|
298
|
+
const changedSkills = [];
|
|
288
299
|
for (const skill of skills) {
|
|
289
300
|
const skillDir = path.join(dst, skill.name);
|
|
290
301
|
await fs.mkdir(skillDir, { recursive: true });
|
|
291
302
|
const content = await fs.readFile(skill.path, 'utf-8');
|
|
292
|
-
await
|
|
303
|
+
const changed = await writeSkillFile(path.join(skillDir, 'SKILL.md'), content);
|
|
304
|
+
if (changed) changedSkills.push(skill.name);
|
|
293
305
|
}
|
|
294
|
-
output.write(` ✓ Claude Code: ${dst} (${formatSkillCount(
|
|
306
|
+
output.write(` ✓ Claude Code: ${dst} (изменилось ${formatSkillCount(changedSkills.length)})\n`);
|
|
307
|
+
return { changedSkills };
|
|
295
308
|
}
|
|
296
309
|
|
|
297
310
|
async function installToCodex(cwd, skills, output = process.stdout) {
|
|
298
311
|
const dst = path.join(cwd, '.codex/skills');
|
|
299
312
|
await fs.mkdir(dst, { recursive: true });
|
|
313
|
+
const changedSkills = [];
|
|
300
314
|
for (const skill of skills) {
|
|
301
315
|
const skillDir = path.join(dst, skill.name);
|
|
302
316
|
await fs.mkdir(skillDir, { recursive: true });
|
|
303
317
|
const content = await fs.readFile(skill.path, 'utf-8');
|
|
304
|
-
await
|
|
318
|
+
const changed = await writeSkillFile(path.join(skillDir, 'SKILL.md'), content);
|
|
319
|
+
if (changed) changedSkills.push(skill.name);
|
|
305
320
|
await removeObsoleteCodexFile(dst, skill.name);
|
|
306
321
|
}
|
|
307
|
-
output.write(` ✓ Codex CLI: ${dst} (${formatSkillCount(
|
|
322
|
+
output.write(` ✓ Codex CLI: ${dst} (изменилось ${formatSkillCount(changedSkills.length)})\n`);
|
|
323
|
+
return { changedSkills };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async function writeSkillFile(filePath, content) {
|
|
327
|
+
const previousContent = await readFileIfExists(filePath);
|
|
328
|
+
await fs.writeFile(filePath, content);
|
|
329
|
+
return previousContent !== content;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async function readFileIfExists(filePath) {
|
|
333
|
+
try {
|
|
334
|
+
return await fs.readFile(filePath, 'utf-8');
|
|
335
|
+
} catch (err) {
|
|
336
|
+
if (err?.code !== 'ENOENT') throw err;
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function formatChangedSkills(actionLabel, skillNames) {
|
|
342
|
+
if (skillNames.length === 0) return `${actionLabel} 0 скилов.\n`;
|
|
343
|
+
return `${actionLabel} ${formatSkillCount(skillNames.length)}: ${skillNames.join(', ')}.\n`;
|
|
308
344
|
}
|
|
309
345
|
|
|
310
346
|
function formatSkillCount(count) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gian-tiaga/eda",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Набор скилов eda-* для Claude Code и Codex CLI: roadmap, explore, plan, execute, fix, review, fix-by-review, send-review, commit, docs, automate",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|