@rt-tools/agent-kit 0.19.0 → 0.20.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.
@@ -241,7 +241,7 @@ function checkEvicted(pull, options) {
241
241
  * своей задачи; сверка же смотрит на состояние очереди целиком.
242
242
  *
243
243
  * Четыре PR так и простояли черновиками двое суток — разбор
244
- * `docs/postmortems/2026-08-18-ready-work-left-in-drafts.md`.
244
+ * запись «2026-08-18-ready-work-left-in-drafts» в приёме.
245
245
  */
246
246
  function checkReadyDraft(pull, options) {
247
247
  if (pull.isDraft !== true) {
@@ -266,7 +266,7 @@ function checkReadyDraft(pull, options) {
266
266
  *
267
267
  * Судится только прямое «конфликтует»: `UNKNOWN` означает, что хостинг сливаемость ещё считает,
268
268
  * и строка о нём краснела бы на каждой свежей вершине. Две заявки так и ушли в разбор с
269
- * конфликтом — разбор `docs/postmortems/2026-08-20-drafts-cleared-without-re-reading-pr-state.md`.
269
+ * конфликтом — разбор запись «2026-08-20-drafts-cleared-without-re-reading-pr-state» в приёме.
270
270
  */
271
271
  function checkConflicting(pull) {
272
272
  if (pull.mergeable !== 'CONFLICTING') {
@@ -6,7 +6,7 @@
6
6
  * паттерн до последнего раздела, следующего движения в нём нет, и ход кончается
7
7
  * отчётом. Так простояло состояние «замысел записан» — оно встречалось один раз,
8
8
  * клеткой таблицы, и дыру нашло происшествие, а не проверка. Разбор —
9
- * `docs/postmortems/2026-08-21-turn-ended-at-the-written-plan.md`.
9
+ * запись «2026-08-21-turn-ended-at-the-written-plan» в приёме.
10
10
  *
11
11
  * Сверяются два множества в обе стороны:
12
12
  * перечень — таблица состояний в правиле ведения работы: имя и ведущий паттерн;
@@ -121,8 +121,13 @@ skill_for_default() {
121
121
  # скриптов зависимостью не является, и правило про версии на неё не вступает.
122
122
  # Оговорка: удаление зависимости приходит правкой без номера версии и сюда не
123
123
  # попадает — его ловит снимок дерева, который правится тем же коммитом.
124
+ # Своя редакция зависимостью не является: строка `"version"` в собственном
125
+ # манифесте говорит о выпуске этого пакета, а не о чужой версии, которую он
126
+ # тянет. Признак номера её ловил наравне с зависимостью, и подъём своей версии
127
+ # вёл исполнителя в правило о чужих версиях — не туда, где сказано, как выпускают.
124
128
  */package.json)
125
- printf '%s' "$written" | grep -qE '"(dependencies|devDependencies|peerDependencies|optionalDependencies|overrides|resolutions|packageManager)"|"[^"]+"[[:space:]]*:[[:space:]]*"[~^]?[0-9]+\.[0-9]+' \
129
+ printf '%s' "$written" | grep -v '"version"[[:space:]]*:' \
130
+ | grep -qE '"(dependencies|devDependencies|peerDependencies|optionalDependencies|overrides|resolutions|packageManager)"|"[^"]+"[[:space:]]*:[[:space:]]*"[~^]?[0-9]+\.[0-9]+' \
126
131
  && printf '%s\n' 'dependencies' ;;
127
132
  */pnpm-lock.yaml | */pnpm-workspace.yaml | */package-lock.json) printf '%s\n' 'dependencies' ;;
128
133
 
@@ -17,6 +17,14 @@
17
17
  # интерпретатора, будет отбита наравне с командой правки. Узкий список стоил бы дороже —
18
18
  # пропущенная форма записи возвращает обход целиком, а найти её можно только промахом.
19
19
  #
20
+ # Удаление и перенос стоят в списке нарочно, а не по недосмотру. Снятие файла — правка
21
+ # разрушительнее любой записи: записанное видно в дереве и откатывается, а снятое без замысла не
22
+ # оставляет следа вовсе, и восстанавливать его приходится из истории. Цена этого выбора известна
23
+ # и платится не там, где её ждут: своё временное, положенное под корнем кода, снимается командой,
24
+ # и гард судит это правкой приложения — требует замысла на диске за действие, к приложению не
25
+ # относящееся. Отличить одно от другого признак не может: путь у обоих лежит под тем же корнем.
26
+ # Лечится это местом, а не признаком, — и сказано об этом ловушкой правила ведения работы.
27
+ #
20
28
  # Перенаправление в пустое устройство и в поток ошибок снимается до разбора: файла оно не
21
29
  # пишет, а выглядит как перенаправление в файл. Так глушат вывод команды чтения, и без этого
22
30
  # `grep -rn x libs/ 2>/dev/null` судится наравне с записью — правило требуется на чтение, а
@@ -40,9 +40,18 @@ transcript="$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/nu
40
40
 
41
41
  root="${CLAUDE_PROJECT_DIR:-.}"
42
42
 
43
- # Каталог записей у дерева свой. Заданный пустым отказ дерева от требования: дереву, которое
44
- # записей не ведёт, гард не навязывается.
45
- notes_dir="${RT_POSTMORTEMS_DIR-docs/postmortems}"
43
+ # Каталог записей у дерева свой, и называет его настройка дерева тем же ключом, каким его
44
+ # читает отправка груза. Одно имя на обе стороны: дерево, унёсшее каталог из истории, иначе
45
+ # получало бы гард, ищущий записи по прежнему адресу, — и тот молчал бы всегда. Переменная
46
+ # остаётся обходом на один запуск, а пустая строка в любой из двух — отказ дерева от требования:
47
+ # дереву, которое записей не ведёт, гард не навязывается.
48
+ if [ -n "${RT_POSTMORTEMS_DIR+set}" ]; then
49
+ notes_dir="$RT_POSTMORTEMS_DIR"
50
+ elif [ -f "$root/.claude/rt-kit.json" ]; then
51
+ notes_dir="$(jq -r '.postmortems // "docs/postmortems"' "$root/.claude/rt-kit.json" 2>/dev/null)"
52
+ else
53
+ notes_dir="docs/postmortems"
54
+ fi
46
55
  [ -z "$notes_dir" ] && exit 0
47
56
  [ -d "$root/$notes_dir" ] || exit 0
48
57
 
@@ -166,7 +166,7 @@ work_re='git (add|commit|push|checkout|merge|rm)|npm run|pnpm (run|exec)|nx (bui
166
166
  # подтягивание, просмотр истории, чтение заявок и прогонов. Образец работы называет их работой,
167
167
  # потому что знает только первое слово — `git` и `gh` стоят в нём целиком, — и ход, в котором
168
168
  # исполнитель перешёл на главную ветку, прочитал историю и написал владельцу отчёт, выходил
169
- # отсюда нулём. Разбор — `docs/postmortems/2026-08-25-read-only-turn-counted-as-work.md`.
169
+ # отсюда нулём. Разбор — запись «2026-08-25-read-only-turn-counted-as-work» в приёме.
170
170
  #
171
171
  # Разведка выглядит работой лучше всего остального: в ней команды, числа и точные ответы. Тем
172
172
  # она и опасна — ход, набитый ею, читается как полный и владельцем, и самим заходом.
@@ -179,7 +179,7 @@ part_re='&&|\|\||;|\n'
179
179
  # Ожидание чужого шага. Прогон, разбор владельцем и слияние идут без исполнителя и от взгляда
180
180
  # быстрее не становятся — правило прямо говорит, что состоянием работы это не бывает. Судится
181
181
  # только ПОСЛЕДНЕЕ действие хода: ожидание в середине законно, а запуск работы в фоне работой
182
- # остаётся. Разбор — `docs/postmortems/2026-08-25-turn-ended-on-waiting.md`.
182
+ # остаётся. Разбор — запись «2026-08-25-turn-ended-on-waiting» в приёме.
183
183
  #
184
184
  # Прежний признак спрашивал одно: была ли за ход работа. Ход, где разобран конфликт, сделаны
185
185
  # коммит и пуш, а последним действием стал цикл до готовности прогона, проходил его целиком —
@@ -264,7 +264,7 @@ commands="$(printf '%s' "$verdict" | jq -r '.ran // ""' 2>/dev/null)"
264
264
  # Ровно так ход и вставал: задача взята, номер назван владельцу, отчёт написан — и следующее
265
265
  # действие состояния «задача-взята», написать замысел, не сделано. Отчёт выглядит работой лучше
266
266
  # всякой другой, а страж, знающий только «была ли за ход работа», подтверждает это: работа была.
267
- # Разбор — `docs/postmortems/2026-08-25-task-taken-and-turn-ended.md`.
267
+ # Разбор — запись «2026-08-25-task-taken-and-turn-ended» в приёме.
268
268
  #
269
269
  # Папка, разобранная коммитом ветки, сюда не попадает: `archived` означает отданную работу, и её
270
270
  # судит прежний ярус. Ветка без номера задачи не судится вовсе — под пробу заводят и такие.
@@ -332,7 +332,7 @@ fi
332
332
  # вся она по сданной задаче: отдача завершает прошлую работу, а не ход. Девять разборов
333
333
  # происшествий за сутки описывают девять разных остановок, и во всех девяти последним действием
334
334
  # хода был текст владельцу: отчёт, сводка, объявление намерения.
335
- # Разбор — `docs/postmortems/2026-08-25-handover-turn-ends-on-intent.md`.
335
+ # Разбор — запись «2026-08-25-handover-turn-ends-on-intent» в приёме.
336
336
  if [ "$handed_over" = "true" ] && [ "$started_next" != "true" ]; then
337
337
  reason="BLOCKED by turn-exit-guard: заявка открыта, а по следующей работе за этот ход не сделано ничего.
338
338
 
@@ -385,7 +385,7 @@ fi
385
385
  # Работа, оставшаяся в рабочем дереве. Ветка ушла вперёд своей удалённой ссылки, а заявки при
386
386
  # ней в этом ходе не открывали: сделанное лежит там, где его не видит никто, кроме сделавшего.
387
387
  # Признак читается без сети и молчит там, где ссылки нет вовсе — под пробу заводят и такие ветки.
388
- # Разбор — `docs/postmortems/2026-08-25-fifteen-branches-over-one-index.md`.
388
+ # Разбор — запись «2026-08-25-fifteen-branches-over-one-index» в приёме.
389
389
  if [ "$worked" = "true" ] && [ "$handed_over" != "true" ]; then
390
390
  unpushed="$(git -C "$root" rev-list --count '@{u}..HEAD' 2>/dev/null)"
391
391
  if [ -n "$unpushed" ] && [ "$unpushed" -gt 0 ] 2>/dev/null; then
@@ -133,6 +133,23 @@ PR описывал дерево на день, когда его написал
133
133
  что ветка везёт теперь, и прогон идёт заново: зелёные задания прошлого прогона после вливания не
134
134
  значат ничего.
135
135
 
136
+ ## Чужие папки задач приезжают вместе с главной веткой
137
+
138
+ Мерж главной ветки везёт всё, что в неё влилось, — включая папки задач соседних работ, если те
139
+ уехали в главную неразобранными. В своей ветке они выглядят как своё: лежат в том же каталоге,
140
+ названы тем же порядком, и разбирать их отсюда некому.
141
+
142
+ Кнопку слияния при этом нажимает человек, а там, где он это делает, хуков нет: гард, стерегущий
143
+ разбор папки, до этого пути не достаёт. Поэтому сверка очереди работ гоняется сразу после мержа
144
+ главной, а не перед пушем:
145
+
146
+ ```bash
147
+ npm run check:board
148
+ ```
149
+
150
+ Она называет папку, у которой нет открытой задачи, — это и есть приехавшая чужая. Своей рукой
151
+ она не разбирается: снимает её тот, чья это работа, и делает это в своей ветке.
152
+
136
153
  ## Частые промахи
137
154
 
138
155
  - «Сохранить обе стороны» применено ко всем файлам одинаково: в спеке это верно, в коде и в
@@ -20,6 +20,16 @@ description: Паттерн правила task-flow. Брать, когда т
20
20
 
21
21
  ## Состояние `разбор-кончился`: папка задачи разбирается
22
22
 
23
+ Разбор здесь свой, а не чужой: имя состояния говорит о папке задачи, которую разбирают
24
+ следующим шагом, — не о заявке, которую читает ревьювер, и не о просьбе владельца, с разбора
25
+ которой работа начиналась. Слово одно на три дела, и на беглом чтении имя выглядит чужим шагом:
26
+ исполнитель говорил владельцу, что ждёт разбора, и брался за следующую задачу, а готовая работа
27
+ стояла лишний ход и возвращалась в работу рукой владельца.
28
+
29
+ Ждать при этом состоянии нечего. Вход в него — два признака, оба читаются в дереве: набор
30
+ зелёный и тексты приведены. Одобрение владельца входом не является, и работа, ждущая его при
31
+ сошедшихся признаках, стоит зря.
32
+
23
33
  Разбор идёт по трём исходам, а не по двум.
24
34
 
25
35
  **Первым отбирается действующее требование.** Всё, что останется верным и завтра, становится
@@ -161,6 +171,14 @@ npm run cargo:mark -- --state fixed \
161
171
  замеченная не разбором, а по ходу работы. Работа вне эпика показывает находки владельцу тем же
162
172
  ходом.
163
173
 
174
+ **Имя файла находок собирается из имени замысла, а не выдумывается заходом.** Файл — это
175
+ `<имя замысла>-findings.md` рядом с самим замыслом: замысел `<тема>.md` копит находки в
176
+ `<тема>-findings.md`. Имя, выбранное на месте, читается только тем заходом, который его дал:
177
+ следующий ищет находки этого эпика перебором каталога замыслов и, не найдя, заводит второй
178
+ файл о том же — а владелец читает один из двух. Постоянного места здесь мало: у каждого эпика
179
+ свой файл, и находит его по имени тот, кто пришёл к замыслу, а не к каталогу. Форма файла —
180
+ образец находок среди образцов пакета.
181
+
164
182
  **Находки, вернувшиеся после того, как ветка ушла, едут веткой следующей задачи.** Пуш в снятую
165
183
  ветку её не обновляет, а заводит заново: коммит остаётся вне главной ветки и пропадает вместе
166
184
  с ней. Следующая задача к этому времени уже взята — её веткой уборка за предыдущей и едет.
@@ -172,6 +190,15 @@ npm run cargo:mark -- --state fixed \
172
190
  деление идёт задним числом, вместе с правкой ссылок на файл. Не влезает — заводится следующая
173
191
  часть, и раздел пишется сразу в неё.
174
192
 
193
+ **Часть называется задачей, которая её завела, а не своим порядковым номером.** Имя —
194
+ `<имя замысла>-findings-<КЛЮЧ>-<номер>.md`. Один эпик ведут несколько рабочих деревьев разом, и
195
+ «следующая часть» каждое из них видит своей: две ветки заводят файл с одним именем, а
196
+ столкновение обнаруживается только при вливании главной ветки — конфликтом на весь файл, где обе
197
+ стороны верны и сложением не разрешаются. Номер задачи занят ею одной, и достаться двум деревьям
198
+ он не может. Первая часть номера не несёт и задним числом не переименовывается: переименование
199
+ правит ссылки во всех текстах, которые на неё смотрят, ради ровного ряда имён. Порядок между
200
+ частями не нужен — находки друг друга не продолжают, и владелец читает их разом.
201
+
175
202
  **Наружу без слова владельца уезжает только сводка наблюдений.** Она говорит, чем пользовались
176
203
  и чем не пользовались ни разу, — это факт, и мнением он не станет. Предложение — другое дело:
177
204
  это заготовка правки чужого дерева, и часть заготовок отпадает при первом же чтении. Уехавшая
@@ -100,6 +100,8 @@ mkdir -p <каталог передачи>
100
100
 
101
101
  Что учесть в этом заходе:
102
102
 
103
+ - разбор работы правилами по <КЛЮЧ>-<номер> запущен фоном и не вернулся — находки писать в
104
+ `<имя замысла>-findings.md` рядом с замыслом эпика;
103
105
  - стенды уже подняты владельцем, свой не поднимать;
104
106
  - зависимости этого дерева отстают от главной ветки — при падении сборки на чужой ошибке
105
107
  сперва установка зависимостей;
@@ -137,7 +139,15 @@ mkdir -p <каталог передачи>
137
139
  4. **Сделано и следующий шаг** — одной строкой каждое; подробности уже в ходе работы.
138
140
  5. **Что учесть** — особенности этого захода, которых нет ни в правилах, ни в ходе работы:
139
141
  поднятые стенды, отставшие зависимости, чужие процессы на портах, незакрытые вопросы к
140
- владельцу.
142
+ владельцу, запущенный фоном и не вернувшийся разбор.
143
+
144
+ **Разбор, запущенный фоном и не вернувшийся к концу захода, называется строкой в «Что учесть».**
145
+ Отвечает роль в переписку, а переписки к следующему заходу уже нет: ответ, пришедший после
146
+ закрытия, не читает никто, и находки пропадают целиком вместе с тем, ради чего разбор и
147
+ запускали. На диске следа тоже нет — файл находок пишет исполнитель по ответу, а ответа ещё не
148
+ было. Строка называет задачу, по которой разбор идёт, и файл, куда писать вернувшееся: без
149
+ второго следующий заход знает, что чего-то ждёт, и не знает, куда это класть. Своего раздела
150
+ разбору не заводится — в заходе, где его не запускали, раздел стоял бы пустым.
141
151
 
142
152
  ### Путь владельцу
143
153
 
@@ -188,3 +188,8 @@ git log --oneline origin/main..HEAD
188
188
  слово стоит на месте: «семь» простояло над восемью перечисленными до самого итога и поехало бы
189
189
  дальше — в отчёт и в замысел эпика. Пишется либо перечень без числа, либо число, посчитанное
190
190
  тем же ходом, каким пишется итог.
191
+ - **Красный набор на ветке, не тронувшей ни строки кода, спрашивается у соседних заходов раньше,
192
+ чем у своей правки.** Стенд у прогонов один на машину: соседний заход, поднявший его под себя,
193
+ роняет чужой набор, и падение выглядит поломкой среды. Прочитанное так, оно заводит второй
194
+ заход на то же место — чинить то, что не ломалось. Порядок обратный: сперва читаются соседние
195
+ заходы и занятые порты, и только потом своя правка.
@@ -193,7 +193,7 @@
193
193
  же, чего гард и добивается.
194
194
  - **Свои черновики судятся все разом.** Уход в соседнюю ветку выключал гард целиком: за один
195
195
  заход так разошлись с главной четыре заявки подряд, и заметил это владелец, а не проверка.
196
- Разбор — `docs/postmortems/2026-08-25-run-left-unwatched.md`.
196
+ Разбор — запись «2026-08-25-run-left-unwatched» в приёме.
197
197
  - **Подпись машинной записи на каждом коммите вклада.** Пять коммитов одной стопки уехали
198
198
  подписанными владельцем, который правки не делал: гард судит только коммит, назвавшийся
199
199
  машинной записью, и ищет расхождение в числе служебного адреса.
@@ -219,3 +219,8 @@
219
219
  ни статус, ни сверка, а команда, прошедшая между прятаньем и возвратом, пишет в те же файлы —
220
220
  и возврат встаёт конфликтом. Так ушли в прятанье восемь незакоммиченных файлов при живом
221
221
  запрете на эту команду: запрет читался в начале захода, а команда набиралась через сорок ходов.
222
+ - **Очередь конвейера, заведённая на всё дерево, снимает ждущего чужим пушем.** Группа
223
+ одновременности с отменой уже идущего экономит машину ровно до первого соседа: его пуш снимает
224
+ прогон чужой ветки, и та остаётся с вершиной без единого прогона — заявка при этом выглядит
225
+ непроверенной, а прогонять её заново некому. Группа поэтому заводится своя на ветку, и общей
226
+ остаётся только у шагов, которым нужен стенд: их и правда нельзя гнать вдвоём на одной машине.
@@ -34,6 +34,14 @@
34
34
  его привязка перестают находиться друг по другу. После разрешения гоняется
35
35
  `npm run check:specs` — конфликт в спеке кода не задевает, и ни сборка, ни линтеры его не
36
36
  увидят.
37
+ - **Сложение отвечает на две дописи, а не на снятие: сторона, у которой текста нет вовсе, тоже
38
+ правка.** Раздел, вынесенный в описание прошлого или свёрнутый в правило, сложением
39
+ возвращается обратно — один абзац встаёт в двух редакциях, и снятая читается как
40
+ действующая. Случай не редкий: он приходит ровно тогда, когда снятия потребовал сам слой
41
+ правил, а ветки, начатые раньше, несут прежнюю редакцию. Признак прямой — у одной стороны
42
+ текста нет; тогда конфликт решается тем, что с разделом сделали, а не сложением. Снятое
43
+ остаётся снятым, а допись второй стороны переезжает туда, куда уехал раздел, — или не
44
+ переезжает вовсе, если уехал он потому, что стал правилом.
37
45
 
38
46
  - **Строку требования к соседнему ресурсу не проверяет ничто, и расхождение видно только
39
47
  счётом.** Правило без неё выглядит целым: разделы на месте, привязки сходятся, сверка
@@ -81,6 +81,14 @@
81
81
  задание, он даёт заходу работу, которой владелец не просил. То же с любой репликой без
82
82
  глагола: спросить, что с этим делать, дешевле, чем написать полсотни файлов мимо просьбы.
83
83
 
84
+ - **Своё временное кладётся вне дерева кода — иначе его снятие судится как правка приложения.**
85
+ Признак записи, которым гарды судят команду оболочки, считает записью и удаление, и это в нём
86
+ нарочно: снятое без замысла не оставляет следа вовсе. Отличить свой временный каталог от
87
+ каталога домена признаку нечем — путь у обоих под тем же корнем, — поэтому гард требует
88
+ замысла на диске за уборку черновика, к приложению не относящуюся. Каталог для своего
89
+ временного называет профиль дерева, и лежит он вне дерева кода; положенный внутрь, он платит
90
+ этим отказом при каждой уборке.
91
+
84
92
  - **Тело задачи, написанное вперёд замысла, называет способ, и способ стареет раньше дефекта.**
85
93
  Задача серии заводится за недели до того, как её берут, и к этому дню предложенный ход бывает
86
94
  уже неверен: привезённое пакетом умеет то, что задача звала написать, названного места в
@@ -201,3 +209,8 @@
201
209
  — сперва на отказе конца хода, потом на переводе колонки, и оба раза номер дописывался заново.
202
210
  Место такому разрешению там же, где передача захода: оно не откатывается вместе с правкой и не
203
211
  принадлежит ни одной задаче.
212
+ - **Задача, вынесенная в другой эпик, снимается из состава прежнего тем же ходом.** Вынос — два
213
+ движения, и сделанное наполовину оставляет задачу в двух составах сразу: итог прежнего эпика
214
+ считается по числу, которого в нём уже нет, и эпик выглядит незакрытым при всех сделанных
215
+ работах. Итог вписывается там же, где правится состав: отложенный, он пишется по памяти о том,
216
+ сколько задач было, а не о том, сколько осталось.
@@ -38,6 +38,15 @@
38
38
  - **Первому прогону сразу после установки браузера верить нельзя.** Два падения сквозного
39
39
  набора не повторились ни при отдельном прогоне тех же тестов, ни при втором полном. Такой
40
40
  прогон повторяют, а выводы делают по второму.
41
+ - **Повторный прогон через гейт пуша повторяет весь набор, а не упавший тест.** Гейт гоняет то,
42
+ что перечислил профиль дерева, целиком и с нуля: у сквозного набора это минуты, и каждая
43
+ попытка пуша стоит их заново. Соседняя ловушка верна ровно до этого места: повторить дёшево —
44
+ через гейт уже нет, и «повторить» превращается в «пушить, пока не пройдёт». Полный набор
45
+ поэтому гоняется руками до вызова пуша, а гейт только подтверждает уже известное. Тест,
46
+ упавший в полном наборе и прошедший при отдельном прогоне, зелёным не считается: это
47
+ нестабильный тест, и он заводится задачей тем же ходом. Прогон до зелёного уносит признак
48
+ вместе с падением, и следующий заход встречает то же самое как новость — а отличить чужую
49
+ нестабильность от своей регрессии ему нечем: оба случая выглядят одинаково.
41
50
  - Сквозная спека, которой нужен вход, без учётных данных в окружении пропускается молча — в
42
51
  отчёте она значится `skipped`, и прогон выглядит успешным. Имена переменных — при дереве.
43
52
  - **Справочник флоу вторых сценариев не заводит.** В `docs/E2E_<ДОМЕН>_FLOWS.md` кладут то,
@@ -80,3 +80,11 @@
80
80
  в него, встаёт целиком там, где мимо него шло ещё несколько ходов дела. Делается всё, что от
81
81
  разрешения не зависит, а несделанное называется в теле заявки, разделом об оставшемся шаге:
82
82
  он ровно про это и написан.
83
+ - **Ответ на реплику владельца, пришедшую посреди хода, ход не кончает.** Выход «вопрос
84
+ владельцу» — про вопрос ОТ исполнителя; обратный случай под него не подходит вовсе, и
85
+ прочитанный так, он превращает каждую реплику владельца в конец захода. За один заход это
86
+ стоило трёх остановок подряд: владелец спрашивал, исполнитель отвечал и вставал.
87
+ - **Работа не гейтится на подтверждение, которого владелец не обещал.** «Скажи — и я сделаю»
88
+ переносит ход к владельцу без его согласия: он не просил, чтобы у него спрашивали, и ответа с
89
+ него никто не ждал. Выглядит это вежливостью, а не остановкой, и потому не читается как
90
+ остановка ни исполнителем, ни им.
@@ -103,7 +103,11 @@ npx agent-kit propose # отправить груз в приём: сво
103
103
  cp -r node_modules/@rt-tools/agent-kit/assets /tmp/agent-kit-assets-<прежняя версия>
104
104
  ```
105
105
 
106
- 2. **Установка и раскладка.** Обычным порядком.
106
+ 2. **Установка и раскладка.** Обычным порядком. Раскладка кладёт ту редакцию, которая **установлена**,
107
+ а не ту, что объявило дерево: перепутать их легко — установленная остаётся от соседней ветки,
108
+ где её как раз поднимали, и ложится целиком, молча, с тем же успешным выходом. Расхождение
109
+ точного номера раскладка отбивает сама и называет обе редакции; починка — поставить
110
+ зависимости и повторить вызов.
107
111
  3. **Сверка замещённых разделов по снимку.** Какие разделы замещены, называет `doctor` — строкой
108
112
  «замещено надстройками разделов» и перечнем «ресурс · заголовок». Каждый из них читается в
109
113
  снимке и в новой редакции: что пакет дописал, дописывается в надстройку руками.
@@ -0,0 +1,27 @@
1
+ # Находки эпика <о чём он>
2
+
3
+ <Копятся здесь, у замысла эпика: папка задачи умирает со слиянием, а находки владелец читает
4
+ разом, когда эпик кончился. Имя файла — имя замысла с хвостом `-findings`, и лежит он рядом с
5
+ самим замыслом.
6
+
7
+ Раздел на задачу, строка на находку. Каждая называет адрес — слой правил, имена этого дерева
8
+ или надстройку над разложенным: без адреса общее оседает в своём дереве и остаётся неизвестным
9
+ всем остальным.
10
+
11
+ Длина смотрится перед первой написанной строкой: раздел задачи занимает десятки строк, и предел
12
+ длины документа он переходит молча. Не влезает — заводится следующая часть с именем той задачи,
13
+ которая её завела: `<имя замысла>-findings-<КЛЮЧ>-<номер>.md`. Порядкового номера у части нет —
14
+ его каждое рабочее дерево видит своим, и два дерева одного эпика заводят один и тот же файл.>
15
+
16
+ ## <КЛЮЧ>-<номер> — <что делала задача>
17
+
18
+ - **<Находка одной фразой — что не так, а не что надо сделать.>** <Чем подтверждена: число,
19
+ отказ, файл. Что это стоило.> **Адрес:** <слой правил | имена этого дерева — <что именно> |
20
+ надстройка над разложенным>.
21
+
22
+ ## Осталось нерешённым
23
+
24
+ <Находка, по которой правки ещё не было. Названная здесь, она переезжает в закрытые вместе с
25
+ той правкой, которая её закрыла, — а не остаётся числиться живой.>
26
+
27
+ - **<находка>** — <почему не закрыта: ждёт решения владельца, заводится своей задачей, спорна>.
@@ -1 +1 @@
1
- {"version":3,"file":"agent-kit.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":";AAeA,OAAO,EAAqC,iBAAiB,EAAqB,MAAM,oBAAoB,CAAC;AAoW7G,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAU9E"}
1
+ {"version":3,"file":"agent-kit.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":";AAeA,OAAO,EAAqC,iBAAiB,EAAqB,MAAM,oBAAoB,CAAC;AAuW7G,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAU9E"}
package/bin/agent-kit.js CHANGED
@@ -79,6 +79,9 @@ function environmentOf(root) {
79
79
  return {
80
80
  root,
81
81
  version: manifest.version,
82
+ // Имя из манифеста, а не записанное здесь: по нему пакет ищет себя в зависимостях дерева,
83
+ // и своя копия имени разошлась бы с манифестом молча — у всякого, кто пакет переименовал.
84
+ name: manifest.name,
82
85
  assetsDir: join(pkg, 'assets'),
83
86
  // Сверка со своими исходниками возможна только отсюда: здесь пакет знает, где лежит сам.
84
87
  // У потребителя исходников рядом нет, и сверка молчит.
@@ -1 +1 @@
1
- {"version":3,"file":"agent-kit.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAmB,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAgB,IAAI,EAAqB,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC7G,OAAO,EAAE,WAAW,EAAW,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,oBAAoB,EAAS,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAwB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,KAAK,GAAsB;IAC7B,qBAAqB;IACrB,EAAE;IACF,mEAAmE;IACnE,8DAA8D;IAC9D,6DAA6D;IAC7D,+EAA+E;IAC/E,qEAAqE;IACrE,oFAAoF;IACpF,gFAAgF;IAChF,qEAAqE;IACrE,yFAAyF;IACzF,wDAAwD;IACxD,gFAAgF;IAChF,8FAA8F;IAC9F,uEAAuE;IACvE,wEAAwE;IACxE,uFAAuF;IACvF,4FAA4F;IAC5F,mEAAmE;IACnE,EAAE;IACF,gEAAgE;IAChE,EAAE;IACF,2BAA2B;IAC3B,EAAE;IACF,6DAA6D;IAC7D,yEAAyE;IACzE,+DAA+D;IAC/D,EAAE;IACF,8EAA8E;IAC9E,EAAE;IACF,gFAAgF;IAChF,oEAAoE;CACvE,CAAC;AAEF;;;GAGG;AACH,MAAM,aAAa,GAAsB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,aAAa,GAAsB;IACrC,8CAA8C;IAC9C,uEAAuE;IACvE,oEAAoE;CACvE,CAAC;AAEF;;;;GAIG;AACH,SAAS,aAAa,CAAC,IAAY;IAC/B,MAAM,GAAG,GAAW,eAAe,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,QAAQ,GAAsC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAG7G,CAAC;IAEF,OAAO;QACH,IAAI;QACJ,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC;QAC9B,yFAAyF;QACzF,uDAAuD;QACvD,KAAK,EAAE,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC;KACxC,CAAC;AACN,CAAC;AAED,gGAAgG;AAChG,SAAS,OAAO,CAAC,IAAY,EAAE,IAAuB;IAClD,IAAI,CAAC;QACD,8IAA8I;QAC9I,OAAO,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxH,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED,qEAAqE;AACrE,SAAS,WAAW,CAAC,IAAY;IAC7B,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC;SAC3B,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1C,MAAM,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC1B,MAAM,KAAK,GAAsB,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnD,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpF,CAAC;AAED,SAAS,QAAQ,CAAC,IAAuB,EAAE,IAAY,EAAE,QAAgB;IACrE,MAAM,KAAK,GAAW,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzC,OAAO,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtE,CAAC;AAED,MAAM,SAAS,GAAmD,CAAC,KAAc,EAA8B,EAAE,CAC7G,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,CAAC;AAEnE;;;;;GAKG;AACH,KAAK,UAAU,YAAY,CAAC,IAAuB,EAAE,SAAiB;IAClE,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAA+B,WAAW,CAAC,SAAS,CAAC,CAAC;IACnE,MAAM,MAAM,GAAW,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEpD,IAAI,MAAM,EAAE,CAAC;QACT,MAAM,KAAK,GAAa,MAAM;aACzB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1C,MAAM,CAAC,OAAO,CAAC,CAAC;QACrB,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAElE,OAAO,OAAO,CAAC,MAAM;YACjB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,iCAAiC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,8BAA8B,CAAC,EAAE;YAC7G,CAAC,CAAC,GAAG,CAAC;IACd,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACZ,OAAO;YACH,IAAI,EAAE,CAAC;YACP,KAAK,EAAE;gBACH,uCAAuC;gBACvC,mEAAmE;gBACnE,oCAAoC;aACvC;SACJ,CAAC;IACN,CAAC;IAED,MAAM,OAAO,GAAuB,OAAO;SACtC,MAAM,CAAC,CAAC,KAAsB,EAAW,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;SAClE,GAAG,CAAC,CAAC,KAAsB,EAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAExG,OAAO,GAAG,CAAC,OAAO,EAAE,wCAAwC,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAAC,IAAW,EAAE,IAAuB;IAC7D,MAAM,MAAM,GAAW,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAsB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAqB,EAAU,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEpG,IAAI,MAAM,EAAE,CAAC;QACT,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC1B,CAAC,CAAC,MAAM;YACR,CAAC,CAAC;gBACI,IAAI,EAAE,CAAC;gBACP,KAAK,EAAE,CAAC,uBAAuB,IAAI,CAAC,IAAI,qBAAqB,MAAM,EAAE,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aACvG,CAAC;IACZ,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;IACxC,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACZ,OAAO;YACH,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC,uCAAuC,EAAE,yBAAyB,IAAI,CAAC,IAAI,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SACvH,CAAC;IACN,CAAC;IAED,OAAO,MAAM,CACT,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAqB,EAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EACrH,IAAI,CAAC,QAAQ,CAChB,CAAC;AACN,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAuB,EAAE,SAAiB;IACjE,MAAM,IAAI,GAAqB,QAAQ,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,MAAM,GAAsC,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAElF,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC;QAClB,CAAC;QAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;IAC/B,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,oFAAoF;AACpF,KAAK,UAAU,OAAO,CAAC,GAAiB,EAAE,IAAuB;IAC7D,MAAM,SAAS,GAAiD,MAAM,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACxG,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,mCAAmC,CAAC,EAAE,CAAC;IACrE,CAAC;IAED,MAAM,QAAQ,GAAsD,MAAM,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3G,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtB,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,OAAO,QAAQ,KAAK,IAAI;QACpB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,mCAAmC,CAAC,EAAE;QAC3D,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,SAAS,OAAO,CAAC,GAAiB,EAAE,IAAuB;IACvD,MAAM,KAAK,GAAW,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IACnD,IAAI,IAAW,CAAC;IAChB,IAAI,CAAC;QACD,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,OAAgB,EAAE,CAAC;QACxB,IAAI,OAAO,YAAY,oBAAoB,EAAE,CAAC;YAC1C,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,CAAC;QACD,MAAM,OAAO,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED,sEAAsE;AACtE,SAAS,QAAQ,CAAC,GAAiB,EAAE,IAAuB;IACxD,MAAM,MAAM,GAAW,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IAE5D,OAAO,KAAK,CAAC,GAAG,EAAE;QACd,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY;QAC/E,6EAA6E;QAC7E,gFAAgF;QAChF,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAChC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,UAAU,CAAC,GAAiB,EAAE,IAAuB;IAChE,MAAM,OAAO,GAAsB,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAChF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO;YACH,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC,oCAAoC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,aAAa,CAAC;SAC1F,CAAC;IACN,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAClC,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QAC1B,yFAAyF;QACzF,qDAAqD;QACrD,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAC9B,8EAA8E;QAC9E,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KAC/C,CAAC,CAAC;AACP,CAAC;AAED,uDAAuD;AACvD,KAAK,UAAU,SAAS,CAAC,GAAiB,EAAE,IAAuB;IAC/D,MAAM,MAAM,GAAmB,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEpD,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,yBAAyB,WAAW,iCAAiC,CAAC,EAAE,CAAC;IACvG,CAAC;IAED,OAAO,MAAM,CAAC;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;QAClC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;QACrC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC;QACjD,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,IAAI,EAAE,UAAU;KACnB,CAAC,CAAC;AACP,CAAC;AAKD,gFAAgF;AAChF,MAAM,QAAQ,GAA0C;IACpD,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,CAAC,GAAiB,EAAqB,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;IACzD,IAAI,EAAE,CAAC,GAAiB,EAAE,IAAuB,EAAqB,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC5G,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,QAAQ;IACf,OAAO,EAAE,UAAU;IACnB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,CAAC,GAAiB,EAAqB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAiB,EAAE,IAAuB,EAAqB,EAAE,CACrE,KAAK,CACD,GAAG,EACH,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAa,EAAW,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CACtH;CACR,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAuB;IAC9C,MAAM,OAAO,GAAW,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,MAAM,GAAG,GAAiB,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1F,MAAM,GAAG,GAA4B,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEtG,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,wBAAwB,OAAO,GAAG,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAClH,CAAC;IAED,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,OAAO,GAAsB,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAC/B,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * Точка входа. Разбирает аргументы, добывает выбор проекта, зовёт команду и печатает то, что\n * она вернула. Своей работы у неё нет: всё, что решает, живёт в `commands.ts` и проверяется\n * спеками — кроме одного, чего команде знать не по чину: откуда взялся выбор законов. У строки\n * запуска это флаг, у терминала — вопрос, у прогона без терминала нет ни того ни другого.\n */\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport process from 'node:process';\n\nimport { unknownFlagsIn } from '../lib/argv.js';\nimport { IEntryOfCatalog, readCatalog, resolveSelection } from '../lib/catalog.js';\nimport { adopt, doctor, IEnvironment, init, IOutcomeOfCommand, list, stats, sync } from '../lib/commands.js';\nimport { CONFIG_PATH, IConfig, readConfig } from '../lib/config.js';\nimport { costLines, costOf, CostUnavailableError, ICost } from '../lib/cost.js';\nimport { enroll, httpEnroll } from '../lib/enroll.js';\nimport { httpShip } from '../lib/ship.js';\nimport { propose, treeSlugOf } from '../lib/shipment.js';\nimport { DEFAULT_DAYS } from '../lib/observations.js';\nimport { staleBuild } from '../lib/freshness.js';\nimport { packageRootFrom } from '../lib/package-root.js';\nimport { IChoice } from '../lib/picker.js';\nimport { IAxis, IOptionOfAxis, readAxes } from '../lib/variants.js';\nimport { ask, askOne, canAsk } from './prompt.js';\n\nconst USAGE: readonly string[] = [\n 'agent-kit <команда>',\n '',\n ' init завести .claude/rt-kit.json и каталог надстроек',\n ' list что везёт пакет и что из этого взято здесь',\n ' sync разложить ресурсы пакета в дерево проекта',\n ' sync --check ничего не писать, отказать при расхождении — для гейта пуша',\n ' doctor рассказать о состоянии раскладки, ничего не меняя',\n ' cost посчитать цену контекста: вход в работу, одно правило, весь слой',\n ' cost --rule <имя> какое правило взвесить; без довода берётся самое тяжёлое',\n ' cost --json то же машиночитаемо — этим числа кладут в замысел',\n ' stats свести наблюдения: чем пользовались, чем ни разу, обо что спотыкались',\n ' stats --days N за сколько дней; без довода — за три',\n ' stats --json то же машиночитаемо — этим сводку прикладывают к предложению',\n ' propose отправить груз в приём: сводку со снимком надстроек, предложения и разборы',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' adopt [файлы] отдать пакету файлы, лежащие на его путях не от него',\n ' enroll --code <код> завести дерево по приглашению владельца: обмен кода на токен',\n ' enroll --token <токен> завести дерево токеном, выданным в админке приёма; в сеть не идёт',\n ' enroll --force перезаписать уже лежащий токен намеренно',\n '',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n '',\n 'Выбор законов при `init`:',\n '',\n ' --all взять все законы, ни о чём не спрашивая',\n ' --laws a,b,c взять только названные; имена — из `agent-kit list`',\n ' без обоих спросить галочками; без терминала — отказ',\n '',\n 'Вид ресурсов при `init` — там, где один закон исполняется разными командами:',\n '',\n ' --<ось> <вид> например `--host gitlab`; оси и виды — из `agent-kit list`',\n ' без флага спросить; без терминала — отказ, кроме `--all`',\n];\n\n/**\n * Доводы отправки. Довод со значением помечен `<>`: за ним идёт отдельным словом путь, и без\n * пометки этот путь читался бы как ещё один незнакомый довод.\n */\nconst PROPOSE_FLAGS: readonly string[] = ['--dry-run', '--root <>'];\n\n/** Что печатает отказ на незнакомом доводе: режимы команды, а не весь свод. */\nconst PROPOSE_USAGE: readonly string[] = [\n ' propose отправить груз в приём',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n];\n\n/**\n * Единственное место, где пакет узнаёт собственное расположение. `import.meta` живёт только\n * здесь: библиотечные модули получают каталог ресурсов входным значением, и трансформ тестов,\n * разбирающий модули как CommonJS, на них уже не спотыкается.\n */\nfunction environmentOf(root: string): IEnvironment {\n const pkg: string = packageRootFrom(dirname(fileURLToPath(import.meta.url)));\n const manifest: { name: string; version: string } = JSON.parse(readFileSync(join(pkg, 'package.json'), 'utf8')) as {\n name: string;\n version: string;\n };\n\n return {\n root,\n version: manifest.version,\n assetsDir: join(pkg, 'assets'),\n // Сверка со своими исходниками возможна только отсюда: здесь пакет знает, где лежит сам.\n // У потребителя исходников рядом нет, и сверка молчит.\n stale: staleBuild(pkg, manifest.name),\n };\n}\n\n/** Вывод git в этом дереве. Отказ и пустота здесь одно и то же: адреса нет — и это не отказ. */\nfunction gitSays(root: string, args: readonly string[]): string {\n try {\n // eslint-disable-next-line sonarjs/no-os-command-from-path -- путь к git у каждой машины свой, и прибитый здесь сделал бы пакет непереносимым\n return execFileSync('git', ['-C', root, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();\n } catch {\n return '';\n }\n}\n\n/** Имена удалённых репозиториев этого дерева, по одному в строке. */\nfunction remoteNames(root: string): readonly string[] {\n return gitSays(root, ['remote'])\n .split('\\n')\n .map((name: string): string => name.trim())\n .filter(Boolean);\n}\n\n/**\n * Чем это дерево себя выдаёт снаружи. Нет удалённого репозитория — нечем, и это не отказ.\n *\n * Имя `origin` — соглашение, а не устройство: рабочая копия, назвавшая свои remotes по хостам,\n * на которые смотрит, оставалась без адреса вовсе, и отправка отказывала словами «удалённого\n * репозитория нет» — при том что репозиторий у неё есть, и не один. Порядок поэтому такой:\n * `origin`, если он есть; ровно один remote — он; несколько без `origin` — адреса нет, и выбор\n * за человеком. Угадать здесь нельзя: угаданное неверно сливает в сводке приёма два дерева в\n * одно, а увидеть это нечем.\n */\nfunction remoteOf(root: string): string {\n const names: readonly string[] = remoteNames(root);\n\n if (names.includes('origin')) {\n return gitSays(root, ['remote', 'get-url', 'origin']);\n }\n\n return names.length === 1 ? gitSays(root, ['remote', 'get-url', names[0]]) : '';\n}\n\nfunction optionOf(argv: readonly string[], name: string, fallback: string): string {\n const index: number = argv.indexOf(name);\n\n return index >= 0 && argv[index + 1] ? argv[index + 1] : fallback;\n}\n\nconst isOutcome: (value: unknown) => value is IOutcomeOfCommand = (value: unknown): value is IOutcomeOfCommand =>\n typeof value === 'object' && value !== null && 'code' in value;\n\n/**\n * Выбор законов для `init`: список идентификаторов, `null` на брошенном выборе или готовый\n * отказ. Пустой список означает «взять всё», поэтому брошенный выбор отличается от него не\n * значением, а `null`: подставить «всё» вместо неотвеченного вопроса значило бы разложить\n * пятнадцать законов тому, кто как раз просил спросить.\n */\nasync function selectionFor(argv: readonly string[], assetsDir: string): Promise<readonly string[] | null | IOutcomeOfCommand> {\n if (argv.includes('--all')) {\n return [];\n }\n\n const catalog: readonly IEntryOfCatalog[] = readCatalog(assetsDir);\n const spoken: string = optionOf(argv, '--laws', '');\n\n if (spoken) {\n const named: string[] = spoken\n .split(',')\n .map((name: string): string => name.trim())\n .filter(Boolean);\n const { ids, unknown } = resolveSelection(named, 'laws', catalog);\n\n return unknown.length\n ? { code: 1, lines: [`таких законов пакет не везёт: ${unknown.join(', ')}`, 'что везёт — `agent-kit list`'] }\n : ids;\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: [\n 'спросить некого: запуск без терминала',\n 'назови законы флагом `--laws a,b,c` или возьми все флагом `--all`',\n 'что везёт пакет — `agent-kit list`',\n ],\n };\n }\n\n const choices: readonly IChoice[] = catalog\n .filter((entry: IEntryOfCatalog): boolean => entry.kind === 'laws')\n .map((entry: IEntryOfCatalog): IChoice => ({ id: entry.id, name: entry.name, title: entry.title }));\n\n return ask(choices, 'Какие законы разложить в этом проекте?');\n}\n\n/**\n * Виды для `init` по осям, объявленным пакетом: что взято из флага, что спрошено.\n *\n * `--all` берёт первый объявленный вид оси и **говорит об этом**: в CI спрашивать некого, а\n * отказ там означал бы, что пакет нельзя разложить без человека. Первый вид — умолчание, а не\n * догадка: порядок в объявлении оси и есть порядок предпочтения.\n */\nasync function variantOfAxis(axis: IAxis, argv: readonly string[]): Promise<string | null | IOutcomeOfCommand> {\n const spoken: string = optionOf(argv, `--${axis.name}`, '');\n const values: readonly string[] = axis.options.map((option: IOptionOfAxis): string => option.value);\n\n if (spoken) {\n return values.includes(spoken)\n ? spoken\n : {\n code: 1,\n lines: [`такого вида по оси «${axis.name}» пакет не везёт: ${spoken}`, `есть: ${values.join(', ')}`],\n };\n }\n\n if (argv.includes('--all')) {\n return axis.options[0]?.value ?? '';\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: ['спросить некого: запуск без терминала', `назови вид флагом \\`--${axis.name} <вид>\\`: ${values.join(', ')}`],\n };\n }\n\n return askOne(\n axis.options.map((option: IOptionOfAxis): IChoice => ({ id: option.value, name: option.value, title: option.title })),\n axis.question\n );\n}\n\nasync function variantsFor(argv: readonly string[], assetsDir: string): Promise<Record<string, string> | null | IOutcomeOfCommand> {\n const axes: readonly IAxis[] = readAxes(assetsDir);\n const chosen: Record<string, string> = {};\n\n for (const axis of axes) {\n const answer: string | null | IOutcomeOfCommand = await variantOfAxis(axis, argv);\n\n if (isOutcome(answer)) {\n return answer;\n }\n\n if (answer === null) {\n return null;\n }\n\n chosen[axis.name] = answer;\n }\n\n return chosen;\n}\n\n/** Заведение настройки: выбор ресурсов и видов, брошенный выбор ничего не пишет. */\nasync function runInit(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const selection: readonly string[] | null | IOutcomeOfCommand = await selectionFor(argv, env.assetsDir);\n if (isOutcome(selection)) {\n return selection;\n }\n if (selection === null) {\n return { code: 1, lines: ['выбор брошен — ничего не заведено'] };\n }\n\n const variants: Record<string, string> | null | IOutcomeOfCommand = await variantsFor(argv, env.assetsDir);\n if (isOutcome(variants)) {\n return variants;\n }\n\n return variants === null\n ? { code: 1, lines: ['выбор брошен — ничего не заведено'] }\n : init(env.root, selection, variants, env.assetsDir);\n}\n\n/**\n * Цена контекста: три веса и то, чем они сняты.\n *\n * Отказ печатается тем же выводом, а не броском: команду зовут глазами, и трассировка стека\n * говорит ей читателю меньше, чем строка о том, чего в дереве нет.\n */\nfunction runCost(env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand {\n const named: string = optionOf(argv, '--rule', '');\n let cost: ICost;\n try {\n cost = costOf(env.root, named === '' ? null : named);\n } catch (failure: unknown) {\n if (failure instanceof CostUnavailableError) {\n return { code: 1, lines: [failure.message] };\n }\n throw failure;\n }\n\n return { code: 0, lines: [...costLines(cost, argv.includes('--json'))] };\n}\n\n/** Сводка наблюдений: отрезок из флага, сегодняшний день — с края. */\nfunction runStats(env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand {\n const spoken: number = Number(optionOf(argv, '--days', ''));\n\n return stats(env, {\n days: Number.isFinite(spoken) && spoken > 0 ? Math.floor(spoken) : DEFAULT_DAYS,\n // Сегодняшний день берётся здесь: у команды своих часов нет, иначе сводку за\n // отрезок не проверить спекой — вчерашняя фикстура завтра станет позавчерашней.\n today: new Date().toISOString().slice(0, 10),\n json: argv.includes('--json'),\n });\n}\n\n/**\n * Отправка накопленного.\n *\n * Единственное действие этой команды необратимо и уходит наружу, поэтому незнакомый довод её\n * кончает, а не пропускается молча: вызов ради списка режимов отправил в приём всё накопленное, и\n * по выводу это не отличалось от «команда ничего не сделала». Прочие команды такого разбора не\n * знают — их действие обратимо.\n */\nasync function runPropose(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const unknown: readonly string[] = unknownFlagsIn(argv.slice(1), PROPOSE_FLAGS);\n if (unknown.length) {\n return {\n code: 1,\n lines: [`таких доводов у \\`propose\\` нет: ${unknown.join(', ')}`, '', ...PROPOSE_USAGE],\n };\n }\n\n return propose(env, {\n dryRun: argv.includes('--dry-run'),\n ship: httpShip,\n remote: remoteOf(env.root),\n // Имена доезжают до отказа: выбор за человеком, и отказ, не назвавший, из чего выбирать,\n // отправляет его смотреть то же самое своими руками.\n remotes: remoteNames(env.root),\n // Отрезок тот же, что у сводки по умолчанию: отправку зовут по свежей задаче.\n days: DEFAULT_DAYS,\n today: new Date().toISOString().slice(0, 10),\n });\n}\n\n/** Приписка дерева к приёмнику по коду приглашения. */\nasync function runEnroll(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const config: IConfig | null = readConfig(env.root);\n\n if (!config) {\n return { code: 1, lines: [`настройки дерева нет: ${CONFIG_PATH}. Заведите её командой \\`init\\``] };\n }\n\n return enroll({\n root: env.root,\n intake: config.intake,\n code: optionOf(argv, '--code', ''),\n issued: optionOf(argv, '--token', ''),\n tree: treeSlugOf(remoteOf(env.root), config.tree),\n token: config.token,\n force: argv.includes('--force'),\n call: httpEnroll,\n });\n}\n\n/** Ветка команды: окружение и доводы строки запуска на входе, вывод и код возврата на выходе. */\ntype TCommandRun = (env: IEnvironment, argv: readonly string[]) => IOutcomeOfCommand | Promise<IOutcomeOfCommand>;\n\n/** Что делает каждая команда строки запуска. Ключ — слово, которым её зовут. */\nconst COMMANDS: Readonly<Record<string, TCommandRun>> = {\n init: runInit,\n list: (env: IEnvironment): IOutcomeOfCommand => list(env),\n sync: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand => sync(env, argv.includes('--check')),\n cost: runCost,\n stats: runStats,\n propose: runPropose,\n enroll: runEnroll,\n doctor: (env: IEnvironment): IOutcomeOfCommand => doctor(env),\n adopt: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand =>\n adopt(\n env,\n argv.slice(1).filter((value: string): boolean => !value.startsWith('--') && value !== optionOf(argv, '--root', ''))\n ),\n};\n\nexport async function main(argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const command: string = argv[0] ?? '';\n const env: IEnvironment = environmentOf(resolve(optionOf(argv, '--root', process.cwd())));\n const run: TCommandRun | undefined = Object.hasOwn(COMMANDS, command) ? COMMANDS[command] : undefined;\n\n if (!run) {\n return { code: command ? 1 : 0, lines: command ? [`неизвестная команда «${command}»`, '', ...USAGE] : USAGE };\n }\n\n return run(env, argv);\n}\n\nconst outcome: IOutcomeOfCommand = await main(process.argv.slice(2));\nfor (const line of outcome.lines) {\n // eslint-disable-next-line no-console\n console.log(line);\n}\nprocess.exit(outcome.code);\n"]}
1
+ {"version":3,"file":"agent-kit.js","sourceRoot":"","sources":["../../../projects/agent-kit/src/bin/agent-kit.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAmB,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAgB,IAAI,EAAqB,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC7G,OAAO,EAAE,WAAW,EAAW,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,oBAAoB,EAAS,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAwB,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,KAAK,GAAsB;IAC7B,qBAAqB;IACrB,EAAE;IACF,mEAAmE;IACnE,8DAA8D;IAC9D,6DAA6D;IAC7D,+EAA+E;IAC/E,qEAAqE;IACrE,oFAAoF;IACpF,gFAAgF;IAChF,qEAAqE;IACrE,yFAAyF;IACzF,wDAAwD;IACxD,gFAAgF;IAChF,8FAA8F;IAC9F,uEAAuE;IACvE,wEAAwE;IACxE,uFAAuF;IACvF,4FAA4F;IAC5F,mEAAmE;IACnE,EAAE;IACF,gEAAgE;IAChE,EAAE;IACF,2BAA2B;IAC3B,EAAE;IACF,6DAA6D;IAC7D,yEAAyE;IACzE,+DAA+D;IAC/D,EAAE;IACF,8EAA8E;IAC9E,EAAE;IACF,gFAAgF;IAChF,oEAAoE;CACvE,CAAC;AAEF;;;GAGG;AACH,MAAM,aAAa,GAAsB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,aAAa,GAAsB;IACrC,8CAA8C;IAC9C,uEAAuE;IACvE,oEAAoE;CACvE,CAAC;AAEF;;;;GAIG;AACH,SAAS,aAAa,CAAC,IAAY;IAC/B,MAAM,GAAG,GAAW,eAAe,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,QAAQ,GAAsC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAG7G,CAAC;IAEF,OAAO;QACH,IAAI;QACJ,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,0FAA0F;QAC1F,0FAA0F;QAC1F,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC;QAC9B,yFAAyF;QACzF,uDAAuD;QACvD,KAAK,EAAE,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC;KACxC,CAAC;AACN,CAAC;AAED,gGAAgG;AAChG,SAAS,OAAO,CAAC,IAAY,EAAE,IAAuB;IAClD,IAAI,CAAC;QACD,8IAA8I;QAC9I,OAAO,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxH,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED,qEAAqE;AACrE,SAAS,WAAW,CAAC,IAAY;IAC7B,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC;SAC3B,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1C,MAAM,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC1B,MAAM,KAAK,GAAsB,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnD,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpF,CAAC;AAED,SAAS,QAAQ,CAAC,IAAuB,EAAE,IAAY,EAAE,QAAgB;IACrE,MAAM,KAAK,GAAW,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzC,OAAO,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtE,CAAC;AAED,MAAM,SAAS,GAAmD,CAAC,KAAc,EAA8B,EAAE,CAC7G,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,CAAC;AAEnE;;;;;GAKG;AACH,KAAK,UAAU,YAAY,CAAC,IAAuB,EAAE,SAAiB;IAClE,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAA+B,WAAW,CAAC,SAAS,CAAC,CAAC;IACnE,MAAM,MAAM,GAAW,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEpD,IAAI,MAAM,EAAE,CAAC;QACT,MAAM,KAAK,GAAa,MAAM;aACzB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1C,MAAM,CAAC,OAAO,CAAC,CAAC;QACrB,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAElE,OAAO,OAAO,CAAC,MAAM;YACjB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,iCAAiC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,8BAA8B,CAAC,EAAE;YAC7G,CAAC,CAAC,GAAG,CAAC;IACd,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACZ,OAAO;YACH,IAAI,EAAE,CAAC;YACP,KAAK,EAAE;gBACH,uCAAuC;gBACvC,mEAAmE;gBACnE,oCAAoC;aACvC;SACJ,CAAC;IACN,CAAC;IAED,MAAM,OAAO,GAAuB,OAAO;SACtC,MAAM,CAAC,CAAC,KAAsB,EAAW,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;SAClE,GAAG,CAAC,CAAC,KAAsB,EAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAExG,OAAO,GAAG,CAAC,OAAO,EAAE,wCAAwC,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAAC,IAAW,EAAE,IAAuB;IAC7D,MAAM,MAAM,GAAW,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAsB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAqB,EAAU,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEpG,IAAI,MAAM,EAAE,CAAC;QACT,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC1B,CAAC,CAAC,MAAM;YACR,CAAC,CAAC;gBACI,IAAI,EAAE,CAAC;gBACP,KAAK,EAAE,CAAC,uBAAuB,IAAI,CAAC,IAAI,qBAAqB,MAAM,EAAE,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aACvG,CAAC;IACZ,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;IACxC,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACZ,OAAO;YACH,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC,uCAAuC,EAAE,yBAAyB,IAAI,CAAC,IAAI,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SACvH,CAAC;IACN,CAAC;IAED,OAAO,MAAM,CACT,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAqB,EAAW,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EACrH,IAAI,CAAC,QAAQ,CAChB,CAAC;AACN,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAuB,EAAE,SAAiB;IACjE,MAAM,IAAI,GAAqB,QAAQ,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,MAAM,GAAsC,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAElF,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC;QAClB,CAAC;QAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;IAC/B,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,oFAAoF;AACpF,KAAK,UAAU,OAAO,CAAC,GAAiB,EAAE,IAAuB;IAC7D,MAAM,SAAS,GAAiD,MAAM,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACxG,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,mCAAmC,CAAC,EAAE,CAAC;IACrE,CAAC;IAED,MAAM,QAAQ,GAAsD,MAAM,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3G,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtB,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,OAAO,QAAQ,KAAK,IAAI;QACpB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,mCAAmC,CAAC,EAAE;QAC3D,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,SAAS,OAAO,CAAC,GAAiB,EAAE,IAAuB;IACvD,MAAM,KAAK,GAAW,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IACnD,IAAI,IAAW,CAAC;IAChB,IAAI,CAAC;QACD,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,OAAgB,EAAE,CAAC;QACxB,IAAI,OAAO,YAAY,oBAAoB,EAAE,CAAC;YAC1C,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,CAAC;QACD,MAAM,OAAO,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED,sEAAsE;AACtE,SAAS,QAAQ,CAAC,GAAiB,EAAE,IAAuB;IACxD,MAAM,MAAM,GAAW,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IAE5D,OAAO,KAAK,CAAC,GAAG,EAAE;QACd,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY;QAC/E,6EAA6E;QAC7E,gFAAgF;QAChF,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAChC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,UAAU,CAAC,GAAiB,EAAE,IAAuB;IAChE,MAAM,OAAO,GAAsB,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAChF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO;YACH,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,CAAC,oCAAoC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,aAAa,CAAC;SAC1F,CAAC;IACN,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAClC,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QAC1B,yFAAyF;QACzF,qDAAqD;QACrD,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAC9B,8EAA8E;QAC9E,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KAC/C,CAAC,CAAC;AACP,CAAC;AAED,uDAAuD;AACvD,KAAK,UAAU,SAAS,CAAC,GAAiB,EAAE,IAAuB;IAC/D,MAAM,MAAM,GAAmB,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEpD,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,yBAAyB,WAAW,iCAAiC,CAAC,EAAE,CAAC;IACvG,CAAC;IAED,OAAO,MAAM,CAAC;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;QAClC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;QACrC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC;QACjD,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,IAAI,EAAE,UAAU;KACnB,CAAC,CAAC;AACP,CAAC;AAKD,gFAAgF;AAChF,MAAM,QAAQ,GAA0C;IACpD,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,CAAC,GAAiB,EAAqB,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;IACzD,IAAI,EAAE,CAAC,GAAiB,EAAE,IAAuB,EAAqB,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC5G,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,QAAQ;IACf,OAAO,EAAE,UAAU;IACnB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,CAAC,GAAiB,EAAqB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAiB,EAAE,IAAuB,EAAqB,EAAE,CACrE,KAAK,CACD,GAAG,EACH,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAa,EAAW,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CACtH;CACR,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAuB;IAC9C,MAAM,OAAO,GAAW,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,MAAM,GAAG,GAAiB,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1F,MAAM,GAAG,GAA4B,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEtG,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,wBAAwB,OAAO,GAAG,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAClH,CAAC;IAED,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,OAAO,GAAsB,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAC/B,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * Точка входа. Разбирает аргументы, добывает выбор проекта, зовёт команду и печатает то, что\n * она вернула. Своей работы у неё нет: всё, что решает, живёт в `commands.ts` и проверяется\n * спеками — кроме одного, чего команде знать не по чину: откуда взялся выбор законов. У строки\n * запуска это флаг, у терминала — вопрос, у прогона без терминала нет ни того ни другого.\n */\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport process from 'node:process';\n\nimport { unknownFlagsIn } from '../lib/argv.js';\nimport { IEntryOfCatalog, readCatalog, resolveSelection } from '../lib/catalog.js';\nimport { adopt, doctor, IEnvironment, init, IOutcomeOfCommand, list, stats, sync } from '../lib/commands.js';\nimport { CONFIG_PATH, IConfig, readConfig } from '../lib/config.js';\nimport { costLines, costOf, CostUnavailableError, ICost } from '../lib/cost.js';\nimport { enroll, httpEnroll } from '../lib/enroll.js';\nimport { httpShip } from '../lib/ship.js';\nimport { propose, treeSlugOf } from '../lib/shipment.js';\nimport { DEFAULT_DAYS } from '../lib/observations.js';\nimport { staleBuild } from '../lib/freshness.js';\nimport { packageRootFrom } from '../lib/package-root.js';\nimport { IChoice } from '../lib/picker.js';\nimport { IAxis, IOptionOfAxis, readAxes } from '../lib/variants.js';\nimport { ask, askOne, canAsk } from './prompt.js';\n\nconst USAGE: readonly string[] = [\n 'agent-kit <команда>',\n '',\n ' init завести .claude/rt-kit.json и каталог надстроек',\n ' list что везёт пакет и что из этого взято здесь',\n ' sync разложить ресурсы пакета в дерево проекта',\n ' sync --check ничего не писать, отказать при расхождении — для гейта пуша',\n ' doctor рассказать о состоянии раскладки, ничего не меняя',\n ' cost посчитать цену контекста: вход в работу, одно правило, весь слой',\n ' cost --rule <имя> какое правило взвесить; без довода берётся самое тяжёлое',\n ' cost --json то же машиночитаемо — этим числа кладут в замысел',\n ' stats свести наблюдения: чем пользовались, чем ни разу, обо что спотыкались',\n ' stats --days N за сколько дней; без довода — за три',\n ' stats --json то же машиночитаемо — этим сводку прикладывают к предложению',\n ' propose отправить груз в приём: сводку со снимком надстроек, предложения и разборы',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' adopt [файлы] отдать пакету файлы, лежащие на его путях не от него',\n ' enroll --code <код> завести дерево по приглашению владельца: обмен кода на токен',\n ' enroll --token <токен> завести дерево токеном, выданным в админке приёма; в сеть не идёт',\n ' enroll --force перезаписать уже лежащий токен намеренно',\n '',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n '',\n 'Выбор законов при `init`:',\n '',\n ' --all взять все законы, ни о чём не спрашивая',\n ' --laws a,b,c взять только названные; имена — из `agent-kit list`',\n ' без обоих спросить галочками; без терминала — отказ',\n '',\n 'Вид ресурсов при `init` — там, где один закон исполняется разными командами:',\n '',\n ' --<ось> <вид> например `--host gitlab`; оси и виды — из `agent-kit list`',\n ' без флага спросить; без терминала — отказ, кроме `--all`',\n];\n\n/**\n * Доводы отправки. Довод со значением помечен `<>`: за ним идёт отдельным словом путь, и без\n * пометки этот путь читался бы как ещё один незнакомый довод.\n */\nconst PROPOSE_FLAGS: readonly string[] = ['--dry-run', '--root <>'];\n\n/** Что печатает отказ на незнакомом доводе: режимы команды, а не весь свод. */\nconst PROPOSE_USAGE: readonly string[] = [\n ' propose отправить груз в приём',\n ' propose --dry-run показать, что уехало бы, и ничего не отправлять',\n ' --root <путь> корень проекта; по умолчанию текущий каталог',\n];\n\n/**\n * Единственное место, где пакет узнаёт собственное расположение. `import.meta` живёт только\n * здесь: библиотечные модули получают каталог ресурсов входным значением, и трансформ тестов,\n * разбирающий модули как CommonJS, на них уже не спотыкается.\n */\nfunction environmentOf(root: string): IEnvironment {\n const pkg: string = packageRootFrom(dirname(fileURLToPath(import.meta.url)));\n const manifest: { name: string; version: string } = JSON.parse(readFileSync(join(pkg, 'package.json'), 'utf8')) as {\n name: string;\n version: string;\n };\n\n return {\n root,\n version: manifest.version,\n // Имя из манифеста, а не записанное здесь: по нему пакет ищет себя в зависимостях дерева,\n // и своя копия имени разошлась бы с манифестом молча — у всякого, кто пакет переименовал.\n name: manifest.name,\n assetsDir: join(pkg, 'assets'),\n // Сверка со своими исходниками возможна только отсюда: здесь пакет знает, где лежит сам.\n // У потребителя исходников рядом нет, и сверка молчит.\n stale: staleBuild(pkg, manifest.name),\n };\n}\n\n/** Вывод git в этом дереве. Отказ и пустота здесь одно и то же: адреса нет — и это не отказ. */\nfunction gitSays(root: string, args: readonly string[]): string {\n try {\n // eslint-disable-next-line sonarjs/no-os-command-from-path -- путь к git у каждой машины свой, и прибитый здесь сделал бы пакет непереносимым\n return execFileSync('git', ['-C', root, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();\n } catch {\n return '';\n }\n}\n\n/** Имена удалённых репозиториев этого дерева, по одному в строке. */\nfunction remoteNames(root: string): readonly string[] {\n return gitSays(root, ['remote'])\n .split('\\n')\n .map((name: string): string => name.trim())\n .filter(Boolean);\n}\n\n/**\n * Чем это дерево себя выдаёт снаружи. Нет удалённого репозитория — нечем, и это не отказ.\n *\n * Имя `origin` — соглашение, а не устройство: рабочая копия, назвавшая свои remotes по хостам,\n * на которые смотрит, оставалась без адреса вовсе, и отправка отказывала словами «удалённого\n * репозитория нет» — при том что репозиторий у неё есть, и не один. Порядок поэтому такой:\n * `origin`, если он есть; ровно один remote — он; несколько без `origin` — адреса нет, и выбор\n * за человеком. Угадать здесь нельзя: угаданное неверно сливает в сводке приёма два дерева в\n * одно, а увидеть это нечем.\n */\nfunction remoteOf(root: string): string {\n const names: readonly string[] = remoteNames(root);\n\n if (names.includes('origin')) {\n return gitSays(root, ['remote', 'get-url', 'origin']);\n }\n\n return names.length === 1 ? gitSays(root, ['remote', 'get-url', names[0]]) : '';\n}\n\nfunction optionOf(argv: readonly string[], name: string, fallback: string): string {\n const index: number = argv.indexOf(name);\n\n return index >= 0 && argv[index + 1] ? argv[index + 1] : fallback;\n}\n\nconst isOutcome: (value: unknown) => value is IOutcomeOfCommand = (value: unknown): value is IOutcomeOfCommand =>\n typeof value === 'object' && value !== null && 'code' in value;\n\n/**\n * Выбор законов для `init`: список идентификаторов, `null` на брошенном выборе или готовый\n * отказ. Пустой список означает «взять всё», поэтому брошенный выбор отличается от него не\n * значением, а `null`: подставить «всё» вместо неотвеченного вопроса значило бы разложить\n * пятнадцать законов тому, кто как раз просил спросить.\n */\nasync function selectionFor(argv: readonly string[], assetsDir: string): Promise<readonly string[] | null | IOutcomeOfCommand> {\n if (argv.includes('--all')) {\n return [];\n }\n\n const catalog: readonly IEntryOfCatalog[] = readCatalog(assetsDir);\n const spoken: string = optionOf(argv, '--laws', '');\n\n if (spoken) {\n const named: string[] = spoken\n .split(',')\n .map((name: string): string => name.trim())\n .filter(Boolean);\n const { ids, unknown } = resolveSelection(named, 'laws', catalog);\n\n return unknown.length\n ? { code: 1, lines: [`таких законов пакет не везёт: ${unknown.join(', ')}`, 'что везёт — `agent-kit list`'] }\n : ids;\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: [\n 'спросить некого: запуск без терминала',\n 'назови законы флагом `--laws a,b,c` или возьми все флагом `--all`',\n 'что везёт пакет — `agent-kit list`',\n ],\n };\n }\n\n const choices: readonly IChoice[] = catalog\n .filter((entry: IEntryOfCatalog): boolean => entry.kind === 'laws')\n .map((entry: IEntryOfCatalog): IChoice => ({ id: entry.id, name: entry.name, title: entry.title }));\n\n return ask(choices, 'Какие законы разложить в этом проекте?');\n}\n\n/**\n * Виды для `init` по осям, объявленным пакетом: что взято из флага, что спрошено.\n *\n * `--all` берёт первый объявленный вид оси и **говорит об этом**: в CI спрашивать некого, а\n * отказ там означал бы, что пакет нельзя разложить без человека. Первый вид — умолчание, а не\n * догадка: порядок в объявлении оси и есть порядок предпочтения.\n */\nasync function variantOfAxis(axis: IAxis, argv: readonly string[]): Promise<string | null | IOutcomeOfCommand> {\n const spoken: string = optionOf(argv, `--${axis.name}`, '');\n const values: readonly string[] = axis.options.map((option: IOptionOfAxis): string => option.value);\n\n if (spoken) {\n return values.includes(spoken)\n ? spoken\n : {\n code: 1,\n lines: [`такого вида по оси «${axis.name}» пакет не везёт: ${spoken}`, `есть: ${values.join(', ')}`],\n };\n }\n\n if (argv.includes('--all')) {\n return axis.options[0]?.value ?? '';\n }\n\n if (!canAsk()) {\n return {\n code: 1,\n lines: ['спросить некого: запуск без терминала', `назови вид флагом \\`--${axis.name} <вид>\\`: ${values.join(', ')}`],\n };\n }\n\n return askOne(\n axis.options.map((option: IOptionOfAxis): IChoice => ({ id: option.value, name: option.value, title: option.title })),\n axis.question\n );\n}\n\nasync function variantsFor(argv: readonly string[], assetsDir: string): Promise<Record<string, string> | null | IOutcomeOfCommand> {\n const axes: readonly IAxis[] = readAxes(assetsDir);\n const chosen: Record<string, string> = {};\n\n for (const axis of axes) {\n const answer: string | null | IOutcomeOfCommand = await variantOfAxis(axis, argv);\n\n if (isOutcome(answer)) {\n return answer;\n }\n\n if (answer === null) {\n return null;\n }\n\n chosen[axis.name] = answer;\n }\n\n return chosen;\n}\n\n/** Заведение настройки: выбор ресурсов и видов, брошенный выбор ничего не пишет. */\nasync function runInit(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const selection: readonly string[] | null | IOutcomeOfCommand = await selectionFor(argv, env.assetsDir);\n if (isOutcome(selection)) {\n return selection;\n }\n if (selection === null) {\n return { code: 1, lines: ['выбор брошен — ничего не заведено'] };\n }\n\n const variants: Record<string, string> | null | IOutcomeOfCommand = await variantsFor(argv, env.assetsDir);\n if (isOutcome(variants)) {\n return variants;\n }\n\n return variants === null\n ? { code: 1, lines: ['выбор брошен — ничего не заведено'] }\n : init(env.root, selection, variants, env.assetsDir);\n}\n\n/**\n * Цена контекста: три веса и то, чем они сняты.\n *\n * Отказ печатается тем же выводом, а не броском: команду зовут глазами, и трассировка стека\n * говорит ей читателю меньше, чем строка о том, чего в дереве нет.\n */\nfunction runCost(env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand {\n const named: string = optionOf(argv, '--rule', '');\n let cost: ICost;\n try {\n cost = costOf(env.root, named === '' ? null : named);\n } catch (failure: unknown) {\n if (failure instanceof CostUnavailableError) {\n return { code: 1, lines: [failure.message] };\n }\n throw failure;\n }\n\n return { code: 0, lines: [...costLines(cost, argv.includes('--json'))] };\n}\n\n/** Сводка наблюдений: отрезок из флага, сегодняшний день — с края. */\nfunction runStats(env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand {\n const spoken: number = Number(optionOf(argv, '--days', ''));\n\n return stats(env, {\n days: Number.isFinite(spoken) && spoken > 0 ? Math.floor(spoken) : DEFAULT_DAYS,\n // Сегодняшний день берётся здесь: у команды своих часов нет, иначе сводку за\n // отрезок не проверить спекой — вчерашняя фикстура завтра станет позавчерашней.\n today: new Date().toISOString().slice(0, 10),\n json: argv.includes('--json'),\n });\n}\n\n/**\n * Отправка накопленного.\n *\n * Единственное действие этой команды необратимо и уходит наружу, поэтому незнакомый довод её\n * кончает, а не пропускается молча: вызов ради списка режимов отправил в приём всё накопленное, и\n * по выводу это не отличалось от «команда ничего не сделала». Прочие команды такого разбора не\n * знают — их действие обратимо.\n */\nasync function runPropose(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const unknown: readonly string[] = unknownFlagsIn(argv.slice(1), PROPOSE_FLAGS);\n if (unknown.length) {\n return {\n code: 1,\n lines: [`таких доводов у \\`propose\\` нет: ${unknown.join(', ')}`, '', ...PROPOSE_USAGE],\n };\n }\n\n return propose(env, {\n dryRun: argv.includes('--dry-run'),\n ship: httpShip,\n remote: remoteOf(env.root),\n // Имена доезжают до отказа: выбор за человеком, и отказ, не назвавший, из чего выбирать,\n // отправляет его смотреть то же самое своими руками.\n remotes: remoteNames(env.root),\n // Отрезок тот же, что у сводки по умолчанию: отправку зовут по свежей задаче.\n days: DEFAULT_DAYS,\n today: new Date().toISOString().slice(0, 10),\n });\n}\n\n/** Приписка дерева к приёмнику по коду приглашения. */\nasync function runEnroll(env: IEnvironment, argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const config: IConfig | null = readConfig(env.root);\n\n if (!config) {\n return { code: 1, lines: [`настройки дерева нет: ${CONFIG_PATH}. Заведите её командой \\`init\\``] };\n }\n\n return enroll({\n root: env.root,\n intake: config.intake,\n code: optionOf(argv, '--code', ''),\n issued: optionOf(argv, '--token', ''),\n tree: treeSlugOf(remoteOf(env.root), config.tree),\n token: config.token,\n force: argv.includes('--force'),\n call: httpEnroll,\n });\n}\n\n/** Ветка команды: окружение и доводы строки запуска на входе, вывод и код возврата на выходе. */\ntype TCommandRun = (env: IEnvironment, argv: readonly string[]) => IOutcomeOfCommand | Promise<IOutcomeOfCommand>;\n\n/** Что делает каждая команда строки запуска. Ключ — слово, которым её зовут. */\nconst COMMANDS: Readonly<Record<string, TCommandRun>> = {\n init: runInit,\n list: (env: IEnvironment): IOutcomeOfCommand => list(env),\n sync: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand => sync(env, argv.includes('--check')),\n cost: runCost,\n stats: runStats,\n propose: runPropose,\n enroll: runEnroll,\n doctor: (env: IEnvironment): IOutcomeOfCommand => doctor(env),\n adopt: (env: IEnvironment, argv: readonly string[]): IOutcomeOfCommand =>\n adopt(\n env,\n argv.slice(1).filter((value: string): boolean => !value.startsWith('--') && value !== optionOf(argv, '--root', ''))\n ),\n};\n\nexport async function main(argv: readonly string[]): Promise<IOutcomeOfCommand> {\n const command: string = argv[0] ?? '';\n const env: IEnvironment = environmentOf(resolve(optionOf(argv, '--root', process.cwd())));\n const run: TCommandRun | undefined = Object.hasOwn(COMMANDS, command) ? COMMANDS[command] : undefined;\n\n if (!run) {\n return { code: command ? 1 : 0, lines: command ? [`неизвестная команда «${command}»`, '', ...USAGE] : USAGE };\n }\n\n return run(env, argv);\n}\n\nconst outcome: IOutcomeOfCommand = await main(process.argv.slice(2));\nfor (const line of outcome.lines) {\n // eslint-disable-next-line no-console\n console.log(line);\n}\nprocess.exit(outcome.code);\n"]}
package/lib/commands.d.ts CHANGED
@@ -14,6 +14,11 @@ export interface IEnvironment {
14
14
  * тем каталогом ресурсов, который им дали, и о существовании исходников не знают.
15
15
  */
16
16
  readonly stale?: IStaleBuild | null;
17
+ /**
18
+ * Имя пакета из его собственного манифеста. Нужно, чтобы найти себя в зависимостях дерева:
19
+ * искать по угаданному имени значило бы промахнуться молча у всякого, кто пакет переименовал.
20
+ */
21
+ readonly name?: string;
17
22
  }
18
23
  /** Куда уезжает прежнее содержимое файла, отданного пакету. */
19
24
  export declare const KEPT_SUFFIX: string;
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/commands.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAsB7C,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,2FAA2F;AAC3F,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACvC;AA2DD,+DAA+D;AAC/D,eAAO,MAAM,WAAW,EAAE,MAAyB,CAAC;AA0ZpD;;;;GAIG;AACH,wBAAgB,IAAI,CAChB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,SAAS,MAAM,EAAO,EAC5B,QAAQ,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EAC/C,SAAS,GAAE,MAAW,GACvB,iBAAiB,CAgCnB;AA8FD,wBAAgB,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,GAAG,iBAAiB,CA8DzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,CA+CpF;AAQD,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CAC1B;AAqHD;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,GAAG,iBAAiB,CAuDlF;AA0BD,wBAAgB,MAAM,CAAC,GAAG,EAAE,YAAY,GAAG,iBAAiB,CA6E3D;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,YAAY,GAAG,iBAAiB,CA2DzD"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../projects/agent-kit/src/lib/commands.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAsB7C,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,2FAA2F;AAC3F,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CAC1B;AA2DD,+DAA+D;AAC/D,eAAO,MAAM,WAAW,EAAE,MAAyB,CAAC;AA0ZpD;;;;GAIG;AACH,wBAAgB,IAAI,CAChB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,SAAS,MAAM,EAAO,EAC5B,QAAQ,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EAC/C,SAAS,GAAE,MAAW,GACvB,iBAAiB,CAgCnB;AAmKD,wBAAgB,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,GAAG,iBAAiB,CA8DzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,CA+CpF;AAQD,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CAC1B;AAqHD;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,GAAG,iBAAiB,CAuDlF;AA0BD,wBAAgB,MAAM,CAAC,GAAG,EAAE,YAAY,GAAG,iBAAiB,CA6E3D;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,YAAY,GAAG,iBAAiB,CA2DzD"}