@spardutti/claude-skills 2.19.5 → 2.20.1
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/lib/setup-hook.mjs +63 -11
- package/package.json +1 -1
package/lib/setup-hook.mjs
CHANGED
|
@@ -579,7 +579,7 @@ const SHIP_GATE_SCRIPT = `#!/usr/bin/env bash
|
|
|
579
579
|
# what makes a fix re-gate itself instead of riding on the previous verdict.
|
|
580
580
|
#
|
|
581
581
|
# Exit codes:
|
|
582
|
-
# 0 clean — nothing over the line limit,
|
|
582
|
+
# 0 clean — nothing over the line limit, nothing survived, nothing uncovered
|
|
583
583
|
# 1 findings that must be dealt with before shipping
|
|
584
584
|
# 2 ran, but could not prove the tests (a mutation tool is missing) — report,
|
|
585
585
|
# don't block; the output names exactly what to install and where
|
|
@@ -629,7 +629,7 @@ GAUNTLET_MAX_LINES=200
|
|
|
629
629
|
GAUNTLET_MUTATE=""
|
|
630
630
|
GAUNTLET_SOURCE_EXT="ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|rb|php|c|h|cpp|hpp|cs|swift|gd"
|
|
631
631
|
GAUNTLET_IGNORE_EXT="md|mdx|txt|rst|adoc|json|ya?ml|toml|lock|cfg|ini|env|csv|tsv|sql|html|css|scss|svg|png|jpg|jpeg|gif|webp|ico|pdf|woff2?|ttf|otf|mp3|mp4|wav|zip|gz|tres|tscn|import|godot"
|
|
632
|
-
GAUNTLET_IGNORE_FILES="*.gen.ts *.gen.tsx *.generated.* */migrations/*.py */alembic/versions/*.py */components/ui/*.tsx"
|
|
632
|
+
GAUNTLET_IGNORE_FILES="*.gen.ts *.gen.tsx *.generated.* */migrations/*.py */alembic/versions/*.py */components/ui/*.tsx */*.config.*"
|
|
633
633
|
[ -n "\${HOME:-}" ] && [ -f "$HOME/.claude/gauntlet.conf" ] && . "$HOME/.claude/gauntlet.conf"
|
|
634
634
|
[ -f ".claude/gauntlet.conf" ] && . ".claude/gauntlet.conf"
|
|
635
635
|
|
|
@@ -677,6 +677,11 @@ SOURCED=$(printf '%s\\n' "$CHANGED" | grep -E "\\.($GAUNTLET_SOURCE_EXT)$" \\
|
|
|
677
677
|
# both checks — and printed, because a silent skip is the same lie as a fake
|
|
678
678
|
# PASS. The leading / is what lets one pattern match components/ui at the repo
|
|
679
679
|
# root and apps/web/src/components/ui alike.
|
|
680
|
+
#
|
|
681
|
+
# */*.config.* is here for the same reason, and became urgent the moment an
|
|
682
|
+
# uncovered line started failing the gate: vitest.config.ts has no tests, will
|
|
683
|
+
# never have tests, and is not a thing anyone writes a test for. Left in, every
|
|
684
|
+
# diff that touches a config reports findings nobody can close.
|
|
680
685
|
# set -f matters: an unquoted list is glob-expanded before it is split, so
|
|
681
686
|
# */components/ui/*.tsx turned itself into the very path it was meant to match
|
|
682
687
|
# and then matched nothing.
|
|
@@ -799,13 +804,24 @@ for owner in $OWNERS; do
|
|
|
799
804
|
# when that one file had no tests, Stryker exited on "No tests were executed"
|
|
800
805
|
# and the gate reported UNPROVEN, which writes a receipt and blocks nothing.
|
|
801
806
|
FLAGS=""
|
|
807
|
+
GLOBBED=","
|
|
802
808
|
while IFS= read -r f; do
|
|
803
809
|
hunks=$(git diff -U0 "$BASE" -- "$f" 2>/dev/null \\
|
|
804
810
|
| grep -oE '^@@ -[0-9,]+ \\+[0-9]+(,[0-9]+)?' | sed 's/.*+//' \\
|
|
805
811
|
| while IFS=, read -r s l; do l=\${l:-1}; [ "$l" -gt 0 ] && echo "$s-$((s+l-1))"; done)
|
|
806
812
|
[ -z "$hunks" ] && hunks="1-$(wc -l < "$f")"
|
|
807
813
|
rel=\${f#$owner/}
|
|
808
|
-
|
|
814
|
+
# A Next.js route folder — [id], [[...slug]] — is a glob expression to
|
|
815
|
+
# Stryker, which refuses "Cannot combine a glob expression with a mutation
|
|
816
|
+
# range" and fails the entire run, not just that file. Escaping the brackets
|
|
817
|
+
# stops the path resolving at all. Replacing each with ? keeps it matching
|
|
818
|
+
# that one file and drops the range, so the file is mutated whole: a
|
|
819
|
+
# superset of the diff, slower than a range but never less than what changed.
|
|
820
|
+
case "$rel" in
|
|
821
|
+
*[][*?{}]*) FLAGS="$FLAGS,$(printf '%s' "$rel" | sed 's/[][*?{}]/?/g')"
|
|
822
|
+
GLOBBED="$GLOBBED$rel," ;;
|
|
823
|
+
*) for r in $hunks; do FLAGS="$FLAGS,$rel:$r"; done ;;
|
|
824
|
+
esac
|
|
809
825
|
done <<< "$OWNED"
|
|
810
826
|
|
|
811
827
|
base=""; RUN=""
|
|
@@ -870,12 +886,39 @@ for owner in $OWNERS; do
|
|
|
870
886
|
# HEADER every run and repeats the word in its table, so a bare grep reports
|
|
871
887
|
# survivors on a clean run — worse than not running at all. Stryker marks each
|
|
872
888
|
# real finding \`[Survived]\`; table and border lines are excluded outright.
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
889
|
+
# NoCoverage is printed exactly like Survived and means something worse: not
|
|
890
|
+
# "a test missed this mutation" but "no test executes this line at all". The
|
|
891
|
+
# gate matched only [Survived], so a diff whose files have no tests came back
|
|
892
|
+
# PASS — 306 uncovered mutants reported as proven on one commit. It is judged
|
|
893
|
+
# only for files that went in WITH a range: a glob-shaped path is mutated
|
|
894
|
+
# whole, so its untouched lines would report uncovered forever, and a finding
|
|
895
|
+
# nobody can close is what teaches people to --force.
|
|
896
|
+
#
|
|
897
|
+
# The status line carries no file name; the line under it does, as
|
|
898
|
+
# file:line:column. They are paired here rather than grepped separately.
|
|
899
|
+
if [ "$TOOL" = stryker ]; then
|
|
900
|
+
ALL=$(printf '%s\\n' "$OUT" | awk -v globbed="$GLOBBED" '
|
|
901
|
+
/^\\[Survived\\]/ { pend = $0; kind = "s"; next }
|
|
902
|
+
/^\\[NoCoverage\\]/ { pend = $0; kind = "n"; next }
|
|
903
|
+
pend != "" {
|
|
904
|
+
file = $0; sub(/:[0-9]+:[0-9]+$/, "", file)
|
|
905
|
+
if (kind == "s" || index(globbed, "," file ",") == 0) print pend " " $0
|
|
906
|
+
pend = ""
|
|
907
|
+
}
|
|
908
|
+
# A survivor with no location under it is still a survivor, never dropped.
|
|
909
|
+
END { if (pend != "" && kind == "s") print pend }
|
|
910
|
+
')
|
|
911
|
+
else
|
|
912
|
+
ALL=$(printf '%s\\n' "$OUT" | grep -E '[Ss]urvived' \\
|
|
913
|
+
| grep -vE '^[[:space:]]*[#│|+-]|# *surviv')
|
|
914
|
+
fi
|
|
915
|
+
# The detail list is capped so one bad file cannot bury the output. The cap
|
|
916
|
+
# used to be the whole story, and it hid the WORST file: 20 findings from one
|
|
917
|
+
# file filled it, and a second file with 54 uncovered mutants never appeared
|
|
918
|
+
# at all. A gate whose biggest finding is invisible gets under-fixed. Every
|
|
919
|
+
# file with findings is now named below the cut, worst first.
|
|
920
|
+
FOUND=$(printf '%s\\n' "$ALL" | grep -c .)
|
|
921
|
+
SURVIVED=$(printf '%s\\n' "$ALL" | head -20)
|
|
879
922
|
FIXED=0
|
|
880
923
|
NOTE=""
|
|
881
924
|
|
|
@@ -916,8 +959,17 @@ for owner in $OWNERS; do
|
|
|
916
959
|
fi
|
|
917
960
|
|
|
918
961
|
if [ -n "$SURVIVED" ]; then
|
|
919
|
-
echo " $label $TOOL —
|
|
962
|
+
echo " $label $TOOL — these lines can break and no test notices:"
|
|
920
963
|
printf '%s\\n' "$SURVIVED" | sed 's/^/ /'
|
|
964
|
+
if [ "$FOUND" -gt 20 ]; then
|
|
965
|
+
echo " ... $((FOUND - 20)) more not shown. Every file with findings:"
|
|
966
|
+
if [ "$TOOL" = stryker ]; then
|
|
967
|
+
printf '%s\\n' "$ALL" \\
|
|
968
|
+
| awk '{ f = $NF; sub(/:[0-9]+:[0-9]+$/, "", f); n[f]++ }
|
|
969
|
+
END { for (k in n) printf "%8d %s\\n", n[k], k }' \\
|
|
970
|
+
| sort -rn | sed 's/^/ /'
|
|
971
|
+
fi
|
|
972
|
+
fi
|
|
921
973
|
[ "$FIXED" -gt 0 ] && echo " ($FIXED baselined survivor(s) now killed — --baseline banks them)"
|
|
922
974
|
STATUS=1
|
|
923
975
|
elif [ $RC -ne 0 ]; then
|
|
@@ -927,7 +979,7 @@ for owner in $OWNERS; do
|
|
|
927
979
|
elif [ -n "$NOTE" ]; then
|
|
928
980
|
printf '%s\\n' "$NOTE"
|
|
929
981
|
else
|
|
930
|
-
echo " $label $TOOL — ok,
|
|
982
|
+
echo " $label $TOOL — ok, nothing survived and nothing was uncovered"
|
|
931
983
|
[ "$FIXED" -gt 0 ] && echo " ($FIXED baselined survivor(s) now killed — --baseline banks them)"
|
|
932
984
|
fi
|
|
933
985
|
done
|