agent-quality-kit 0.2.2
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/LICENSE +21 -0
- package/README.md +155 -0
- package/kit/docs/ai/agent-harness-playbook.md +596 -0
- package/kit/docs/ai/ai-native-development.md +371 -0
- package/kit/docs/ai/ai-sdlc.md +221 -0
- package/kit/docs/ai/anthropic-ai-native-sdlc-2026-08.md +294 -0
- package/kit/docs/ai/app-owner-strategy.md +921 -0
- package/kit/docs/ai/deep-research-2026-07.md +161 -0
- package/kit/docs/ai/harness-best-practices.md +385 -0
- package/kit/docs/ai/index.md +64 -0
- package/kit/docs/ai/project-baseline.md +261 -0
- package/kit/docs/ai/quality-gates-checklist.md +322 -0
- package/kit/docs/ai/sources-building-with-agents.md +111 -0
- package/kit/docs/ai/stream-2026-08-ai-coding-panel.md +304 -0
- package/kit/docs/ready-made-rules.md +170 -0
- package/kit/gates/README.md +231 -0
- package/kit/gates/_skip.sh +75 -0
- package/kit/gates/commit-explains-itself/README.md +45 -0
- package/kit/gates/commit-explains-itself/check.sh +63 -0
- package/kit/gates/commit-explains-itself/gate.yml +10 -0
- package/kit/gates/commit-explains-itself/green/COMMIT_MSG +6 -0
- package/kit/gates/commit-explains-itself/red/COMMIT_MSG +3 -0
- package/kit/gates/complexity-limit/README.md +37 -0
- package/kit/gates/complexity-limit/check.sh +44 -0
- package/kit/gates/complexity-limit/gate.yml +13 -0
- package/kit/gates/complexity-limit/green/flat.py +10 -0
- package/kit/gates/complexity-limit/red/deep.py +9 -0
- package/kit/gates/dead-code/README.md +30 -0
- package/kit/gates/dead-code/gate.yml +23 -0
- package/kit/gates/dead-code/green/mod.py +9 -0
- package/kit/gates/dead-code/red/mod.py +9 -0
- package/kit/gates/deps-are-pinned/README.md +29 -0
- package/kit/gates/deps-are-pinned/check.sh +49 -0
- package/kit/gates/deps-are-pinned/gate.yml +9 -0
- package/kit/gates/deps-are-pinned/green/nodep-go/go.mod +3 -0
- package/kit/gates/deps-are-pinned/green/package-lock.json +3 -0
- package/kit/gates/deps-are-pinned/green/package.json +4 -0
- package/kit/gates/deps-are-pinned/green/requirements.txt +2 -0
- package/kit/gates/deps-are-pinned/red/package.json +4 -0
- package/kit/gates/deps-are-pinned/red/requirements.txt +2 -0
- package/kit/gates/deps-are-pinned/red/withdep-go/go.mod +5 -0
- package/kit/gates/duplicate-code/README.md +40 -0
- package/kit/gates/duplicate-code/check.sh +58 -0
- package/kit/gates/duplicate-code/gate.yml +12 -0
- package/kit/gates/duplicate-code/green/common.py +9 -0
- package/kit/gates/duplicate-code/green/use.py +9 -0
- package/kit/gates/duplicate-code/red/a.py +12 -0
- package/kit/gates/duplicate-code/red/b.py +12 -0
- package/kit/gates/entry-links-exist/README.md +22 -0
- package/kit/gates/entry-links-exist/check.sh +24 -0
- package/kit/gates/entry-links-exist/gate.yml +16 -0
- package/kit/gates/entry-links-exist/green/AGENTS.md +5 -0
- package/kit/gates/entry-links-exist/green/rules/general.md +3 -0
- package/kit/gates/entry-links-exist/red/AGENTS.md +3 -0
- package/kit/gates/file-size-limit/README.md +22 -0
- package/kit/gates/file-size-limit/check.sh +34 -0
- package/kit/gates/file-size-limit/gate.yml +9 -0
- package/kit/gates/file-size-limit/green/a.py +251 -0
- package/kit/gates/file-size-limit/green/b.py +251 -0
- package/kit/gates/file-size-limit/red/big.py +601 -0
- package/kit/gates/gate-has-samples/README.md +29 -0
- package/kit/gates/gate-has-samples/check.sh +48 -0
- package/kit/gates/gate-has-samples/gate.yml +9 -0
- package/kit/gates/gate-has-samples/green/.aqk.yml +10 -0
- package/kit/gates/gate-has-samples/green/gates/no-print-in-prod/check.sh +2 -0
- package/kit/gates/gate-has-samples/green/gates/no-print-in-prod/green/good.py +2 -0
- package/kit/gates/gate-has-samples/green/gates/no-print-in-prod/red/bad.py +1 -0
- package/kit/gates/gate-has-samples/red/.aqk.yml +10 -0
- package/kit/gates/gate-has-samples/red/gates/no-print-in-prod/check.sh +2 -0
- package/kit/gates/gates-are-runnable/README.md +23 -0
- package/kit/gates/gates-are-runnable/check.sh +35 -0
- package/kit/gates/gates-are-runnable/gate.yml +9 -0
- package/kit/gates/gates-are-runnable/green/.aqk.yml +9 -0
- package/kit/gates/gates-are-runnable/green/checks/lint.sh +2 -0
- package/kit/gates/gates-are-runnable/red/.aqk.yml +6 -0
- package/kit/gates/gates-run-in-ci/README.md +29 -0
- package/kit/gates/gates-run-in-ci/check.sh +42 -0
- package/kit/gates/gates-run-in-ci/gate.yml +12 -0
- package/kit/gates/gates-run-in-ci/green/.aqk.yml +6 -0
- package/kit/gates/gates-run-in-ci/green/.github/workflows/ci.yml +7 -0
- package/kit/gates/gates-run-in-ci/green/checks/lint.sh +2 -0
- package/kit/gates/gates-run-in-ci/red/.aqk.yml +6 -0
- package/kit/gates/gates-run-in-ci/red/.github/workflows/ci.yml +7 -0
- package/kit/gates/gates-run-in-ci/red/checks/lint.sh +2 -0
- package/kit/gates/lesson-has-outcome/README.md +37 -0
- package/kit/gates/lesson-has-outcome/check.sh +50 -0
- package/kit/gates/lesson-has-outcome/gate.yml +11 -0
- package/kit/gates/lesson-has-outcome/green/.aqk.yml +2 -0
- package/kit/gates/lesson-has-outcome/green/incidents/README.md +32 -0
- package/kit/gates/lesson-has-outcome/red/.aqk.yml +2 -0
- package/kit/gates/lesson-has-outcome/red/incidents/README.md +13 -0
- package/kit/gates/no-print-in-prod/README.md +44 -0
- package/kit/gates/no-print-in-prod/check.sh +36 -0
- package/kit/gates/no-print-in-prod/gate.yml +15 -0
- package/kit/gates/no-print-in-prod/green/docs.ts +15 -0
- package/kit/gates/no-print-in-prod/green/legacy.py +9 -0
- package/kit/gates/no-print-in-prod/green/main.go +8 -0
- package/kit/gates/no-print-in-prod/green/main.rs +4 -0
- package/kit/gates/no-print-in-prod/green/service.py +8 -0
- package/kit/gates/no-print-in-prod/red/main.go +8 -0
- package/kit/gates/no-print-in-prod/red/main.rs +4 -0
- package/kit/gates/no-print-in-prod/red/service.py +3 -0
- package/kit/gates/secrets-not-in-code/README.md +29 -0
- package/kit/gates/secrets-not-in-code/check.sh +18 -0
- package/kit/gates/secrets-not-in-code/gate.yml +9 -0
- package/kit/gates/secrets-not-in-code/green/settings.py +4 -0
- package/kit/gates/secrets-not-in-code/red/settings.py +2 -0
- package/kit/gates/swallowed-error/README.md +26 -0
- package/kit/gates/swallowed-error/check.sh +54 -0
- package/kit/gates/swallowed-error/gate.yml +12 -0
- package/kit/gates/swallowed-error/green/loader.py +11 -0
- package/kit/gates/swallowed-error/green/run.js +8 -0
- package/kit/gates/swallowed-error/red/loader.py +5 -0
- package/kit/gates/swallowed-error/red/run.js +3 -0
- package/kit/gates/todo-without-task/README.md +26 -0
- package/kit/gates/todo-without-task/check.sh +19 -0
- package/kit/gates/todo-without-task/gate.yml +12 -0
- package/kit/gates/todo-without-task/green/order.py +9 -0
- package/kit/gates/todo-without-task/red/order.py +8 -0
- package/kit/ratchet/ratchet.sh +62 -0
- package/kit/rules/general.md +55 -0
- package/kit/rules/security.md +33 -0
- package/kit/rules/testing.md +46 -0
- package/package.json +41 -0
- package/tool/commands/doctor.mjs +230 -0
- package/tool/commands/gates.mjs +445 -0
- package/tool/commands/project.mjs +316 -0
- package/tool/lib/core.mjs +98 -0
- package/tool/lib/manifest.mjs +140 -0
- package/tool/lib/repo.mjs +270 -0
- package/tool/lib/templates.mjs +187 -0
- package/tool/program.mjs +81 -0
- package/tool/selfcheck/conditional.sh +24 -0
- package/tool/selfcheck/gates.sh +127 -0
- package/tool/selfcheck/smoke.sh +539 -0
- package/tool/selfcheck/syntax.sh +23 -0
- package/tool/selfcheck/units.mjs +105 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tool/selfcheck/gates.sh — проверка записей каталога. Это фильтр на входе: запись, чей
|
|
3
|
+
# арбитр не краснеет на красном образце или не молчит на зелёном, в каталог не
|
|
4
|
+
# попадает. Отбор делает машина, а не внимательность рецензента, — иначе каталог
|
|
5
|
+
# за полгода превращается в свалку правдоподобных утверждений.
|
|
6
|
+
#
|
|
7
|
+
# bash tool/selfcheck/gates.sh
|
|
8
|
+
|
|
9
|
+
set -uo pipefail
|
|
10
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
11
|
+
CAT="$ROOT/kit/gates"
|
|
12
|
+
PASS=0; FAIL=0; WARN=0; UNVERIFIED=0
|
|
13
|
+
|
|
14
|
+
ok() { printf ' \033[32m✔\033[0m %s\n' "$1"; PASS=$((PASS+1)); }
|
|
15
|
+
bad() { printf ' \033[31m✘\033[0m %s\n' "$1"; FAIL=$((FAIL+1)); }
|
|
16
|
+
warn() { printf ' \033[33m!\033[0m %s\n' "$1"; WARN=$((WARN+1)); }
|
|
17
|
+
# «Условная запись» и «нечем проверить здесь» — разные состояния, и счётчики разные.
|
|
18
|
+
skip() { printf ' \033[33m~\033[0m %s\n' "$1"; UNVERIFIED=$((UNVERIFIED+1)); }
|
|
19
|
+
|
|
20
|
+
field() { sed -n "s/^$2:[[:space:]]*\(.*\)$/\1/p" "$1" | head -1; }
|
|
21
|
+
|
|
22
|
+
printf '\n\033[1mtool/selfcheck/gates.sh\033[0m\n\n'
|
|
23
|
+
[ -d "$CAT" ] || { echo " каталога гейтов нет"; exit 1; }
|
|
24
|
+
|
|
25
|
+
for GATE in "$CAT"/*/; do
|
|
26
|
+
SLUG="$(basename "$GATE")"
|
|
27
|
+
YML="$GATE/gate.yml"
|
|
28
|
+
|
|
29
|
+
[ -f "$YML" ] || { bad "$SLUG: нет gate.yml"; continue; }
|
|
30
|
+
|
|
31
|
+
# --- обязательные поля -----------------------------------------------------
|
|
32
|
+
INTENT="$(field "$YML" intent)"
|
|
33
|
+
PROOF="$(field "$YML" proof)"
|
|
34
|
+
[ -n "$INTENT" ] || bad "$SLUG: пустое поле intent — по нему идёт дедупликация"
|
|
35
|
+
|
|
36
|
+
# Заготовка от `aqk new` не должна проехать как запись: незаполненный гейт — мёртвое
|
|
37
|
+
# правило, а мёртвое правило учит игнорировать и живые.
|
|
38
|
+
if grep -q 'ЗАПОЛНИ' "$YML" "$GATE/README.md" "$GATE/check.sh" 2>/dev/null; then
|
|
39
|
+
bad "$SLUG: заготовка не заполнена — остались метки ЗАПОЛНИ"
|
|
40
|
+
continue
|
|
41
|
+
fi
|
|
42
|
+
[ -n "$PROOF" ] || bad "$SLUG: пустое поле proof — «это хорошая практика» не принимается"
|
|
43
|
+
grep -q '^trigger:' "$YML" || bad "$SLUG: нет trigger — запись показывалась бы всем подряд"
|
|
44
|
+
|
|
45
|
+
# Файл, на который не ссылается ни один recipes, — мёртвый вес: рецепт может дискриминировать
|
|
46
|
+
# red/green совсем другой командой, и проверка образцов этого не увидит. Найдено на разборе
|
|
47
|
+
# чужого репозитория: инструмент семь месяцев никто не запускал, и об этом узнали только
|
|
48
|
+
# прогоном, не чтением.
|
|
49
|
+
if [ -f "$GATE/check.sh" ] && ! grep -q 'check\.sh' "$YML"; then
|
|
50
|
+
bad "$SLUG: check.sh есть, но ни один recipes на него не ссылается — мёртвый файл"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Два раздела README обязательны нормой каталога. Пока их не проверяла машина, четыре записи
|
|
54
|
+
# из четырнадцати жили без раздела про готовый аналог и четыре — без «чего НЕ ловит».
|
|
55
|
+
# Правило нормы, за которым не следит машина, — это пожелание.
|
|
56
|
+
grep -qiE 'готовы(й аналог|й инструмент|е правил)|готового аналога' "$GATE/README.md" 2>/dev/null \
|
|
57
|
+
|| bad "$SLUG: в README нет раздела про готовый аналог — «не искал» и «нет» разные утверждения"
|
|
58
|
+
grep -qiE 'чего НЕ ловит' "$GATE/README.md" 2>/dev/null \
|
|
59
|
+
|| bad "$SLUG: в README нет раздела «чего НЕ ловит» — граница записи обязана быть названа"
|
|
60
|
+
|
|
61
|
+
case "$PROOF" in
|
|
62
|
+
*incidents/*) : ;;
|
|
63
|
+
*) warn "$SLUG: доказательство не ссылается на журнал шишек — запись условная" ;;
|
|
64
|
+
esac
|
|
65
|
+
|
|
66
|
+
# --- образцы ---------------------------------------------------------------
|
|
67
|
+
# Проверяем переносимым рецептом, если он есть. Если его нет — берём первый рецепт под язык,
|
|
68
|
+
# чью программу видно в системе: запись, которой нужен готовый инструмент, законна (правило
|
|
69
|
+
# «сперва готовое»), но проверить её можно только там, где инструмент стоит.
|
|
70
|
+
RECIPE="$(sed -n 's/^[[:space:]]*any:[[:space:]]*\(.*\)$/\1/p' "$YML" | head -1)"
|
|
71
|
+
if [ -z "$RECIPE" ]; then
|
|
72
|
+
# Каким рецептом написаны образцы — говорит сама запись. Угадывать нельзя: в системе может
|
|
73
|
+
# стоять npx, и питоновские образцы поедут проверяться фронтовым инструментом. Так и вышло.
|
|
74
|
+
FOR="$(sed -n 's/^samples_for:[[:space:]]*\(.*\)$/\1/p' "$YML" | head -1)"
|
|
75
|
+
if [ -z "$FOR" ]; then
|
|
76
|
+
bad "$SLUG: нет ни рецепта any, ни поля samples_for — нечем проверить образцы"
|
|
77
|
+
continue
|
|
78
|
+
fi
|
|
79
|
+
RECIPE="$(sed -n "s/^[[:space:]]*$FOR:[[:space:]]*\(.*\)\$/\1/p" "$YML" | head -1)"
|
|
80
|
+
if [ -z "$RECIPE" ]; then
|
|
81
|
+
bad "$SLUG: samples_for указывает на «$FOR», а такого рецепта нет"
|
|
82
|
+
continue
|
|
83
|
+
fi
|
|
84
|
+
PROG="$(printf '%s' "$RECIPE" | awk '{print $1}')"
|
|
85
|
+
if ! command -v "$PROG" >/dev/null 2>&1; then
|
|
86
|
+
skip "$SLUG: НЕ ПРОВЕРЕНА здесь — нужен «$PROG»"
|
|
87
|
+
continue
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
90
|
+
if [ ! -d "$GATE/red" ] || [ ! -d "$GATE/green" ]; then
|
|
91
|
+
bad "$SLUG: нет красного или зелёного образца"; continue
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Прогон арбитра по образцу. Возвращаем и код, и вывод: код возврата в одиночку
|
|
95
|
+
# обманчив — отсутствующий скрипт тоже даёт ненулевой код, и «гейт покраснел»
|
|
96
|
+
# неотличимо от «гейта нет». Урок audit_project 2026-08-27, п. 11.
|
|
97
|
+
probe() {
|
|
98
|
+
local cmd; cmd="$(echo "$RECIPE" | sed "s|{gate}|$GATE|; s|{dir}|$1|")"
|
|
99
|
+
OUT="$(eval "$cmd" 2>&1)"; CODE=$?
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
probe "$GATE/red"; RED_CODE=$CODE; RED_OUT="$OUT"
|
|
103
|
+
probe "$GATE/green"; GRN_CODE=$CODE; GRN_OUT="$OUT"
|
|
104
|
+
|
|
105
|
+
if [ "$RED_CODE" -eq 127 ] || [ "$GRN_CODE" -eq 127 ]; then
|
|
106
|
+
bad "$SLUG: арбитр не запускается — команда не найдена"
|
|
107
|
+
elif [ "$RED_CODE" -eq 0 ]; then
|
|
108
|
+
bad "$SLUG: арбитр промолчал на КРАСНОМ образце — гейт не ловит брак"
|
|
109
|
+
elif [ -z "$RED_OUT" ]; then
|
|
110
|
+
bad "$SLUG: арбитр покраснел на красном молча — по коду возврата не видно, ту ли поломку он нашёл"
|
|
111
|
+
elif [ "$GRN_CODE" -ne 0 ]; then
|
|
112
|
+
bad "$SLUG: арбитр покраснел на ЗЕЛЁНОМ образце — гейт ругается на исправный код"
|
|
113
|
+
else
|
|
114
|
+
ok "$SLUG"
|
|
115
|
+
fi
|
|
116
|
+
done
|
|
117
|
+
|
|
118
|
+
printf '\n'
|
|
119
|
+
if [ "$FAIL" -eq 0 ]; then
|
|
120
|
+
printf ' \033[32mзаписей принято: %s\033[0m' "$PASS"
|
|
121
|
+
else
|
|
122
|
+
printf ' \033[31mотклонено: %s из %s\033[0m' "$FAIL" "$((PASS+FAIL))"
|
|
123
|
+
fi
|
|
124
|
+
[ "$WARN" -gt 0 ] && printf ' \033[33m(условных: %s)\033[0m' "$WARN"
|
|
125
|
+
[ "$UNVERIFIED" -gt 0 ] && printf ' \033[33m(не проверено здесь: %s)\033[0m' "$UNVERIFIED"
|
|
126
|
+
printf '\n\n'
|
|
127
|
+
exit "$FAIL"
|