@rt-tools/agent-kit 0.3.0 → 0.5.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/README.md +194 -30
- package/assets/agents/business-analyst.md +74 -0
- package/assets/agents/project-manager.md +70 -0
- package/assets/agents/qa-engineer.md +72 -0
- package/assets/agents/skill-curator.md +110 -0
- package/assets/agents/spec-critic.md +44 -0
- package/assets/agents/spec-writer.md +50 -0
- package/assets/checks/board.github.mjs +329 -0
- package/assets/checks/check-board.github.mjs +181 -0
- package/assets/checks/check-doc-paths.mjs +163 -0
- package/assets/checks/check-dupes.mjs +277 -0
- package/assets/checks/check-lib-layers.mjs +573 -0
- package/assets/checks/check-reuse.mjs +208 -0
- package/assets/checks/check-schema-drift.mjs +186 -0
- package/assets/checks/check-specs.mjs +1086 -0
- package/assets/checks/check-styles.mjs +109 -0
- package/assets/checks/rt-kit-checks.config.mjs +134 -0
- package/assets/checks/task-new.github.mjs +198 -0
- package/assets/commands/skill-curator.md +70 -0
- package/assets/defaults/gate-map.sh +106 -0
- package/assets/defaults/project.sh +204 -0
- package/assets/hooks/browser-device-id.sh +0 -0
- package/assets/hooks/browser-guard-device-id.sh +2 -1
- package/assets/hooks/browser-guard-no-asking.sh +27 -0
- package/assets/hooks/browser-guard-no-listing.sh +2 -1
- package/assets/hooks/browser-guard-no-other-drivers.sh +2 -1
- package/assets/hooks/browser-guard-require-select.sh +2 -1
- package/assets/hooks/commit-msg.sh +1 -1
- package/assets/hooks/constitution-index.sh +5 -4
- package/assets/hooks/dev-server-guard.sh +8 -6
- package/assets/hooks/docs-guard.sh +223 -37
- package/assets/hooks/git-guard-delivery.sh +171 -31
- package/assets/hooks/git-guard-main.sh +1 -0
- package/assets/hooks/git-guard-push-tests.sh +34 -13
- package/assets/hooks/glossary-load.sh +23 -0
- package/assets/hooks/grill-gate.sh +96 -0
- package/assets/hooks/lint-after-edit.sh +155 -30
- package/assets/hooks/qa-dataid-guard.sh +72 -32
- package/assets/hooks/reuse-first-guard.sh +105 -34
- package/assets/hooks/skill-gate-rearm.sh +1 -0
- package/assets/hooks/skill-gate.sh +75 -15
- package/assets/hooks/skill-loaded.sh +1 -0
- package/assets/hooks/sql-guard.sh +606 -56
- package/assets/hooks/task-context-load.sh +100 -0
- package/assets/hooks/task-flow-guard.sh +118 -0
- package/assets/laws/{access.md → application/access.md} +1 -4
- package/assets/laws/{locales.md → application/locales.md} +1 -3
- package/assets/laws/application/money.md +41 -0
- package/assets/laws/application/ownership.md +32 -0
- package/assets/laws/{search-visibility.md → application/search-visibility.md} +1 -1
- package/assets/laws/code-structure.md +7 -6
- package/assets/laws/delivery.md +53 -3
- package/assets/laws/entity-editing.md +49 -55
- package/assets/laws/entity-models.md +4 -14
- package/assets/laws/frontend-application.md +5 -5
- package/assets/laws/lib-imports.md +14 -1
- package/assets/laws/lists.md +33 -0
- package/assets/laws/navigation.md +40 -0
- package/assets/laws/project-documentation.md +27 -8
- package/assets/laws/reuse-first.md +26 -21
- package/assets/laws/shared-code.md +13 -1
- package/assets/laws/verifiability.md +30 -1
- package/assets/laws/work-conduct.md +59 -0
- package/assets/patterns/admin-lists-screen.md +131 -0
- package/assets/patterns/admin-nav-item.md +71 -0
- package/assets/patterns/angular-patterns-state.md +29 -22
- package/assets/patterns/api-layer-pair.md +40 -30
- package/assets/patterns/browser-verification-measure.md +41 -38
- package/assets/patterns/browser-verification-stand.md +106 -42
- package/assets/patterns/component-structure-new.md +33 -32
- package/assets/patterns/dependencies-upgrade.md +65 -0
- package/assets/patterns/doc-style-sweep.md +65 -28
- package/assets/patterns/doc-style-write.md +36 -33
- package/assets/patterns/entity-aside.md +136 -0
- package/assets/patterns/entity-models-new.md +124 -0
- package/assets/patterns/entity-store.md +91 -0
- package/assets/patterns/git-workflow-commit.azure.md +259 -0
- package/assets/patterns/git-workflow-commit.github.md +337 -0
- package/assets/patterns/git-workflow-commit.gitlab.md +283 -0
- package/assets/patterns/git-workflow-merge.md +42 -25
- package/assets/patterns/git-workflow-migration.md +61 -31
- package/assets/patterns/git-workflow-restart.md +20 -20
- package/assets/patterns/lib-layers-move.md +50 -32
- package/assets/patterns/lib-layers-new.md +41 -29
- package/assets/patterns/ownership-scope-resolve.md +69 -0
- package/assets/patterns/permissions-procedure.md +35 -33
- package/assets/patterns/platform-access-di.md +39 -25
- package/assets/patterns/pricing-quote.md +71 -0
- package/assets/patterns/reuse-first-extend.md +22 -22
- package/assets/patterns/seo-page.md +52 -40
- package/assets/patterns/seo-verify.md +48 -29
- package/assets/patterns/shared-code-new.md +37 -31
- package/assets/patterns/spec-driven-domain.md +60 -37
- package/assets/patterns/spec-driven-rule.md +55 -40
- package/assets/patterns/styling-bem-component.md +43 -32
- package/assets/patterns/styling-bem-layout.md +30 -24
- package/assets/patterns/task-flow-close.md +154 -0
- package/assets/patterns/task-flow-resume.md +94 -0
- package/assets/patterns/task-flow-start.md +129 -0
- package/assets/patterns/testing-e2e.md +53 -51
- package/assets/patterns/testing-unit.md +70 -46
- package/assets/patterns/translations-key.md +32 -19
- package/assets/patterns/ts-procedure.md +24 -25
- package/assets/rules/angular-patterns.md +50 -27
- package/assets/rules/api-layer.md +46 -28
- package/assets/rules/browser-verification.md +67 -48
- package/assets/rules/component-structure.md +43 -27
- package/assets/rules/dependencies.md +66 -0
- package/assets/rules/doc-style.md +95 -39
- package/assets/rules/entity-conventions.md +78 -0
- package/assets/rules/entity-models.md +70 -0
- package/assets/rules/git-workflow.azure.md +116 -0
- package/assets/rules/git-workflow.github.md +123 -0
- package/assets/rules/git-workflow.gitlab.md +113 -0
- package/assets/rules/lib-layers.md +56 -30
- package/assets/rules/lists.md +73 -0
- package/assets/rules/navigation.md +78 -0
- package/assets/rules/ownership-scope.md +63 -0
- package/assets/rules/permissions.md +43 -25
- package/assets/rules/platform-access.md +57 -29
- package/assets/rules/pricing.md +64 -0
- package/assets/rules/reuse-first.md +57 -43
- package/assets/rules/seo.md +51 -30
- package/assets/rules/shared-code.md +51 -26
- package/assets/rules/spec-driven.md +107 -51
- package/assets/rules/styling-bem.md +54 -39
- package/assets/rules/task-flow.md +150 -0
- package/assets/rules/testing.md +78 -47
- package/assets/rules/translations.md +48 -31
- package/assets/rules/typescript-conventions.md +57 -27
- package/assets/skills/agent-kit.md +85 -0
- package/assets/skills/write-a-skill.md +108 -0
- package/assets/templates/gate-map.sh +23 -15
- package/assets/templates/implementation.md +14 -8
- package/assets/templates/pattern.md +1 -1
- package/assets/templates/project.sh +32 -19
- package/assets/templates/rule.md +2 -2
- package/assets/variants.json +20 -0
- package/assets/workflows/feature.js +134 -0
- package/assets/workflows/plan.js +150 -0
- package/bin/agent-kit.d.ts.map +1 -1
- package/bin/agent-kit.js +78 -5
- package/bin/agent-kit.js.map +1 -1
- package/bin/prompt.d.ts +5 -0
- package/bin/prompt.d.ts.map +1 -1
- package/bin/prompt.js +19 -7
- package/bin/prompt.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/lib/assets.d.ts +8 -3
- package/lib/assets.d.ts.map +1 -1
- package/lib/assets.js +13 -3
- package/lib/assets.js.map +1 -1
- package/lib/catalog.d.ts +52 -5
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +104 -16
- package/lib/catalog.js.map +1 -1
- package/lib/commands.d.ts +22 -1
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +202 -14
- package/lib/commands.js.map +1 -1
- package/lib/companion.d.ts +5 -1
- package/lib/companion.d.ts.map +1 -1
- package/lib/companion.js +29 -2
- package/lib/companion.js.map +1 -1
- package/lib/config.d.ts +26 -9
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +41 -15
- package/lib/config.js.map +1 -1
- package/lib/freshness.d.ts +14 -0
- package/lib/freshness.d.ts.map +1 -0
- package/lib/freshness.js +116 -0
- package/lib/freshness.js.map +1 -0
- package/lib/hooks-map.d.ts +27 -0
- package/lib/hooks-map.d.ts.map +1 -0
- package/lib/hooks-map.js +77 -0
- package/lib/hooks-map.js.map +1 -0
- package/lib/integrity.d.ts +36 -0
- package/lib/integrity.d.ts.map +1 -0
- package/lib/integrity.js +44 -0
- package/lib/integrity.js.map +1 -0
- package/lib/picker.d.ts +11 -1
- package/lib/picker.d.ts.map +1 -1
- package/lib/picker.js +44 -6
- package/lib/picker.js.map +1 -1
- package/lib/sync.d.ts +26 -0
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +59 -4
- package/lib/sync.js.map +1 -1
- package/lib/variants.d.ts +44 -0
- package/lib/variants.d.ts.map +1 -0
- package/lib/variants.js +82 -0
- package/lib/variants.js.map +1 -0
- package/package.json +1 -1
- package/rt-tools-agent-kit-0.5.0.tgz +0 -0
- package/assets/laws/admin-lists.md +0 -35
- package/assets/laws/admin-navigation.md +0 -38
- package/assets/patterns/git-workflow-commit.md +0 -175
- package/assets/rules/git-workflow.md +0 -106
- package/rt-tools-agent-kit-0.3.0.tgz +0 -0
|
@@ -1,35 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# rt-hook: PreToolUse Edit|Write|MultiEdit|mcp__webstorm__create_new_file
|
|
2
3
|
# Гард «ничего не пишется с нуля». PreToolUse на правке кода и разметки.
|
|
3
4
|
#
|
|
4
|
-
# Линтеры знают правила, но не знают ИНВЕНТАРЬ: линтер стилей поймает сырой цвет, линтер кода
|
|
5
|
-
#
|
|
6
|
-
#
|
|
5
|
+
# Линтеры знают правила, но не знают ИНВЕНТАРЬ: линтер стилей поймает сырой цвет, линтер кода —
|
|
6
|
+
# нетипизированное значение, но ни один из них не знает, что готовое сообщение уже написано, и
|
|
7
|
+
# молча пропустит свою область оповещения с текстом, кнопкой и стилями. Гард закрывает ровно
|
|
7
8
|
# эту дыру: сверяет то, что пишется, с тем, что в дереве уже есть.
|
|
8
9
|
#
|
|
9
10
|
# Правило целиком — `reuse-first`.
|
|
10
11
|
#
|
|
11
|
-
# Что считается переизобретением, знает профиль
|
|
12
|
-
#
|
|
13
|
-
# нет функции — гард пропускает: инвентарь дерева пакет знать не может.
|
|
12
|
+
# Что считается переизобретением, знает профиль дерева: функция `rt_reinvented_in <файл>`
|
|
13
|
+
# печатает по строке на правило, четырьмя полями через табуляцию:
|
|
14
14
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
15
|
+
# <над чем> <образец> <образец отмены> <чем заменить>
|
|
16
|
+
#
|
|
17
|
+
# «Над чем» — `added` (только новый текст правки) или `whole` (правка вместе с содержимым
|
|
18
|
+
# файла). Второе нужно там, где признак виден только целиком: наследование основы и метка
|
|
19
|
+
# процедуры в точечную правку не попадают. «Образец отмены» гасит правило: маппер, который уже
|
|
20
|
+
# наследует общую основу, переизобретением не является; пустое поле не гасит ничего.
|
|
21
|
+
#
|
|
22
|
+
# Функция получает путь и вправе решать по нему сама — заглянуть в инвентарь кита, различить
|
|
23
|
+
# слой дерева, промолчать на файле, который уже существует. Нет профиля или нет функции — гард
|
|
24
|
+
# пропускает: инвентарь дерева пакет знать не может.
|
|
25
|
+
#
|
|
26
|
+
# Образцы разбирает `perl`: конъюнкция и отрицание пишутся заглядыванием вперёд, а без них
|
|
27
|
+
# самодельный оверлей не отличить от липкой шапки, а нативную кнопку — от кнопки кита.
|
|
28
|
+
#
|
|
29
|
+
# Осознанный выход: маркер отступления в тексте правки. Он объясняет, чего именно не хватает;
|
|
30
|
+
# «эти строки были здесь раньше» причиной не считается, и оттого проверяется только НОВЫЙ текст.
|
|
18
31
|
#
|
|
19
32
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: нет разборщика, битый ввод, чужой инструмент — пропуск.
|
|
20
33
|
|
|
21
34
|
input="$(cat 2>/dev/null)"
|
|
22
35
|
[ -z "$input" ] && exit 0
|
|
23
36
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
37
|
+
command -v perl >/dev/null 2>&1 || exit 0
|
|
24
38
|
|
|
25
39
|
tool="$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null)"
|
|
26
40
|
case "$tool" in
|
|
41
|
+
# Инструмент среды заводит файл теми же двумя данными, только называет их иначе — без этой
|
|
42
|
+
# ветки файл заводился мимо всех проверок.
|
|
27
43
|
Edit | Write | MultiEdit | mcp__webstorm__create_new_file) ;;
|
|
28
44
|
*) exit 0 ;;
|
|
29
45
|
esac
|
|
30
46
|
|
|
31
47
|
path="$(printf '%s' "$input" | jq -r '.tool_input.file_path // .tool_input.pathInProject // empty' 2>/dev/null)"
|
|
32
|
-
# Путь от корня
|
|
48
|
+
# Путь от корня дерева приводится к абсолютному один раз, чтобы образцы не двоились.
|
|
33
49
|
case "$path" in
|
|
34
50
|
/*) ;;
|
|
35
51
|
?*) path="${CLAUDE_PROJECT_DIR:-.}/$path" ;;
|
|
@@ -39,43 +55,98 @@ case "$path" in
|
|
|
39
55
|
*) exit 0 ;;
|
|
40
56
|
esac
|
|
41
57
|
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
profile="${CLAUDE_PROJECT_DIR:-.}/{{projectProfile}}"
|
|
50
|
-
[ -f "$profile" ] || exit 0
|
|
51
|
-
# shellcheck disable=SC1090
|
|
52
|
-
. "$profile" 2>/dev/null || exit 0
|
|
58
|
+
# Профиль дерева: сперва умолчание пакета, поверх него — надстройка проекта, если она есть.
|
|
59
|
+
rt_hooks_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
60
|
+
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
|
|
61
|
+
# shellcheck disable=SC1090
|
|
62
|
+
[ -f "$profile" ] && . "$profile" 2>/dev/null
|
|
63
|
+
done
|
|
53
64
|
command -v rt_reinvented_in >/dev/null 2>&1 || exit 0
|
|
54
65
|
|
|
66
|
+
# Правила этого дерева действуют на код этого дерева: без положительной проверки гард требовал
|
|
67
|
+
# бы собирать готовым и в черновике за пределами дерева.
|
|
68
|
+
if command -v rt_is_app_code >/dev/null 2>&1; then
|
|
69
|
+
rt_is_app_code "$path" || exit 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Готовое собирается там, где ему и место: внутри кита нативные контролы и примитивы уместны,
|
|
73
|
+
# витрина и спеки — тоже не забота этого гарда.
|
|
74
|
+
if [ -n "${RT_REUSE_SKIP_RE:-}" ] && printf '%s' "$path" | grep -qE "$RT_REUSE_SKIP_RE"; then
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
55
78
|
# Только новый текст: строка, уже лежавшая в файле, этой правкой не заводилась.
|
|
56
79
|
added="$(printf '%s' "$input" | jq -r '
|
|
57
|
-
[.tool_input.content
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
(.tool_input.edits? // [] | map(.new_string) | join("\n"))] | join("\n")' 2>/dev/null)"
|
|
80
|
+
[ .tool_input.content?, .tool_input.text?, .tool_input.new_string?, (.tool_input.edits[]?.new_string) ]
|
|
81
|
+
| map(select(. != null)) | join("\n")
|
|
82
|
+
' 2>/dev/null)"
|
|
61
83
|
[ -z "$added" ] && exit 0
|
|
62
84
|
|
|
63
|
-
|
|
64
|
-
|
|
85
|
+
# Явный отказ от правила: готового такого нет, автор это осознал и пометил. Считается по
|
|
86
|
+
# исходному тексту правки, до вычёркивания ниже: маркер обычно и стоит на строке, которая уже
|
|
87
|
+
# лежит в файле, и вычеркнутый маркер отбивал бы правку соседней строки.
|
|
88
|
+
case "$added" in
|
|
89
|
+
*native-ok*) exit 0 ;;
|
|
90
|
+
esac
|
|
91
|
+
|
|
92
|
+
# Перенос — не написание заново. Строку, которая уже лежит в файле, гард из проверяемого текста
|
|
93
|
+
# вычёркивает: блок, переехавший вместе с экраном из одного места файла в другое, отбивался
|
|
94
|
+
# наравне с новым, и маркер отступления приходилось ставить вслепую.
|
|
95
|
+
#
|
|
96
|
+
# Сверка идёт без отступов: при переезде блок меняет отступ, оставаясь тем же кодом.
|
|
97
|
+
if [ -f "$path" ]; then
|
|
98
|
+
added="$(
|
|
99
|
+
printf '%s' "$added" | awk '
|
|
100
|
+
NR == FNR {
|
|
101
|
+
line = $0
|
|
102
|
+
gsub(/^[ \t]+|[ \t]+$/, "", line)
|
|
103
|
+
if (line != "") { existing[line] = 1 }
|
|
104
|
+
next
|
|
105
|
+
}
|
|
106
|
+
{
|
|
107
|
+
line = $0
|
|
108
|
+
gsub(/^[ \t]+|[ \t]+$/, "", line)
|
|
109
|
+
if (line == "" || !(line in existing)) { print }
|
|
110
|
+
}
|
|
111
|
+
' "$path" - 2>/dev/null
|
|
112
|
+
)"
|
|
113
|
+
[ -z "${added//[[:space:]]/}" ] && exit 0
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Признак, который виден только целиком по файлу (наследование основы, метка процедуры),
|
|
117
|
+
# считается по итоговому содержимому: точечная правка приносит кусок без объявления класса.
|
|
118
|
+
whole="$added"
|
|
119
|
+
if [ -f "$path" ]; then
|
|
120
|
+
whole="$added
|
|
121
|
+
$(cat "$path" 2>/dev/null)"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
has_re() {
|
|
125
|
+
printf '%s' "$1" | RT_RE="$2" perl -0777 -ne 'exit(/$ENV{RT_RE}/s ? 0 : 1)' 2>/dev/null
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
found=''
|
|
129
|
+
while IFS="$(printf '\t')" read -r scope pattern cancel replacement; do
|
|
65
130
|
[ -z "$pattern" ] && continue
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
131
|
+
case "$scope" in
|
|
132
|
+
whole) text="$whole" ;;
|
|
133
|
+
*) text="$added" ;;
|
|
134
|
+
esac
|
|
135
|
+
has_re "$text" "$pattern" || continue
|
|
136
|
+
[ -n "$cancel" ] && has_re "$text" "$cancel" && continue
|
|
137
|
+
found="${found}
|
|
138
|
+
- ${replacement}"
|
|
69
139
|
done <<EOF
|
|
70
|
-
$(rt_reinvented_in "$path")
|
|
140
|
+
$(rt_reinvented_in "$path" 2>/dev/null)
|
|
71
141
|
EOF
|
|
72
142
|
|
|
73
143
|
[ -z "$found" ] && exit 0
|
|
74
144
|
|
|
75
|
-
reason="
|
|
76
|
-
|
|
145
|
+
reason="BLOCKED: это уже написано. Файл: ${path##*/}
|
|
77
146
|
${found}
|
|
78
|
-
|
|
147
|
+
|
|
148
|
+
Порядок действий: 1) открой готовое — барель кита или базовый класс — и используй его; 2) найди в дереве экран, где этот случай уже собран, и повтори сборку; 3) если готового правда не хватает — расширяй его на месте, у готового, а не клонируй рядом: клон забирает правки на себя и расходится с оригиналом с первой же.
|
|
149
|
+
Свой примитив, своя основа и свои инлайновые стили заводятся только с явного одобрения владельца, и спрашивается это до первого написанного файла. Разовое исключение помечается маркером отступления в той же строке, с объяснением, чего именно нет в готовом. Переименованием файла это не обходится."
|
|
79
150
|
|
|
80
151
|
jq -n --arg r "$reason" '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}' 2>/dev/null \
|
|
81
152
|
|| printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Написано своё там, где готовое уже есть."}}\n'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# rt-hook: PreToolUse Edit|Write|MultiEdit|Bash
|
|
2
3
|
# Гейт правил: не даёт править файл, пока не загружено правило, под которое он подпадает.
|
|
3
4
|
#
|
|
4
5
|
# Закон и правило, которых никто не открывает, не действуют. Напоминание в подсказке помогает
|
|
@@ -6,9 +7,17 @@
|
|
|
6
7
|
# для каждой области, а после загрузки правила та же область проходит молча — повторов нет, и
|
|
7
8
|
# стоит это почти ничего.
|
|
8
9
|
#
|
|
9
|
-
# Карта «файл — правило» живёт не
|
|
10
|
-
#
|
|
11
|
-
#
|
|
10
|
+
# Карта «файл — правило» живёт не здесь, а в двух файлах рядом, и это не дублирование.
|
|
11
|
+
# Умолчание — `.claude/rt-kit/defaults/gate-map.sh` — везёт пакет: деревья этой мастерской
|
|
12
|
+
# устроены одинаково, и переписывать одну и ту же карту в каждом заново значило бы заводить
|
|
13
|
+
# столько её редакций, сколько репозиториев. Надстройку — `.claude/rt-kit/gate-map.sh` — пишет
|
|
14
|
+
# проект, и она необязательна: витрина, свой род файлов, чужая раскладка есть не у всех.
|
|
15
|
+
# Обе объявляют `skill_for <род вызова> <цель> <текст правки>`, печатающую имена правил через
|
|
16
|
+
# пробел; надстройка грузится второй и вправе позвать умолчание обратно — `skill_for_default`.
|
|
17
|
+
# Нет ни одной — гейт пропускает всё: пустой гейт лучше гейта, отбивающего наугад.
|
|
18
|
+
#
|
|
19
|
+
# Род вызова — `edit`, `bash` или `browser`. Браузерная проверка — единственная область, где
|
|
20
|
+
# правило нужно не под правку файла, а под инструмент: врут там не файлы, а стенд и координаты.
|
|
12
21
|
#
|
|
13
22
|
# ОТКАЗ В ПОЛЬЗУ РАБОТЫ: любая ошибка и любой неопознанный путь пропускают правку (exit 0).
|
|
14
23
|
# Сломанный гейт не имеет права остановить работу совсем.
|
|
@@ -19,16 +28,20 @@ input="$(cat 2>/dev/null)"
|
|
|
19
28
|
sid="$(printf '%s' "$input" | jq -r '.session_id // "nosession"' 2>/dev/null)"
|
|
20
29
|
tool="$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null)"
|
|
21
30
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
# Умолчание карты ищется и рядом с самим хуком: уезжают они вместе.
|
|
32
|
+
rt_hooks_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
33
|
+
for map in "$rt_hooks_dir/../rt-kit/defaults/gate-map.sh" "$rt_hooks_dir/../defaults/gate-map.sh" "${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/defaults/gate-map.sh" "${CLAUDE_PROJECT_DIR:-.}/.claude/rt-kit/gate-map.sh"; do
|
|
34
|
+
# shellcheck disable=SC1090
|
|
35
|
+
[ -f "$map" ] && . "$map" 2>/dev/null
|
|
36
|
+
done
|
|
26
37
|
command -v skill_for >/dev/null 2>&1 || exit 0
|
|
27
38
|
|
|
28
39
|
req=""
|
|
29
40
|
target=""
|
|
30
41
|
case "$tool" in
|
|
31
|
-
|
|
42
|
+
# Инструмент среды заводит файл теми же двумя данными, только называет их иначе — без этой
|
|
43
|
+
# ветки файл заводился мимо гейта.
|
|
44
|
+
Edit|Write|MultiEdit|mcp__webstorm__create_new_file)
|
|
32
45
|
target="$(printf '%s' "$input" | jq -r '.tool_input.file_path // .tool_input.pathInProject // empty' 2>/dev/null)"
|
|
33
46
|
[ -z "$target" ] && exit 0
|
|
34
47
|
# Путь от корня проекта приводится к абсолютному один раз: иначе карту пришлось бы
|
|
@@ -43,25 +56,72 @@ case "$tool" in
|
|
|
43
56
|
"${CLAUDE_PROJECT_DIR:-.}"/*) ;;
|
|
44
57
|
*) exit 0 ;;
|
|
45
58
|
esac
|
|
46
|
-
|
|
59
|
+
# Текст правки идёт карте вторым доводом: есть правила, которые вступают не от того,
|
|
60
|
+
# ЧТО за файл правится, а от того, ЧТО в него пишут, — обращение к среде исполнения
|
|
61
|
+
# приходит в обычный сервис, а число-настройка в обычный класс.
|
|
62
|
+
written="$(printf '%s' "$input" | jq -r '[.tool_input.content, .tool_input.text, .tool_input.new_string, (.tool_input.edits[]?.new_string)] | map(select(. != null)) | join("\n")' 2>/dev/null)"
|
|
63
|
+
req="$(skill_for edit "$target" "$written" 2>/dev/null)"
|
|
47
64
|
;;
|
|
48
|
-
|
|
65
|
+
# Терминал среды исполняет ту же командную строку и кладёт её в то же поле: без этой ветки
|
|
66
|
+
# коммит из него не требовал правила, тогда как тот же коммит из оболочки требовал.
|
|
67
|
+
Bash|mcp__webstorm__execute_terminal_command|mcp__webstorm__execute_tool)
|
|
49
68
|
target="$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)"
|
|
50
69
|
[ -z "$target" ] && exit 0
|
|
51
|
-
|
|
70
|
+
# Универсальный исполнитель прячет настоящую команду во вложенной строке.
|
|
71
|
+
if [ "$tool" = "mcp__webstorm__execute_tool" ] && command -v perl >/dev/null 2>&1; then
|
|
72
|
+
inner="$(printf '%s' "$target" | perl -0ne '
|
|
73
|
+
if (/--command(?:=|\s+)(?:"((?:[^"\\]|\\.)*)"|\x27([^\x27]*)\x27|(.+))/s) {
|
|
74
|
+
print defined $1 ? $1 : (defined $2 ? $2 : $3);
|
|
75
|
+
}
|
|
76
|
+
' 2>/dev/null)"
|
|
77
|
+
[ -n "$inner" ] && target="$inner"
|
|
78
|
+
fi
|
|
79
|
+
req="$(skill_for bash "$target" "" 2>/dev/null)"
|
|
80
|
+
;;
|
|
81
|
+
mcp__claude-in-chrome__*)
|
|
82
|
+
req="$(skill_for browser "$tool" "" 2>/dev/null)"
|
|
52
83
|
;;
|
|
53
84
|
*) exit 0 ;;
|
|
54
85
|
esac
|
|
55
86
|
|
|
56
87
|
[ -z "$req" ] && exit 0
|
|
57
88
|
|
|
58
|
-
#
|
|
89
|
+
# Карта вправе назвать несколько правил: доменное правило и то, что действует вторым слоем.
|
|
90
|
+
# Требуется первое незагруженное, а не все сразу: отказ, перечисляющий три правила, читается
|
|
91
|
+
# как «загрузи три», и загружают их подряд, теряя ту самую однократность.
|
|
59
92
|
loaded="${TMPDIR:-/tmp}/claude-skill-gate/${sid}.loaded"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
93
|
+
root="${CLAUDE_PROJECT_DIR:-.}"
|
|
94
|
+
rules_dir="${RT_RULES_DIR:-.claude/skills}"
|
|
95
|
+
want=""
|
|
96
|
+
for name in $req; do
|
|
97
|
+
# Правила, которого в дереве нет, гейт не требует. Карта умолчания называет и то, от чего
|
|
98
|
+
# дерево отказалось списком: правило предметной области, чужой род файлов. Отказ «загрузи
|
|
99
|
+
# правило X» на такое имя — отказ без действия: загружать нечего, и работа встаёт совсем.
|
|
100
|
+
[ -f "$root/$rules_dir/${name}/SKILL.md" ] || continue
|
|
101
|
+
# Принимается и голое имя правила, и имя с областью каталога («<каталог>:<имя>»).
|
|
102
|
+
if [ -f "$loaded" ] && grep -qE "^([^:]*:)?$(printf '%s' "$name" | sed 's/[][\.*^$/]/\\&/g')$" "$loaded" 2>/dev/null; then
|
|
103
|
+
continue
|
|
104
|
+
fi
|
|
105
|
+
want="$name"
|
|
106
|
+
break
|
|
107
|
+
done
|
|
108
|
+
[ -z "$want" ] && exit 0
|
|
109
|
+
req="$want"
|
|
63
110
|
|
|
64
111
|
reason="Отбито гейтом правил: загрузи правило «${req}» инструментом Skill и повтори действие. Для этой области это происходит один раз за сессию."
|
|
112
|
+
|
|
113
|
+
# Правило называет свой закон одним словом, а слоёв законов два: общий лежит в корне, закон
|
|
114
|
+
# приложения — в каталоге под ним. Путь ищется, а не собирается из имени, иначе отказ ведёт в
|
|
115
|
+
# несуществующий файл ровно у тех правил, чей закон предметен.
|
|
116
|
+
laws_dir="${RT_LAWS_DIR:-docs/constitution}"
|
|
117
|
+
law="$(sed -n 's/^law:[[:space:]]*//p' "$root/$rules_dir/${req}/SKILL.md" 2>/dev/null | head -1)"
|
|
118
|
+
if [ -n "$law" ]; then
|
|
119
|
+
law_path="$laws_dir/${law}.md"
|
|
120
|
+
[ -f "$root/$law_path" ] || law_path="$laws_dir/application/${law}.md"
|
|
121
|
+
[ -f "$root/$law_path" ] \
|
|
122
|
+
&& reason="Отбито гейтом правил: загрузи правило «${req}» инструментом Skill — оно применяет закон ${law_path} к этому дереву — и повтори действие. Для этой области это происходит один раз за сессию."
|
|
123
|
+
fi
|
|
124
|
+
|
|
65
125
|
jq -n --arg r "$reason" '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}' 2>/dev/null \
|
|
66
126
|
|| printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Загрузи правило %s и повтори."}}\n' "$req"
|
|
67
127
|
|