@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 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 # обновить скилы, показать их количество и создать docs/settings.yaml, если его ещё нет
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` идемпотентно перезаписывает файлы в обеих папках и в конце пишет, сколько скилов обновлено. При обновлении старые файлы Codex-формата `<project>/.codex/skills/<skill>.md`, созданные версиями `eda` до этой структуры, удаляются. Если ты хочешь подправить скил локально — лучше копию сделай рядом, а не прямо в `.claude/skills/` или `.codex/skills/`, иначе при следующем `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
- if (targets.includes('claude')) await installToClaude(cwd, skills, output);
222
- if (targets.includes('codex')) await installToCodex(cwd, skills, output);
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
- output.write(`${actionLabel} ${formatSkillCount(skills.length)}.\n`);
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 fs.writeFile(path.join(skillDir, 'SKILL.md'), content);
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(skills.length)})\n`);
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 fs.writeFile(path.join(skillDir, 'SKILL.md'), content);
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(skills.length)})\n`);
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.1",
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": {