@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 +4 -3
- package/lib/install.js +51 -7
- package/package.json +1 -1
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
|
|
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` больше не
|
|
84
|
-
- **У `eda-polish` больше нет порога.** Цикл завершается только при нуле находок и останавливается досрочно, если за круг число открытых находок не сократилось.
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|