@boyingliu01/xp-gate 0.35.7 → 0.35.8
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/hooks/pre-commit +77 -13
- package/lib/__tests__/mirror-manifest.test.js +64 -0
- package/lib/mattpocock-license-verdict.json +1 -1
- package/lib/mirror-manifest.js +112 -0
- package/mock-policy/AGENTS.md +2 -2
- package/mutation/AGENTS.md +2 -2
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +2 -2
- package/plugins/dsh/package.json +1 -1
- package/plugins/dsh/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/dsh/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +2 -2
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +2 -2
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +2 -2
- package/principles/AGENTS.md +2 -2
- package/skills/delphi-review/AGENTS.md +2 -2
- package/skills/sprint-flow/AGENTS.md +2 -2
- package/skills/test-specification-alignment/AGENTS.md +2 -2
package/hooks/pre-commit
CHANGED
|
@@ -342,7 +342,9 @@ file_exists_in_subdir() {
|
|
|
342
342
|
# in every gate, so their definitions lead the first call.
|
|
343
343
|
# ============================================================================
|
|
344
344
|
AUDIT_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
345
|
-
|
|
345
|
+
# PROJECT_ROOT is resolved once above (line ~235); re-running `git rev-parse` here
|
|
346
|
+
# costs another ~90ms fork on every commit for the same answer (#640).
|
|
347
|
+
PROJECT_ROOT_FOR_AUDIT="${PROJECT_ROOT:-$(cd "$AUDIT_SCRIPT_DIR/../.." 2>/dev/null && pwd)}"
|
|
346
348
|
|
|
347
349
|
# Audit attribution safety net: if a previous commit's post-commit never fired
|
|
348
350
|
# (hooks skipped, crash, or an earlier --no-verify), its staged entries are
|
|
@@ -759,6 +761,10 @@ if [ "$is_protected" = "true" ]; then
|
|
|
759
761
|
else
|
|
760
762
|
# Check if staged changes include VERSION or CHANGELOG.md
|
|
761
763
|
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
764
|
+
# #640: a fork costs ~90ms on Windows (measured: 100 `git rev-parse` = 9456ms),
|
|
765
|
+
# and this exact query is re-run by later gates. Cache it once; consumers below
|
|
766
|
+
# read $XP_STAGED_ACM. Subprocess COUNT, not scan duration, is the bottleneck.
|
|
767
|
+
XP_STAGED_ACM="$STAGED_FILES"
|
|
762
768
|
for file in $STAGED_FILES; do
|
|
763
769
|
case "$file" in
|
|
764
770
|
VERSION) has_version_change=true ;;
|
|
@@ -918,7 +924,7 @@ echo ""
|
|
|
918
924
|
# scope rationale as the mirror exclusion (#507 Delphi round-2 follow-up).
|
|
919
925
|
MIRROR_PATH_FILTER='^src/npm-package/'
|
|
920
926
|
DASHBOARD_PATH_FILTER='^dashboard/'
|
|
921
|
-
RAW_CHANGED_FILES
|
|
927
|
+
RAW_CHANGED_FILES="${XP_STAGED_ACM:-$(git diff --cached --name-only --diff-filter=ACM)}"
|
|
922
928
|
|
|
923
929
|
# Dependencies and build output are not project code (#649).
|
|
924
930
|
#
|
|
@@ -2345,7 +2351,7 @@ else
|
|
|
2345
2351
|
GATE_5_SKIP_COUNT=0
|
|
2346
2352
|
GATE_5_DELETED_TESTS=""
|
|
2347
2353
|
if declare -f classify_test_focus >/dev/null 2>&1; then
|
|
2348
|
-
STAGED_TEST_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null \
|
|
2354
|
+
STAGED_TEST_FILES=$(printf '%s\n' "${XP_STAGED_ACM:-$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null)}" \
|
|
2349
2355
|
| grep -E '\.(test|spec)\.(ts|tsx|js|jsx|mjs|cjs|py|go|java|kt|cs|scala|ps1)$|(^|/)(test_[^/]*\.py|[^/]*_test\.(py|go))$' || true)
|
|
2350
2356
|
if [ -n "$STAGED_TEST_FILES" ]; then
|
|
2351
2357
|
while IFS= read -r _tf; do
|
|
@@ -2751,7 +2757,7 @@ else
|
|
|
2751
2757
|
# Gate 5b: Mock Density ADVISORY Scan (pure bash — no npx tsx overhead)
|
|
2752
2758
|
# 30% = ADVISORY, 50% = suggests @mock-justified. Does NOT block commit.
|
|
2753
2759
|
# ========================================================================
|
|
2754
|
-
CHANGED_TEST_FILES=$(git diff --cached --name-only --diff-filter=ACM | filter_project_paths | grep -E '\.(test|spec)\.(ts|tsx|js|jsx|cjs|mjs|py|go)$' || true)
|
|
2760
|
+
CHANGED_TEST_FILES=$(printf '%s\n' "${XP_STAGED_ACM:-$(git diff --cached --name-only --diff-filter=ACM)}" | filter_project_paths | grep -E '\.(test|spec)\.(ts|tsx|js|jsx|cjs|mjs|py|go)$' || true)
|
|
2755
2761
|
|
|
2756
2762
|
# Nested plugin sub-projects (plugins/<name>/) own their own vitest config and
|
|
2757
2763
|
# are excluded from the root suite (`vitest.config.ts` excludes `plugins/**`,
|
|
@@ -2899,7 +2905,7 @@ else
|
|
|
2899
2905
|
CHANGED_TEST_FILE_COUNT=$(echo "$SELECTED_TEST_FILES" | grep -c '.' || true)
|
|
2900
2906
|
|
|
2901
2907
|
# Also get changed source files (non-test) for related-test lookup
|
|
2902
|
-
CHANGED_SRC_FILES=$(git diff --cached --name-only --diff-filter=ACM | filter_project_paths | grep -E '\.(ts|tsx|js|jsx)$' | grep -v '\.test\.' | grep -v '\.spec\.' | grep -v '__tests__' | grep -v '\.d\.ts$' | grep -v '__snapshots__' || true)
|
|
2908
|
+
CHANGED_SRC_FILES=$(printf '%s\n' "${XP_STAGED_ACM:-$(git diff --cached --name-only --diff-filter=ACM)}" | filter_project_paths | grep -E '\.(ts|tsx|js|jsx)$' | grep -v '\.test\.' | grep -v '\.spec\.' | grep -v '__tests__' | grep -v '\.d\.ts$' | grep -v '__snapshots__' || true)
|
|
2903
2909
|
# Nested plugin sub-projects are excluded from the root suite; their
|
|
2904
2910
|
# sources must not drive root-vitest related-test lookup either (it
|
|
2905
2911
|
# would resolve to plugin-local paths vitest cannot collect).
|
|
@@ -3134,16 +3140,16 @@ else
|
|
|
3134
3140
|
# partial so Stage 2 warns instead of falsely blocking.
|
|
3135
3141
|
# full -> unchanged behavior: whole suite + real threshold.
|
|
3136
3142
|
# skip -> nothing test-relevant changed; no pytest at all.
|
|
3137
|
-
PY_CHANGED_TEST_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null \
|
|
3143
|
+
PY_CHANGED_TEST_FILES=$(printf '%s\n' "${XP_STAGED_ACM:-$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null)}" \
|
|
3138
3144
|
| filter_project_paths \
|
|
3139
3145
|
| grep -E '(^|/)test_[^/]*\.py$|_test\.py$' || true)
|
|
3140
|
-
PY_CHANGED_SRC_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null \
|
|
3146
|
+
PY_CHANGED_SRC_FILES=$(printf '%s\n' "${XP_STAGED_ACM:-$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null)}" \
|
|
3141
3147
|
| filter_project_paths \
|
|
3142
3148
|
| grep -E '\.py$' | grep -vE '(^|/)test_[^/]*\.py$|_test\.py$' || true)
|
|
3143
3149
|
# NOT filtered on purpose: this list answers "did a requirements
|
|
3144
3150
|
# file change", which is a property of the whole commit including
|
|
3145
3151
|
# paths under a vendor/ tree that filter_project_paths removes.
|
|
3146
|
-
PY_CHANGED_ALL
|
|
3152
|
+
PY_CHANGED_ALL="${XP_STAGED_ACM:-$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true)}"
|
|
3147
3153
|
# `grep -c '.'` prints its own zero AND exits 1 on an empty list
|
|
3148
3154
|
# (#493), so the count is derived with `|| true` + wc -l instead.
|
|
3149
3155
|
PY_TEST_COUNT=$(printf '%s\n' "$PY_CHANGED_TEST_FILES" | grep -c '.' || true)
|
|
@@ -3890,14 +3896,21 @@ else
|
|
|
3890
3896
|
exit 1
|
|
3891
3897
|
fi
|
|
3892
3898
|
echo " Running archlint for TypeScript..."
|
|
3893
|
-
#
|
|
3894
|
-
#
|
|
3895
|
-
|
|
3899
|
+
# #640: archlint costs ~8s and scans the whole tree, but an architecture
|
|
3900
|
+
# violation cannot be introduced by a commit that touches no source file.
|
|
3901
|
+
# Gating on "did any source change" removes the single largest fixed cost
|
|
3902
|
+
# from docs/config-only commits without weakening the check at all.
|
|
3903
|
+
if ! printf '%s\n' "${XP_STAGED_ACM:-}" | grep -qE '\.(ts|tsx|js|jsx|mjs|cjs|py|go|java|kt|kts|rs|cpp|cc|cxx|c|h|hpp|swift|dart)$'; then
|
|
3904
|
+
echo " ⏭️ SKIPPED - Architecture validation (no source files changed)"
|
|
3905
|
+
ARCHLINT_OUTPUT=""
|
|
3906
|
+
ARCHLINT_EXIT=0
|
|
3907
|
+
elif [ -f "$PROJECT_ROOT/.architecture-baseline.json" ]; then
|
|
3896
3908
|
ARCHLINT_OUTPUT=$(run_archlint diff .architecture-baseline.json --fail-on high 2>&1)
|
|
3909
|
+
ARCHLINT_EXIT=$?
|
|
3897
3910
|
else
|
|
3898
3911
|
ARCHLINT_OUTPUT=$(run_archlint scan . -f table --quiet 2>&1)
|
|
3912
|
+
ARCHLINT_EXIT=$?
|
|
3899
3913
|
fi
|
|
3900
|
-
ARCHLINT_EXIT=$?
|
|
3901
3914
|
echo "$ARCHLINT_OUTPUT" | tail -30
|
|
3902
3915
|
if [ "$ARCHLINT_EXIT" -ne 0 ]; then
|
|
3903
3916
|
echo ""
|
|
@@ -4606,7 +4619,58 @@ fi
|
|
|
4606
4619
|
# ============================================================================
|
|
4607
4620
|
|
|
4608
4621
|
# ============================================================================
|
|
4609
|
-
# GATE
|
|
4622
|
+
# GATE 12b: Mirror Parity (#654)
|
|
4623
|
+
#
|
|
4624
|
+
# `githooks/**` and `plugins/*/src/**` are canonical; `src/npm-package/**` holds
|
|
4625
|
+
# byte-identical mirrors that get published. Editing only the mirror means the next
|
|
4626
|
+
# prepack silently regenerates it over the change -- v0.27.3 shipped exactly that
|
|
4627
|
+
# bug, and mirror/sync rework accounts for 58 failures in the session logs.
|
|
4628
|
+
#
|
|
4629
|
+
# The check used to run only at pre-push, which turns a two-second fix into a
|
|
4630
|
+
# five-minute wait. It runs here now, but ONLY over files in this commit: a
|
|
4631
|
+
# full-tree scan on every commit is the cost that pushed it to pre-push in the
|
|
4632
|
+
# first place.
|
|
4633
|
+
# ============================================================================
|
|
4634
|
+
MIRROR_STAGED=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true)
|
|
4635
|
+
if [ -n "$MIRROR_STAGED" ] && printf '%s\n' "$MIRROR_STAGED" | grep -qE '^(githooks/|plugins/[^/]+/src/)'; then
|
|
4636
|
+
# Reuse PROJECT_ROOT: `git rev-parse` costs ~90ms per fork on Windows and this
|
|
4637
|
+
# gate must not add two of them to every commit (#640).
|
|
4638
|
+
MIRROR_REPO_ROOT="${PROJECT_ROOT:-}"
|
|
4639
|
+
if [ -n "$MIRROR_REPO_ROOT" ] && [ -f "$MIRROR_REPO_ROOT/scripts/check-hook-mirror.sh" ]; then
|
|
4640
|
+
# Scope to the touched families only: a mirror pair is clean or dirty
|
|
4641
|
+
# independently, and checking untouched families is the slow path this gate
|
|
4642
|
+
# exists to avoid.
|
|
4643
|
+
MIRROR_FAIL=0
|
|
4644
|
+
while IFS= read -r _mf; do
|
|
4645
|
+
[ -n "$_mf" ] || continue
|
|
4646
|
+
case "$_mf" in
|
|
4647
|
+
githooks/*) _mm="src/npm-package/hooks/${_mf#githooks/}" ;;
|
|
4648
|
+
plugins/*/src/*) _mm=$(printf '%s' "$_mf" | sed 's|^plugins/\([^/]*\)/src/|src/npm-package/plugins/\1/src/|') ;;
|
|
4649
|
+
*) continue ;;
|
|
4650
|
+
esac
|
|
4651
|
+
if [ ! -f "$MIRROR_REPO_ROOT/$_mm" ]; then
|
|
4652
|
+
echo "❌ BLOCKED - Gate 12b: $_mf has no mirror at $_mm"
|
|
4653
|
+
echo " Run: node src/npm-package/scripts/sync-package-content.js --fix"
|
|
4654
|
+
MIRROR_FAIL=$((MIRROR_FAIL + 1))
|
|
4655
|
+
elif ! cmp -s "$MIRROR_REPO_ROOT/$_mf" "$MIRROR_REPO_ROOT/$_mm"; then
|
|
4656
|
+
echo "❌ BLOCKED - Gate 12b: $_mm differs from canonical $_mf"
|
|
4657
|
+
echo " Run: node src/npm-package/scripts/sync-package-content.js --fix"
|
|
4658
|
+
MIRROR_FAIL=$((MIRROR_FAIL + 1))
|
|
4659
|
+
fi
|
|
4660
|
+
done <<< "$MIRROR_STAGED"
|
|
4661
|
+
if [ "$MIRROR_FAIL" -gt 0 ]; then
|
|
4662
|
+
echo ""
|
|
4663
|
+
echo "❌ BLOCKED - Gate 12b: $MIRROR_FAIL mirror parity violation(s)."
|
|
4664
|
+
echo " The mirror is what gets published; a mirror-only fix is silently"
|
|
4665
|
+
echo " reverted by the next prepack (v0.27.3 shipped that bug)."
|
|
4666
|
+
GATE_FAILED=1
|
|
4667
|
+
else
|
|
4668
|
+
echo "✅ PASSED - Gate 12b: mirror parity (touched files)"
|
|
4669
|
+
fi
|
|
4670
|
+
fi
|
|
4671
|
+
fi
|
|
4672
|
+
# ============================================================================
|
|
4673
|
+
|
|
4610
4674
|
# The compiler is the first and cheapest static analyser for a compiled language
|
|
4611
4675
|
# and XP-Gate never used it as one: cpp.sh only runs clang-tidy/cppcheck over the
|
|
4612
4676
|
# first 20 files, and Gate 9's build-integrity half is TypeScript-and-Maven only.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @test REQ-654 镜像清单必须自证完整:漏登记的规范源文件要报错,而不是静默不同步
|
|
3
|
+
* @intent 会话日志里 `mirror/sync` 类失败 **58 次**,git 历史反复出现
|
|
4
|
+
* `fix(mirror): ...` / `fix(package): 把 java.sh 改动落到真正的源文件`。
|
|
5
|
+
*
|
|
6
|
+
* 根因不是模型不知道规则——`AGENTS.md` 写得很清楚——而是这类约束是
|
|
7
|
+
* **结构性信息**:哪个文件是源、哪个是镜像、谁依赖谁。模型即使知道规则,
|
|
8
|
+
* 也要在多文件编辑中持续追踪映射关系,而这正是工具该做的事。
|
|
9
|
+
*
|
|
10
|
+
* 提示词救不了的部分,必须靠**漏登记即报错**来兜底。静默不同步是最坏的形态:
|
|
11
|
+
* 它让一次疏忽变成一次发布回滚(v0.27.3 正是只改镜像导致发布回滚)。
|
|
12
|
+
* @covers AC-654-01, AC-654-02, AC-654-03
|
|
13
|
+
*/
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const fs = require('node:fs');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
const { findUnlistedSources, declareSources } = require('../mirror-manifest');
|
|
19
|
+
|
|
20
|
+
const REPO = path.join(__dirname, '..', '..', '..', '..');
|
|
21
|
+
|
|
22
|
+
describe('镜像清单完整性 (#654)', () => {
|
|
23
|
+
it('AC-654-01: 列出 canonical 目录下所有应被镜像的文件', () => {
|
|
24
|
+
const declared = declareSources({ cwd: REPO });
|
|
25
|
+
expect(Array.isArray(declared)).toBe(true);
|
|
26
|
+
// A manifest that silently returns nothing would pass every other assertion here,
|
|
27
|
+
// so pin the shape: real file lists are non-trivial.
|
|
28
|
+
expect(declared.length).toBeGreaterThan(20);
|
|
29
|
+
for (const entry of declared) {
|
|
30
|
+
expect(typeof entry.source).toBe('string');
|
|
31
|
+
expect(typeof entry.mirror).toBe('string');
|
|
32
|
+
// Both paths are repo-relative, forward-slashed, so drift messages are readable.
|
|
33
|
+
expect(entry.source.includes('\\')).toBe(false);
|
|
34
|
+
expect(entry.mirror.includes('\\')).toBe(false);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('AC-654-02: 实际存在的规范源文件若未登记,必须被报出来', () => {
|
|
39
|
+
const unlisted = findUnlistedSources({ cwd: REPO });
|
|
40
|
+
// The invariant the issue asks for: zero unlisted sources. This is the assertion
|
|
41
|
+
// that turns "someone forgot to register java.sh" from a publish-time rollback
|
|
42
|
+
// into a red test at commit time.
|
|
43
|
+
expect(unlisted).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('AC-654-03: 合成一个未登记文件时能被检出(防止检测器本身失效)', () => {
|
|
47
|
+
// A detector that never fires is indistinguishable from "no drift". Prove it fires
|
|
48
|
+
// on a synthetic tree rather than trusting the empty result above.
|
|
49
|
+
const fixture = {
|
|
50
|
+
'githooks/pre-commit': 'x',
|
|
51
|
+
'githooks/lib/known.sh': 'x',
|
|
52
|
+
'githooks/lib/orphan.sh': 'x',
|
|
53
|
+
};
|
|
54
|
+
const unlisted = findUnlistedSources({
|
|
55
|
+
cwd: REPO,
|
|
56
|
+
files: Object.keys(fixture),
|
|
57
|
+
declared: [
|
|
58
|
+
{ source: 'githooks/pre-commit', mirror: 'src/npm-package/hooks/pre-commit' },
|
|
59
|
+
{ source: 'githooks/lib/known.sh', mirror: 'src/npm-package/hooks/lib/known.sh' },
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
expect(unlisted).toEqual(['githooks/lib/orphan.sh']);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mirror manifest: which canonical sources must be byte-identical in the npm package
|
|
3
|
+
* (#654).
|
|
4
|
+
*
|
|
5
|
+
* `githooks/**` and `plugins/*/src/**` are canonical; `src/npm-package/**` holds
|
|
6
|
+
* byte-identical mirrors that get published. Editing a mirror only means the next
|
|
7
|
+
* prepack silently regenerates it — v0.27.3 shipped exactly that bug.
|
|
8
|
+
*
|
|
9
|
+
* `AGENTS.md` states the rule clearly and it still gets violated ~58 times, because
|
|
10
|
+
* the constraint is *structural* (which file is source, which is mirror, who depends
|
|
11
|
+
* on whom), not stylistic. Knowing the rule does not remove the need to track the
|
|
12
|
+
* mapping across a multi-file edit; that is tooling's job.
|
|
13
|
+
*
|
|
14
|
+
* Hence this module: the mapping is data, and a canonical file missing from the
|
|
15
|
+
* mapping is an error rather than a silent no-op.
|
|
16
|
+
*/
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const fs = require('node:fs');
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
|
|
22
|
+
/** Directories (repo-relative) whose files mirror into the package. */
|
|
23
|
+
const MIRRORED_ROOTS = [
|
|
24
|
+
{ from: 'githooks', to: 'src/npm-package/hooks' },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/** Individual canonical files that mirror into a different location. */
|
|
28
|
+
const INDIVIDUAL_PAIRS = [
|
|
29
|
+
{ source: 'githooks/pre-commit', mirror: 'src/npm-package/hooks/pre-commit' },
|
|
30
|
+
{ source: 'githooks/pre-push', mirror: 'src/npm-package/hooks/pre-push' },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/** Paths inside a mirrored root that are NOT mirrored (tests, docs). */
|
|
34
|
+
const EXCLUDED_PREFIXES = ['__tests__/', 'node_modules/', '.git/'];
|
|
35
|
+
|
|
36
|
+
function toPosix(p) {
|
|
37
|
+
return p.split(path.sep).join('/');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Recursively list files under `dir`, repo-relative and forward-slashed. */
|
|
41
|
+
function listFiles(root, dir, out = []) {
|
|
42
|
+
let entries;
|
|
43
|
+
try {
|
|
44
|
+
entries = fs.readdirSync(path.join(root, dir), { withFileTypes: true });
|
|
45
|
+
} catch {
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
if (!Array.isArray(entries)) return out;
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
const rel = toPosix(path.join(dir, entry.name));
|
|
51
|
+
if (entry.isDirectory()) {
|
|
52
|
+
if (EXCLUDED_PREFIXES.some((p) => `${entry.name}/` === p)) continue;
|
|
53
|
+
listFiles(root, rel, out);
|
|
54
|
+
} else {
|
|
55
|
+
out.push(rel);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Expand the declared mapping into concrete source→mirror pairs.
|
|
63
|
+
*
|
|
64
|
+
* @param {{cwd?: string}} opts
|
|
65
|
+
* @returns {Array<{source: string, mirror: string}>}
|
|
66
|
+
*/
|
|
67
|
+
function declareSources(opts = {}) {
|
|
68
|
+
const cwd = opts.cwd || process.cwd();
|
|
69
|
+
const pairs = [...INDIVIDUAL_PAIRS];
|
|
70
|
+
const seen = new Set(pairs.map((p) => p.source));
|
|
71
|
+
for (const root of MIRRORED_ROOTS) {
|
|
72
|
+
for (const file of listFiles(cwd, root.from)) {
|
|
73
|
+
if (seen.has(file)) continue;
|
|
74
|
+
const rest = file.slice(root.from.length + 1);
|
|
75
|
+
if (EXCLUDED_PREFIXES.some((prefix) => rest.startsWith(prefix))) continue;
|
|
76
|
+
pairs.push({ source: file, mirror: `${root.to}/${rest}` });
|
|
77
|
+
seen.add(file);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return pairs.sort((a, b) => a.source.localeCompare(b.source));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Canonical files that exist but appear in no mapping entry.
|
|
85
|
+
*
|
|
86
|
+
* This is the check that turns "someone forgot to register java.sh" from a
|
|
87
|
+
* publish-time rollback into a red test at commit time. Silence here is the failure
|
|
88
|
+
* mode worth preventing: a file that is never mirrored looks fine locally and
|
|
89
|
+
* disappears from the published package.
|
|
90
|
+
*
|
|
91
|
+
* @param {{cwd?: string, files?: string[], declared?: Array<{source: string}>}} opts
|
|
92
|
+
* @returns {string[]}
|
|
93
|
+
*/
|
|
94
|
+
function findUnlistedSources(opts = {}) {
|
|
95
|
+
const cwd = opts.cwd || process.cwd();
|
|
96
|
+
const declared = opts.declared || declareSources({ cwd });
|
|
97
|
+
const declaredSet = new Set(declared.map((entry) => entry.source));
|
|
98
|
+
const present = opts.files || listFiles(cwd, 'githooks');
|
|
99
|
+
return present
|
|
100
|
+
.filter((file) => !EXCLUDED_PREFIXES.some((prefix) => file.slice('githooks/'.length).startsWith(prefix)))
|
|
101
|
+
.filter((file) => !declaredSet.has(file))
|
|
102
|
+
.sort();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Human-readable drift report; empty array means clean. */
|
|
106
|
+
function describeUnlisted(unlisted) {
|
|
107
|
+
return unlisted.map(
|
|
108
|
+
(file) => `${file} is a canonical source with no mirror entry — the published package will not carry it`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = { declareSources, findUnlistedSources, describeUnlisted, MIRRORED_ROOTS };
|
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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": "xp-gate",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.8",
|
|
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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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.35.
|
|
3
|
+
"version": "0.35.8",
|
|
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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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.35.
|
|
3
|
+
"version": "0.35.8",
|
|
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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.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
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** b3549c25
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.8.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|