@rt-tools/agent-kit 0.10.0 → 0.11.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/check-state-next.mjs +194 -0
- package/assets/checks/check-states.mjs +142 -0
- package/assets/checks/check-turn-map.mjs +146 -0
- package/assets/commands/agent-kit-digest.md +6 -5
- package/assets/defaults/project.sh +58 -6
- package/assets/defaults/turn-map.md +46 -0
- package/assets/hooks/browser-device-id.sh +2 -0
- package/assets/hooks/browser-guard-device-id.sh +2 -0
- package/assets/hooks/browser-guard-no-asking.sh +2 -0
- package/assets/hooks/browser-guard-no-listing.sh +2 -0
- package/assets/hooks/browser-guard-no-other-drivers.sh +2 -0
- package/assets/hooks/browser-guard-require-select.sh +2 -0
- package/assets/hooks/claim-guard.sh +2 -0
- package/assets/hooks/commit-msg.sh +2 -0
- package/assets/hooks/conscience-guard.sh +2 -0
- package/assets/hooks/constitution-index.sh +2 -0
- package/assets/hooks/dev-server-guard.sh +2 -0
- package/assets/hooks/docs-guard.sh +2 -0
- package/assets/hooks/exam-guard.sh +2 -0
- package/assets/hooks/git-guard-delivery-signature.sh +2 -0
- package/assets/hooks/git-guard-delivery.sh +2 -0
- package/assets/hooks/git-guard-main.sh +2 -0
- package/assets/hooks/git-guard-push-tests.sh +2 -0
- package/assets/hooks/glossary-load.sh +2 -0
- package/assets/hooks/grill-gate.sh +2 -0
- package/assets/hooks/handoff-entry-guard.sh +2 -0
- package/assets/hooks/handoff-write.sh +103 -0
- package/assets/hooks/lint-after-edit.sh +2 -0
- package/assets/hooks/observe.sh +2 -0
- package/assets/hooks/postmortem-guard.sh +2 -0
- package/assets/hooks/proposal-guard.sh +2 -0
- package/assets/hooks/prose-style-guard.sh +2 -0
- package/assets/hooks/qa-dataid-guard.sh +2 -0
- package/assets/hooks/rerun-guard.sh +2 -0
- package/assets/hooks/reuse-first-guard.sh +2 -0
- package/assets/hooks/roles.sh +2 -0
- package/assets/hooks/skill-gate-layers.sh +2 -0
- package/assets/hooks/skill-gate-rearm.sh +2 -0
- package/assets/hooks/skill-gate.sh +2 -0
- package/assets/hooks/skill-loaded.sh +2 -0
- package/assets/hooks/sql-guard-parse.sh +2 -0
- package/assets/hooks/sql-guard-request.sh +2 -0
- package/assets/hooks/sql-guard-target.sh +2 -0
- package/assets/hooks/sql-guard-write.sh +2 -0
- package/assets/hooks/sql-guard.sh +2 -0
- package/assets/hooks/task-context-load.sh +2 -0
- package/assets/hooks/task-flow-guard.sh +2 -0
- package/assets/hooks/turn-entry-load.sh +62 -0
- package/assets/hooks/turn-exit-guard.sh +2 -0
- package/assets/hooks/utf8.sh +35 -0
- package/assets/hooks/waiting-turn-guard.sh +2 -0
- package/assets/hooks/window-fill-guard.sh +31 -1
- package/assets/laws/work-conduct.md +29 -0
- package/assets/patterns/cargo-triage-mark.md +119 -0
- package/assets/patterns/task-flow-close.md +21 -0
- package/assets/patterns/task-flow-handoff.md +18 -0
- package/assets/patterns/task-flow-resume.md +6 -0
- package/assets/patterns/task-flow-start.md +41 -0
- package/assets/patterns/turn-entry-map.md +81 -0
- package/assets/rules/cargo-triage.md +126 -0
- package/assets/rules/task-flow.md +14 -1
- package/assets/rules/turn-entry.md +93 -0
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +42 -1
- package/bin/agent-kit.js.map +1 -1
- package/lib/cargo-state.d.ts +62 -0
- package/lib/cargo-state.d.ts.map +1 -0
- package/lib/cargo-state.js +118 -0
- package/lib/cargo-state.js.map +1 -0
- package/lib/cargo.d.ts +42 -0
- package/lib/cargo.d.ts.map +1 -1
- package/lib/cargo.js +2 -0
- package/lib/cargo.js.map +1 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +64 -4
- package/lib/commands.js.map +1 -1
- package/lib/observations.d.ts +35 -1
- package/lib/observations.d.ts.map +1 -1
- package/lib/observations.js +14 -2
- package/lib/observations.js.map +1 -1
- package/lib/ship.d.ts +3 -0
- package/lib/ship.d.ts.map +1 -1
- package/lib/ship.js +56 -0
- package/lib/ship.js.map +1 -1
- package/lib/thresholds.d.ts +49 -0
- package/lib/thresholds.d.ts.map +1 -0
- package/lib/thresholds.js +151 -0
- package/lib/thresholds.js.map +1 -0
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.11.0.tgz +0 -0
- package/rt-tools-agent-kit-0.10.0.tgz +0 -0
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
#
|
|
9
9
|
# Файл с идентификатором в репозиторий не коммитится: у каждой машины он свой.
|
|
10
10
|
|
|
11
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
12
|
+
|
|
11
13
|
if [ -n "${RT_BROWSER_DEVICE_ID:-}" ]; then
|
|
12
14
|
printf '%s\n' "$RT_BROWSER_DEVICE_ID"
|
|
13
15
|
exit 0
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
#
|
|
12
12
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: помощник не назвал профиль — пропуск.
|
|
13
13
|
|
|
14
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
15
|
+
|
|
14
16
|
input="$(cat 2>/dev/null)"
|
|
15
17
|
|
|
16
18
|
device_id="$("${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/browser-device-id.sh" 2>/dev/null)"
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
#
|
|
15
15
|
# FAIL-OPEN when browser-device-id.sh prints nothing.
|
|
16
16
|
|
|
17
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
18
|
+
|
|
17
19
|
input="$(cat 2>/dev/null)"
|
|
18
20
|
|
|
19
21
|
device_id="$("${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/browser-device-id.sh" 2>/dev/null)"
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: помощник не назвал профиль — пропуск. Гард, который не может назвать
|
|
11
11
|
# нужный профиль, ничего не предлагает взамен, и слепой отказ только заводил бы работу в тупик.
|
|
12
12
|
|
|
13
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
14
|
+
|
|
13
15
|
cat >/dev/null 2>&1
|
|
14
16
|
|
|
15
17
|
device_id="$("${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/browser-device-id.sh" 2>/dev/null)"
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
#
|
|
14
14
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: помощник не назвал профиль — пропуск.
|
|
15
15
|
|
|
16
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
17
|
+
|
|
16
18
|
input="$(cat 2>/dev/null)"
|
|
17
19
|
|
|
18
20
|
device_id="$("${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/browser-device-id.sh" 2>/dev/null)"
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
#
|
|
21
21
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: помощник не назвал профиль — пропуск.
|
|
22
22
|
|
|
23
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
24
|
+
|
|
23
25
|
input="$(cat 2>/dev/null)"
|
|
24
26
|
|
|
25
27
|
device_id="$("${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/browser-device-id.sh" 2>/dev/null)"
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: при любой ошибке, нехватке `jq`, отсутствии записи хода или пустом
|
|
26
26
|
# тексте ход РАЗРЕШАЕТСЯ (exit 0). Сломанный гард не имеет права заклинить разговор.
|
|
27
27
|
|
|
28
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
29
|
+
|
|
28
30
|
input="$(cat 2>/dev/null)"
|
|
29
31
|
[ -z "$input" ] && exit 0
|
|
30
32
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: проверяльщика нет (свежий клон без установленных зависимостей) —
|
|
16
16
|
# пропуск. Формат тогда не проверяется, и это лучше, чем заклинивший коммит.
|
|
17
17
|
|
|
18
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
19
|
+
|
|
18
20
|
msg_file="$1"
|
|
19
21
|
[ -z "$msg_file" ] && exit 0
|
|
20
22
|
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: нет `jq`, нет записи хода, роль молчит или отвечает не по форме — ход
|
|
20
20
|
# разрешается. Сломанная совесть не имеет права заклинить разговор.
|
|
21
21
|
|
|
22
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
23
|
+
|
|
22
24
|
input="$(cat 2>/dev/null)"
|
|
23
25
|
[ -z "$input" ] && exit 0
|
|
24
26
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: любая ошибка начинает сессию без добавленного контекста (exit 0).
|
|
13
13
|
# Сломанный вход не имеет права остановить сессию.
|
|
14
14
|
|
|
15
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
16
|
+
|
|
15
17
|
dir="${CLAUDE_PROJECT_DIR:-.}/docs/constitution"
|
|
16
18
|
[ -d "$dir" ] || exit 0
|
|
17
19
|
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
# Где именно подняты приложения, знает профиль проекта: .claude/rt-kit/project.sh, переменная
|
|
15
15
|
# RT_STANDS. Нет профиля — текст отказа остаётся общим, сам гард работает.
|
|
16
16
|
|
|
17
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
18
|
+
|
|
17
19
|
input="$(cat 2>/dev/null)"
|
|
18
20
|
|
|
19
21
|
tool="$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null)"
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: не репозиторий, нет разборщика, битый ввод, пустой список файлов —
|
|
27
27
|
# пропуск.
|
|
28
28
|
|
|
29
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
30
|
+
|
|
29
31
|
input="$(cat 2>/dev/null)"
|
|
30
32
|
[ -z "$input" ] && exit 0
|
|
31
33
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
# FAIL-OPEN: нет jq, нет записи хода, чужой инструмент → пропуск. Сломанный гард не должен
|
|
19
19
|
# мешать работать.
|
|
20
20
|
|
|
21
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
22
|
+
|
|
21
23
|
input="$(cat 2>/dev/null)"
|
|
22
24
|
[ -z "$input" ] && exit 0
|
|
23
25
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
# Вынесен он отсюда потому, что гард дорос до предела длины: предметов в нём пять, и подпись
|
|
11
11
|
# среди них самая отдельная — своя точка проверки, свои условия молчания, свой отказ.
|
|
12
12
|
|
|
13
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
14
|
+
|
|
13
15
|
rt_delivery_signature() {
|
|
14
16
|
# --- подпись машинного коммита ------------------------------------------------------------
|
|
15
17
|
#
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
#
|
|
38
38
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: не репозиторий, нет разборщика, битый ввод, нет профиля — пропуск.
|
|
39
39
|
|
|
40
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
41
|
+
|
|
40
42
|
input="$(cat 2>/dev/null)"
|
|
41
43
|
[ -z "$input" ] && exit 0
|
|
42
44
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: не репозиторий, нет гита, открепившийся HEAD, битый ввод — пропуск.
|
|
14
14
|
# Сломанный гард не должен мешать работать.
|
|
15
15
|
|
|
16
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
17
|
+
|
|
16
18
|
input="$(cat 2>/dev/null)"
|
|
17
19
|
[ -z "$input" ] && exit 0
|
|
18
20
|
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
#
|
|
10
10
|
# FAIL-OPEN: нет файла или нет `jq` — выходим молча. Сессия важнее словаря.
|
|
11
11
|
|
|
12
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
13
|
+
|
|
12
14
|
GLOSSARY="${CLAUDE_PROJECT_DIR:-.}/docs/GLOSSARY.md"
|
|
13
15
|
[ -f "$GLOSSARY" ] || exit 0
|
|
14
16
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: при любой ошибке, отсутствии записи хода и повторном заходе ход
|
|
23
23
|
# РАЗРЕШАЕТСЯ (exit 0). Сломанный гард не имеет права заклинить разговор.
|
|
24
24
|
|
|
25
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
26
|
+
|
|
25
27
|
input="$(cat 2>/dev/null)"
|
|
26
28
|
[ -z "$input" ] && exit 0
|
|
27
29
|
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
#
|
|
15
15
|
# FAIL-OPEN: нет `jq`, нет записи хода, передачи в реплике нет → пропуск.
|
|
16
16
|
|
|
17
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
18
|
+
|
|
17
19
|
input="$(cat 2>/dev/null)"
|
|
18
20
|
[ -z "$input" ] && exit 0
|
|
19
21
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# rt-hook: PreCompact .*
|
|
3
|
+
# Требует: hooks/profile-check.sh
|
|
4
|
+
# Передача захода пишется перед сжатием контекста, а не рукой исполнителя.
|
|
5
|
+
#
|
|
6
|
+
# Заход кончается двумя способами: исполнитель доводит работу до точки и пишет передачу сам —
|
|
7
|
+
# либо контекст переполняется, и сжатие приходит от инструмента. Второй случай раньше терял
|
|
8
|
+
# передачу целиком: писать её в этот момент уже некому, а после сжатия пересказывать нечего.
|
|
9
|
+
# Ночью, когда напомнить некому, так кончается каждый заход.
|
|
10
|
+
#
|
|
11
|
+
# Хук собирает передачу из того, что лежит на диске: ход работы даёт состояние и следующий шаг,
|
|
12
|
+
# дерево — ветку, незакоммиченное и коммиты сверх главной. Ничего от себя он не добавляет:
|
|
13
|
+
# передача пересказывает записанное, а не заменяет его.
|
|
14
|
+
#
|
|
15
|
+
# Написанное руками не затирается молча: файл один, и последняя запись побеждает. Исполнитель,
|
|
16
|
+
# закрывающий заход по правилу, пишет поверх — его передача полнее, потому что он знает то,
|
|
17
|
+
# чего на диске нет.
|
|
18
|
+
#
|
|
19
|
+
# FAIL-OPEN: нет разборщика, пустой ввод, не репозиторий, нет каталога передачи — хук выходит
|
|
20
|
+
# нулём и молчит. Сжатие он не отбивает никогда: остановленное сжатие оставит заход без места.
|
|
21
|
+
|
|
22
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
23
|
+
|
|
24
|
+
input="$(cat 2>/dev/null)"
|
|
25
|
+
[ -z "$input" ] && exit 0
|
|
26
|
+
|
|
27
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
28
|
+
|
|
29
|
+
rt_hooks_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
30
|
+
for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../defaults/project.sh" \
|
|
31
|
+
"${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/defaults/project.sh" "${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/project.sh"; do
|
|
32
|
+
# shellcheck disable=SC1090
|
|
33
|
+
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
workdir="$(printf '%s' "$input" | jq -r '.cwd // empty' 2>/dev/null)"
|
|
37
|
+
[ -z "$workdir" ] && workdir="${CLAUDE_PROJECT_DIR:-.}"
|
|
38
|
+
cd "$workdir" 2>/dev/null || exit 0
|
|
39
|
+
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
|
|
40
|
+
|
|
41
|
+
branch="$(git branch --show-current 2>/dev/null)"
|
|
42
|
+
[ -z "$branch" ] && exit 0
|
|
43
|
+
|
|
44
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
45
|
+
[ -z "$root" ] && exit 0
|
|
46
|
+
|
|
47
|
+
handoff_dir="${RT_HANDOFF_DIR:-.claude/handoff}"
|
|
48
|
+
tasks_dir="${RT_TASKS_DIR:-docs/tasks}"
|
|
49
|
+
|
|
50
|
+
mkdir -p "$root/$handoff_dir" 2>/dev/null || exit 0
|
|
51
|
+
[ -d "$root/$handoff_dir" ] || exit 0
|
|
52
|
+
|
|
53
|
+
# Ручное сжатие от автоматического отличается одним: при ручном исполнитель у клавиатуры и
|
|
54
|
+
# может дописать передачу сам. Пишется она в обоих случаях — заход, сжатый руками, теряет
|
|
55
|
+
# контекст ровно так же.
|
|
56
|
+
trigger="$(printf '%s' "$input" | jq -r '.trigger // "auto"' 2>/dev/null)"
|
|
57
|
+
[ -z "$trigger" ] && trigger='auto'
|
|
58
|
+
|
|
59
|
+
progress="$root/$tasks_dir/$branch/progress.md"
|
|
60
|
+
|
|
61
|
+
# Строка раздела «Где стоим» по её названию. Пусто — работа идёт вне папки задачи, и выдумывать
|
|
62
|
+
# за неё состояние нельзя: в передаче тогда стоит то, что известно дереву.
|
|
63
|
+
line_of() {
|
|
64
|
+
[ -f "$progress" ] || return 0
|
|
65
|
+
sed -n "s/^[[:space:]]*[-*][[:space:]]*\*\*$1:\*\*[[:space:]]*\(.*\)/\1/p" "$progress" 2>/dev/null | head -1
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
state="$(line_of 'Состояние')"
|
|
69
|
+
stage="$(line_of 'Этап')"
|
|
70
|
+
next_step="$(line_of 'Следующий шаг')"
|
|
71
|
+
pull="$(line_of 'PR')"
|
|
72
|
+
|
|
73
|
+
uncommitted="$(git status --short 2>/dev/null | head -20)"
|
|
74
|
+
[ -z "$uncommitted" ] && uncommitted='нет'
|
|
75
|
+
|
|
76
|
+
ahead="$(git log --oneline origin/main..HEAD 2>/dev/null | head -20)"
|
|
77
|
+
[ -z "$ahead" ] && ahead='нет коммитов сверх главной'
|
|
78
|
+
|
|
79
|
+
target="$root/$handoff_dir/$branch.md"
|
|
80
|
+
|
|
81
|
+
{
|
|
82
|
+
printf '# Передача захода — сжатие контекста (%s)\n\n' "$trigger"
|
|
83
|
+
printf '**Рабочее дерево:** %s\n' "$root"
|
|
84
|
+
printf '**Ветка:** %s\n\n' "$branch"
|
|
85
|
+
|
|
86
|
+
if [ -n "$state" ]; then
|
|
87
|
+
printf '## Где стоим\n\n'
|
|
88
|
+
printf -- '- **Состояние:** %s\n' "$state"
|
|
89
|
+
[ -n "$stage" ] && printf -- '- **Этап:** %s\n' "$stage"
|
|
90
|
+
[ -n "$next_step" ] && printf -- '- **Следующий шаг:** %s\n' "$next_step"
|
|
91
|
+
[ -n "$pull" ] && printf -- '- **PR:** %s\n' "$pull"
|
|
92
|
+
printf '\nХод работы целиком — `%s/%s/progress.md`; замысел рядом с ним.\n\n' "$tasks_dir" "$branch"
|
|
93
|
+
else
|
|
94
|
+
printf '## Где стоим\n\nПапки задачи у этой ветки нет: состояние работы взять неоткуда.\n\n'
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
printf '## Незакоммиченное\n\n```\n%s\n```\n\n' "$uncommitted"
|
|
98
|
+
printf '## Коммиты сверх главной\n\n```\n%s\n```\n\n' "$ahead"
|
|
99
|
+
printf 'Написана хуком перед сжатием контекста. Всё, что здесь стоит, проверяется деревом:\n'
|
|
100
|
+
printf 'передача пересказывает записанное и описывает минуту, когда её собрали.\n'
|
|
101
|
+
} > "$target" 2>/dev/null
|
|
102
|
+
|
|
103
|
+
exit 0
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
|
|
30
30
|
# Сколько файлов линтуется за один перенос. Переезд либы трогает десятки файлов, и прогон по
|
|
31
31
|
# каждому превратил бы хук в минутную паузу; на нарушение границы хватает первых.
|
|
32
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
33
|
+
|
|
32
34
|
MAX_FILES=12
|
|
33
35
|
|
|
34
36
|
input="$(cat 2>/dev/null)"
|
package/assets/hooks/observe.sh
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
# Значение, годное к записи. Путь не выносится ни при каких обстоятельствах, остальное чистится
|
|
21
21
|
# до имени и обрезается: длинное значение в наблюдении не значит ничего, кроме утечки.
|
|
22
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
23
|
+
|
|
22
24
|
rt_observe_clean() {
|
|
23
25
|
case "$1" in
|
|
24
26
|
*/*) return 0 ;;
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: при любой ошибке, отсутствии записи хода и повторном заходе ход
|
|
22
22
|
# РАЗРЕШАЕТСЯ (exit 0). Сломанный гард не имеет права заклинить разговор.
|
|
23
23
|
|
|
24
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
25
|
+
|
|
24
26
|
input="$(cat 2>/dev/null)"
|
|
25
27
|
[ -z "$input" ] && exit 0
|
|
26
28
|
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: при любой ошибке, нехватке `jq`, отсутствии записи хода и повторном
|
|
21
21
|
# заходе ход РАЗРЕШАЕТСЯ (exit 0). Сломанный гард не имеет права заклинить разговор.
|
|
22
22
|
|
|
23
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
24
|
+
|
|
23
25
|
input="$(cat 2>/dev/null)"
|
|
24
26
|
[ -z "$input" ] && exit 0
|
|
25
27
|
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
#
|
|
13
13
|
# FAIL-OPEN: нет узла, нет проверки, чужой инструмент, не `.md` → пропуск.
|
|
14
14
|
|
|
15
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
16
|
+
|
|
15
17
|
input="$(cat 2>/dev/null)"
|
|
16
18
|
[ -z "$input" ] && exit 0
|
|
17
19
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
#
|
|
26
26
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: нет разборщика, битый ввод, чужой инструмент — пропуск.
|
|
27
27
|
|
|
28
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
29
|
+
|
|
28
30
|
input="$(cat 2>/dev/null)"
|
|
29
31
|
[ -z "$input" ] && exit 0
|
|
30
32
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
# похож на перезапуск — пропуск. Гард без номера судить не берётся: перезапуск последнего
|
|
21
21
|
# упавшего прогона зовут и без него, а угадывать, о каком задании речь, значит отбивать наугад.
|
|
22
22
|
|
|
23
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
24
|
+
|
|
23
25
|
input="$(cat 2>/dev/null)"
|
|
24
26
|
[ -z "$input" ] && exit 0
|
|
25
27
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
#
|
|
33
33
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: нет разборщика, битый ввод, чужой инструмент — пропуск.
|
|
34
34
|
|
|
35
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
36
|
+
|
|
35
37
|
input="$(cat 2>/dev/null)"
|
|
36
38
|
[ -z "$input" ] && exit 0
|
|
37
39
|
command -v jq >/dev/null 2>&1 || exit 0
|
package/assets/hooks/roles.sh
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
|
|
21
21
|
# Уже названное вторым разом не требуется: отказ, перечисляющий одно правило дважды, читается
|
|
22
22
|
# как два разных требования.
|
|
23
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
24
|
+
|
|
23
25
|
rt_layer_add() {
|
|
24
26
|
case " $req " in
|
|
25
27
|
*" $1 "*) return 0 ;;
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: любая ошибка и любой неопознанный путь пропускают правку (exit 0).
|
|
24
24
|
# Сломанный гейт не имеет права остановить работу совсем.
|
|
25
25
|
|
|
26
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
27
|
+
|
|
26
28
|
input="$(cat 2>/dev/null)"
|
|
27
29
|
[ -z "$input" ] && exit 0
|
|
28
30
|
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
# команда становилась одним сегментом, доказательство чтения из первой строки покрывало
|
|
14
14
|
# неразобранный вызов из второй, и запись на боевую базу проходила молча — тот же обход,
|
|
15
15
|
# что чинили для `&&`, только набранный с новой строки.
|
|
16
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
17
|
+
|
|
16
18
|
normalize() {
|
|
17
19
|
perl -0ne '
|
|
18
20
|
# Продолжение длинной команды обратным слешем — это одна строка, а не две: без
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
# Три вида ввода: запрос через подключение редактора, команда оболочки и та же команда,
|
|
12
12
|
# завёрнутая в универсальный исполнитель. Инструмент, не названный здесь, гарда не касается.
|
|
13
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
14
|
+
|
|
13
15
|
sql_read_request() {
|
|
14
16
|
sql=""
|
|
15
17
|
context=""
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
# подключения, и по одному SQL отличить прод от локальной копии невозможно. Поэтому
|
|
19
19
|
# подключения опознаются в лицо. Список сверяется вызовом list_database_connections;
|
|
20
20
|
# добавили новое — допишите сюда, иначе оно попадёт в «неизвестные» ниже.
|
|
21
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
22
|
+
|
|
21
23
|
sql_resolve_target() {
|
|
22
24
|
is_prod=""
|
|
23
25
|
PROD_CONNECTIONS="${RT_PROD_CONNECTIONS:-}"
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
# Глаголы ищутся в сегментах ВЫЗОВА, а не по всей строке: иначе слово из шаблона поиска в
|
|
9
9
|
# соседнем звене цепочки объявляло записью читающую команду.
|
|
10
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
11
|
+
|
|
10
12
|
sql_detect_write() {
|
|
11
13
|
is_write=""
|
|
12
14
|
write_scope="$segments"
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
# пропускаются целиком — иначе слова «drop» и «update» в описании коммита читались бы как
|
|
41
41
|
# запрос. Доставки запроса внутри такой команды не бывает, так что цена послабления нулевая.
|
|
42
42
|
|
|
43
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
44
|
+
|
|
43
45
|
input="$(cat 2>/dev/null)"
|
|
44
46
|
[ -z "$input" ] && exit 0
|
|
45
47
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
# FAIL-OPEN: нет `jq`, не git-репозиторий, нет папки задачи — выходим молча. Сессия важнее
|
|
15
15
|
# контекста.
|
|
16
16
|
|
|
17
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
18
|
+
|
|
17
19
|
ROOT="${CLAUDE_PROJECT_DIR:-.}"
|
|
18
20
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
19
21
|
cd "$ROOT" 2>/dev/null || exit 0
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
# FAIL-OPEN: нет jq, не git-репозиторий, битый ввод, чужой инструмент → пропуск. Сломанный
|
|
26
26
|
# гард не должен мешать работать.
|
|
27
27
|
|
|
28
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
29
|
+
|
|
28
30
|
input="$(cat 2>/dev/null)"
|
|
29
31
|
[ -z "$input" ] && exit 0
|
|
30
32
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# rt-hook: SessionStart startup|resume|compact|clear
|
|
3
|
+
# Требует: hooks/handoff-write.sh
|
|
4
|
+
# SessionStart: передача прошлого захода и карта хода уезжают в контекст на каждом запуске.
|
|
5
|
+
#
|
|
6
|
+
# Передачу пишет хук перед сжатием — и на этом её путь кончался: читать её не умел никто, и
|
|
7
|
+
# в новый заход её клал человек. Написанная и не прочитанная, она равна ненаписанной.
|
|
8
|
+
#
|
|
9
|
+
# Второе, чего заход после сжатия не знает, — как здесь ведут работу. Перечень состояний с
|
|
10
|
+
# обязательными действиями лежит в правиле, а правило после сжатия не загружено: заход первым
|
|
11
|
+
# движением идёт читать его целиком, то есть тратит на восстановление порядка ту часть окна,
|
|
12
|
+
# ради которой сжатие и случилось. Карта отвечает на этот вопрос до того, как он задан.
|
|
13
|
+
#
|
|
14
|
+
# Подаётся это на всех четырёх запусках, а не только после сжатия: заход после обрыва и заход
|
|
15
|
+
# после очистки начинают с того же пустого места, и разница между ними исполнителю не видна.
|
|
16
|
+
#
|
|
17
|
+
# FAIL-OPEN: не git-репозиторий, нет ветки, нет каталога передач, нет карты, нечитаемый файл —
|
|
18
|
+
# хук выходит нулём и молчит о той части, которой нет. Запуск он не отбивает никогда: сессия
|
|
19
|
+
# важнее контекста.
|
|
20
|
+
|
|
21
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
22
|
+
|
|
23
|
+
ROOT="${CLAUDE_PROJECT_DIR:-.}"
|
|
24
|
+
cd "$ROOT" 2>/dev/null || exit 0
|
|
25
|
+
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
|
|
26
|
+
|
|
27
|
+
branch="$(git branch --show-current 2>/dev/null)"
|
|
28
|
+
|
|
29
|
+
# Профиль дерева: сперва умолчание пакета, поверх него — надстройка проекта, если она есть.
|
|
30
|
+
rt_hooks_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
31
|
+
for profile in "$rt_hooks_dir/../rt-kit/defaults/project.sh" "$rt_hooks_dir/../defaults/project.sh" \
|
|
32
|
+
"$ROOT/.claude/rt-kit/defaults/project.sh" "$ROOT/.claude/rt-kit/project.sh"; do
|
|
33
|
+
# shellcheck disable=SC1090
|
|
34
|
+
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
handoff_dir="${RT_HANDOFF_DIR:-.claude/handoff}"
|
|
38
|
+
map="$rt_hooks_dir/../rt-kit/defaults/turn-map.md"
|
|
39
|
+
[ -f "$map" ] || map="$ROOT/.claude/rt-kit/defaults/turn-map.md"
|
|
40
|
+
|
|
41
|
+
# Передача берётся по имени текущей ветки. Чужая, поданная как своя, описывает работу, которой
|
|
42
|
+
# в этом дереве нет, — поэтому имя файла собирается из ветки, а не выбирается из каталога.
|
|
43
|
+
handoff=''
|
|
44
|
+
[ -n "$branch" ] && handoff="$ROOT/$handoff_dir/$branch.md"
|
|
45
|
+
|
|
46
|
+
if [ -n "$handoff" ] && [ -r "$handoff" ]; then
|
|
47
|
+
printf 'ПЕРЕДАЧА ПРОШЛОГО ЗАХОДА — `%s/%s.md`, ниже целиком.\n\n' "$handoff_dir" "$branch"
|
|
48
|
+
printf 'Она написана прошлым заходом и описывает минуту, когда её собрали. Всё, что в ней\n'
|
|
49
|
+
printf 'стоит о дереве, проверяется деревом: команда этого хода главнее записанной вчера.\n\n'
|
|
50
|
+
cat "$handoff" 2>/dev/null
|
|
51
|
+
printf '\n\n'
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [ -r "$map" ]; then
|
|
55
|
+
printf 'КАРТА ХОДА — состояния работы и то, чем ход кончается. Ниже целиком.\n\n'
|
|
56
|
+
printf 'Это выжимка правила ведения работы, а не оно само: правило объясняет, карта\n'
|
|
57
|
+
printf 'называет. Своё состояние заход читает в разделе «Где стоим» хода работы.\n\n'
|
|
58
|
+
cat "$map" 2>/dev/null
|
|
59
|
+
printf '\n'
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
exit 0
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
# или строки состояния ход РАЗРЕШАЕТСЯ (exit 0). Сломанный страж не имеет права заклинить
|
|
30
30
|
# разговор.
|
|
31
31
|
|
|
32
|
+
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utf8.sh" 2>/dev/null || true
|
|
33
|
+
|
|
32
34
|
input="$(cat 2>/dev/null)"
|
|
33
35
|
[ -z "$input" ] && exit 0
|
|
34
36
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Локаль исполнения гарда. Подключается первой строкой тела: `. "<каталог гардов>/utf8.sh"`.
|
|
3
|
+
#
|
|
4
|
+
# Образцы гардов написаны словами того языка, на котором говорит дерево, и совпадение с ними
|
|
5
|
+
# зависит от локали процесса. В локали C складывание регистра работает только для латиницы:
|
|
6
|
+
# «В дереве этого нет» под образцом `(в дереве|здесь)…` не находится вовсе, гард выходит нулём
|
|
7
|
+
# и пропускает ход, который обязан был вернуть. Счёт `{0,30}` там же считает байты, а не буквы,
|
|
8
|
+
# и буква вне латиницы весит два.
|
|
9
|
+
#
|
|
10
|
+
# Заметить это на своей машине нечем: терминал разработчика идёт в UTF-8, а служба, запускающая
|
|
11
|
+
# ту же работу, наследует пустую локаль. Три сценария так и падали в конвейере, проходя на
|
|
12
|
+
# машине, где их писали.
|
|
13
|
+
#
|
|
14
|
+
# FAIL-OPEN: локали UTF-8 в системе не нашлось — ничего не объявляется, и гард работает как
|
|
15
|
+
# прежде. Отобрать у него работу из-за отсутствия локали хуже, чем оставить прежнее поведение.
|
|
16
|
+
|
|
17
|
+
rt_use_utf8_locale() {
|
|
18
|
+
case "${LC_ALL:-${LC_CTYPE:-${LANG:-}}}" in
|
|
19
|
+
*UTF-8* | *utf-8* | *UTF8* | *utf8*) return 0 ;;
|
|
20
|
+
esac
|
|
21
|
+
|
|
22
|
+
local available candidate
|
|
23
|
+
available="$(locale -a 2>/dev/null)" || return 0
|
|
24
|
+
|
|
25
|
+
for candidate in C.UTF-8 en_US.UTF-8 ru_RU.UTF-8; do
|
|
26
|
+
if printf '%s\n' "$available" | grep -qx -- "$candidate"; then
|
|
27
|
+
export LC_ALL="$candidate"
|
|
28
|
+
return 0
|
|
29
|
+
fi
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
return 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
rt_use_utf8_locale
|