@boyingliu01/xp-gate 0.20.0 → 0.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/adapters/gate-8.sh +115 -73
- package/adapters/powershell.sh +60 -5
- package/adapters/python.sh +38 -4
- package/build-integrity/__tests__/import-resolver.test.ts +59 -0
- package/build-integrity/gate-10.ts +17 -2
- package/gate-8.sh +115 -73
- package/hooks/gate-8.sh +115 -73
- package/hooks/pre-commit +130 -27
- package/lib/mattpocock-license-verdict.json +1 -1
- package/mock-policy/AGENTS.md +4 -4
- package/mutation/AGENTS.md +4 -4
- package/package.json +2 -2
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +4 -4
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +4 -4
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +4 -4
- package/plugins/dsh/package.json +1 -1
- package/plugins/dsh/skills/delphi-review/AGENTS.md +4 -4
- package/plugins/dsh/skills/sprint-flow/AGENTS.md +4 -4
- package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +4 -4
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +4 -4
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +4 -4
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +4 -4
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +4 -4
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +4 -4
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +4 -4
- package/principles/AGENTS.md +4 -4
- package/principles/boy-scout.ts +36 -6
- package/scripts/sync-package-content.js +13 -6
- package/skills/delphi-review/AGENTS.md +4 -4
- package/skills/sprint-flow/AGENTS.md +4 -4
- package/skills/test-specification-alignment/AGENTS.md +4 -4
package/hooks/pre-commit
CHANGED
|
@@ -459,10 +459,25 @@ record_gate_audit "gate-0" "version-consistency" "$GATE_0_STATUS" "0" "$GATE_0_S
|
|
|
459
459
|
|
|
460
460
|
echo ""
|
|
461
461
|
|
|
462
|
-
# Get list of changed files
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
462
|
+
# Get list of changed files.
|
|
463
|
+
#
|
|
464
|
+
# Byte-identical mirrors (src/npm-package/**) are governed by CI Mirror Parity,
|
|
465
|
+
# not by re-linting. Leaving them in this scan set double-counted every
|
|
466
|
+
# lint/complexity signal and made jscpd report the source-vs-mirror pair as a
|
|
467
|
+
# 100% whole-file clone, which then tripped Gate 6's "<=5 warnings must clear
|
|
468
|
+
# to zero" rule on ANY edit to a mirrored file -- a warning that is
|
|
469
|
+
# structurally impossible to clear. (Gate 6's MIRROR_EXCLUDE and #494's test
|
|
470
|
+
# selection already exclude mirrors for the same reason.)
|
|
471
|
+
#
|
|
472
|
+
# IMPORTANT: the exclusion applies to the LINT SCAN CORPUS only. The early
|
|
473
|
+
# exit below must key on the RAW staged list -- Gate 8 (secret scanning) is
|
|
474
|
+
# unconditional and fail-closed (#499), and gating it behind a path-filtered
|
|
475
|
+
# list would let a mirror-only commit land with zero secret scanning and no
|
|
476
|
+
# CI backstop.
|
|
477
|
+
RAW_CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
478
|
+
CHANGED_FILES=$(printf '%s\n' "$RAW_CHANGED_FILES" | grep -v '^src/npm-package/' || true)
|
|
479
|
+
|
|
480
|
+
if [ -z "$RAW_CHANGED_FILES" ]; then
|
|
466
481
|
echo "No files changed. Skipping gates."
|
|
467
482
|
exit 0
|
|
468
483
|
fi
|
|
@@ -857,11 +872,21 @@ has_project_lang() {
|
|
|
857
872
|
}
|
|
858
873
|
# Switch to subdirectory if detected (for single-language subdirectory projects).
|
|
859
874
|
# Multi-language projects stay at root — each adapter handles its own path.
|
|
875
|
+
#
|
|
876
|
+
# IN_PROJECT_SUBDIR records whether this cd actually happened. Git reports
|
|
877
|
+
# staged paths relative to the repo root; after cd "$PROJECT_SUBDIR" the [ -f ]
|
|
878
|
+
# probes below need subdirectory-relative paths (hence the PROJECT_SUBDIR
|
|
879
|
+
# prefix strips in Gates 5a/5b/5c), but when the hook stays at the root
|
|
880
|
+
# (multi-language projects) stripping the prefix makes every path-based check
|
|
881
|
+
# resolve against the wrong directory — false BLOCKs in Gate 5a, silent no-ops
|
|
882
|
+
# in 5b/5c. Only strip when we really are inside the subdirectory.
|
|
860
883
|
ORIGINAL_DIR=""
|
|
884
|
+
IN_PROJECT_SUBDIR=0
|
|
861
885
|
_lang_count=$(echo "$PROJECT_LANGS" | wc -w)
|
|
862
886
|
if [ -n "$PROJECT_SUBDIR" ] && [ "$PROJECT_SUBDIR" != "." ] && [ "$PROJECT_LANG" != "documentation-only" ] && [ "$_lang_count" -le 1 ]; then
|
|
863
887
|
ORIGINAL_DIR=$(pwd)
|
|
864
888
|
cd "$PROJECT_SUBDIR"
|
|
889
|
+
IN_PROJECT_SUBDIR=1
|
|
865
890
|
echo "Working in: $PROJECT_SUBDIR/"
|
|
866
891
|
echo ""
|
|
867
892
|
fi
|
|
@@ -891,20 +916,67 @@ else
|
|
|
891
916
|
# in githooks/lib/typecheck.sh so a project's own checker (vue-tsc, svelte-check,
|
|
892
917
|
# a `typecheck` script) is used instead of a hardcoded tsc that cannot resolve
|
|
893
918
|
# single-file components (#436).
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
919
|
+
#
|
|
920
|
+
# Resolve the TS project directory first (#470). The probes below used to run
|
|
921
|
+
# against the repo root only; in multi-language monorepos (e.g. web/ +
|
|
922
|
+
# backend/, where the hook stays at the root — see the cd block above)
|
|
923
|
+
# tsconfig.json / biome.json live in the language subdirectory, so the whole
|
|
924
|
+
# TS half of Gate 1 silently SKIPped ("tsconfig.json not found") while a
|
|
925
|
+
# project config existed. Order: repo root first (unchanged behaviour for
|
|
926
|
+
# plain projects), then the detected language subdirectory, then a shallow
|
|
927
|
+
# search.
|
|
928
|
+
TS_PROJECT_DIR=""
|
|
929
|
+
for _ts_dir in "." "${PROJECT_SUBDIR:-}"; do
|
|
930
|
+
[ -z "$_ts_dir" ] && continue
|
|
931
|
+
if [ -f "$_ts_dir/tsconfig.json" ] || [ -f "$_ts_dir/biome.json" ] || [ -f "$_ts_dir/biome.jsonc" ] \
|
|
932
|
+
|| [ -f "$_ts_dir/eslint.config.js" ] || [ -f "$_ts_dir/.eslintrc.json" ] \
|
|
933
|
+
|| [ -f "$_ts_dir/.eslintrc.js" ] || [ -f "$_ts_dir/.eslintrc.cjs" ]; then
|
|
934
|
+
TS_PROJECT_DIR="$_ts_dir"
|
|
935
|
+
break
|
|
936
|
+
fi
|
|
937
|
+
done
|
|
938
|
+
if [ -z "$TS_PROJECT_DIR" ]; then
|
|
939
|
+
_TSCONFIG_CAND=$(find . -maxdepth 2 \( -name tsconfig.json -o -name biome.json -o -name biome.jsonc -o -name eslint.config.js -o -name .eslintrc.json -o -name .eslintrc.js -o -name .eslintrc.cjs \) -not -path './.git/*' -not -path './node_modules/*' 2>/dev/null | head -1)
|
|
940
|
+
if [ -n "$_TSCONFIG_CAND" ]; then
|
|
941
|
+
TS_PROJECT_DIR=$(dirname "$_TSCONFIG_CAND")
|
|
942
|
+
fi
|
|
943
|
+
fi
|
|
944
|
+
[ -z "$TS_PROJECT_DIR" ] && TS_PROJECT_DIR="."
|
|
945
|
+
if [ "$TS_PROJECT_DIR" != "." ]; then
|
|
946
|
+
echo " TypeScript project directory: $TS_PROJECT_DIR/"
|
|
947
|
+
# typecheck.sh is cwd-relative: run it from the TS project subdirectory in a
|
|
948
|
+
# subshell so the language loop's next iteration still starts at the root.
|
|
949
|
+
# Exit contract: 0 clean, 1 findings (block), 2 checker unavailable (skip).
|
|
950
|
+
# A cd/source infrastructure failure must NOT read as "type errors": map it
|
|
951
|
+
# to 2 (skip) so 1 stays reserved for real findings (#508 walkthrough).
|
|
952
|
+
( cd "$TS_PROJECT_DIR" 2>/dev/null || exit 2 \
|
|
953
|
+
; [ -r "${AUDIT_SCRIPT_DIR}/lib/typecheck.sh" ] || exit 2 \
|
|
954
|
+
; source "${AUDIT_SCRIPT_DIR}/lib/typecheck.sh" && run_typescript_typecheck )
|
|
955
|
+
TS_CHECK_EXIT=$?
|
|
956
|
+
else
|
|
957
|
+
source "${AUDIT_SCRIPT_DIR}/lib/typecheck.sh"
|
|
958
|
+
run_typescript_typecheck
|
|
959
|
+
TS_CHECK_EXIT=$?
|
|
960
|
+
fi
|
|
897
961
|
if [ "$TS_CHECK_EXIT" -eq 1 ]; then
|
|
898
962
|
exit 1
|
|
899
963
|
fi
|
|
900
964
|
|
|
901
|
-
# Run ESLint linting if config exists
|
|
902
|
-
if [ -f "
|
|
965
|
+
# Run ESLint linting if config exists (root or TS project subdirectory)
|
|
966
|
+
if [ -f "$TS_PROJECT_DIR/.eslintrc.json" ] || [ -f "$TS_PROJECT_DIR/.eslintrc.js" ] || [ -f "$TS_PROJECT_DIR/.eslintrc.cjs" ] || [ -f "$TS_PROJECT_DIR/eslint.config.js" ]; then
|
|
903
967
|
echo "Running ESLint linting..."
|
|
904
968
|
# Filter to only TS/JS files - ESLint config ignores non-matching files
|
|
905
969
|
ESLINT_FILES=$(echo "$CHANGED_FILES" | grep -E '\.(ts|tsx|js|jsx)$' || true)
|
|
906
970
|
if [ -n "$ESLINT_FILES" ]; then
|
|
907
|
-
|
|
971
|
+
# File paths from git are repo-root relative, so they are correct from
|
|
972
|
+
# the root. Legacy .eslintrc.* configs are discovered by walking up from
|
|
973
|
+
# each linted file (found in the subdirectory automatically); flat
|
|
974
|
+
# configs are discovered from the CWD, so point at them explicitly.
|
|
975
|
+
if [ "$TS_PROJECT_DIR" != "." ] && [ -f "$TS_PROJECT_DIR/eslint.config.js" ]; then
|
|
976
|
+
ESLINT_OUTPUT=$(npx eslint --config "$TS_PROJECT_DIR/eslint.config.js" $ESLINT_FILES -f json --no-warn-ignored 2>&1)
|
|
977
|
+
else
|
|
978
|
+
ESLINT_OUTPUT=$(npx eslint $ESLINT_FILES -f json --no-warn-ignored 2>&1)
|
|
979
|
+
fi
|
|
908
980
|
ESLINT_EXIT=$?
|
|
909
981
|
if [ "$ESLINT_EXIT" -ne 0 ]; then
|
|
910
982
|
if [ -f ".xp-gate/lint-baseline.json" ] && command -v node &> /dev/null; then
|
|
@@ -951,8 +1023,8 @@ else
|
|
|
951
1023
|
fi
|
|
952
1024
|
else
|
|
953
1025
|
echo "ℹ️ No ESLint configuration found - Skipping"
|
|
954
|
-
if [ -f "package.json" ] && command -v node &> /dev/null; then
|
|
955
|
-
HAS_ESLINT=$(node -e "try{const p=JSON.parse(require('fs').readFileSync('package.json','utf8'));const d=p.devDependencies||{};const deps=p.dependencies||{};console.log((d.eslint||deps.eslint)?'yes':'no')}catch{console.log('no')}") && true
|
|
1026
|
+
if [ -f "$TS_PROJECT_DIR/package.json" ] && command -v node &> /dev/null; then
|
|
1027
|
+
HAS_ESLINT=$(node -e "try{const p=JSON.parse(require('fs').readFileSync('$TS_PROJECT_DIR/package.json','utf8'));const d=p.devDependencies||{};const deps=p.dependencies||{};console.log((d.eslint||deps.eslint)?'yes':'no')}catch{console.log('no')}") && true
|
|
956
1028
|
if [ "$HAS_ESLINT" = "yes" ]; then
|
|
957
1029
|
echo "⚠️ WARNING: eslint is installed in package.json but no eslint config found"
|
|
958
1030
|
echo " Either create .eslintrc.* / eslint.config.* or remove eslint from dependencies"
|
|
@@ -962,9 +1034,17 @@ else
|
|
|
962
1034
|
fi
|
|
963
1035
|
|
|
964
1036
|
# ── Biome lint/format check ──
|
|
965
|
-
|
|
1037
|
+
# Default the project dir so this branch stays runnable standalone
|
|
1038
|
+
# (the gate-1-biome-noop suite extracts it verbatim); a no-op inside the
|
|
1039
|
+
# hook, where TS_PROJECT_DIR is resolved above.
|
|
1040
|
+
TS_PROJECT_DIR="${TS_PROJECT_DIR:-.}"
|
|
1041
|
+
if [ -f "$TS_PROJECT_DIR/biome.json" ] || [ -f "$TS_PROJECT_DIR/biome.jsonc" ]; then
|
|
966
1042
|
echo "Running Biome lint/format check..."
|
|
967
|
-
|
|
1043
|
+
# Run from the TS project directory so Biome auto-discovers its config and
|
|
1044
|
+
# scopes --staged to that subdirectory (mirrors the single-language subdir
|
|
1045
|
+
# mode, which executes after cd "$PROJECT_SUBDIR"). Empirically verified:
|
|
1046
|
+
# `biome check --staged .` from the subdir checks the staged files under it.
|
|
1047
|
+
BIOME_OUT=$(cd "$TS_PROJECT_DIR" && npx biome check --staged . 2>&1)
|
|
968
1048
|
BIOME_STATUS=$?
|
|
969
1049
|
if [ "$BIOME_STATUS" -ne 0 ]; then
|
|
970
1050
|
# Biome exits 1 with `internalError/io - No files were processed` when the
|
|
@@ -989,8 +1069,8 @@ else
|
|
|
989
1069
|
echo "✅ PASSED - Biome check."
|
|
990
1070
|
fi
|
|
991
1071
|
else
|
|
992
|
-
if [ -f "package.json" ] && command -v node &> /dev/null; then
|
|
993
|
-
HAS_BIOME=$(node -e "try{const p=JSON.parse(require('fs').readFileSync('package.json','utf8'));const d=p.devDependencies||{};const deps=p.dependencies||{};console.log((d['@biomejs/biome']||deps['@biomejs/biome'])?'yes':'no')}catch{console.log('no')}") && true
|
|
1072
|
+
if [ -f "$TS_PROJECT_DIR/package.json" ] && command -v node &> /dev/null; then
|
|
1073
|
+
HAS_BIOME=$(node -e "try{const p=JSON.parse(require('fs').readFileSync('$TS_PROJECT_DIR/package.json','utf8'));const d=p.devDependencies||{};const deps=p.dependencies||{};console.log((d['@biomejs/biome']||deps['@biomejs/biome'])?'yes':'no')}catch{console.log('no')}") && true
|
|
994
1074
|
if [ "$HAS_BIOME" = "yes" ]; then
|
|
995
1075
|
echo ""
|
|
996
1076
|
echo "⚠️ WARNING: @biomejs/biome is installed in package.json but no biome.json found"
|
|
@@ -1480,11 +1560,15 @@ else
|
|
|
1480
1560
|
# --- BLOCK path: New .ts/.tsx files without corresponding tests ---
|
|
1481
1561
|
NEW_TS_FILES=$(git diff --cached --name-only --diff-filter=A | grep -E '\.(ts|tsx)$' | grep -v '\.d\.ts$' | grep -v '__tests__' | grep -v '\.test\.' | grep -v '\.spec\.' | grep -v '__snapshots__' | grep -v 'node_modules/' | grep -v '\.next/' | grep -v '\.nuxt/' | grep -v 'dist/' | grep -v 'build/' | grep -v '.turbo/' | grep -v '.cache/' | grep -Ev '(^|/)vitest\.config\.' | grep -Ev '(^|/)vite\.config\.' | grep -Ev '(^|/)jest\.config\.' | grep -Ev '(^|/)tsconfig\.' | grep -Ev '(^|/)eslint\.' | grep -Ev '(^|/)prettier\.' | grep -Ev '(^|/)tailwind\.' || true)
|
|
1482
1562
|
|
|
1483
|
-
# Strip PROJECT_SUBDIR prefix from new-TS-file paths when
|
|
1484
|
-
#
|
|
1485
|
-
#
|
|
1563
|
+
# Strip PROJECT_SUBDIR prefix from new-TS-file paths ONLY when the hook
|
|
1564
|
+
# actually cd'd into the subdirectory (IN_PROJECT_SUBDIR=1; single-language
|
|
1565
|
+
# subdirectory projects). git diff returns repo-root relative paths; after
|
|
1566
|
+
# cd "$PROJECT_SUBDIR" the test-pairing [ -f ] checks below need
|
|
1567
|
+
# subdirectory-relative paths. When the hook stays at the repo root
|
|
1568
|
+
# (multi-language projects) the paths must KEEP their prefix or every
|
|
1569
|
+
# [ -f ] lookup misses and paired files are falsely BLOCKED.
|
|
1486
1570
|
# (Mirrors the v0.14.31+ Gate 5b fix at lines 1603-1608; Gate 5a was missing it.)
|
|
1487
|
-
if [
|
|
1571
|
+
if [ "$IN_PROJECT_SUBDIR" = "1" ] && [ -n "$NEW_TS_FILES" ]; then
|
|
1488
1572
|
NEW_TS_FILES=$(echo "$NEW_TS_FILES" | sed "s|^${PROJECT_SUBDIR}/||")
|
|
1489
1573
|
fi
|
|
1490
1574
|
|
|
@@ -1695,10 +1779,13 @@ else
|
|
|
1695
1779
|
# each plugin directory).
|
|
1696
1780
|
CHANGED_TEST_FILES=$(echo "$CHANGED_TEST_FILES" | grep -vE '^plugins/[^/]+/' || true)
|
|
1697
1781
|
|
|
1698
|
-
# Strip PROJECT_SUBDIR prefix from test file paths when
|
|
1699
|
-
#
|
|
1700
|
-
# vitest and [ -f ]
|
|
1701
|
-
|
|
1782
|
+
# Strip PROJECT_SUBDIR prefix from test file paths ONLY when the hook
|
|
1783
|
+
# actually cd'd into the subdirectory (IN_PROJECT_SUBDIR=1). git diff returns
|
|
1784
|
+
# repo-root relative paths; after cd "$PROJECT_SUBDIR" vitest and [ -f ]
|
|
1785
|
+
# checks need subdirectory-relative paths. At the repo root (multi-language
|
|
1786
|
+
# projects) stripping would silently skip the mock-density scan and feed
|
|
1787
|
+
# vitest paths that do not exist. (v0.14.31+ fix, gated on the cd in v0.19.x)
|
|
1788
|
+
if [ "$IN_PROJECT_SUBDIR" = "1" ] && [ -n "$CHANGED_TEST_FILES" ]; then
|
|
1702
1789
|
CHANGED_TEST_FILES=$(echo "$CHANGED_TEST_FILES" | sed "s|^${PROJECT_SUBDIR}/||")
|
|
1703
1790
|
fi
|
|
1704
1791
|
|
|
@@ -1884,14 +1971,20 @@ else
|
|
|
1884
1971
|
CHANGED_SRC_FILES=$(echo "$CHANGED_SRC_FILES" | grep -vE '^plugins/[^/]+/' || true)
|
|
1885
1972
|
# Mirror handling is identical for source files: their test-adjacent
|
|
1886
1973
|
# paths must never reach vitest as root-project targets (#494).
|
|
1974
|
+
# Selection runs on repo-root relative paths (git diff output), before
|
|
1975
|
+
# any PROJECT_SUBDIR stripping, so the bundled-mirror prefixes match.
|
|
1887
1976
|
SELECTED_SRC_FILES=$(select_root_suite_targets "$CHANGED_SRC_FILES")
|
|
1888
1977
|
if [ "$SELECTED_SRC_FILES" != "$CHANGED_SRC_FILES" ]; then
|
|
1889
1978
|
echo " ↪ Source selection adjusted for bundled mirrors (#494):"
|
|
1890
1979
|
echo " was: $(echo "$CHANGED_SRC_FILES" | tr '\n' ' ')"
|
|
1891
1980
|
echo " now: $(echo "$SELECTED_SRC_FILES" | tr '\n' ' ')"
|
|
1892
1981
|
fi
|
|
1893
|
-
# Strip PROJECT_SUBDIR prefix
|
|
1894
|
-
|
|
1982
|
+
# Strip PROJECT_SUBDIR prefix ONLY when the hook cd'd into the
|
|
1983
|
+
# subdirectory (IN_PROJECT_SUBDIR=1; same gate as the CHANGED_TEST_FILES
|
|
1984
|
+
# fix above — at the repo root the paths must stay root-relative or the
|
|
1985
|
+
# related-test lookup and vitest targets resolve against the wrong dir,
|
|
1986
|
+
# #470)
|
|
1987
|
+
if [ "$IN_PROJECT_SUBDIR" = "1" ] && [ -n "$SELECTED_SRC_FILES" ]; then
|
|
1895
1988
|
SELECTED_SRC_FILES=$(echo "$SELECTED_SRC_FILES" | sed "s|^${PROJECT_SUBDIR}/||")
|
|
1896
1989
|
fi
|
|
1897
1990
|
CHANGED_SRC_COUNT=$(echo "$SELECTED_SRC_FILES" | grep -c '.' || true)
|
|
@@ -2648,7 +2741,17 @@ else
|
|
|
2648
2741
|
echo "❌ BLOCKED - Boy Scout Rule violations detected ($VIOLATION_COUNT)"
|
|
2649
2742
|
exit 1
|
|
2650
2743
|
fi
|
|
2651
|
-
|
|
2744
|
+
|
|
2745
|
+
# REQ-4 (#452): the auto-init rewrites a committed file, which used to
|
|
2746
|
+
# surface as an unexplained dirty ` M .warnings-baseline.json` after
|
|
2747
|
+
# every commit that touched a first-time-modified file. Stage it so the
|
|
2748
|
+
# budget update travels with the commit that caused it; when the
|
|
2749
|
+
# baseline is unchanged (the common case) this is a no-op.
|
|
2750
|
+
if [ -n "$(git status --porcelain -- .warnings-baseline.json 2>/dev/null)" ]; then
|
|
2751
|
+
git add .warnings-baseline.json 2>/dev/null || true
|
|
2752
|
+
echo " ℹ️ .warnings-baseline.json auto-updated and staged with this commit."
|
|
2753
|
+
fi
|
|
2754
|
+
|
|
2652
2755
|
echo " ✅ PASSED - Boy Scout Rule compliance."
|
|
2653
2756
|
fi
|
|
2654
2757
|
else
|
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Mock layering policy enforcement — Gate M3 of pre-push hook. Ensures integration tests use real implementations for internal dependencies, mock external dependencies, and annotate pending mocks with removal plans. Combines project scope scanning, mock decision engine, and per-file validation into a single pipeline.
|
package/mutation/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MUTATION KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**Gate M** (incremental mutation testing) + **Gate M2** helpers (test-layer detection used by `src/mock-policy/`). Pre-push quality gate. TypeScript-only; uses Stryker.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boyingliu01/xp-gate",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "AI-driven development workflow: 6 quality gates + Delphi review + Sprint Flow",
|
|
5
5
|
"bin": {
|
|
6
6
|
"xp-gate": "./bin/xp-gate.js"
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"node": ">=18.0.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"version": "0.
|
|
45
|
+
"version": "0.20.0",
|
|
46
46
|
"license-check": "node scripts/check-mattpocock-license.cjs",
|
|
47
47
|
"prepack": "node scripts/check-mattpocock-license.cjs && node scripts/sync-package-content.js",
|
|
48
48
|
"test": "echo \"Run tests\" && exit 0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 12 pre-commit gates (Gate 0-11), 8 pre-push gates, Sprint Flow (6 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
package/plugins/dsh/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boyingliu01/dsh-plugin-xp-gate",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "XP-Gate deterministic quality gates + AI workflow skills as a DeepSeek Harness (DSH) native plugin: gate-check / gate-principles / gate-arch tools + 12 SKILL.md skills",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 12 pre-commit gates (Gate 0-11), 8 pre-push gates, Sprint Flow (6 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
package/principles/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# PRINCIPLES CHECKER MODULE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.20.
|
|
3
|
+
**Generated:** 2026-10-08
|
|
4
|
+
**Commit:** unknown
|
|
5
|
+
**Branch:** unknown
|
|
6
|
+
**Version:** 0.20.1.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Clean Code & SOLID principles checker — **Gate 4** of pre-commit. 14 rules × 9 language adapters, SARIF 2.1.0 output. Houses the **Boy Scout Rule** enforcement engine (Gate 6) and warning-baseline storage.
|
package/principles/boy-scout.ts
CHANGED
|
@@ -785,12 +785,44 @@ function reportBaselineUpdate(
|
|
|
785
785
|
console.log(` preserved:${preserved.length > 0 ? ` ${list(preserved)}` : ' (none)'}`);
|
|
786
786
|
}
|
|
787
787
|
|
|
788
|
+
/**
|
|
789
|
+
* Record budget entries for files the gate meets for the first time, then save
|
|
790
|
+
* and report the write. Split out of `runEnforcement` to keep both under the
|
|
791
|
+
* long-function threshold; also carries the #452 REQ-2 visibility contract:
|
|
792
|
+
* the report distinguishes "created" from "updated" and names every entry the
|
|
793
|
+
* auto-init introduced, never just a count.
|
|
794
|
+
*/
|
|
795
|
+
async function autoInitMissingEntries(
|
|
796
|
+
baseline: Record<string, BaselineEntry>,
|
|
797
|
+
missingBaselineEntries: string[],
|
|
798
|
+
currentWarnings: Record<string, number>,
|
|
799
|
+
baselinePath: string,
|
|
800
|
+
baselineExisted: boolean,
|
|
801
|
+
): Promise<void> {
|
|
802
|
+
recordAutoInitializedEntries(baseline, missingBaselineEntries, currentWarnings);
|
|
803
|
+
await saveBaseline(baselinePath, baseline);
|
|
804
|
+
const action = baselineExisted ? 'updated' : 'created';
|
|
805
|
+
const noun = missingBaselineEntries.length === 1 ? 'entry' : 'entries';
|
|
806
|
+
console.log(`ℹ️ Baseline ${action}: ${baselinePath}`);
|
|
807
|
+
console.log(` auto-initialized ${noun}: ${missingBaselineEntries.join(', ')}`);
|
|
808
|
+
}
|
|
809
|
+
|
|
788
810
|
async function runEnforcement(newFiles: string[], modifiedFiles: string[], baselinePath: string): Promise<EnforcementResult> {
|
|
789
811
|
const allFiles = [...newFiles.filter(f => f.trim()), ...modifiedFiles.filter(f => f.trim())];
|
|
790
812
|
const currentWarnings = await analyzeWarningsForFiles(allFiles);
|
|
791
|
-
|
|
813
|
+
|
|
814
|
+
// Distinguishing "created" from "updated" is part of the auto-init contract
|
|
815
|
+
// (#452 REQ-2): a silently rewritten baseline is how unrelated entries used
|
|
816
|
+
// to vanish without anyone noticing.
|
|
817
|
+
let baselineExisted = false;
|
|
818
|
+
try {
|
|
819
|
+
await fs.access(baselinePath);
|
|
820
|
+
baselineExisted = true;
|
|
821
|
+
} catch {
|
|
822
|
+
baselineExisted = false;
|
|
823
|
+
}
|
|
792
824
|
const baseline = await loadBaseline(baselinePath);
|
|
793
|
-
|
|
825
|
+
|
|
794
826
|
// Check for missing baseline entries for modified files
|
|
795
827
|
const missingBaselineEntries: string[] = [];
|
|
796
828
|
for (const file of modifiedFiles) {
|
|
@@ -798,13 +830,11 @@ async function runEnforcement(newFiles: string[], modifiedFiles: string[], basel
|
|
|
798
830
|
missingBaselineEntries.push(file);
|
|
799
831
|
}
|
|
800
832
|
}
|
|
801
|
-
|
|
833
|
+
|
|
802
834
|
// Files being modified for the first time get their current count recorded, so
|
|
803
835
|
// the next modification is compared against a real budget instead of nothing.
|
|
804
836
|
if (missingBaselineEntries.length > 0) {
|
|
805
|
-
|
|
806
|
-
await saveBaseline(baselinePath, baseline);
|
|
807
|
-
console.log(`ℹ️ Auto-initialized baseline for ${missingBaselineEntries.length} files`);
|
|
837
|
+
await autoInitMissingEntries(baseline, missingBaselineEntries, currentWarnings, baselinePath, baselineExisted);
|
|
808
838
|
}
|
|
809
839
|
|
|
810
840
|
const deltaResults: DeltaResult[] = [];
|
|
@@ -419,7 +419,7 @@ function checkAdapterDrift(srcRootPath, mirrorRootPath) {
|
|
|
419
419
|
if (mismatched.length > 0) {
|
|
420
420
|
console.error(`[drift-check] ERROR: ${mismatched.length} adapter file(s) have drifted (SHA-256 mismatch):`);
|
|
421
421
|
for (const f of mismatched) console.error(` - ${f}`);
|
|
422
|
-
console.error('[drift-check] Fix: Run `node src/npm-package/scripts/sync-package-content.js` (
|
|
422
|
+
console.error('[drift-check] Fix: Run `node src/npm-package/scripts/sync-package-content.js --fix` to resync (plain invocation is a check-only gate for CI).');
|
|
423
423
|
}
|
|
424
424
|
|
|
425
425
|
if (srcOnly.length > 0 || mirrorOnly.length > 0 || mismatched.length > 0) {
|
|
@@ -449,11 +449,18 @@ function checkDocsDrift(preCommitPath, prePushPath, readmePath, agentsPath) {
|
|
|
449
449
|
function main() {
|
|
450
450
|
console.error(`[sync] repo root: ${REPO_ROOT}`);
|
|
451
451
|
console.error(`[sync] package root: ${PKG_ROOT}`);
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
452
|
+
// Drift gates run BEFORE the sync on purpose: CI's Mirror Parity job relies
|
|
453
|
+
// on a drifted commit failing here rather than being silently healed by the
|
|
454
|
+
// copy loop. Local repair therefore needs the explicit `--fix` escape hatch
|
|
455
|
+
// (the pre-sync "Fix: Run …" advice used to deadlock against this gate).
|
|
456
|
+
const fixMode = process.argv.includes('--fix');
|
|
457
|
+
if (!fixMode) {
|
|
458
|
+
if (checkDocsDrift() === false) {
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
if (checkAdapterDrift() === false) {
|
|
462
|
+
process.exit(1);
|
|
463
|
+
}
|
|
457
464
|
}
|
|
458
465
|
const skills = syncSkills();
|
|
459
466
|
const plugins = syncPlugins();
|