@rt-tools/agent-kit 0.12.0 → 0.14.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/assets/checks/board-runs.github.mjs +132 -0
- package/assets/checks/board.github.mjs +43 -41
- package/assets/checks/check-board.github.mjs +73 -8
- package/assets/checks/check-schema-drift.mjs +28 -5
- package/assets/checks/rt-kit-checks.config.mjs +12 -0
- package/assets/checks/task-new.github.mjs +15 -3
- package/assets/commands/feedback.md +8 -0
- package/assets/defaults/project.sh +50 -5
- package/assets/hooks/browser-guard-no-other-drivers.sh +1 -1
- package/assets/hooks/claim-guard.sh +34 -0
- package/assets/hooks/dev-server-guard.sh +1 -1
- package/assets/hooks/dispatch.sh +48 -15
- package/assets/hooks/git-guard-delivery-folder.sh +99 -0
- package/assets/hooks/git-guard-delivery-signature.sh +10 -4
- package/assets/hooks/git-guard-delivery.sh +21 -69
- package/assets/hooks/git-guard-push-tests.sh +2 -2
- package/assets/hooks/hook-input.sh +62 -0
- package/assets/hooks/override-write-guard.sh +107 -0
- package/assets/hooks/rerun-guard.sh +1 -1
- package/assets/hooks/rule-source-guard.sh +126 -0
- package/assets/hooks/task-flow-guard.sh +18 -0
- package/assets/hooks/turn-exit-guard.sh +33 -1
- package/assets/hooks/waiting-turn-guard.sh +39 -3
- package/assets/patterns/git-workflow-pr.azure.md +4 -4
- package/assets/patterns/git-workflow-pr.github.md +4 -4
- package/assets/patterns/git-workflow-pr.gitlab.md +4 -4
- package/assets/patterns/task-flow-archive.md +23 -21
- package/assets/patterns/task-flow-close.md +98 -96
- package/assets/patterns/task-flow-resume.md +5 -3
- package/assets/pitfalls/agent-kit.md +80 -0
- package/assets/pitfalls/git-workflow.github.md +8 -0
- package/assets/rules/deploy-flow.azure.md +15 -7
- package/assets/rules/deploy-flow.github.md +15 -6
- package/assets/rules/deploy-flow.gitlab.md +15 -7
- package/assets/rules/git-workflow.github.md +10 -5
- package/assets/rules/task-flow.md +44 -26
- package/assets/rules/turn-conduct.md +33 -0
- package/assets/skills/agent-kit.md +32 -77
- package/assets/templates/proposal.md +16 -1
- package/lib/proposals.d.ts +5 -1
- package/lib/proposals.d.ts.map +1 -1
- package/lib/proposals.js +74 -5
- package/lib/proposals.js.map +1 -1
- package/lib/shipment.d.ts.map +1 -1
- package/lib/shipment.fixture.d.ts +39 -0
- package/lib/shipment.fixture.d.ts.map +1 -0
- package/lib/shipment.fixture.js +99 -0
- package/lib/shipment.fixture.js.map +1 -0
- package/lib/shipment.js +59 -7
- package/lib/shipment.js.map +1 -1
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.14.0.tgz +0 -0
- package/rt-tools-agent-kit-0.12.0.tgz +0 -0
|
@@ -49,7 +49,7 @@ done
|
|
|
49
49
|
|
|
50
50
|
# Вызов перезапуска: слово перезапуска отдельным словом рядом со словом прогона.
|
|
51
51
|
host_cli="${RT_HOST_CLI:-gh}"
|
|
52
|
-
printf '%s' "$cmd" | grep -qE "
|
|
52
|
+
printf '%s' "$cmd" | grep -qE "${RT_CMD_BOUND}${host_cli}([[:space:]]|\$)" || exit 0
|
|
53
53
|
printf '%s' "$cmd" | grep -qE '(^|[[:space:]])(run|workflow)([[:space:]]|$)' || exit 0
|
|
54
54
|
printf '%s' "$cmd" | grep -qE '(^|[[:space:]])rerun([[:space:]]|$)' || exit 0
|
|
55
55
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# rt-hook: PreToolUse Edit|Write|MultiEdit|Bash|mcp__webstorm__create_new_file|mcp__webstorm__execute_terminal_command|mcp__webstorm__execute_tool
|
|
3
|
+
# Требует: hooks/profile-check.sh, hooks/deny-tail.sh
|
|
4
|
+
# Гард места правки: слой правил чинится там, где сломано, а не там, где виден.
|
|
5
|
+
#
|
|
6
|
+
# Слой правил правит тот же исполнитель, которым слой правил управляет, и разницы между
|
|
7
|
+
# «исполняю правило» и «правлю правило» в дереве не видно ничем: разложенная копия лежит рядом
|
|
8
|
+
# с обычными файлами и правится так же. Правка доходит до диска и не доходит до места, где
|
|
9
|
+
# промах чинится: в дереве она видна, в пакете её нет, а через месяц раскладка отказывает по
|
|
10
|
+
# правленому файлу целиком — и цену платит тот, кто в этот день правил соседний ресурс.
|
|
11
|
+
#
|
|
12
|
+
# Знал об этом только `sync --check`, и говорил он на следующей раскладке, то есть в чужой
|
|
13
|
+
# ветке и чужим ходом. Гард говорит в минуту правки и называет адрес: источник пакета, если
|
|
14
|
+
# дерево его держит, иначе — надстройку.
|
|
15
|
+
#
|
|
16
|
+
# ЧТО СУДИТСЯ. Файл, который правят, несёт шапку раскладки: `rt-kit v<версия> · <ресурс> ·
|
|
17
|
+
# <дайджест>`. Ресурс из неё и есть адрес: `<источники>/<ресурс>` в дереве пакета,
|
|
18
|
+
# `.claude/rt-kit/overrides/<ресурс>` у потребителя.
|
|
19
|
+
#
|
|
20
|
+
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: нет `jq`, битый ввод, чужой инструмент, файла нет, шапки в нём нет,
|
|
21
|
+
# не git-репозиторий — правка РАЗРЕШАЕТСЯ. Сломанный гард не имеет права заклинить работу.
|
|
22
|
+
|
|
23
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
24
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/hook-input.sh" 2>/dev/null || true
|
|
25
|
+
|
|
26
|
+
rt_hook_read
|
|
27
|
+
input="$RT_HOOK_INPUT"
|
|
28
|
+
[ -z "$input" ] && exit 0
|
|
29
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
30
|
+
|
|
31
|
+
rt_hooks_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
32
|
+
for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../defaults/project.sh" "${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/defaults/project.sh" "${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/project.sh"; do
|
|
33
|
+
# shellcheck disable=SC1090
|
|
34
|
+
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
# shellcheck disable=SC1090
|
|
38
|
+
[ -f "$rt_hooks_dir/profile-check.sh" ] && . "$rt_hooks_dir/profile-check.sh"
|
|
39
|
+
command -v rt_needs >/dev/null 2>&1 || rt_needs() { command -v "$1" >/dev/null 2>&1; }
|
|
40
|
+
|
|
41
|
+
# shellcheck disable=SC1090
|
|
42
|
+
[ -f "$rt_hooks_dir/deny-tail.sh" ] && . "$rt_hooks_dir/deny-tail.sh" 2>/dev/null
|
|
43
|
+
command -v rt_deny_tail >/dev/null 2>&1 || rt_deny_tail() { printf ''; }
|
|
44
|
+
|
|
45
|
+
deny() {
|
|
46
|
+
# shellcheck disable=SC1090
|
|
47
|
+
[ -f "$rt_hooks_dir/observe.sh" ] && . "$rt_hooks_dir/observe.sh" 2>/dev/null
|
|
48
|
+
command -v rt_note >/dev/null 2>&1 && rt_note guard-deny res=rule-source-guard
|
|
49
|
+
|
|
50
|
+
reason="$1 $(rt_deny_tail "$2")"
|
|
51
|
+
jq -n --arg r "$reason" '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}' 2>/dev/null \
|
|
52
|
+
|| printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Гард места правки."}}\n'
|
|
53
|
+
exit 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Цели записи, названные командой прямо. Печатает по одной в строке.
|
|
57
|
+
rt_write_targets() {
|
|
58
|
+
tr "\"'\`" ' ' \
|
|
59
|
+
| sed -E 's/>>?/\n>/g' \
|
|
60
|
+
| sed -nE '
|
|
61
|
+
s/^>[[:space:]]*([^[:space:]|&;]+).*/\1/p
|
|
62
|
+
s/(^|.*[[:space:]])tee[[:space:]]+(-a[[:space:]]+)?([^[:space:]|&;]+).*/\3/p
|
|
63
|
+
s/(^|.*[[:space:]])sed[[:space:]]+-i[[:space:]]+([^[:space:]]+[[:space:]]+)*([^[:space:]|&;]+)$/\3/p
|
|
64
|
+
s/(^|.*[[:space:]])(cp|mv|install)[[:space:]]+([^[:space:]]+[[:space:]]+)+([^[:space:]|&;]+).*/\4/p
|
|
65
|
+
' \
|
|
66
|
+
| sort -u
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
tool="$(rt_hook_tool)"
|
|
70
|
+
candidates=""
|
|
71
|
+
case "$tool" in
|
|
72
|
+
Edit | Write | MultiEdit | mcp__webstorm__create_new_file)
|
|
73
|
+
candidates="$(printf '%s' "$input" | jq -r '.tool_input.file_path // .tool_input.pathInProject // empty' 2>/dev/null)"
|
|
74
|
+
;;
|
|
75
|
+
Bash | mcp__webstorm__execute_terminal_command | mcp__webstorm__execute_tool)
|
|
76
|
+
cmd="$(rt_hook_cmd)"
|
|
77
|
+
[ -z "$cmd" ] && exit 0
|
|
78
|
+
# Здесь берётся не общий признак записи, а цель, названная в команде прямо:
|
|
79
|
+
# перенаправление, `tee`, правка на месте, копирование поверх. Общий признак широк
|
|
80
|
+
# намеренно — в нём и имя интерпретатора, — и запуск разложенной проверки читался бы
|
|
81
|
+
# как правка её самой. Отбитие на чтении стоит дороже пропуска: гард, мешающий читать,
|
|
82
|
+
# выключают в первый же день.
|
|
83
|
+
#
|
|
84
|
+
# Снятие копии сюда не входит намеренно: снятый файл раскладка кладёт заново, и так
|
|
85
|
+
# чинят копию, которую переписал форматтер.
|
|
86
|
+
candidates="$(printf '%s' "$cmd" | rt_write_targets)"
|
|
87
|
+
;;
|
|
88
|
+
*) exit 0 ;;
|
|
89
|
+
esac
|
|
90
|
+
[ -z "$candidates" ] && exit 0
|
|
91
|
+
|
|
92
|
+
root="${CLAUDE_PROJECT_DIR:-.}"
|
|
93
|
+
|
|
94
|
+
# Каталог источников пакета в этом дереве. Есть он только у дерева, которое пакет и везёт; у
|
|
95
|
+
# потребителя источника нет вовсе, и адрес правки у него один — надстройка.
|
|
96
|
+
sources=""
|
|
97
|
+
if rt_needs rt_kit_sources_dir rule-source-guard; then
|
|
98
|
+
sources="$(rt_kit_sources_dir 2>/dev/null)"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
while IFS= read -r candidate; do
|
|
102
|
+
[ -z "$candidate" ] && continue
|
|
103
|
+
case "$candidate" in
|
|
104
|
+
/*) ;;
|
|
105
|
+
*) candidate="$root/$candidate" ;;
|
|
106
|
+
esac
|
|
107
|
+
[ -f "$candidate" ] || continue
|
|
108
|
+
|
|
109
|
+
# Шапка стоит в начале файла, но не первой строкой: у сценария её отодвигает `#!`, у
|
|
110
|
+
# правила — заголовок с именем и родом ресурса. Десяти строк хватает обоим, а читать файл
|
|
111
|
+
# целиком нельзя: гард стоит на каждой правке.
|
|
112
|
+
resource="$(head -12 "$candidate" 2>/dev/null | sed -nE 's/.*rt-kit v[^ ]+ · ([^ ]+) · [0-9a-f]+.*/\1/p' | head -1)"
|
|
113
|
+
[ -z "$resource" ] && continue
|
|
114
|
+
|
|
115
|
+
if [ -n "$sources" ] && [ -f "$root/$sources/$resource" ]; then
|
|
116
|
+
deny "BLOCKED by rule-source-guard: «${candidate#"$root"/}» разложен пакетом, и правка на его месте теряется на следующей раскладке — а до тех пор раскладка отказывает по этому файлу целиком, и цену платит тот, кто в этот день правит соседний ресурс. Ресурс — «${resource}». Правь источник: ${sources}/${resource} — потом собери пакет и разложи." \
|
|
117
|
+
"правка, верная только этому дереву, идёт в надстройку .claude/rt-kit/overrides/${resource} — она сливается по разделу «## » и раскладку переживает"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
deny "BLOCKED by rule-source-guard: «${candidate#"$root"/}» разложен пакетом @rt-tools/agent-kit, и правка на его месте теряется на следующей раскладке. Ресурс — «${resource}». Правь надстройку: .claude/rt-kit/overrides/${resource} — она сливается по разделу «## » и раскладку переживает." \
|
|
121
|
+
"то, что верно любому дереву, правится в самом пакете и приезжает сюда новой редакцией"
|
|
122
|
+
done <<EOF
|
|
123
|
+
$candidates
|
|
124
|
+
EOF
|
|
125
|
+
|
|
126
|
+
exit 0
|
|
@@ -110,6 +110,7 @@ EOF
|
|
|
110
110
|
|
|
111
111
|
# Каталог папок задач: у дерева он свой, но имя обычно общее.
|
|
112
112
|
tasks_dir="${RT_TASKS_DIR:-docs/tasks}"
|
|
113
|
+
main_branch="${RT_MAIN_BRANCH:-main}"
|
|
113
114
|
|
|
114
115
|
# Общий хвост отказа: два законных хода и законная форма обхода, если она у отказа есть. Файл
|
|
115
116
|
# может быть не разложен — тогда хвоста нет, а причина отказа остаётся прежней.
|
|
@@ -146,6 +147,23 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
|
146
147
|
dir="$root/$tasks_dir/$branch"
|
|
147
148
|
plan="$dir/plan.md"
|
|
148
149
|
|
|
150
|
+
# Папка, разобранная коммитом этой ветки, — признак того, что работа отдана. Замысел с диска к
|
|
151
|
+
# этой минуте снят намеренно: уборка стоит до открытия заявки, потому что кнопку слияния
|
|
152
|
+
# нажимает человек на хостинге и закрывающему коммиту места после одобрения не остаётся.
|
|
153
|
+
# Правка после уборки — это правка по замечаниям разбора, и требовать под неё замысла значило
|
|
154
|
+
# бы запирать ветку собственным порядком. Признак берётся из истории ветки, а не с диска:
|
|
155
|
+
# снесённая, но не закоммиченная папка отданной работы не означает.
|
|
156
|
+
folder_archived() {
|
|
157
|
+
[ -n "$(git ls-tree -d --name-only HEAD -- "$tasks_dir/$branch" 2>/dev/null | head -1)" ] && return 1
|
|
158
|
+
base="$(git merge-base "$main_branch" HEAD 2>/dev/null)"
|
|
159
|
+
[ -z "$base" ] && return 1
|
|
160
|
+
had="$(git ls-tree -d --name-only "$base" -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
|
|
161
|
+
[ -z "$had" ] && had="$(git log "$base..HEAD" --diff-filter=A --name-only --pretty=format: -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
|
|
162
|
+
[ -n "$had" ]
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
folder_archived && exit 0
|
|
166
|
+
|
|
149
167
|
if [ ! -f "$plan" ]; then
|
|
150
168
|
deny "BLOCKED by task-flow: нет замысла — '${tasks_dir}/${branch}/plan.md'. Собери папку задачи с образца (cp -r ${tasks_dir}/_template ${tasks_dir}/${branch}) и заполни шапку, след задачи и этапы, затем повтори. Правило — скил task-flow."
|
|
151
169
|
fi
|
|
@@ -74,6 +74,30 @@ case "$state" in
|
|
|
74
74
|
работа-отдана | влито) exit 0 ;;
|
|
75
75
|
esac
|
|
76
76
|
|
|
77
|
+
# То же самое, но объявить это на диске уже нечем: папка задачи разбирается до открытия заявки,
|
|
78
|
+
# и ход работы уезжает вместе с ней. Признак берётся из истории ветки — папка, снятая её
|
|
79
|
+
# коммитом.
|
|
80
|
+
#
|
|
81
|
+
# Отпускать по нему ход нельзя: папка снимается ДО заявки, и между этими двумя движениями работа
|
|
82
|
+
# не отдана никому. Ход, попавший в зазор, прежде выходил отсюда нулём — а до отдачи ему
|
|
83
|
+
# оставался ровно один шаг, и он его не сделал. Признак поэтому только снимает требование
|
|
84
|
+
# состояния: дальше ход судится вторым признаком, как всякий другой. Ход, в котором заявку
|
|
85
|
+
# открыли или прочитали, второй признак пропускает сам — вызов клиента хостинга он считает
|
|
86
|
+
# работой.
|
|
87
|
+
folder_archived() {
|
|
88
|
+
[ -n "$branch" ] || return 1
|
|
89
|
+
[ -n "$(git ls-tree -d --name-only HEAD -- "$tasks_dir/$branch" 2>/dev/null | head -1)" ] && return 1
|
|
90
|
+
main_branch="${RT_MAIN_BRANCH:-main}"
|
|
91
|
+
base="$(git merge-base "$main_branch" HEAD 2>/dev/null)"
|
|
92
|
+
[ -z "$base" ] && return 1
|
|
93
|
+
had="$(git ls-tree -d --name-only "$base" -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
|
|
94
|
+
[ -z "$had" ] && had="$(git log "$base..HEAD" --diff-filter=A --name-only --pretty=format: -- "$tasks_dir/$branch" 2>/dev/null | head -1)"
|
|
95
|
+
[ -n "$had" ]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
archived=false
|
|
99
|
+
[ -z "$progress" ] && folder_archived && archived=true
|
|
100
|
+
|
|
77
101
|
# Следующий шаг из хода работы — его страж и называет в отказе: исполнитель, которому сказано
|
|
78
102
|
# только «работа не кончена», перечитывает ту же строку сам.
|
|
79
103
|
next_step=""
|
|
@@ -177,7 +201,15 @@ fi
|
|
|
177
201
|
|
|
178
202
|
[ "$worked" = "true" ] && exit 0
|
|
179
203
|
|
|
180
|
-
if [
|
|
204
|
+
if [ "$archived" = "true" ]; then
|
|
205
|
+
reason="BLOCKED by turn-exit-guard: папка задачи снята коммитом ветки, а за этот ход не сделано ничего — ни правки, ни команды, меняющей дерево.
|
|
206
|
+
|
|
207
|
+
Снятая папка означает середину отдачи, а не её конец: убирают её ДО того, как открыта заявка, и между этими двумя движениями работу не видит никто, кроме того, кто её сделал. Состояние работы с этой минуты объявить нечем, поэтому ход судится по второму признаку — была ли за него работа.
|
|
208
|
+
|
|
209
|
+
Оставшийся шаг один: открыть заявку черновиком. Заявка уже открыта — возьми следующую задачу: ожидание чужого прогона работой не является и ходом не кончается.
|
|
210
|
+
|
|
211
|
+
Страж судит один ход: следующий заход не отбивается."
|
|
212
|
+
elif [ -z "$state" ]; then
|
|
181
213
|
reason="BLOCKED by turn-exit-guard: за этот ход не сделано ничего — ни правки, ни команды, меняющей дерево. Папки задачи у этой работы нет, и состояние взять неоткуда, но ход это не кончает.
|
|
182
214
|
|
|
183
215
|
Ход кончается четырьмя способами, и других нет: вопрос владельцу, ответа на который в правилах нет; отказ гарда; заполненное окно захода; отданная работа с начатой следующей. Названная и не запущенная команда выходом не является: строка «сейчас запущу» — объявление намерения, а оно прямо названо ложным концом хода.
|
|
@@ -63,12 +63,19 @@ red_re='completed[[:space:]]+failure|"conclusion"[[:space:]]*:[[:space:]]*"failu
|
|
|
63
63
|
# по следующей задаче не считается — она чинит прежнюю, а не двигает работу дальше.
|
|
64
64
|
moved_re='task:new|task:move|checkout[[:space:]]+-b|docs/tasks/'
|
|
65
65
|
|
|
66
|
+
# Чем ход показывает, что отданную работу он довёл до конца, а не бросил черновиком. Снятие
|
|
67
|
+
# черновика — очевидный случай; чтение прогона — тот, где снимать ещё нечего, но исполнитель
|
|
68
|
+
# посмотрел, а не сказал «жду». Две готовые заявки простояли черновиками именно потому, что
|
|
69
|
+
# следующая задача была взята вместо этого, а не сверх этого.
|
|
70
|
+
ready_re='pr[[:space:]]+ready|run[[:space:]]+(list|view|watch)|pr[[:space:]]+checks|check-runs|check:board|board\.mjs'
|
|
71
|
+
|
|
66
72
|
# Ход — это всё, что записано после последнего настоящего ввода владельца. Ответ инструмента
|
|
67
73
|
# приходит той же ролью, поэтому строки с `tool_result` вводом не считаются.
|
|
68
74
|
#
|
|
69
75
|
# Хвост в 400 строк: запись хода растёт всю сессию, а судится только последний ход.
|
|
70
76
|
verdict="$(tail -n 400 "$transcript" 2>/dev/null | jq -s -r \
|
|
71
|
-
--arg opened "$opened_re" --arg moved "$moved_re" --arg read "$read_re" --arg red "$red_re"
|
|
77
|
+
--arg opened "$opened_re" --arg moved "$moved_re" --arg read "$read_re" --arg red "$red_re" \
|
|
78
|
+
--arg ready "$ready_re" '
|
|
72
79
|
def is_input:
|
|
73
80
|
.type == "user"
|
|
74
81
|
and (((.message.content // []) | if type == "array"
|
|
@@ -90,12 +97,41 @@ verdict="$(tail -n 400 "$transcript" 2>/dev/null | jq -s -r \
|
|
|
90
97
|
| ($ran | test($opened; "i")) as $opened_pr
|
|
91
98
|
| (($ran | test($read; "i")) and ($out | test($red; "i"))) as $red_run
|
|
92
99
|
| ($ran | test($moved; "i")) as $went_on
|
|
93
|
-
|
|
|
94
|
-
|
|
100
|
+
| ($ran | test($ready; "i")) as $checked
|
|
101
|
+
| if $opened_pr and ($went_on | not) then "owe:pr"
|
|
102
|
+
elif $opened_pr and ($checked | not) then "owe:draft"
|
|
103
|
+
elif $went_on then "pass"
|
|
95
104
|
elif $red_run then "owe:run"
|
|
96
105
|
else "pass" end
|
|
97
106
|
' 2>/dev/null)"
|
|
98
107
|
|
|
108
|
+
# Черновик, оставленный при взятой следующей задаче, — отдельный отказ: там требование не про
|
|
109
|
+
# следующую задачу, а про доведение отданной.
|
|
110
|
+
if [ "$verdict" = "owe:draft" ]; then
|
|
111
|
+
reason="BLOCKED by waiting-turn-guard: в этом ходе открыт PR, следующая задача взята, а состояние отданной работы не спрошено ни одной командой.
|
|
112
|
+
|
|
113
|
+
Черновик читается владельцем как «работа не кончена»: кнопка слияния у него заблокирована самим хостингом, и по списку заявок готовое от недоделанного не отличить — серое и там и там. Довести отданное до снятого черновика обязан тот, кто его отдал.
|
|
114
|
+
|
|
115
|
+
Спроси прогон на вершине этим же ходом — `gh run list`, `gh pr checks` или сверку очереди работ — и сними черновик, когда он зелёный, а ветка сливается. Прогон ещё идёт — так и скажи владельцу, назвав его вывод.
|
|
116
|
+
|
|
117
|
+
Следующая задача берётся сверх этого, а не вместо: обе готовые заявки простояли черновиками ровно на такой подмене.
|
|
118
|
+
|
|
119
|
+
Гард судит один ход: следующий заход не отбивается."
|
|
120
|
+
|
|
121
|
+
# shellcheck disable=SC1090
|
|
122
|
+
[ -f "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/deny-tail.sh" ] \
|
|
123
|
+
&& . "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/deny-tail.sh" 2>/dev/null
|
|
124
|
+
command -v rt_deny_tail >/dev/null 2>&1 || rt_deny_tail() { :; }
|
|
125
|
+
deny_tail_text="$(rt_deny_tail "")"
|
|
126
|
+
[ -n "$deny_tail_text" ] && reason="${reason}
|
|
127
|
+
|
|
128
|
+
${deny_tail_text}"
|
|
129
|
+
|
|
130
|
+
jq -n --arg r "$reason" '{decision:"block",reason:$r}' 2>/dev/null \
|
|
131
|
+
|| printf '{"decision":"block","reason":"waiting-turn-guard: отданная работа осталась черновиком — спроси прогон и сними черновик."}\n'
|
|
132
|
+
exit 0
|
|
133
|
+
fi
|
|
134
|
+
|
|
99
135
|
case "$verdict" in
|
|
100
136
|
owe:pr) said="в этом ходе открыт PR" ;;
|
|
101
137
|
owe:run) said="в этом ходе прочитан красный прогон" ;;
|
|
@@ -114,17 +114,17 @@ az repos pr update --id 205 --description "$(cat тело.md)"
|
|
|
114
114
|
|
|
115
115
|
## Оставшийся шаг
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
Папка задачи разобрана коммитом `<sha>` — за работой убрано. Осталось дождаться прогона и снять
|
|
118
|
+
черновик; до этого кнопка слияния заблокирована хостингом.
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное тело,
|
|
122
|
-
— в тот ход, которым
|
|
122
|
+
— в тот ход, которым снимается черновик:
|
|
123
123
|
|
|
124
124
|
```markdown
|
|
125
125
|
## Оставшийся шаг
|
|
126
126
|
|
|
127
|
-
Не осталось:
|
|
127
|
+
Не осталось: прогон зелёный, черновик снят. Можно вливать.
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
|
|
@@ -141,17 +141,17 @@ Closes #86
|
|
|
141
141
|
|
|
142
142
|
## Оставшийся шаг
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
Папка задачи разобрана коммитом `<sha>` — за работой убрано. Осталось дождаться прогона и снять
|
|
145
|
+
черновик; до этого кнопка слияния заблокирована хостингом.
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное тело,
|
|
149
|
-
— в тот ход, которым
|
|
149
|
+
— в тот ход, которым снимается черновик:
|
|
150
150
|
|
|
151
151
|
```markdown
|
|
152
152
|
## Оставшийся шаг
|
|
153
153
|
|
|
154
|
-
Не осталось:
|
|
154
|
+
Не осталось: прогон зелёный, черновик снят. Можно вливать.
|
|
155
155
|
```
|
|
156
156
|
|
|
157
157
|
Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
|
|
@@ -125,17 +125,17 @@ Closes #86
|
|
|
125
125
|
|
|
126
126
|
## Оставшийся шаг
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
Папка задачи разобрана коммитом `<sha>` — за работой убрано. Осталось дождаться прогона и снять
|
|
129
|
+
черновик; до этого кнопка слияния заблокирована хостингом.
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
Раздел «Оставшийся шаг» стоит последним и переписывается тем же вызовом, что и остальное
|
|
133
|
-
описание, — в тот ход, которым
|
|
133
|
+
описание, — в тот ход, которым снимается черновик:
|
|
134
134
|
|
|
135
135
|
```markdown
|
|
136
136
|
## Оставшийся шаг
|
|
137
137
|
|
|
138
|
-
Не осталось:
|
|
138
|
+
Не осталось: прогон зелёный, черновик снят. Можно вливать.
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
Стоит он там потому, что решение о слиянии принимается на этой странице, а не в переписке:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: task-flow-archive
|
|
3
3
|
kind: pattern
|
|
4
4
|
rule: task-flow
|
|
5
|
-
description: Паттерн правила task-flow. Брать, когда
|
|
5
|
+
description: Паттерн правила task-flow. Брать, когда тексты приведены и папка задачи разбирается последним коммитом до открытия заявки: переезд в описание прошлого, сверка очереди работ, разбор закрытой работы правилами и то, что делать с его находками. Не брать для вливания договорённости, открытия заявки и снятия черновика — это паттерн task-flow-close.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Разбор папки задачи и разбор работы правилами
|
|
@@ -14,7 +14,7 @@ description: Паттерн правила task-flow. Брать, когда р
|
|
|
14
14
|
## Когда брать
|
|
15
15
|
|
|
16
16
|
- Договорённость влита, тексты домена приведены, и папка задачи разбирается последним
|
|
17
|
-
коммитом
|
|
17
|
+
коммитом ветки — до открытия заявки, а не после одобрения.
|
|
18
18
|
- Работа слита человеком, и её разбирают правилами.
|
|
19
19
|
- Разбор вернул находки, и их надо куда-то положить.
|
|
20
20
|
|
|
@@ -55,8 +55,12 @@ cat docs/tasks/<КЛЮЧ>-<номер>-<slug>/grill.md > docs/archive/<ЧТО_Р
|
|
|
55
55
|
rm -r docs/tasks/<КЛЮЧ>-<номер>-<slug>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
Разбор идёт
|
|
59
|
-
|
|
58
|
+
Разбор идёт последним коммитом ветки, до открытия заявки: открытие с лежащей папкой отбивает
|
|
59
|
+
гард поставки. Прежде уборка стояла после одобрения — считалось, что замысел нужен на диске всё
|
|
60
|
+
время разбора. Но кнопку слияния нажимает человек на хостинге, куда гард не достаёт, и вливает
|
|
61
|
+
он, как только видит зелёное: трижды подряд папка уехала в главную неразобранной. Замысла после
|
|
62
|
+
уборки на диске нет намеренно, и правку по замечаниям гард хода работы пропускает по признаку
|
|
63
|
+
из истории ветки.
|
|
60
64
|
|
|
61
65
|
### Работа, разбирающая чужую папку, разбирает две
|
|
62
66
|
|
|
@@ -75,8 +79,8 @@ rm -r docs/tasks/<своя>
|
|
|
75
79
|
Две записи в архиве, а не одна: работы разные, и решения в них разные. Сверка очереди работ
|
|
76
80
|
после этого не называет ни одной папки — этим и проверяется, что разобраны обе.
|
|
77
81
|
|
|
78
|
-
**Следующее движение:** разобранная папка уезжает в ветку тем же коммитом,
|
|
79
|
-
|
|
82
|
+
**Следующее движение:** разобранная папка уезжает в ветку тем же коммитом, следом сверяется
|
|
83
|
+
очередь работ, и тем же ходом открывается заявка — паттерн `task-flow-close`.
|
|
80
84
|
|
|
81
85
|
## Состояние `папка-разобрана`: сверка очереди работ
|
|
82
86
|
|
|
@@ -87,7 +91,7 @@ npm run check:docs # пути, названные в текстах, суще
|
|
|
87
91
|
```
|
|
88
92
|
|
|
89
93
|
**Следующее движение:** расхождения, названные сверками, чинятся тем же ходом; чинить нечего —
|
|
90
|
-
тот же ход
|
|
94
|
+
тот же ход открывает заявку черновиком и называет владельцу номер, паттерн `task-flow-close`.
|
|
91
95
|
|
|
92
96
|
## Состояние `влито`: работа разбирается правилами — фоном, следом за PR
|
|
93
97
|
|
|
@@ -156,20 +160,18 @@ npm run check:docs # пути, названные в текстах, суще
|
|
|
156
160
|
|
|
157
161
|
## Ловушки
|
|
158
162
|
|
|
159
|
-
- **Папку разбирают до
|
|
160
|
-
задачу закрытой по слиянию:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
приведение текстов домена, разбор папки. Понадобилась правка кода после разбора — замысел
|
|
172
|
-
восстанавливается на диске на время правки, и разбор повторяется тем же коммитом.
|
|
163
|
+
- **Папку разбирают до открытия заявки — потом о ней уже никто не вспомнит.** Сверка очереди
|
|
164
|
+
считает задачу закрытой по слиянию: после него за папку никто не отвечает — работа перешла к
|
|
165
|
+
следующей задаче, и находка достанется чужому заходу. Три раза подряд папка закрытой задачи
|
|
166
|
+
так и уехала в главную ветку, в последний раз их набралось пять. Держит это гард поставки:
|
|
167
|
+
открытие заявки отбивается, пока папка лежит в ветке.
|
|
168
|
+
- **Разбор папки идёт последним коммитом, после того как гейт пуша прошёл целиком.** Порядок
|
|
169
|
+
один: мерж главной ветки, все линтеры и проверки зелёные, вливание договорённости, приведение
|
|
170
|
+
текстов домена, разбор папки — и только потом заявка.
|
|
171
|
+
- **После разбора замысла на диске нет, и собирать папку заново не надо.** Правку по замечаниям
|
|
172
|
+
разбора и починку красного прогона гард хода работы пропускает по признаку из истории ветки:
|
|
173
|
+
папка, снятая её коммитом, и есть признак отданной работы. Собранная заново папка вернула бы
|
|
174
|
+
отказ гарда поставки на следующем же вызове.
|
|
173
175
|
- **Если папку просто удалить, первым пропадёт `grill.md`.** Удалить проще, чем разобрать, а
|
|
174
176
|
слова владельца записаны только там, и восстановить их неоткуда. Поэтому гард требует, чтобы
|
|
175
177
|
ветка добавила запись в архив. Что именно перенесли, он не проверяет — это смотрит владелец
|