agent-quality-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/README.md +8 -3
- package/README.ru.md +8 -3
- package/kit/gates/_native.sh +4 -0
- package/kit/gates/_skip.sh +7 -0
- package/kit/gates/api-contract-has-arbiter/check.sh +7 -0
- package/kit/gates/color-from-token/check.sh +7 -0
- package/kit/gates/commit-explains-itself/check.sh +8 -2
- package/kit/gates/complexity-limit/check.sh +22 -4
- package/kit/gates/complexity-limit/gate.yml +2 -2
- package/kit/gates/complexity-limit/red/deep.js +15 -0
- package/kit/gates/duplicate-code/check.sh +7 -0
- package/kit/gates/duplicate-code/gate.yml +5 -1
- package/kit/gates/file-size-limit/check.sh +7 -0
- package/kit/gates/file-size-limit/red/big.js +600 -0
- package/kit/gates/gate-not-weakened/check.sh +7 -0
- package/kit/gates/gate-not-weakened/green/suppress.js +4 -0
- package/kit/gates/gate-not-weakened/red/suppress.js +5 -0
- package/kit/gates/mcp-server-resolves/check.sh +7 -0
- package/kit/gates/no-phantom-package/check.sh +7 -0
- package/kit/gates/no-print-in-prod/gate.yml +3 -3
- package/kit/gates/personal-config-not-shared/check.sh +7 -0
- package/kit/gates/protection-not-removed/check.sh +22 -13
- package/kit/gates/secrets-not-in-code/check.sh +7 -0
- package/kit/gates/secrets-not-in-code/green/config.js +4 -0
- package/kit/gates/secrets-not-in-code/red/leak.js +6 -0
- package/kit/gates/swallowed-error/gate.yml +3 -3
- package/kit/gates/test-has-assertion/check.sh +7 -0
- package/kit/gates/test-has-assertion/green/checkout.test.js +5 -0
- package/kit/gates/test-has-assertion/red/checkout.test.js +8 -0
- package/kit/gates/test-not-adjusted/check.sh +8 -2
- package/kit/gates/todo-without-task/check.sh +7 -0
- package/kit/gates/todo-without-task/gate.yml +2 -2
- package/kit/gates/todo-without-task/green/app.js +2 -0
- package/kit/gates/todo-without-task/red/later.js +4 -0
- package/llms.txt +4 -2
- package/package.json +1 -1
- package/tool/commands/badge.mjs +1 -1
- package/tool/commands/context.mjs +8 -0
- package/tool/commands/doctor.mjs +18 -148
- package/tool/commands/gates.mjs +2 -0
- package/tool/commands/probe.mjs +197 -41
- package/tool/commands/report.mjs +1 -1
- package/tool/i18n/en-docs.mjs +2 -0
- package/tool/i18n/en-gates.mjs +19 -5
- package/tool/i18n/en.mjs +3 -0
- package/tool/i18n/ru-docs.mjs +2 -0
- package/tool/i18n/ru-gates.mjs +20 -6
- package/tool/i18n/ru.mjs +3 -0
- package/tool/lib/evidence.mjs +15 -2
- package/tool/lib/execution.mjs +67 -0
- package/tool/lib/history.mjs +79 -8
- package/tool/lib/protection.mjs +52 -0
- package/tool/lib/prove.mjs +40 -13
- package/tool/lib/run.mjs +165 -0
- package/tool/selfcheck/gates.sh +32 -4
- package/tool/selfcheck/smoke/_fixture.mjs +24 -2
- package/tool/selfcheck/smoke/fail-closed.test.mjs +112 -0
- package/tool/selfcheck/smoke/own-samples.test.mjs +131 -0
- package/tool/selfcheck/smoke/protection.test.mjs +101 -0
- package/tool/selfcheck/smoke/release-tools.test.mjs +55 -0
- package/tool/selfcheck/smoke.sh +15 -1
- package/tool/selfcheck/units-context.mjs +24 -0
- package/tool/selfcheck/units-evidence.mjs +34 -0
- package/tool/selfcheck/units-execution.mjs +88 -0
- package/tool/selfcheck/units-level.mjs +32 -1
- package/tool/selfcheck/units-probe.mjs +282 -22
package/README.md
CHANGED
|
@@ -14,13 +14,18 @@ Your `AGENTS.md` says what the project promises. Nothing checks that those promi
|
|
|
14
14
|
that the commands it lists even run. AQK is that missing layer: one command reads the repository,
|
|
15
15
|
reports a level from AQK-0 to AQK-3, and names every guard that is missing.
|
|
16
16
|
|
|
17
|
+
And one step further than the tools next door: `probe` plants a known defect into a copy of your
|
|
18
|
+
project and checks whether your **declared** guards actually go red. "Tests exist" and "tests
|
|
19
|
+
catch" are different claims — readiness scores measure the first one.
|
|
20
|
+
|
|
17
21
|
```bash
|
|
18
22
|
npx agent-quality-kit doctor # code already exists: your level and what to install
|
|
19
23
|
npx agent-quality-kit start # no code yet: day-zero guards, right away
|
|
20
24
|
```
|
|
21
25
|
|
|
22
26
|
`doctor` only reads. It writes no file and sends nothing anywhere — safe to point at a repository
|
|
23
|
-
you have decided nothing about yet. Nothing to install: `npx` fetches the package (
|
|
27
|
+
you have decided nothing about yet. Nothing to install: `npx` fetches the package (574.1 kB, measured 2026-09-10 — nothing guards this number, so check it
|
|
28
|
+
when it matters).
|
|
24
29
|
|
|
25
30
|
The one exception, named here because it is the only one: with `--brief` (how the hooks run it)
|
|
26
31
|
`doctor` asks the npm registry for its own latest version — **at most once a day, never in CI**,
|
|
@@ -340,7 +345,7 @@ Already using [pre-commit](https://pre-commit.com)? Three lines in the file you
|
|
|
340
345
|
```yaml
|
|
341
346
|
repos:
|
|
342
347
|
- repo: https://github.com/arsen-ask-lx/Agent_Quality_Kit
|
|
343
|
-
rev: v0.
|
|
348
|
+
rev: v0.11.0
|
|
344
349
|
hooks:
|
|
345
350
|
- id: aqk # runs what the repository declares; blocks below AQK-1
|
|
346
351
|
# - id: aqk-doctor # read-only: the level and what is missing, blocks nothing
|
|
@@ -361,7 +366,7 @@ layer AQK adds.
|
|
|
361
366
|
[](https://github.com/marketplace/actions/agent-quality-kit-aqk)
|
|
362
367
|
|
|
363
368
|
```yaml
|
|
364
|
-
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.
|
|
369
|
+
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.11.0
|
|
365
370
|
with:
|
|
366
371
|
min: 1 # the build fails below AQK-1, or if any declared gate failed
|
|
367
372
|
```
|
package/README.ru.md
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
вообще перечисленные там команды. AQK — тот самый недостающий слой: одна команда читает
|
|
15
15
|
репозиторий, называет ступень от AQK-0 до AQK-3 и перечисляет каждого недостающего сторожа.
|
|
16
16
|
|
|
17
|
+
И один шаг дальше, чем соседние инструменты: `probe` подсаживает заведомый дефект в копию вашего
|
|
18
|
+
проекта и смотрит, покраснеет ли **объявленная** защита. «Тесты есть» и «тесты ловят» — разные
|
|
19
|
+
утверждения, и оценки готовности меряют первое.
|
|
20
|
+
|
|
17
21
|
```bash
|
|
18
22
|
npx agent-quality-kit doctor # код уже есть: уровень и что поставить
|
|
19
23
|
npx agent-quality-kit start # кода ещё нет: сторожа дня 0 сразу
|
|
@@ -21,7 +25,8 @@ npx agent-quality-kit start # кода ещё нет: сторожа дня
|
|
|
21
25
|
|
|
22
26
|
`doctor` только читает: ни одного файла не пишет и никуда ничего не отправляет — его можно
|
|
23
27
|
направить на репозиторий, о котором ещё ничего не решено. Ставить ничего не нужно, `npx` скачает
|
|
24
|
-
пакет сам (
|
|
28
|
+
пакет сам (574.1 kB, замер 2026-09-10 — это число не сторожит никто, так что при случае
|
|
29
|
+
перемерьте).
|
|
25
30
|
|
|
26
31
|
Единственное исключение, и названо оно здесь именно потому, что единственное: с `--brief`
|
|
27
32
|
(так его запускают хуки) `doctor` спрашивает у реестра npm свою последнюю версию — **не чаще
|
|
@@ -343,7 +348,7 @@ aqk badge --check # в конвейере: код 1 в тот день, ког
|
|
|
343
348
|
```yaml
|
|
344
349
|
repos:
|
|
345
350
|
- repo: https://github.com/arsen-ask-lx/Agent_Quality_Kit
|
|
346
|
-
rev: v0.
|
|
351
|
+
rev: v0.11.0
|
|
347
352
|
hooks:
|
|
348
353
|
- id: aqk # запускает объявленное; роняет коммит ниже AQK-1
|
|
349
354
|
# - id: aqk-doctor # только осмотр: уровень и чего не хватает, ничего не роняет
|
|
@@ -362,7 +367,7 @@ repos:
|
|
|
362
367
|
[](https://github.com/marketplace/actions/agent-quality-kit-aqk)
|
|
363
368
|
|
|
364
369
|
```yaml
|
|
365
|
-
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.
|
|
370
|
+
- uses: arsen-ask-lx/Agent_Quality_Kit@v0.11.0
|
|
366
371
|
with:
|
|
367
372
|
min: 1 # сборка падает ниже AQK-1 или если упал любой объявленный гейт
|
|
368
373
|
```
|
package/kit/gates/_native.sh
CHANGED
|
@@ -21,6 +21,10 @@ shift || true
|
|
|
21
21
|
[ "$#" -gt 0 ] || { echo "нечего запускать: не передана команда инструмента"; exit 2; }
|
|
22
22
|
|
|
23
23
|
. "$(dirname "$0")/_skip.sh" 2>/dev/null || { echo "не найден _skip.sh рядом с _native.sh"; exit 2; }
|
|
24
|
+
if [ "${AQK_SKIP_READY:-}" != 1 ]; then
|
|
25
|
+
echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
|
|
26
|
+
exit 2
|
|
27
|
+
fi
|
|
24
28
|
|
|
25
29
|
# Два фильтра, а не один: own_samples_filter прячет образцы гейтов и то, что назвал проект
|
|
26
30
|
# в .aqkignore, а skip_paths_filter — общий список каталогов, который переносимые проверки
|
package/kit/gates/_skip.sh
CHANGED
|
@@ -182,3 +182,10 @@ drop_comments() { grep -vE '^[^:]*:[0-9]+:[[:space:]]*(//|\*|#|/\*|--)' ; }
|
|
|
182
182
|
# `sh` в списке нет намеренно: печать в скрипте — его способ говорить с человеком, и запрет
|
|
183
183
|
# отладочной печати покрасил бы каждый из них.
|
|
184
184
|
only_code() { grep -E "\.($(printf '%s' "$CODE_EXT" | tr ' ' '|'))$"; }
|
|
185
|
+
|
|
186
|
+
# Метка собранности. Ставится ПОСЛЕДНЕЙ строкой намеренно: она подтверждает, что файл дочитан
|
|
187
|
+
# до конца, а не только начат. Подключающий обязан её проверить — до 2026-09-10 он проверял
|
|
188
|
+
# лишь НАЛИЧИЕ файла, и подмена содержимого давала код 0: гейт печатал «command not found» и
|
|
189
|
+
# объявлял проект чистым. Библиотеку подключает каждая запись каталога, то есть одним
|
|
190
|
+
# испорченным файлом гасился весь набор защит.
|
|
191
|
+
AQK_SKIP_READY=1
|
|
@@ -21,6 +21,13 @@ if [ ! -f "$SKIP_LIB" ]; then
|
|
|
21
21
|
exit 2
|
|
22
22
|
fi
|
|
23
23
|
. "$SKIP_LIB"
|
|
24
|
+
# Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
|
|
25
|
+
# поэтому проверка ловит и обрыв файла на середине.
|
|
26
|
+
if [ "${AQK_SKIP_READY:-}" != 1 ]; then
|
|
27
|
+
echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
|
|
28
|
+
echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
|
|
29
|
+
exit 2
|
|
30
|
+
fi
|
|
24
31
|
|
|
25
32
|
# --- есть ли договор ----------------------------------------------------------
|
|
26
33
|
# По имени файла, а не по расположению: спецификацию кладут в корень, в `docs/`, рядом с
|
|
@@ -18,6 +18,13 @@ if [ ! -f "$SKIP_LIB" ]; then
|
|
|
18
18
|
exit 2
|
|
19
19
|
fi
|
|
20
20
|
. "$SKIP_LIB"
|
|
21
|
+
# Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
|
|
22
|
+
# поэтому проверка ловит и обрыв файла на середине.
|
|
23
|
+
if [ "${AQK_SKIP_READY:-}" != 1 ]; then
|
|
24
|
+
echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
|
|
25
|
+
echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
|
|
26
|
+
exit 2
|
|
27
|
+
fi
|
|
21
28
|
|
|
22
29
|
# Расширения, где живёт ТЕМИЗИРУЕМЫЙ интерфейс. Своё, а не общий CODE_EXT: там нет ни css, ни
|
|
23
30
|
# vue — они не код в смысле «отладочная печать», но именно в них живёт цвет.
|
|
@@ -15,8 +15,14 @@ if [ -f "$DIR/.aqk-commit-msg" ]; then
|
|
|
15
15
|
MSG=$(cat "$DIR/.aqk-commit-msg")
|
|
16
16
|
else
|
|
17
17
|
if ! (cd "$DIR" 2>/dev/null && git rev-parse --git-dir >/dev/null 2>&1); then
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# НЕ «проверять нечего», а «проверить нечем»: без истории свидетель слеп, и код 0 здесь
|
|
19
|
+
# неотличим от «проверено и чисто». Договор комплекта: 0 — чисто, 1 — находка, остальное —
|
|
20
|
+
# не смогли. Тот же довод уже записан ниже про мелкий клон и в protection-not-removed:
|
|
21
|
+
# когда свидетель слеп, зеленеть нельзя.
|
|
22
|
+
echo "не git-репозиторий — историю смотреть нечем, проверка НЕ СОСТОЯЛАСЬ"
|
|
23
|
+
echo " почини: запусти проверку в репозитории, либо убери запись из манифеста —"
|
|
24
|
+
echo " почини: гейт, который не может посмотреть, не защищает ничего."
|
|
25
|
+
exit 2
|
|
20
26
|
fi
|
|
21
27
|
# Мелкий клон: у коммита не видно родителя, и git выдаёт всё дерево как изменённое. Состав
|
|
22
28
|
# коммита в этом случае не определить, а требовать отчёт вслепую нельзя — конвейер краснел бы
|
|
@@ -19,6 +19,13 @@ if [ ! -f "$SKIP_LIB" ]; then
|
|
|
19
19
|
exit 2
|
|
20
20
|
fi
|
|
21
21
|
. "$SKIP_LIB"
|
|
22
|
+
# Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
|
|
23
|
+
# поэтому проверка ловит и обрыв файла на середине.
|
|
24
|
+
if [ "${AQK_SKIP_READY:-}" != 1 ]; then
|
|
25
|
+
echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
|
|
26
|
+
echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
|
|
27
|
+
exit 2
|
|
28
|
+
fi
|
|
22
29
|
MAX="${AQK_MAX_DEPTH:-5}"
|
|
23
30
|
|
|
24
31
|
# Тесты исключены намеренно — тем же списком, что и в duplicate-code. Глубокая вложенность в
|
|
@@ -36,8 +43,19 @@ find "$DIR" $(skip_find "$DIR") $TESTS -type f \
|
|
|
36
43
|
# Разметка вложена по природе: пять уровней тегов — это не сложная логика, а обычная
|
|
37
44
|
# вёрстка. Меряя её тем же пределом, гейт краснеет на нормальном коде и его выключают.
|
|
38
45
|
function limit() { return (wf ~ /\.(jsx|tsx|vue|svelte)$/) ? MAX + 3 : MAX }
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
# Шаг отступа берётся ИЗ ФАЙЛА, а не считается равным четырём. Пока он был прибит к
|
|
47
|
+
# четырём, проверка видела ВДВОЕ МЕНЬШУЮ вложенность в javascript и typescript, где
|
|
48
|
+
# общепринятый отступ — два пробела: шесть уровней давали «три» и проходили предел
|
|
49
|
+
# молча. Замечено 2026-09-10, когда в каталог впервые добавили образец на .js: go и
|
|
50
|
+
# python отступают на четыре, и на них дефекта не видно в принципе.
|
|
51
|
+
# Минимум зажат снизу двойкой: файл с одиночным пробелом в продолжении строки иначе
|
|
52
|
+
# вчетверо завысил бы вложенность и дал ложную тревогу.
|
|
53
|
+
function unit() { return (step >= 2 && step <= 8) ? step : 4 }
|
|
54
|
+
function flush() {
|
|
55
|
+
if (wf != "" && int(worstN / unit()) > limit())
|
|
56
|
+
print wf ":" wl ": вложенность " int(worstN / unit()) ", предел " limit()
|
|
57
|
+
}
|
|
58
|
+
FNR == 1 { flush(); worstN = 0; wl = 0; step = 0; wf = FILENAME }
|
|
41
59
|
/^[[:space:]]*$/ { next }
|
|
42
60
|
{
|
|
43
61
|
# ширина отступа: табуляция считается за четыре пробела. Отступ берётся ОДНИМ
|
|
@@ -45,8 +63,8 @@ find "$DIR" $(skip_find "$DIR") $TESTS -type f \
|
|
|
45
63
|
# символ отступа и стоил больше, чем весь остальной разбор. Замер 2026-09-08 на uv.
|
|
46
64
|
match($0, /^[ \t]*/); ind = substr($0, 1, RLENGTH)
|
|
47
65
|
n = gsub(/\t/, "", ind) * 4 + length(ind)
|
|
48
|
-
|
|
49
|
-
if (
|
|
66
|
+
if (n > 0 && (step == 0 || n < step)) step = n
|
|
67
|
+
if (n > worstN) { worstN = n; wl = FNR }
|
|
50
68
|
}
|
|
51
69
|
END { flush() }
|
|
52
70
|
' > /tmp/.cplx.$$ 2>/dev/null
|
|
@@ -8,7 +8,7 @@ recipes:
|
|
|
8
8
|
# Переносимая мера грубая — глубина вложенности. Готовые правила считают ветвления и
|
|
9
9
|
# инструкции, это точнее; см. kit/docs/ready-made-rules.md
|
|
10
10
|
any: bash {gate}/check.sh {dir}
|
|
11
|
-
python: ruff check --select C901,PLR0912,PLR0915 {dir}
|
|
12
|
-
typescript: eslint --rule '{"complexity":["error",10],"max-depth":["error",4]}' {dir}
|
|
11
|
+
python: ruff check -q --output-format=concise --select C901,PLR0912,PLR0915 {dir}
|
|
12
|
+
typescript: eslint --no-config-lookup --ignore-pattern 'gates/*/red/**' --ignore-pattern 'gates/*/green/**' --rule '{"complexity":["error",10],"max-depth":["error",4]}' {dir}
|
|
13
13
|
|
|
14
14
|
proof: incidents/README.md — «2026-08-27 ревизия гейтов», п. 6: 75 функций сложнее нормы, худшая с 29 ветвлениями
|
|
@@ -18,6 +18,13 @@ if [ ! -f "$SKIP_LIB" ]; then
|
|
|
18
18
|
exit 2
|
|
19
19
|
fi
|
|
20
20
|
. "$SKIP_LIB"
|
|
21
|
+
# Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
|
|
22
|
+
# поэтому проверка ловит и обрыв файла на середине.
|
|
23
|
+
if [ "${AQK_SKIP_READY:-}" != 1 ]; then
|
|
24
|
+
echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
|
|
25
|
+
echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
|
|
26
|
+
exit 2
|
|
27
|
+
fi
|
|
21
28
|
WIN="${AQK_DUP_LINES:-8}"
|
|
22
29
|
|
|
23
30
|
# Тесты исключены намеренно. Повтор в тестах часто осознанный: читаемость там важнее сухости,
|
|
@@ -25,6 +25,10 @@ recipes:
|
|
|
25
25
|
# Родной инструмент стека, а не jscpd: питоновскому проекту незачем ставить Node ради одной
|
|
26
26
|
# проверки. R0801 сравнивает не байты, а разобранный код — переименованная переменная его
|
|
27
27
|
# не обманет, в отличие от переносимого рецепта.
|
|
28
|
-
|
|
28
|
+
# `--ignore-paths` — исключение на ВХОДЕ, а не фильтром вывода. `aqk add` кладёт красные
|
|
29
|
+
# образцы в проект, и они по построению дублируют друг друга: без исключения pylint
|
|
30
|
+
# предъявлял пользователю НАШИ ЖЕ файлы как его дубликаты. Найдено 2026-09-10 табличной
|
|
31
|
+
# проверкой own-samples в тот час, когда pylint появился на машине.
|
|
32
|
+
python: pylint --disable=all --enable=R0801 --min-similarity-lines=8 --ignore-paths='.*gates/[^/]+/(red|green)(/|$).*' {dir}
|
|
29
33
|
|
|
30
34
|
proof: incidents/README.md — «2026-08-25 разбор 1069 коммитов»: число моделей захардкожено в четырёх местах четырьмя разными значениями
|
|
@@ -18,6 +18,13 @@ if [ ! -f "$SKIP_LIB" ]; then
|
|
|
18
18
|
exit 2
|
|
19
19
|
fi
|
|
20
20
|
. "$SKIP_LIB"
|
|
21
|
+
# Файл на месте — этого мало: подмена содержимого давала код 0. Метка стоит в КОНЦЕ _skip.sh,
|
|
22
|
+
# поэтому проверка ловит и обрыв файла на середине.
|
|
23
|
+
if [ "${AQK_SKIP_READY:-}" != 1 ]; then
|
|
24
|
+
echo "_skip.sh есть, но обход не собрался — проверка НЕ СОСТОЯЛАСЬ, а не прошла"
|
|
25
|
+
echo " почини: замени kit/gates/_skip.sh целым файлом из каталога"
|
|
26
|
+
exit 2
|
|
27
|
+
fi
|
|
21
28
|
|
|
22
29
|
# Один обход и один wc на все файлы разом: на проекте в 36 тысяч файлов цикл с wc на каждый
|
|
23
30
|
# не укладывался в две минуты.
|