@gian-tiaga/eda 2.0.0 → 3.1.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.
Files changed (64) hide show
  1. package/MIGRATION.md +68 -67
  2. package/README.md +44 -86
  3. package/agents/eda-aim-planner/prompt.md +1 -1
  4. package/agents/eda-review-api/prompt.md +5 -3
  5. package/agents/eda-review-architecture/prompt.md +6 -4
  6. package/agents/eda-review-business/prompt.md +5 -3
  7. package/agents/eda-review-code-quality/prompt.md +7 -5
  8. package/agents/eda-review-correctness/prompt.md +5 -3
  9. package/agents/eda-review-database/prompt.md +5 -3
  10. package/agents/eda-review-documentation/prompt.md +5 -3
  11. package/agents/eda-review-frontend/prompt.md +5 -3
  12. package/agents/eda-review-performance/prompt.md +7 -5
  13. package/agents/eda-review-plan-alignment/prompt.md +5 -3
  14. package/agents/eda-review-previous-reviews/prompt.md +6 -4
  15. package/agents/eda-review-references/prompt.md +5 -3
  16. package/agents/eda-review-rules/prompt.md +5 -3
  17. package/agents/eda-review-security/prompt.md +5 -3
  18. package/agents/eda-review-tests/prompt.md +5 -3
  19. package/bin/cli.js +2 -2
  20. package/lib/install.js +124 -160
  21. package/package.json +1 -1
  22. package/skills/eda-aim/SKILL.md +2 -2
  23. package/skills/eda-business/SKILL.md +47 -32
  24. package/skills/eda-discover-automations/SKILL.md +9 -9
  25. package/skills/eda-explore/SKILL.md +3 -3
  26. package/skills/eda-fix/SKILL.md +6 -6
  27. package/skills/eda-fix-by-review/SKILL.md +47 -58
  28. package/skills/eda-manual-test/SKILL.md +5 -5
  29. package/skills/eda-new-project/SKILL.md +3 -3
  30. package/skills/eda-orhestra/SKILL.md +2 -2
  31. package/skills/eda-plan/SKILL.md +92 -111
  32. package/skills/eda-plan-execute/SKILL.md +43 -68
  33. package/skills/eda-plan-polish/SKILL.md +51 -42
  34. package/skills/eda-plan-review/SKILL.md +89 -135
  35. package/skills/eda-plan-review-fix/SKILL.md +38 -63
  36. package/skills/eda-polish/SKILL.md +25 -35
  37. package/skills/eda-prepare-ai/SKILL.md +1 -1
  38. package/skills/eda-review/SKILL.md +18 -17
  39. package/skills/eda-roadmap/SKILL.md +5 -5
  40. package/skills/eda-send-review/SKILL.md +11 -11
  41. package/agents/eda-plan-review-api/agent.json +0 -9
  42. package/agents/eda-plan-review-api/prompt.md +0 -34
  43. package/agents/eda-plan-review-architecture/agent.json +0 -9
  44. package/agents/eda-plan-review-architecture/prompt.md +0 -34
  45. package/agents/eda-plan-review-database/agent.json +0 -9
  46. package/agents/eda-plan-review-database/prompt.md +0 -34
  47. package/agents/eda-plan-review-execution/agent.json +0 -9
  48. package/agents/eda-plan-review-execution/prompt.md +0 -34
  49. package/agents/eda-plan-review-feasibility/agent.json +0 -9
  50. package/agents/eda-plan-review-feasibility/prompt.md +0 -34
  51. package/agents/eda-plan-review-frontend/agent.json +0 -9
  52. package/agents/eda-plan-review-frontend/prompt.md +0 -34
  53. package/agents/eda-plan-review-performance/agent.json +0 -9
  54. package/agents/eda-plan-review-performance/prompt.md +0 -34
  55. package/agents/eda-plan-review-previous/agent.json +0 -9
  56. package/agents/eda-plan-review-previous/prompt.md +0 -28
  57. package/agents/eda-plan-review-requirements/agent.json +0 -9
  58. package/agents/eda-plan-review-requirements/prompt.md +0 -34
  59. package/agents/eda-plan-review-rules/agent.json +0 -9
  60. package/agents/eda-plan-review-rules/prompt.md +0 -34
  61. package/agents/eda-plan-review-security/agent.json +0 -9
  62. package/agents/eda-plan-review-security/prompt.md +0 -34
  63. package/agents/eda-plan-review-verification/agent.json +0 -9
  64. package/agents/eda-plan-review-verification/prompt.md +0 -34
package/lib/install.js CHANGED
@@ -19,6 +19,22 @@ const SKILLS_SRC = path.join(PACKAGE_ROOT, 'skills');
19
19
  const AGENTS_SRC = path.join(PACKAGE_ROOT, 'agents');
20
20
  const PACKAGE_JSON_PATH = path.join(PACKAGE_ROOT, 'package.json');
21
21
  const SETTINGS_RELATIVE_PATH = 'docs/settings.yaml';
22
+ const ARTIFACTS_RELATIVE_PATH = 'docs/artifacts';
23
+ const ARTIFACT_DIRECTORY_NAMES = [
24
+ 'aims',
25
+ 'automations',
26
+ 'executions',
27
+ 'fixes',
28
+ 'manual-tests',
29
+ 'plan-review-fixes',
30
+ 'plan-reviews',
31
+ 'plans',
32
+ 'project-starts',
33
+ 'researches',
34
+ 'review-fixes',
35
+ 'reviews',
36
+ 'roadmaps'
37
+ ];
22
38
  const TARGET_CHOICES = [
23
39
  { value: 'claude', label: 'Claude Code', dir: '.claude/skills/' },
24
40
  { value: 'codex', label: 'Codex CLI', dir: '.codex/skills/' }
@@ -34,7 +50,19 @@ const RETIRED_SKILLS = [
34
50
  'eda-start'
35
51
  ];
36
52
  const RETIRED_AGENTS = [
37
- 'eda-commit-context'
53
+ 'eda-commit-context',
54
+ 'eda-plan-review-requirements',
55
+ 'eda-plan-review-rules',
56
+ 'eda-plan-review-architecture',
57
+ 'eda-plan-review-feasibility',
58
+ 'eda-plan-review-execution',
59
+ 'eda-plan-review-verification',
60
+ 'eda-plan-review-api',
61
+ 'eda-plan-review-database',
62
+ 'eda-plan-review-security',
63
+ 'eda-plan-review-frontend',
64
+ 'eda-plan-review-performance',
65
+ 'eda-plan-review-previous'
38
66
  ];
39
67
  const MANIFEST_FILE = 'eda-manifest.json';
40
68
  const SETTINGS_VERSION = 3;
@@ -170,114 +198,6 @@ const DEFAULT_REVIEW_AGENTS = Object.fromEntries(REVIEW_AGENT_DEFINITIONS.map(ag
170
198
  }
171
199
  }
172
200
  ]));
173
- const PLAN_REVIEW_AGENT_DEFINITIONS = [
174
- {
175
- key: 'requirements',
176
- description: 'Проверяет соответствие плана задаче, scope, критериям готовности и применимым business-требованиям.',
177
- auto: 'Эта базовая проверка по умолчанию запускается всегда.',
178
- mode: 'always',
179
- claude: 'sonnet',
180
- codex: 'gpt-5.6-terra'
181
- },
182
- {
183
- key: 'rules',
184
- description: 'Проверяет соблюдение AGENTS.md, CLAUDE.md и docs/rules.md.',
185
- auto: 'Эта базовая проверка по умолчанию запускается всегда.',
186
- mode: 'always',
187
- claude: 'haiku',
188
- codex: 'gpt-5.6-luna'
189
- },
190
- {
191
- key: 'architecture',
192
- description: 'Проверяет архитектурные границы, зависимости и соответствие docs/arch.md.',
193
- auto: 'Эта базовая проверка по умолчанию запускается всегда.',
194
- mode: 'always',
195
- claude: 'opus',
196
- codex: 'gpt-5.6-sol'
197
- },
198
- {
199
- key: 'feasibility',
200
- description: 'Проверяет реализуемость плана относительно фактического кода и отсутствие скрытого исследования.',
201
- auto: 'Эта базовая проверка по умолчанию запускается всегда.',
202
- mode: 'always',
203
- claude: 'opus',
204
- codex: 'gpt-5.6-sol'
205
- },
206
- {
207
- key: 'execution',
208
- description: 'Проверяет связность фаз, ID задач, зависимости и размер работы для одного исполнителя.',
209
- auto: 'Эта базовая проверка по умолчанию запускается всегда.',
210
- mode: 'always',
211
- claude: 'sonnet',
212
- codex: 'gpt-5.6-terra'
213
- },
214
- {
215
- key: 'verification',
216
- description: 'Проверяет тесты, команды проверок, ошибки, логирование, документацию и эксплуатационную готовность.',
217
- auto: 'Эта базовая проверка по умолчанию запускается всегда.',
218
- mode: 'always',
219
- claude: 'sonnet',
220
- codex: 'gpt-5.6-terra'
221
- },
222
- {
223
- key: 'api',
224
- description: 'Проверяет API, DTO, события, очереди, внешние интеграции и совместимость контрактов.',
225
- auto: 'В auto запускается при изменении API, событий, очередей или внешних интеграций.',
226
- mode: 'auto',
227
- claude: 'sonnet',
228
- codex: 'gpt-5.6-terra'
229
- },
230
- {
231
- key: 'database',
232
- description: 'Проверяет схему данных, миграции, backfill, индексы, транзакции и rollback.',
233
- auto: 'В auto запускается при изменении хранения, моделей, SQL, схем или миграций.',
234
- mode: 'auto',
235
- claude: 'opus',
236
- codex: 'gpt-5.6-sol'
237
- },
238
- {
239
- key: 'security',
240
- description: 'Проверяет auth, permissions, внешний ввод, секреты, персональные данные и опасные операции.',
241
- auto: 'В auto запускается для auth, permissions, внешнего ввода, секретов и чувствительных данных.',
242
- mode: 'auto',
243
- claude: 'opus',
244
- codex: 'gpt-5.6-sol'
245
- },
246
- {
247
- key: 'frontend',
248
- description: 'Проверяет пользовательский сценарий, состояния UI, ошибки, accessibility и адаптивность.',
249
- auto: 'В auto запускается для компонентов, стилей, клиентских маршрутов и состояния UI.',
250
- mode: 'auto',
251
- claude: 'sonnet',
252
- codex: 'gpt-5.6-terra'
253
- },
254
- {
255
- key: 'performance',
256
- description: 'Проверяет нагрузку, запросы, конкурентность, кеши и горячие пути.',
257
- auto: 'В auto запускается для запросов, пакетной обработки, кешей, конкурентности и горячих путей.',
258
- mode: 'auto',
259
- claude: 'opus',
260
- codex: 'gpt-5.6-sol'
261
- },
262
- {
263
- key: 'previous',
264
- description: 'Проверяет закрытие findings предыдущей связанной итерации plan-review.',
265
- auto: 'В auto запускается только при наличии связанной цепочки review/fix для текущего SHA-256 плана.',
266
- mode: 'auto',
267
- claude: 'haiku',
268
- codex: 'gpt-5.6-luna'
269
- }
270
- ];
271
- const DEFAULT_PLAN_REVIEW_AGENTS = Object.fromEntries(PLAN_REVIEW_AGENT_DEFINITIONS.map(agent => [
272
- agent.key,
273
- {
274
- mode: agent.mode,
275
- model: {
276
- claude: agent.claude,
277
- codex: agent.codex
278
- }
279
- }
280
- ]));
281
201
  const ORHESTRA_STEP_DEFINITIONS = [
282
202
  {
283
203
  id: 'plan',
@@ -343,11 +263,10 @@ const DEFAULT_SETTINGS = {
343
263
  loggingStrategy: 'ask_each_time'
344
264
  },
345
265
  planReview: {
346
- threshold: 95,
347
- agents: DEFAULT_PLAN_REVIEW_AGENTS
266
+ threshold: 100
348
267
  },
349
268
  planPolish: {
350
- limit: 3
269
+ limit: 2
351
270
  },
352
271
  review: {
353
272
  agents: DEFAULT_REVIEW_AGENTS
@@ -431,11 +350,11 @@ const ORHESTRA_POLISH_LIMIT_CHOICES = [1, 2, 3, 5, 10].map(value => ({
431
350
  value,
432
351
  name: `${value} ${value === 1 ? 'итерация' : value < 5 ? 'итерации' : 'итераций'}`
433
352
  }));
434
- const PLAN_REVIEW_THRESHOLD_CHOICES = [90, 95, 100].map(value => ({
353
+ const PLAN_REVIEW_THRESHOLD_CHOICES = [80, 90, 100].map(value => ({
435
354
  value,
436
355
  name: `${value}/100`
437
356
  }));
438
- const PLAN_POLISH_LIMIT_CHOICES = [1, 2, 3, 5, 10].map(value => ({
357
+ const PLAN_POLISH_LIMIT_CHOICES = [1, 2, 3].map(value => ({
439
358
  value,
440
359
  name: `${value} ${value === 1 ? 'итерация' : value < 5 ? 'итерации' : 'итераций'}`
441
360
  }));
@@ -542,6 +461,7 @@ export async function update({ cwd, input = process.stdin, output = process.stdo
542
461
  return;
543
462
  }
544
463
  output.write(`Найдены установленные среды: ${targets.join(', ')}\n`);
464
+ await migrateArtifactDirectories(cwd, output);
545
465
  await configureSettings(cwd, { input, output });
546
466
  await syncPackage(cwd, targets, output, { action: 'update' });
547
467
  }
@@ -611,6 +531,7 @@ export async function updateAll({
611
531
  }
612
532
 
613
533
  output.write(`Найдены установленные среды: ${targets.join(', ')}\n`);
534
+ await migrateArtifactDirectories(projectDir, output);
614
535
  const projectSettingsPath = path.join(projectDir, SETTINGS_RELATIVE_PATH);
615
536
  if (resolvedSettingsMode === 'skip' && await fileExists(projectSettingsPath)) {
616
537
  const existingContent = await fs.readFile(projectSettingsPath, 'utf8');
@@ -793,15 +714,6 @@ export async function askSettings({
793
714
  target[property] = await selectPrompt({ message, choices, default: target[property] }, { input, output });
794
715
  }
795
716
 
796
- if (requestedSections.has('plan-review')) {
797
- settings.planReview.agents = await askPlanReviewAgentSettings({
798
- input,
799
- output,
800
- selectPrompt,
801
- seedAgents: settings.planReview.agents,
802
- missingKeys
803
- });
804
- }
805
717
  if (requestedSections.has('review')) {
806
718
  settings.review.agents = await askReviewAgentSettings({
807
719
  input,
@@ -833,25 +745,6 @@ export async function askReviewAgentSettings({
833
745
  });
834
746
  }
835
747
 
836
- export async function askPlanReviewAgentSettings({
837
- input = process.stdin,
838
- output = process.stdout,
839
- selectPrompt = select,
840
- seedAgents = DEFAULT_PLAN_REVIEW_AGENTS,
841
- missingKeys = null
842
- } = {}) {
843
- return askAgentSettings({
844
- input,
845
- output,
846
- selectPrompt,
847
- definitions: PLAN_REVIEW_AGENT_DEFINITIONS,
848
- seedAgents,
849
- missingKeys,
850
- keyPrefix: 'planReview.agents',
851
- label: 'plan-review'
852
- });
853
- }
854
-
855
748
  async function askAgentSettings({ input, output, selectPrompt, definitions, seedAgents, missingKeys, keyPrefix, label }) {
856
749
  const configuredAgents = structuredClone(seedAgents);
857
750
  const shouldAsk = key => missingKeys === null || missingKeys.has(key);
@@ -1010,6 +903,92 @@ async function findInstalledProjects(rootDir, maxDepth) {
1010
903
  return projects;
1011
904
  }
1012
905
 
906
+ async function migrateArtifactDirectories(cwd, output = process.stdout) {
907
+ const docsDir = path.join(cwd, 'docs');
908
+ const artifactsDir = path.join(cwd, ARTIFACTS_RELATIVE_PATH);
909
+ const legacyDirectories = [];
910
+
911
+ for (const directoryName of ARTIFACT_DIRECTORY_NAMES) {
912
+ const legacyPath = path.join(docsDir, directoryName);
913
+ const legacyStat = await lstatIfExists(legacyPath);
914
+ if (!legacyStat) continue;
915
+ if (!legacyStat.isDirectory() || legacyStat.isSymbolicLink()) {
916
+ throw new Error(`Ожидался каталог артефактов: ${legacyPath}`);
917
+ }
918
+ legacyDirectories.push({ directoryName, legacyPath });
919
+ }
920
+
921
+ if (legacyDirectories.length === 0) {
922
+ return { migratedDirectories: 0, movedFiles: 0, discardedFiles: 0 };
923
+ }
924
+
925
+ const artifactsStat = await lstatIfExists(artifactsDir);
926
+ if (artifactsStat && (!artifactsStat.isDirectory() || artifactsStat.isSymbolicLink())) {
927
+ throw new Error(`Ожидался каталог артефактов: ${artifactsDir}`);
928
+ }
929
+ await fs.mkdir(artifactsDir, { recursive: true });
930
+
931
+ const result = {
932
+ migratedDirectories: legacyDirectories.length,
933
+ movedFiles: 0,
934
+ discardedFiles: 0
935
+ };
936
+ for (const { directoryName, legacyPath } of legacyDirectories) {
937
+ await mergeArtifactEntry(legacyPath, path.join(artifactsDir, directoryName), result);
938
+ }
939
+
940
+ output.write(
941
+ `Артефакты перенесены в ${ARTIFACTS_RELATIVE_PATH}/: каталогов ${result.migratedDirectories}, `
942
+ + `файлов перемещено ${result.movedFiles}, конфликтующих старых файлов удалено ${result.discardedFiles}.\n`
943
+ );
944
+ return result;
945
+ }
946
+
947
+ async function mergeArtifactEntry(sourcePath, destinationPath, result) {
948
+ const sourceStat = await fs.lstat(sourcePath);
949
+ const destinationStat = await lstatIfExists(destinationPath);
950
+
951
+ if (!destinationStat) {
952
+ result.movedFiles += await countArtifactFiles(sourcePath, sourceStat);
953
+ await fs.mkdir(path.dirname(destinationPath), { recursive: true });
954
+ await fs.rename(sourcePath, destinationPath);
955
+ return;
956
+ }
957
+
958
+ const mergeDirectories = sourceStat.isDirectory()
959
+ && !sourceStat.isSymbolicLink()
960
+ && destinationStat.isDirectory()
961
+ && !destinationStat.isSymbolicLink();
962
+ if (!mergeDirectories) {
963
+ result.discardedFiles += await countArtifactFiles(sourcePath, sourceStat);
964
+ await fs.rm(sourcePath, { recursive: true, force: true });
965
+ return;
966
+ }
967
+
968
+ const entries = await fs.readdir(sourcePath, { withFileTypes: true });
969
+ entries.sort((left, right) => left.name.localeCompare(right.name));
970
+ for (const entry of entries) {
971
+ await mergeArtifactEntry(
972
+ path.join(sourcePath, entry.name),
973
+ path.join(destinationPath, entry.name),
974
+ result
975
+ );
976
+ }
977
+ await fs.rmdir(sourcePath);
978
+ }
979
+
980
+ async function countArtifactFiles(entryPath, entryStat = null) {
981
+ const stat = entryStat ?? await fs.lstat(entryPath);
982
+ if (!stat.isDirectory() || stat.isSymbolicLink()) return 1;
983
+
984
+ let count = 0;
985
+ const entries = await fs.readdir(entryPath, { withFileTypes: true });
986
+ for (const entry of entries) {
987
+ count += await countArtifactFiles(path.join(entryPath, entry.name));
988
+ }
989
+ return count;
990
+ }
991
+
1013
992
  async function ensureSettings(cwd, { input = process.stdin, output = process.stdout } = {}) {
1014
993
  const settingsPath = path.join(cwd, SETTINGS_RELATIVE_PATH);
1015
994
  const existingContent = await readFileIfExists(settingsPath);
@@ -1144,13 +1123,6 @@ function migrateSettingsContent(content) {
1144
1123
 
1145
1124
  const planReview = objectValue(raw['plan-review']);
1146
1125
  transfer('planReview.threshold', planReview.threshold, score, value => { settings.planReview.threshold = value; });
1147
- transferAgentSettings({
1148
- rawAgents: objectValue(planReview.agents),
1149
- settingsAgents: settings.planReview.agents,
1150
- definitions: PLAN_REVIEW_AGENT_DEFINITIONS,
1151
- prefix: 'planReview.agents',
1152
- missingKeys
1153
- });
1154
1126
 
1155
1127
  const planPolish = objectValue(raw['plan-polish']);
1156
1128
  transfer('planPolish.limit', planPolish.limit, positiveInt, value => { settings.planPolish.limit = value; });
@@ -1295,11 +1267,6 @@ ${onFailureThen}
1295
1267
  # Модель для Codex.
1296
1268
  codex: ${configured.model.codex}`;
1297
1269
  }).join('\n\n');
1298
- const planReviewAgents = formatAgents(
1299
- PLAN_REVIEW_AGENT_DEFINITIONS,
1300
- settings.planReview.agents,
1301
- DEFAULT_PLAN_REVIEW_AGENTS
1302
- );
1303
1270
  const reviewAgents = formatAgents(REVIEW_AGENT_DEFINITIONS, settings.review.agents, DEFAULT_REVIEW_AGENTS);
1304
1271
 
1305
1272
  return `version: ${SETTINGS_VERSION}
@@ -1329,7 +1296,7 @@ plan:
1329
1296
  # Включает кросс-CLI ревью в eda-plan.
1330
1297
  # true | false
1331
1298
  strict: ${settings.plan.strict ? 'true' : 'false'}
1332
- # Запускает один eda-plan-review и при необходимости один eda-plan-review-fix.
1299
+ # Запускает изолированный цикл eda-plan-polish.
1333
1300
  # true | false
1334
1301
  review: ${settings.plan.review !== false ? 'true' : 'false'}
1335
1302
  # Задаёт размер плана.
@@ -1346,12 +1313,9 @@ plan:
1346
1313
  logging_strategy: ${settings.plan.loggingStrategy}
1347
1314
 
1348
1315
  plan-review:
1349
- # План готов только без обязательных findings и при score не ниже этого порога.
1316
+ # Доля закрытых пунктов чек-листа, при которой план считается готовым.
1350
1317
  # 1..100
1351
1318
  threshold: ${settings.planReview.threshold}
1352
- # Каждая проверка имеет собственный режим запуска и модели для обеих сред.
1353
- agents:
1354
- ${planReviewAgents}
1355
1319
 
1356
1320
  plan-polish:
1357
1321
  # Максимальное число подтверждающих review-итераций.
@@ -1369,7 +1333,7 @@ send-review:
1369
1333
  close_previous_reviews: ${settings.sendReview.closePreviousReviews ? 'true' : 'false'}
1370
1334
 
1371
1335
  discover-automations:
1372
- # Добавляет docs/plans/ в обычный запуск eda-discover-automations.
1336
+ # Добавляет docs/artifacts/plans/ в обычный запуск eda-discover-automations.
1373
1337
  # true | false
1374
1338
  include_plans: ${settings.discoverAutomations.includePlans ? 'true' : 'false'}
1375
1339
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gian-tiaga/eda",
3
- "version": "2.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Пакет скилов и специализированных агентов eda-* для Claude Code и Codex CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,7 +28,7 @@ aim:
28
28
 
29
29
  В автоматическом режиме основной агент сам выбирает ответ на рабочие вопросы по рекомендации субагента и фактам проекта. Это не отменяет одно обязательное подтверждение человеком точного списка целей до создания нового файла.
30
30
 
31
- Если пользователь передал существующий файл из `docs/aims/`, продолжай его с текущего статуса. Не создавай второй файл для той же цели.
31
+ Если пользователь передал существующий файл из `docs/artifacts/aims/`, продолжай его с текущего статуса. Не создавай второй файл для той же цели.
32
32
 
33
33
  ## Пакетные агенты
34
34
 
@@ -59,7 +59,7 @@ aim:
59
59
 
60
60
  ## Файл цели
61
61
 
62
- После подтверждения `eda-aim-planner` создаёт `docs/aims/{YYYY-MM-DD}_{HH-MM}_{slug}.md`. Файл должен оставаться коротким и содержать только цель и фактический журнал:
62
+ После подтверждения `eda-aim-planner` создаёт `docs/artifacts/aims/{YYYY-MM-DD}_{HH-MM}_{slug}.md`. Файл должен оставаться коротким и содержать только цель и фактический журнал:
63
63
 
64
64
  ```markdown
65
65
  # <Короткое название>
@@ -5,7 +5,7 @@ description: 'Создаёт и обновляет согласованное о
5
5
 
6
6
  # Скил: Бизнес-логика (eda-business)
7
7
 
8
- Создаёшь и поддерживаешь согласованную бизнес-документацию проекта: короткое оглавление `docs/business.md` и самостоятельные тематические карточки в `docs/business/`. Документы отвечают на вопросы «что должен делать продукт», «для кого», «по каким правилам» и «какой результат считается правильным», но не проектируют техническую реализацию.
8
+ Создаёшь и поддерживаешь согласованную бизнес-документацию проекта: короткое оглавление `docs/business.md` и самостоятельные тематические карточки в `docs/business/`. Каждая карточка подробно фиксирует значимые решения своей темы, но не засоряется сведениями соседних тем и деталями конкретной реализации.
9
9
 
10
10
  ## Вход из сообщения пользователя
11
11
 
@@ -22,11 +22,16 @@ description: 'Создаёт и обновляет согласованное о
22
22
  1. **Только business-документация.** Меняй лишь `docs/business.md` и Markdown-файлы непосредственно в `docs/business/`. Не правь код, настройки, правила, архитектуру, планы, тесты или другие документы.
23
23
  2. **Целевое поведение.** Карточки фиксируют согласованные требования и бизнес-логику, даже если код пока им не соответствует. Фактические отличия вынеси в последний раздел `Расхождения с реализацией`.
24
24
  3. **Никаких догадок как фактов.** Код помогает найти существующие сценарии и вопросы, но не подтверждает продуктовые решения сам по себе.
25
- 4. **Одна тема за раз.** После согласования общего списка полностью проработай текущую тему и получи подтверждение её содержания до записи, затем переходи к следующей.
25
+ 4. **Одна тема за раз.** После согласования общего списка полно опиши и подтверди значимые решения текущей темы до записи, затем переходи к следующей.
26
26
  5. **В индекс — только готовое.** Не записывай предложенные, незавершённые или спорные темы в `docs/business.md` и не создавай для них черновые карточки.
27
27
  6. **Самодостаточные карточки.** Основной текст не должен требовать чтения исходного кода, плана или внешнего материала, чтобы понять бизнес-правило.
28
- 7. **Не проектируй реализацию.** Не назначай классы, таблицы, endpoints, очереди, библиотеки, модули или порядок технических изменений.
28
+ 7. **Не проектируй конкретную реализацию.** Не назначай язык, фреймворк, библиотеку, конкретную СУБД, схему данных, классы, функции, внутренние модули или порядок технических изменений.
29
29
  8. **Сохраняй подтверждённое.** При обновлении не удаляй и не ослабляй существующее правило, не переименовывай и не удаляй карточку без явного решения пользователя.
30
+ 9. **Полнота без шума.** Зафиксируй все подтверждённые детали, которые меняют целевое поведение темы: правила, выбранные алгоритмы, состояния, переходы, ограничения, исключения и наблюдаемые результаты. Не сокращай сложную тему ради краткости; убирай повторы, общие рассуждения и факты, не влияющие на правило.
31
+ 10. **Строгая граница темы.** Карточка описывает только названную тему. Сведения о соседнем домене, внутреннем модуле или другой карточке опускай; если у них есть самостоятельное бизнес-значение, предложи отдельную тему, но не включай её в текущую.
32
+ 11. **`about` — только обзор.** Это не сводная бизнес-спецификация и не каталог остальных карточек. Кратко опиши сам проект и перечисли его основные пользовательские возможности; не раскладывай их по модулям и не детализируй правила, сценарии и исключения других тем.
33
+ 12. **Карточка не привязана к коду.** Код, тесты и конфиги используй для поиска вопросов и проверки текущего поведения, но пиши карточку устойчивым предметным языком. Не включай пути и строки исходников, имена классов, функций, файлов и внутренних модулей — в том числе в `about` и `Расхождения с реализацией`.
34
+ 13. **Алгоритм допустим, стек — нет.** Фиксируй выбранный функциональный или security-механизм, если он определяет поведение продукта: например, JWT либо непрозрачные токены с хранением в базе данных, правила выпуска, срока действия, обновления и отзыва. Не регламентируй язык, framework, библиотеку, конкретную СУБД, таблицы и способ программной сборки механизма, если это не отдельное подтверждённое ограничение продукта.
30
35
 
31
36
  ## Интерактивные вопросы
32
37
 
@@ -43,7 +48,7 @@ description: 'Создаёт и обновляет согласованное о
43
48
 
44
49
  ### 1. Прочитать существующий контекст
45
50
 
46
- Прочитай `docs/business.md` и только карточки, которые относятся к текущей теме. Затем изучи релевантные README, стартовые документы, правила, архитектуру, пользовательские сценарии, routes, модели, тесты и историю, достаточные для понимания фактического поведения.
51
+ Прочитай `docs/business.md` и только карточки, которые относятся к текущей теме. Затем изучи минимальный набор релевантных источников, достаточный для понимания именно этой темы. Для `about` обычно достаточно основного README, метаданных проекта и пользовательских точек входа; не обходи каждый внутренний модуль, route, модель или тест.
47
52
 
48
53
  Не загружай все карточки и весь код без необходимости. Разделяй:
49
54
 
@@ -54,60 +59,61 @@ description: 'Создаёт и обновляет согласованное о
54
59
 
55
60
  ### 2. Выбрать темы при пустом вызове
56
61
 
57
- Если тема не задана, составь короткий список только из реально применимых тем. Для каждой укажи, что именно будет описано и почему тема нужна проекту. Не используй обязательный универсальный набор: `auth`, `posts`, `payments` и другие названия допустимы только при наличии соответствующего поведения.
62
+ Если тема не задана, составь короткий список только из реально применимых и непересекающихся тем. Для каждой одной фразой укажи, что именно будет описано. Не используй обязательный универсальный набор и не создавай тему для каждого технического модуля: `auth`, `posts`, `payments` и другие названия допустимы только при наличии самостоятельных правил продукта.
58
63
 
59
64
  Покажи список через `AskUserQuestion` и попроси подтвердить его или изменить. До подтверждения ничего не записывай. После ответа прорабатывай темы последовательно. Если работа прервана, следующий пустой вызов заново анализирует индекс и предлагает только отсутствующие или требующие актуализации темы.
60
65
 
61
66
  ### 3. Согласовать текущую тему
62
67
 
63
- Собери достаточную бизнес-спецификацию:
68
+ Сначала сформулируй суть темы в одном-двух предложениях. Затем собери все конкретные решения, необходимые для полного описания целевого поведения этой темы. Требования, термины, сценарии, состояния, ограничения, исключения и критерии приёмки добавляй по смыслу, а не ради заполнения универсального чеклиста. Не пропускай значимую конкретику только потому, что карточка получится длинной.
64
69
 
65
- - назначение и границы темы;
66
- - участники, роли и значимые термины;
67
- - требования, правила и инварианты;
68
- - основные сценарии и порядок бизнес-действий;
69
- - состояния, переходы, ограничения и исключения;
70
- - ошибки и пограничные случаи, видимые пользователю или внешнему потребителю;
71
- - проверяемые критерии приёмки.
70
+ Например, карточка аутентификации может подробно фиксировать выбранный вид токенов, их выпуск, срок действия, обновление, отзыв, завершение сессий и значимые ошибки. В ней допустимо выбрать JWT или токены, хранящиеся в базе данных, но не следует назначать язык, framework, библиотеку, конкретную СУБД, таблицы, классы и файлы.
72
71
 
73
- Для `about` вместо детального алгоритма зафиксируй назначение проекта, аудиторию, решаемую проблему, границы, ключевые возможности, основные пользовательские сценарии и общие бизнес-ограничения.
72
+ Для `about` подготовь короткое описание проекта и компактный список его основных возможностей. Не включай аудиторию, решаемую проблему, границы, общие ограничения или пользовательские сценарии отдельными разделами, если пользователь их явно не запросил и они не нужны для самого краткого описания. Не упоминай устройство внутренних модулей и не пересказывай содержимое тематических карточек.
74
73
 
75
- Сравни целевое поведение с реализацией. Подготовь отдельный список подтверждённых расхождений с точными путями и строками, когда они доступны. Отсутствие реализации также является расхождением, если требование уже подтверждено.
74
+ Сравни с реализацией только подтверждённые правила непосредственно текущей темы. Расхождение описывай как отличие наблюдаемого поведения от целевого, без ссылок на исходники и без пересказа устройства кода. В `Расхождения с реализацией` не добавляй наблюдения о соседних модулях, случайно замеченные дефекты, технический долг и неполноту других карточек. Для `about` не перечисляй пофункциональные расхождения: они относятся к отдельным тематическим карточкам. Если прямого существенного расхождения по теме нет, напиши `Известных расхождений не обнаружено.`
76
75
 
77
- Покажи человеку собранное содержание и запроси итоговое подтверждение через `AskUserQuestion`. Если остаётся спорное решение, сначала закрой его отдельным вопросом. Не записывай карточку до подтверждения.
76
+ Покажи человеку короткий текст будущей карточки целиком и запроси итоговое подтверждение через `AskUserQuestion`. Если остаётся спорное решение, сначала закрой его отдельным вопросом. Не записывай карточку до подтверждения.
78
77
 
79
78
  ### 4. Записать карточку и индекс
80
79
 
81
80
  Используй стабильное имя файла в lowercase ASCII kebab-case: `docs/business/<topic>.md`.
82
81
 
83
- Обычная тематическая карточка:
82
+ У обычной тематической карточки нет обязательного набора содержательных разделов. Выбирай структуру по сложности темы и фиксируй в ней всю значимую подтверждённую конкретику без лишних разделов, например:
84
83
 
85
84
  ```markdown
86
85
  # <Название темы>
87
86
 
88
- ## Назначение и границы
89
- <что покрывает тема и что не покрывает>
87
+ <краткое описание темы>
90
88
 
91
- ## Участники и термины
92
- <роли и доменные понятия>
89
+ ## Правила
93
90
 
94
- ## Требования и правила
95
- <согласованные требования и инварианты>
91
+ - <только необходимые согласованные правила>
96
92
 
97
- ## Сценарии и алгоритмы
98
- <пошаговое бизнес-поведение без технической реализации>
93
+ ## Расхождения с реализацией
94
+
95
+ <подтверждённые отличия с доказательствами либо «Известных расхождений не обнаружено.»>
96
+ ```
97
+
98
+ Если отдельный раздел `Правила` не нужен, не создавай его. Для сложной темы добавь столько смысловых разделов, сколько требуется, чтобы не смешивать правила, алгоритмы, состояния, исключения и критерии. Для простой темы не создавай пустые или формальные разделы.
99
99
 
100
- ## Состояния и исключения
101
- <переходы, ограничения, ошибки и пограничные случаи>
100
+ Для `about.md` используй простой обзорный формат:
102
101
 
103
- ## Критерии приёмки
104
- <наблюдаемые условия корректного поведения>
102
+ ```markdown
103
+ # О проекте
104
+
105
+ <краткое описание проекта>
106
+
107
+ ## Основные возможности
108
+
109
+ - <возможность на уровне пользователя>
105
110
 
106
111
  ## Расхождения с реализацией
107
- <подтверждённые отличия с доказательствами либо «Известных расхождений не обнаружено.»>
112
+
113
+ Известных расхождений не обнаружено.
108
114
  ```
109
115
 
110
- Для `about.md` используй подходящие смысловые разделы из шага 3, но всегда оставляй последним `## Расхождения с реализацией`.
116
+ Сохраняй `Расхождения с реализацией` последним разделом любой карточки.
111
117
 
112
118
  Создай или обнови `docs/business.md` как короткое оглавление только существующих согласованных карточек:
113
119
 
@@ -116,7 +122,7 @@ description: 'Создаёт и обновляет согласованное о
116
122
 
117
123
  | Описание | Карточка |
118
124
  |---|---|
119
- | Назначение проекта, аудитория и основные возможности | [О проекте](business/about.md) |
125
+ | Краткое описание проекта и основные возможности | [О проекте](business/about.md) |
120
126
  | Регистрация, вход, восстановление доступа и права пользователей | [Авторизация](business/auth.md) |
121
127
  ```
122
128
 
@@ -128,6 +134,11 @@ description: 'Создаёт и обновляет согласованное о
128
134
 
129
135
  - индекс содержит только существующие согласованные карточки и ровно две колонки `Описание` и `Карточка`;
130
136
  - новая или обновлённая карточка соответствует подтверждённому содержанию;
137
+ - карточка не содержит сведений о соседних темах и не раздута необязательными разделами;
138
+ - `about` остаётся коротким обзором проекта и его основных возможностей без описания внутренних модулей;
139
+ - сложная тема подробно фиксирует все значимые подтверждённые правила, алгоритмы, состояния и исключения;
140
+ - текст карточки не ссылается на файлы, строки, классы, функции и внутренние модули текущей реализации;
141
+ - выбранный механизм поведения отделён от языка, framework, библиотеки, конкретной СУБД и схемы реализации;
131
142
  - каждое правило однозначно и проверяемо на уровне поведения;
132
143
  - техническая реализация не выдана за бизнес-требование;
133
144
  - раздел `Расхождения с реализацией` последний и отделяет целевое состояние от текущего;
@@ -142,6 +153,10 @@ description: 'Создаёт и обновляет согласованное о
142
153
  - Записывать неподтверждённые темы или черновики в индекс.
143
154
  - Выводить бизнес-правило только из текущего кода и сразу считать его целевым.
144
155
  - Подменять карточку исследованием, roadmap, архитектурой или планом реализации.
156
+ - Сокращать сложную тему до общего описания и терять подтверждённые правила или алгоритмы.
157
+ - Переписывать в карточку структуру кода, пути, строки, классы, функции и внутренние модули.
158
+ - Использовать `about` как сводку всех доменов, модулей, правил и расхождений проекта.
159
+ - Переносить в текущую карточку подробности и расхождения соседней темы «для контекста».
145
160
  - Создавать ссылки из индекса на отсутствующие файлы.
146
161
  - Молча удалять, переименовывать или ослаблять подтверждённые требования.
147
162
  - Сохранять business-документацию вне `docs/business.md` и `docs/business/`.