@miroshnik/elves 0.0.0 → 2026.1018.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.
- package/AGENTS.md +310 -0
- package/README.md +344 -0
- package/bin/ai-dev.ts +7 -0
- package/bin/elves.ts +2847 -0
- package/bin/shims/timeout +113 -0
- package/claude/CLAUDE.md +71 -0
- package/dist/github/scripts/github.js +3428 -0
- package/dist/spec/scripts/architecture.js +628 -0
- package/dist/spec/scripts/eslint-config.js +54 -0
- package/dist/spec/scripts/harness-qzb932c8.js +959 -0
- package/dist/spec/scripts/harness-v9s1v9w3.js +16045 -0
- package/dist/spec/scripts/harness.js +53 -0
- package/dist/spec/scripts/knip-hints.cjs +34 -0
- package/docs/ci-concurrency.md +82 -0
- package/docs/cloud-sessions.md +203 -0
- package/docs/judgment.md +81 -0
- package/docs/parallel-checkouts.md +220 -0
- package/docs/pr-checks.md +117 -0
- package/docs/testing.md +304 -0
- package/package.json +70 -1
- package/skills/ci-wait/SKILL.md +180 -0
- package/skills/ci-wait/scripts/wait-ci.sh +377 -0
- package/skills/dashboard/SKILL.md +212 -0
- package/skills/dashboard/scripts/dashboard.ts +912 -0
- package/skills/dashboard/scripts/sessions.ts +772 -0
- package/skills/est/SKILL.md +221 -0
- package/skills/est/reference.md +381 -0
- package/skills/est/scripts/est.ts +4854 -0
- package/skills/github/SKILL.md +206 -0
- package/skills/github/locales/en.json +449 -0
- package/skills/github/locales/ru.json +449 -0
- package/skills/github/reference.md +1073 -0
- package/skills/github/scripts/github.ts +4390 -0
- package/skills/github/scripts/locale.ts +495 -0
- package/skills/github/scripts/package.json +3 -0
- package/skills/slot/SKILL.md +145 -0
- package/skills/slot/scripts/package.json +3 -0
- package/skills/slot/scripts/slot.ts +279 -0
- package/skills/spec/SKILL.md +247 -0
- package/skills/spec/canon.md +219 -0
- package/skills/spec/checks.md +709 -0
- package/skills/spec/ci.md +378 -0
- package/skills/spec/migration.md +125 -0
- package/skills/spec/reference.md +889 -0
- package/skills/spec/scripts/architecture.ts +839 -0
- package/skills/spec/scripts/c4.ts +184 -0
- package/skills/spec/scripts/eslint-config.ts +82 -0
- package/skills/spec/scripts/harness.ts +1483 -0
- package/skills/spec/scripts/knip-hints.cjs +34 -0
- package/skills/spec/scripts/knip-hints.d.cts +17 -0
- package/skills/spec/scripts/package-run.ts +22 -0
- package/skills/spec/scripts/package.json +3 -0
- package/skills/spec/scripts/spec-break.ts +232 -0
- package/skills/spec/scripts/spec-claims.ts +198 -0
- package/skills/spec/scripts/spec-diff.ts +1111 -0
- package/skills/spec/scripts/spec-doc.ts +744 -0
- package/skills/spec/scripts/spec-exceptions.ts +233 -0
- package/skills/spec/scripts/spec-publish.ts +214 -0
- package/skills/spec/scripts/spec-run.ts +235 -0
- package/skills/spec/scripts/spec-shard.ts +267 -0
- package/skills/spec/scripts/speclib.ts +826 -0
- package/skills/spec/scripts/vendor/babel-parser.LICENSE +19 -0
- package/skills/spec/scripts/vendor/babel-parser.cjs +14615 -0
- package/skills/spec/scripts/vendor/babel-parser.d.cts +3 -0
- package/skills/task-env/SKILL.md +231 -0
- package/skills/task-env/proxy/compose.yaml +51 -0
- package/skills/task-env/reference.md +254 -0
- package/skills/task-env/scripts/task-env.ts +1017 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
{
|
|
2
|
+
"issueTypes": {
|
|
3
|
+
"task": "Задача",
|
|
4
|
+
"bug": "Баг",
|
|
5
|
+
"epic": "Эпик"
|
|
6
|
+
},
|
|
7
|
+
"sections": {
|
|
8
|
+
"questions": "## Вопросы",
|
|
9
|
+
"scenarios": "## Сценарии"
|
|
10
|
+
},
|
|
11
|
+
"labels": {
|
|
12
|
+
"questions": "вопросы",
|
|
13
|
+
"questionsDescription": "Есть открытые вопросы в разделе «## Вопросы»",
|
|
14
|
+
"epicDescription": "Эпик: большая задача с подзадачами",
|
|
15
|
+
"externalBlocker": "внешний блокер"
|
|
16
|
+
},
|
|
17
|
+
"status": {
|
|
18
|
+
"backlog": "Бэклог",
|
|
19
|
+
"inProgress": "В работе",
|
|
20
|
+
"done": "Готово"
|
|
21
|
+
},
|
|
22
|
+
"fields": {
|
|
23
|
+
"estimate": "Оценка, ч",
|
|
24
|
+
"actual": "Факт, ч",
|
|
25
|
+
"tokens": "Токены, млн",
|
|
26
|
+
"cost": "Стоимость, $"
|
|
27
|
+
},
|
|
28
|
+
"views": {
|
|
29
|
+
"board": "Доска",
|
|
30
|
+
"table": "Таблица",
|
|
31
|
+
"roadmap": "Роадмэп"
|
|
32
|
+
},
|
|
33
|
+
"labelMarkers": {
|
|
34
|
+
"decision": "Решение:",
|
|
35
|
+
"slice": "Разрез:",
|
|
36
|
+
"architecturePath": "tests/architecture — правило или модуль {name}"
|
|
37
|
+
},
|
|
38
|
+
"comments": {
|
|
39
|
+
"state": "Состояние",
|
|
40
|
+
"actual": "Факт:",
|
|
41
|
+
"closedByPr": "Закрыта по PR {prs}: GitHub не связал PR с задачей",
|
|
42
|
+
"externalBlocker": "Внешний блокер:"
|
|
43
|
+
},
|
|
44
|
+
"subagentPrompt": {
|
|
45
|
+
"task": "Задача",
|
|
46
|
+
"epic": "эпик"
|
|
47
|
+
},
|
|
48
|
+
"mainRed": {
|
|
49
|
+
"title": "{base} красный",
|
|
50
|
+
"check": "чек {names}",
|
|
51
|
+
"checks": "чеки {names}"
|
|
52
|
+
},
|
|
53
|
+
"actualize": {
|
|
54
|
+
"lead": "{task} #{number} ({epicWord} #{epic}): актуализация блока после мержа — открытые задачи эпика привести в соответствие с выкаченным.",
|
|
55
|
+
"fetch": "Задание целиком — тексты открытых задач эпика, файлы PR, что назвал скрипт, проверки по смыслу — печатает `{command}`: позови первым, вне песочницы (gh в ней не работает); задачи и PR сам не собирай.",
|
|
56
|
+
"shipped": "Репозиторий {repo}. Выкачено: #{number} «{title}», {shipped}.",
|
|
57
|
+
"prs": "PR {list}",
|
|
58
|
+
"noPr": "PR не найден — коммиты {command}",
|
|
59
|
+
"files": "Файлы PR #{pr}:",
|
|
60
|
+
"epic": "## Эпик #{epic} «{title}»",
|
|
61
|
+
"openTasks": "## Открытые задачи эпика — его подзадачи (sub-issues), а не список в описании эпика",
|
|
62
|
+
"openTask": "### #{number} «{title}»",
|
|
63
|
+
"noBody": "(описания нет)",
|
|
64
|
+
"copies": "## Копии связей в тексте — убрать: связи держит GitHub (sub-issue, blocked by)",
|
|
65
|
+
"copy": "- #{number}: «{line}»",
|
|
66
|
+
"answers": "## Ответы на открытые вопросы в комментариях — сверить, что это ответ на этот вопрос, и перенести в «{questions}» (✅ и ответ у вопроса, нумерация та же); не он — оставить",
|
|
67
|
+
"commentAnswer": "- #{number}, вопрос {k}: «{text}» — {url}",
|
|
68
|
+
"checks": "## Проверки по смыслу — твои (канон — reference.md скилла github, «Epic refresh on task close»); механику — blocked by на выполненных задачах, метку вопросов без открытых вопросов, milestone без открытых задач — сделал скрипт",
|
|
69
|
+
"scope": "Меняешь только задачи GitHub — описание, «{questions}», связи, статус; скрипт скилла github — `{script}`: без выполнения — `task drop <N>`, новая — `task new … --branch-type <тип> --epic {epic}` (оценку ставит сама); ответ у вопроса — `task answer <N> <k> \"<ответ>\"`. Код, ветки и git не трогать; #{number}, эпик #{epic} и их milestone не закрывать — это сделает task close после тебя.",
|
|
70
|
+
"comment": "Итог — всегда, последним шагом: комментарий к эпику #{epic} (`gh issue comment {epic} --repo {repo}`) одной строкой «{report}» — после двоеточия что поправил, а править нечего — «блок актуален». По нему `task close {number}` видит, что актуализация закончена: без него закрытие откажет.",
|
|
71
|
+
"answer": "Ответ — правки по строке с номерами задач и вопросы владельцу, если есть; иначе «Блок актуален».",
|
|
72
|
+
"linkWords": "после|зависит от|заблокирована|заблокирован|заблокировано|блокирует|ждёт|ждет",
|
|
73
|
+
"report": "Актуализация после #{number}, итог: {text}",
|
|
74
|
+
"mechanics": "Актуализация после #{number}, скрипт: {fixes}.",
|
|
75
|
+
"unblocked": "у #{task} снят blocked by на выполненных {blockers}",
|
|
76
|
+
"unlabeled": "у #{task} снята метка «{label}»: открытых вопросов нет",
|
|
77
|
+
"milestone": "закрыт milestone «{title}»: открытых задач в нём нет"
|
|
78
|
+
},
|
|
79
|
+
"queue": {
|
|
80
|
+
"prompt": "{task} #{number} в {repo}{epic}: ты исполнитель сессии-диспетчера. Задание целиком печатает `{command}` — позови первым, вне песочницы (gh в ней не работает).",
|
|
81
|
+
"epic": " ({epicWord} #{epic})",
|
|
82
|
+
"lead": "{task} #{number} «{title}» в {repo}{epic}: ты исполнитель сессии-диспетчера — сделай задачу целиком по канону, как сессия в режиме auto: вопросы задачи, `{script} task status {number} \"{inProgress}\" --branch <тип>/{number}-<slug>`, ветка от свежего origin/main, код и тесты, PR, зелёный CI, `pr premerge`, мерж, деплой, актуализация эпика, `{script} task close {number}`.",
|
|
83
|
+
"resume": "Задача уже «{inProgress}» и у неё есть ветка {branches} — это перезапуск: продолжи её работу. Ветка взята в другом worktree (`git worktree list`) — работай в нём, а не в своём новом: в Claude Code — `EnterWorktree` с его путём; незакоммиченное — `git status` там. Ни в одном worktree её нет — возьми её в свой.",
|
|
84
|
+
"subagent": "Ты субагент, а не сессия:",
|
|
85
|
+
"session": "- сессию не переименовывай и не архивируй, последнюю строку («{done}») не пиши — это делает диспетчер;",
|
|
86
|
+
"wait": "- CI и деплой жди обычным вызовом, не в фоне: фоновая команда субагента не будит, а вызов Bash живёт до 10 минут — `{waitCi} pr <PR> --timeout 540` (после мержа — `merged <PR>`), на TIMEOUT — тот же вызов снова;",
|
|
87
|
+
"git": "- git — отдельными вызовами, без `cd`, `&&` и `|`: составную команду с git изоляция worktree не пропускает;",
|
|
88
|
+
"subagents": "- пишущих субагентов запускай по необходимости, без лимита: каждому — свой worktree и «{task} #{number}» в начале промпта (по нему `est` привяжет его работу); их коммиты перенеси в свою ветку, их worktree и ветки после мержа убери сам — что не убралось, назови в ответе;",
|
|
89
|
+
"live": "- пока работает хоть один твой субагент, ответ не отдавай: жди их ответов — фоновый субагент будит тебя своим ответом; ответ при живых субагентах выглядит провалом, и диспетчер отдал бы задачу второму исполнителю рядом с тобой. Ждать нельзя — ответь `ждёт субагентов: <какие и что делают>`: это не «сломалось», второго исполнителя не будет;",
|
|
90
|
+
"found": "- найденная работа вне задачи — `{script} task new …` (работа эпика задачи — с `--epic`: диспетчер её подхватит) — назови её в ответе: ставить ли её в очередь, решает владелец;",
|
|
91
|
+
"question": "- вопрос без ясной рекомендации — в «{questions}» задачи; код, который от него зависит, не начинай и ответь диспетчеру: ответ владельца придёт сюда же.",
|
|
92
|
+
"answer": "Ответ диспетчеру — одной строкой: `влито #<PR>` · `вопрос: <вопрос, варианты, рекомендация>` · `ждёт субагентов: <какие и что делают>` · `сломалось: <что и где остановилось>`.",
|
|
93
|
+
"alive": "{task} #{number} в {repo}: у задачи жив прежний исполнитель или его субагент — строки `!` выше. Задачу не бери и ничего не меняй: ответь диспетчеру одной строкой `ждёт прежнего исполнителя: <worktree и почему он жив>` — диспетчер перезапускает задачу, только когда ни один worktree прежнего исполнителя и его субагентов не заблокирован живым процессом и не получает коммитов.",
|
|
94
|
+
"cloudEpic": " ({epicWord} {epic})",
|
|
95
|
+
"cloud": "{task} #{number} «{title}» в {repo}{epic}: ты облачный исполнитель сессии-диспетчера — сделай задачу целиком по канону, как сессия в режиме auto: вопросы задачи, код и тесты, PR, зелёный CI, мерж, деплой.",
|
|
96
|
+
"cloudDoc": "- облако — по `docs/cloud-sessions.md` канона, прочитай его первым: из скриптов скилла github там работают `task show`, `task answer` и `task new` (через REST), остальные отказывают, раздел сценариев — правкой описания через REST, поля проекта из облака не ставятся; ветка — та, что назначило облако, не переименовывай;",
|
|
97
|
+
"cloudClose": "- после мержа — его раздел «Closing a task from the cloud»: комментарий «{actual}» от `est fact {number}` и комментарий «{state}» с тем, что из облака не сделать, — оба в задачу;",
|
|
98
|
+
"cloudDispatcher": "- диспетчер ждёт закрытия задачи и закрывает её локально — факт, статус, влитая ветка, архив этой сессии: сообщать ему не нужно, сессию не архивируй;",
|
|
99
|
+
"cloudQuestion": "- вопрос без ясной рекомендации — в «{questions}» задачи и владельцу в этой сессии, код, который от него зависит, не начинай; остановился (вопрос, сбой, лимит) — комментарий «{state}» в задачу."
|
|
100
|
+
},
|
|
101
|
+
"est": {
|
|
102
|
+
"answer": "Ответ",
|
|
103
|
+
"manual": "+ вручную:",
|
|
104
|
+
"reason": "Причина:",
|
|
105
|
+
"hours": "ч",
|
|
106
|
+
"closingWords": "закрывает закрыт закрыта закрыто закрыты закрыть исправляет решает устраняет",
|
|
107
|
+
"stopWords": "для без при что как или все это его из от до за под над про через после перед если чем где когда только также уже ещё еще так",
|
|
108
|
+
"fact": {
|
|
109
|
+
"unavailable": "Факт недоступен: сессии не найдены (покрытие none).",
|
|
110
|
+
"body": "{h} ч активных в {agents} ({estimate}). {sessions}, {prompts},{subagents} стена {wall} ч, покрытие {cov}.",
|
|
111
|
+
"estimate": "оценка {h} ч{ratio}",
|
|
112
|
+
"noEstimate": "оценки нет",
|
|
113
|
+
"sessions": {
|
|
114
|
+
"one": "сессия",
|
|
115
|
+
"few": "сессии",
|
|
116
|
+
"many": "сессий",
|
|
117
|
+
"other": "сессии"
|
|
118
|
+
},
|
|
119
|
+
"prompts": {
|
|
120
|
+
"one": "промпт",
|
|
121
|
+
"few": "промпта",
|
|
122
|
+
"many": "промптов",
|
|
123
|
+
"other": "промпта"
|
|
124
|
+
},
|
|
125
|
+
"subagents": {
|
|
126
|
+
"one": "субагент",
|
|
127
|
+
"few": "субагента",
|
|
128
|
+
"many": "субагентов",
|
|
129
|
+
"other": "субагента"
|
|
130
|
+
},
|
|
131
|
+
"commits": {
|
|
132
|
+
"one": "коммит",
|
|
133
|
+
"few": "коммита",
|
|
134
|
+
"many": "коммитов",
|
|
135
|
+
"other": "коммита"
|
|
136
|
+
},
|
|
137
|
+
"prs": " PR {list};",
|
|
138
|
+
"noPr": " PR нет;",
|
|
139
|
+
"diff": " {commits}, дифф {diff}.",
|
|
140
|
+
"diffLines": "{n} строк",
|
|
141
|
+
"diffNa": "н/д (без PR)",
|
|
142
|
+
"shared": "общий {unit} с {list} (доля 1/{k})",
|
|
143
|
+
"commitUnit": "коммит {oid}",
|
|
144
|
+
"taken": " Не засчитано повторно: {h} ч уже в факте #{issue}.",
|
|
145
|
+
"overlap": " Пересечение с фактом #{issue}: {h} ч — пересчитать #{issue}.",
|
|
146
|
+
"cloudMissing": " Облачная сессия https://claude.ai/code/{sid} не импортирована — est cloud-import.",
|
|
147
|
+
"tokens": "Токены: {total} млн",
|
|
148
|
+
"tokensSplit": " (вход {in} · выход {out} · запись кэша {cw} · чтение кэша {cr})",
|
|
149
|
+
"cost": "; стоимость по API-тарифам ≈ ${usd}",
|
|
150
|
+
"unpriced": "; без цены (нет в прайсе): {models}",
|
|
151
|
+
"steps": "Ходы: {n} (субагентов {agents}, их ходов {agentSteps}), преамбула {preamble} тыс., контекст в конце {end} тыс., ходов с контекстом > {tail} тыс. — {share} %.",
|
|
152
|
+
"waits": "Ожидания: CI {ci} мин · после мержа {merged} · проверки {checks}{slot} · остальное {rest}.",
|
|
153
|
+
"waitsSlot": " (очередь slot {slot})",
|
|
154
|
+
"and": " и ",
|
|
155
|
+
"cloudAgent": "облачной сессии Claude Code"
|
|
156
|
+
},
|
|
157
|
+
"cloud": {
|
|
158
|
+
"actual": "Факт (облако):",
|
|
159
|
+
"body": "{h} ч активных в облачной сессии Claude Code, {prompts}.",
|
|
160
|
+
"tokens": " Токены: {total} млн{cost}.",
|
|
161
|
+
"cost": ", по API-тарифам ≈ ${usd}",
|
|
162
|
+
"fields": " Сессия: https://claude.ai/code/{sid}. Поля проекта поставит локальная сессия: est fact {number} --write.",
|
|
163
|
+
"unavailable": "Факт недоступен (облако): задача сделана в облачной сессии Claude Code — там est не видит проекта GitHub; цифру даст локальная сессия, импортировав события этой сессии (est cloud-import) (покрытие none).",
|
|
164
|
+
"session": " Сессия: https://claude.ai/code/{sid}."
|
|
165
|
+
},
|
|
166
|
+
"estimate": {
|
|
167
|
+
"headline": "Оценка: {h} ч",
|
|
168
|
+
"tokens": ", ≈ {tok} млн токенов",
|
|
169
|
+
"partial": " (токены и стоимость по {k} из {n} аналогов)",
|
|
170
|
+
"body": "{headline} (тип {type}, доверие {conf}; {basis}). Аналоги{auto}: {analogs}.{correction}{spread} {k}.",
|
|
171
|
+
"auto": " (подбор скриптом)",
|
|
172
|
+
"forecast": "прогноз по фактам аналогов",
|
|
173
|
+
"expertOver": "экспертная оценка; по аналогам вышло бы {h} ч, токены и стоимость пересчитаны ×{ratio}",
|
|
174
|
+
"expert": "экспертная оценка, аналогов с фактом нет",
|
|
175
|
+
"spread": " Разброс фактов аналогов {min}…{max} ч — взята медиана.",
|
|
176
|
+
"correction": " Поправка: ×{mult}{note}.",
|
|
177
|
+
"tokCorrection": " Поправка токенов и стоимости: ×{mult}{note}.",
|
|
178
|
+
"k": "k={k} (n={n}, уровень «{level}»; справочно, к прогнозу не применяется)",
|
|
179
|
+
"noK": "k: истории нет",
|
|
180
|
+
"levelRepo": "репо",
|
|
181
|
+
"levelAll": "все репо",
|
|
182
|
+
"none": "нет",
|
|
183
|
+
"otherProject": "из проекта {repo}: {list}",
|
|
184
|
+
"analog": "{label} (факт {h} ч{why})",
|
|
185
|
+
"unknown": "{label} (факт неизвестен)",
|
|
186
|
+
"partialCoverage": "{label} (факт {h} ч, покрытие {cov} — не учтён)",
|
|
187
|
+
"notInProject": "{label} (нет в проекте)",
|
|
188
|
+
"labels": {
|
|
189
|
+
"one": "метка",
|
|
190
|
+
"few": "метки",
|
|
191
|
+
"many": "меток",
|
|
192
|
+
"other": "метки"
|
|
193
|
+
},
|
|
194
|
+
"type": "тип {type}",
|
|
195
|
+
"words": {
|
|
196
|
+
"one": "слово",
|
|
197
|
+
"few": "слова",
|
|
198
|
+
"many": "слов",
|
|
199
|
+
"other": "слова"
|
|
200
|
+
},
|
|
201
|
+
"size": "описание ×{ratio}"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"updateCommit": "флоу Elves {version}",
|
|
205
|
+
"updateTask": "Обновить флоу Elves",
|
|
206
|
+
"formerly": {
|
|
207
|
+
"updateTask": "Обновить флоу ai-dev"
|
|
208
|
+
},
|
|
209
|
+
"standardIssue": "Стандарт ·",
|
|
210
|
+
"autoAnswer": "✅ авто",
|
|
211
|
+
"lastLine": {
|
|
212
|
+
"done": "Всё сделано. Сессию можно закрывать.",
|
|
213
|
+
"questions": "Всё сделано, но есть вопросы:",
|
|
214
|
+
"remaining": "Осталось:"
|
|
215
|
+
},
|
|
216
|
+
"prSpecSection": "## Спека (тесты)",
|
|
217
|
+
"spec": {
|
|
218
|
+
"tests": {
|
|
219
|
+
"one": "тест",
|
|
220
|
+
"few": "теста",
|
|
221
|
+
"many": "тестов",
|
|
222
|
+
"other": "теста"
|
|
223
|
+
},
|
|
224
|
+
"lint": {
|
|
225
|
+
"allRules": "все правила",
|
|
226
|
+
"noReason": "без причины"
|
|
227
|
+
},
|
|
228
|
+
"doc": {
|
|
229
|
+
"mark": "<!-- spec-doc: сгенерировано из названий тестов, руками не править -->",
|
|
230
|
+
"title": "Спецификация",
|
|
231
|
+
"intro": "Сгенерировано из дерева `tests/`, названий тестов и их JSDoc (скилл `spec`, `spec-doc`). Руками не править: правка — в тестах.",
|
|
232
|
+
"capabilities": "Что делает система",
|
|
233
|
+
"architecture": "Из чего состоит",
|
|
234
|
+
"standards": "Каким правилам подчиняется код",
|
|
235
|
+
"skippedCount": {
|
|
236
|
+
"one": "пропущен",
|
|
237
|
+
"few": "пропущено",
|
|
238
|
+
"many": "пропущено",
|
|
239
|
+
"other": "пропущено"
|
|
240
|
+
},
|
|
241
|
+
"failingCount": {
|
|
242
|
+
"one": "падает",
|
|
243
|
+
"few": "падают",
|
|
244
|
+
"many": "падают",
|
|
245
|
+
"other": "падают"
|
|
246
|
+
},
|
|
247
|
+
"variants": {
|
|
248
|
+
"one": "вариант",
|
|
249
|
+
"few": "варианта",
|
|
250
|
+
"many": "вариантов",
|
|
251
|
+
"other": "варианта"
|
|
252
|
+
},
|
|
253
|
+
"skipped": "пропущен",
|
|
254
|
+
"failing": "падает",
|
|
255
|
+
"todo": "todo",
|
|
256
|
+
"outside": "Вне дерева",
|
|
257
|
+
"outsideIntro": "Тесты без дома в {homes} и {last} — перенести:",
|
|
258
|
+
"none": "— нет.",
|
|
259
|
+
"rules": "Правила"
|
|
260
|
+
},
|
|
261
|
+
"c4": {
|
|
262
|
+
"title": "Архитектура",
|
|
263
|
+
"intro": "Сгенерировано из модели `tests/architecture/model.ts` (скилл `spec`, `spec-doc`): схемы C4 и таблица модулей. Правка — в модели; с кодом её сверяют правила архитектуры.",
|
|
264
|
+
"system": "Система",
|
|
265
|
+
"context": "Система и внешние системы",
|
|
266
|
+
"containers": "Контейнеры",
|
|
267
|
+
"components": "Модули",
|
|
268
|
+
"perimeter": "периметр",
|
|
269
|
+
"viaModule": "через модуль {modules}",
|
|
270
|
+
"viaModules": "через модули {modules}",
|
|
271
|
+
"uses": "использует",
|
|
272
|
+
"dependsOn": "зависит",
|
|
273
|
+
"calls": "вызывает",
|
|
274
|
+
"library": "библиотека",
|
|
275
|
+
"table": "| Модуль | Назначение | Каталог | API | Зависит от | Пакеты |",
|
|
276
|
+
"summary": "модель: {parts}",
|
|
277
|
+
"moduleCount": {
|
|
278
|
+
"one": "модуль",
|
|
279
|
+
"few": "модуля",
|
|
280
|
+
"many": "модулей",
|
|
281
|
+
"other": "модуля"
|
|
282
|
+
},
|
|
283
|
+
"containerCount": {
|
|
284
|
+
"one": "контейнер",
|
|
285
|
+
"few": "контейнера",
|
|
286
|
+
"many": "контейнеров",
|
|
287
|
+
"other": "контейнера"
|
|
288
|
+
},
|
|
289
|
+
"externalCount": {
|
|
290
|
+
"one": "внешняя система",
|
|
291
|
+
"few": "внешние системы",
|
|
292
|
+
"many": "внешних систем",
|
|
293
|
+
"other": "внешней системы"
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
"diff": {
|
|
297
|
+
"base": "_База: `{base}`._",
|
|
298
|
+
"unchanged": "Тесты не менялись.",
|
|
299
|
+
"removed": "Удалены",
|
|
300
|
+
"changed": "Изменены",
|
|
301
|
+
"added": "Добавлены",
|
|
302
|
+
"empty": "**{title}:** нет.",
|
|
303
|
+
"outsideMark": "вне дерева",
|
|
304
|
+
"moved": "**Перенесены в дерево ({n}):** названия те же, что вне `{tests}/` на базе; из {files}.",
|
|
305
|
+
"movedFolder": "{tests} из {files}",
|
|
306
|
+
"files": {
|
|
307
|
+
"one": "файла",
|
|
308
|
+
"few": "файлов",
|
|
309
|
+
"many": "файлов",
|
|
310
|
+
"other": "файла"
|
|
311
|
+
},
|
|
312
|
+
"summary": "**Сводка по папкам** — {tests}, больше порога {limit}: полный список — `spec-diff --full` (в CI — summary джоба).",
|
|
313
|
+
"folder": "Папка",
|
|
314
|
+
"harnessColumn": "Из них харнесса",
|
|
315
|
+
"total": "Всего",
|
|
316
|
+
"outsideFiles": "**Вне дерева `{tests}/`** изменены файлы тестов: {files}.",
|
|
317
|
+
"notStatements": "⚠️ **Названия — не утверждения: {n}** — новые в этом PR; `spec-doc` называет их предупреждениями.",
|
|
318
|
+
"scenarios": "Сценарии задачи",
|
|
319
|
+
"noScenarios": "В задаче нет раздела «{section}» — сверять не с чем.",
|
|
320
|
+
"becameTests": "**Стали тестами ({n}):** в списках выше.",
|
|
321
|
+
"noTest": "теста нет",
|
|
322
|
+
"extraMark": "сверх сценариев",
|
|
323
|
+
"extraTitle": "Тесты сверх сценариев",
|
|
324
|
+
"extraListed": "в списках выше, с пометкой «{mark}».",
|
|
325
|
+
"extraFull": "списком — `spec-diff --full`.",
|
|
326
|
+
"harnessCheck": "проверка харнесса",
|
|
327
|
+
"fromReport": "по отчёту",
|
|
328
|
+
"harnessNote": "_Тесты харнесса — по отчёту; база — ветка {branch} (исходник {source}{gap})._",
|
|
329
|
+
"harnessGap": " старше базы диффа {sha}: в списках возможны тесты PR, влитых между ними",
|
|
330
|
+
"noSpecBase": "_Тесты харнесса: в ветке {branch} нет tests.json для базы — дифф по исходникам, тестов харнесса в нём не видно._",
|
|
331
|
+
"partialReport": "⚠️ **Отчёт неполный:** в нём нет тестов из {folders}, чьи названия знает только прогон, — их тесты не сравнивались ({n} в ветке {branch}) и в «{removed}» не попали; полный дифф — с отчётом прогона всех тестов.",
|
|
332
|
+
"modelModule": "модуль {module}",
|
|
333
|
+
"modelDependency": "зависимость {from} → {to}",
|
|
334
|
+
"modelPackage": "пакет {package} модуля {module}",
|
|
335
|
+
"registry": "реестр",
|
|
336
|
+
"registryNamed": "реестр «{value}»",
|
|
337
|
+
"rule": "правило",
|
|
338
|
+
"ruleNamed": "правило {value}",
|
|
339
|
+
"deadCode": "код без потребителя",
|
|
340
|
+
"deadCodeNamed": "код без потребителя ({value})",
|
|
341
|
+
"architecture": "модель архитектуры",
|
|
342
|
+
"modelTitle": "Модель архитектуры",
|
|
343
|
+
"exceptionsTitle": "Исключения",
|
|
344
|
+
"checksTitle": "Проверки харнесса",
|
|
345
|
+
"removedKind": "{title} — снято",
|
|
346
|
+
"addedKind": "{title} — добавлено",
|
|
347
|
+
"summarized": "**{title} ({n}), сводкой:**"
|
|
348
|
+
},
|
|
349
|
+
"claims": {
|
|
350
|
+
"describe": "Каждая точка входа вызывается хотя бы одним тестом capability",
|
|
351
|
+
"registry": "точки входа",
|
|
352
|
+
"unique": "id точек входа в реестре не повторяются",
|
|
353
|
+
"called": "{entry} вызывается тестом capability",
|
|
354
|
+
"known": "id из журнала есть в реестре"
|
|
355
|
+
},
|
|
356
|
+
"harness": {
|
|
357
|
+
"registryNotEmpty": "реестр «{registry}» не пуст{tag}",
|
|
358
|
+
"registryFinds": "реестр «{registry}» находит {items}{tag}",
|
|
359
|
+
"violator": "нарушитель не проходит{tag}: {name}",
|
|
360
|
+
"oneRecord": "у элемента одна запись — отметка или exceptions/ и outside{tag}",
|
|
361
|
+
"markOneElement": "отметка — в файле одного элемента{tag}",
|
|
362
|
+
"elementFiles": "файлы элементов из fileOf есть на диске{tag}",
|
|
363
|
+
"outside": "вне охвата{tag}: {item}",
|
|
364
|
+
"exception": "исключение{tag}: {item} (#{issue})",
|
|
365
|
+
"exceptionFiles": "исключения — файлом на элемент в exceptions/, а не в exceptions.ts",
|
|
366
|
+
"exceptionJson": "исключения — файлы <элемент>.json в exceptions/ папки решения",
|
|
367
|
+
"exceptionRules": "исключения с rule — к правилам инвариантов папки",
|
|
368
|
+
"markRules": "отметки с rule — к правилам инвариантов папки",
|
|
369
|
+
"badExample": "у правила {rule} есть пример «нельзя»",
|
|
370
|
+
"bad": "нельзя",
|
|
371
|
+
"good": "можно",
|
|
372
|
+
"outsideExample": "вне охвата",
|
|
373
|
+
"codeFiles": "в {dirs} есть файлы кода",
|
|
374
|
+
"lintExceptions": "исключения в {file}: {rules}{issues}",
|
|
375
|
+
"knip": {
|
|
376
|
+
"files": "нет файлов без потребителя",
|
|
377
|
+
"exports": "нет экспортов без потребителя",
|
|
378
|
+
"types": "нет типов без потребителя",
|
|
379
|
+
"dependencies": "нет зависимостей без импорта",
|
|
380
|
+
"unlisted": "нет импортов неустановленных пакетов",
|
|
381
|
+
"unresolved": "нет нерезолвящихся импортов",
|
|
382
|
+
"enumMembers": "нет членов перечислений без потребителя",
|
|
383
|
+
"nsMembers": "нет членов пространств имён без потребителя",
|
|
384
|
+
"duplicates": "нет экспортов-дублей",
|
|
385
|
+
"binaries": "нет вызовов неустановленных бинарников",
|
|
386
|
+
"catalog": "нет лишних записей каталога пакетов",
|
|
387
|
+
"catalogReferences": "нет ссылок на отсутствующие записи каталога пакетов",
|
|
388
|
+
"known": "все находки knip — известных видов{tag}",
|
|
389
|
+
"hints": "нет подсказок конфигурации knip{tag}"
|
|
390
|
+
},
|
|
391
|
+
"ignoreNoReason": "вне охвата без причины: {items}",
|
|
392
|
+
"env": {
|
|
393
|
+
"inCode": "переменные окружения в коде",
|
|
394
|
+
"declaredName": "{name} объявлена",
|
|
395
|
+
"undeclared": "переменная без объявления",
|
|
396
|
+
"declared": "объявленные переменные окружения",
|
|
397
|
+
"readName": "{name} читается в коде",
|
|
398
|
+
"unread": "объявлена и не читается"
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
"architecture": {
|
|
402
|
+
"dirsRegistry": "каталоги кода",
|
|
403
|
+
"dirName": "каталог {dir} — в модуле {module}",
|
|
404
|
+
"dirViolator": "каталог вне модулей",
|
|
405
|
+
"workspaceRegistry": "пакеты workspace",
|
|
406
|
+
"workspaceName": "пакет workspace {path} — в корнях кода",
|
|
407
|
+
"workspaceViolator": "пакет workspace вне корней",
|
|
408
|
+
"importsRegistry": "внешние пакеты модулей",
|
|
409
|
+
"importsName": "{module} импортирует {package}",
|
|
410
|
+
"importsViolator": "пакет, не разрешённый модулю",
|
|
411
|
+
"allowedRegistry": "разрешённые пакеты модели",
|
|
412
|
+
"allowedName": "{module} использует разрешённый пакет {package}",
|
|
413
|
+
"allowedViolator": "разрешённый пакет без импорта",
|
|
414
|
+
"containersRegistry": "модули в контейнерах",
|
|
415
|
+
"libraryName": "библиотека {module} — в контейнерах {containers}",
|
|
416
|
+
"moduleName": "модуль {module} — в контейнере {container}",
|
|
417
|
+
"containersViolator": "модуль вне контейнеров",
|
|
418
|
+
"edgesRegistry": "зависимости модулей",
|
|
419
|
+
"edgeName": "зависимость {from} → {to} — внутри контейнера",
|
|
420
|
+
"edgeViolator": "зависимость через контейнер",
|
|
421
|
+
"unitsRegistry": "развёртываемые единицы",
|
|
422
|
+
"unitName": "развёртываемая единица {unit} — контейнер {container}",
|
|
423
|
+
"unitViolator": "единица вне модели",
|
|
424
|
+
"clientsRegistry": "клиенты хранилищ в контейнерах",
|
|
425
|
+
"clientName": "клиент {package} хранилища {storage} — в контейнере {container}",
|
|
426
|
+
"clientViolator": "клиент без связи",
|
|
427
|
+
"hostsRegistry": "хосты внешних систем",
|
|
428
|
+
"hostName": "хост {host} — только в {adapters}",
|
|
429
|
+
"hostPerimeter": "хост {host} внешней системы {system} — не в коде: адаптера нет",
|
|
430
|
+
"hostViolator": "хост вне модели",
|
|
431
|
+
"inAdapter": "адаптере {list}",
|
|
432
|
+
"inAdapters": "адаптерах {list}",
|
|
433
|
+
"packagesRegistry": "пакеты внешних систем",
|
|
434
|
+
"packageName": "пакет {package} внешней системы {system} — только у {adapters}",
|
|
435
|
+
"packagePerimeter": "пакет {package} внешней системы {system} — ни у одного модуля: адаптера нет",
|
|
436
|
+
"packageViolator": "пакет без адаптера",
|
|
437
|
+
"withAdapter": "адаптера {list}",
|
|
438
|
+
"withAdapters": "адаптеров {list}",
|
|
439
|
+
"envRegistry": "ключи окружения внешних систем",
|
|
440
|
+
"envNoun": "ключ",
|
|
441
|
+
"headersRegistry": "заголовки внешних систем",
|
|
442
|
+
"headerNoun": "заголовок",
|
|
443
|
+
"readName": "{noun} {key} внешней системы {system} читает только адаптер {list}",
|
|
444
|
+
"readNameMany": "{noun} {key} внешней системы {system} читают только адаптеры {list}",
|
|
445
|
+
"readPerimeter": "{noun} {key} внешней системы {system} — не в коде: адаптера нет",
|
|
446
|
+
"readViolator": "{noun} вне адаптера"
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|