@gian-tiaga/eda 3.1.0 → 3.1.1

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/MIGRATION.md CHANGED
@@ -71,7 +71,7 @@ docs/
71
71
 
72
72
  Версия npm-пакета и версия схемы настроек независимы: в eda 3.1 актуальным остаётся `docs/settings.yaml` с `version: 3`.
73
73
 
74
- Установщик по-прежнему сохраняет полный валидный v3 байт-в-байт. Старый, неизвестный или неполный YAML нормализуется: известные валидные значения переносятся, а отсутствующие спрашиваются в TTY или получают defaults без TTY.
74
+ Установщик по-прежнему сохраняет полный валидный v3 байт-в-байт — кроме случая, когда в файле остались устаревшие ключи: тогда он перезаписывает файл без вопросов и печатает, что именно убрал. Старый, неизвестный или неполный YAML нормализуется: известные валидные значения переносятся, а отсутствующие спрашиваются в TTY или получают defaults без TTY.
75
75
 
76
76
  В `eda update-all` режим `configure` один раз спрашивает общий профиль v3 и записывает его во все проекты. Режим `skip` сохраняет полный v3, индивидуально переносит остальные конфиги и создаёт defaults только при отсутствии файла.
77
77
 
@@ -80,8 +80,8 @@ docs/
80
80
  Что в 3.1 изменится в уже настроенном проекте:
81
81
 
82
82
  - **Удалены двенадцать агентов `eda-plan-review-*`.** Проверку плана целиком выполняет один субагент по фиксированному чек-листу. `eda update` стирает файлы этих агентов из `.claude/agents/` и `.codex/agents/`.
83
- - **Секция `plan-review.agents` больше не читается** и при нормализации настроек отбрасывается. Дефолт `plan-review.threshold` — `100`, `plan-polish.limit` — `2`.
84
- - **У `eda-polish` больше нет порога.** Цикл завершается только при нуле находок и останавливается досрочно, если за круг число открытых находок не сократилось. Существующий валидный `docs/settings.yaml` установщик не переписывает, поэтому аргумент вида `args: "threshold 90 limit 2"` в шаге оркестратора останется в файле и будет игнорироваться — убери из него `threshold N` вручную.
83
+ - **Секция `plan-review.agents` больше не читается.** Начиная с 3.1.1 `eda update` находит её в готовом файле настроек и убирает вместе с другими устаревшими ключами — `review-check`, `review.strict`, `review.include_code_quality`. Дефолт `plan-review.threshold` — `100`, `plan-polish.limit` — `2`.
84
+ - **У `eda-polish` больше нет порога.** Цикл завершается только при нуле находок и останавливается досрочно, если за круг число открытых находок не сократилось. Аргумент вида `args: "threshold 90 limit 2"` в шаге оркестратора `eda update` приводит к виду `args: "limit 2"`.
85
85
  - **Формат ревью дополнен.** У каждой находки появилось поле `repro` — чем проблема воспроизводится, — а в отчёт добавлен раздел «Отклонено» с причинами отклонения. `eda-fix-by-review` может отклонить находку, но только фактически неверную и с обоснованием в отчёте. Старые файлы ревью читаются как есть.
86
86
 
87
87
  ## Проверка миграции
@@ -92,6 +92,7 @@ docs/
92
92
  - `docs/business.md`, `docs/business/`, `docs/references.md`, `docs/references/`, `docs/arch.md` и `docs/rules.md` остались на месте;
93
93
  - `docs/settings.yaml` содержит `version: 3`;
94
94
  - `eda --version` выводит версию `3.1.x`;
95
+ - в `docs/settings.yaml` нет секции `plan-review.agents` и аргумента `threshold N` у шага `eda-polish`;
95
96
  - в `.claude/agents/` и `.codex/agents/` не осталось файлов `eda-plan-review-*`;
96
97
  - в `.claude/` или `.codex/` установлены обновлённые скилы и агенты.
97
98
 
package/lib/install.js CHANGED
@@ -64,6 +64,12 @@ const RETIRED_AGENTS = [
64
64
  'eda-plan-review-performance',
65
65
  'eda-plan-review-previous'
66
66
  ];
67
+ const RETIRED_SETTINGS_PATHS = [
68
+ 'plan-review.agents',
69
+ 'review-check',
70
+ 'review.strict',
71
+ 'review.include_code_quality'
72
+ ];
67
73
  const MANIFEST_FILE = 'eda-manifest.json';
68
74
  const SETTINGS_VERSION = 3;
69
75
  const REVIEW_AGENT_DEFINITIONS = [
@@ -536,11 +542,13 @@ export async function updateAll({
536
542
  if (resolvedSettingsMode === 'skip' && await fileExists(projectSettingsPath)) {
537
543
  const existingContent = await fs.readFile(projectSettingsPath, 'utf8');
538
544
  const migrated = migrateSettingsContent(existingContent);
539
- if (migrated.version === SETTINGS_VERSION && migrated.missingKeys.size === 0) {
545
+ if (migrated.version === SETTINGS_VERSION && migrated.missingKeys.size === 0 && migrated.retiredPaths.length === 0) {
540
546
  output.write(`Полный файл настроек сохранён: ${SETTINGS_RELATIVE_PATH}\n`);
541
547
  } else {
542
548
  await writeSettingsContent(projectDir, formatSettings(migrated.settings));
543
- output.write(`Старый или неполный файл настроек перенесён на version: ${SETTINGS_VERSION}: ${SETTINGS_RELATIVE_PATH}\n`);
549
+ output.write(migrated.retiredPaths.length > 0
550
+ ? `Из файла настроек убраны устаревшие ключи (${migrated.retiredPaths.join(', ')}): ${SETTINGS_RELATIVE_PATH}\n`
551
+ : `Старый или неполный файл настроек перенесён на version: ${SETTINGS_VERSION}: ${SETTINGS_RELATIVE_PATH}\n`);
544
552
  }
545
553
  } else {
546
554
  await writeSettingsContent(projectDir, sharedSettingsContent);
@@ -1000,12 +1008,18 @@ async function ensureSettings(cwd, { input = process.stdin, output = process.std
1000
1008
  }
1001
1009
 
1002
1010
  const migrated = migrateSettingsContent(existingContent);
1003
- if (migrated.version === SETTINGS_VERSION && migrated.missingKeys.size === 0) {
1011
+ const needsMigration = migrated.version !== SETTINGS_VERSION || migrated.missingKeys.size > 0;
1012
+ if (!needsMigration && migrated.retiredPaths.length === 0) {
1004
1013
  output.write(`Настройки уже есть: ${SETTINGS_RELATIVE_PATH}\n`);
1005
1014
  return;
1006
1015
  }
1007
1016
 
1008
- output.write(`Переношу ${SETTINGS_RELATIVE_PATH} на version: ${SETTINGS_VERSION}; спрашиваются только отсутствующие значения.\n`);
1017
+ if (migrated.retiredPaths.length > 0) {
1018
+ output.write(`Убираю устаревшие настройки: ${migrated.retiredPaths.join(', ')}.\n`);
1019
+ }
1020
+ if (needsMigration) {
1021
+ output.write(`Переношу ${SETTINGS_RELATIVE_PATH} на version: ${SETTINGS_VERSION}; спрашиваются только отсутствующие значения.\n`);
1022
+ }
1009
1023
  const settings = await askSettings({
1010
1024
  input,
1011
1025
  output,
@@ -1028,12 +1042,18 @@ async function configureSettings(cwd, { input = process.stdin, output = process.
1028
1042
  }
1029
1043
 
1030
1044
  const migrated = migrateSettingsContent(existingContent);
1031
- if (migrated.version === SETTINGS_VERSION && migrated.missingKeys.size === 0) {
1045
+ const needsMigration = migrated.version !== SETTINGS_VERSION || migrated.missingKeys.size > 0;
1046
+ if (!needsMigration && migrated.retiredPaths.length === 0) {
1032
1047
  output.write(`Настройки ${SETTINGS_RELATIVE_PATH} версии ${SETTINGS_VERSION} полные — вопросы не требуются.\n`);
1033
1048
  return;
1034
1049
  }
1035
1050
 
1036
- output.write(`Переношу ${SETTINGS_RELATIVE_PATH} на version: ${SETTINGS_VERSION}; спрашиваются только отсутствующие значения.\n`);
1051
+ if (migrated.retiredPaths.length > 0) {
1052
+ output.write(`Убираю устаревшие настройки: ${migrated.retiredPaths.join(', ')}.\n`);
1053
+ }
1054
+ if (needsMigration) {
1055
+ output.write(`Переношу ${SETTINGS_RELATIVE_PATH} на version: ${SETTINGS_VERSION}; спрашиваются только отсутствующие значения.\n`);
1056
+ }
1037
1057
  const settings = await askSettings({
1038
1058
  input,
1039
1059
  output,
@@ -1159,6 +1179,7 @@ function migrateSettingsContent(content) {
1159
1179
  return {
1160
1180
  settings,
1161
1181
  missingKeys,
1182
+ retiredPaths: findRetiredSettingsPaths(raw),
1162
1183
  version: Number.isInteger(raw.version) ? raw.version : null
1163
1184
  };
1164
1185
  }
@@ -1179,6 +1200,12 @@ function transferAgentSettings({ rawAgents, settingsAgents, definitions, prefix,
1179
1200
  }
1180
1201
  }
1181
1202
 
1203
+ // У eda-polish больше нет порога: цикл завершается по нулю находок.
1204
+ function stripRetiredStepArgs(skill, args) {
1205
+ if (skill !== 'eda-polish') return args;
1206
+ return args.replace(/\bthreshold\s+\d+\s*/gi, '').replace(/\s+/g, ' ').trim();
1207
+ }
1208
+
1182
1209
  function normalizeStoredOrhestraSteps(value) {
1183
1210
  if (!Array.isArray(value) || value.length === 0) return null;
1184
1211
  const steps = [];
@@ -1192,7 +1219,7 @@ function normalizeStoredOrhestraSteps(value) {
1192
1219
  id: step.id,
1193
1220
  skill: step.skill,
1194
1221
  enabled: step.enabled !== false,
1195
- args: step.args ?? ''
1222
+ args: stripRetiredStepArgs(step.skill, step.args ?? '')
1196
1223
  };
1197
1224
  const onFailure = objectValue(step.on_failure);
1198
1225
  if (Object.keys(onFailure).length > 0) {
@@ -1216,6 +1243,23 @@ function objectValue(value) {
1216
1243
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
1217
1244
  }
1218
1245
 
1246
+ function findRetiredSettingsPaths(raw) {
1247
+ const found = [];
1248
+ for (const settingPath of RETIRED_SETTINGS_PATHS) {
1249
+ let current = raw;
1250
+ let present = true;
1251
+ for (const segment of settingPath.split('.')) {
1252
+ if (!current || typeof current !== 'object' || Array.isArray(current) || !(segment in current)) {
1253
+ present = false;
1254
+ break;
1255
+ }
1256
+ current = current[segment];
1257
+ }
1258
+ if (present && current !== undefined) found.push(settingPath);
1259
+ }
1260
+ return found;
1261
+ }
1262
+
1219
1263
  async function writeFileAtomically(filePath, content) {
1220
1264
  const currentStat = await fs.stat(filePath);
1221
1265
  const tempPath = path.join(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gian-tiaga/eda",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Пакет скилов и специализированных агентов eda-* для Claude Code и Codex CLI",
5
5
  "type": "module",
6
6
  "bin": {