@boyingliu01/xp-gate 0.11.2 → 0.11.4
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/adapter-common.sh +135 -55
- package/hooks/adapter-common.sh +135 -55
- package/mock-policy/AGENTS.md +4 -4
- package/mutation/AGENTS.md +4 -4
- package/mutation/__tests__/pitest-runner.test.ts +574 -0
- package/mutation/gate-m.ts +138 -94
- package/mutation/runners/index.ts +3 -0
- package/mutation/runners/pitest-runner.ts +290 -0
- package/package.json +1 -1
- 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/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/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/adapter-common.sh
CHANGED
|
@@ -2,65 +2,90 @@
|
|
|
2
2
|
|
|
3
3
|
# Common adapter functions for language detection and routing
|
|
4
4
|
|
|
5
|
+
# OS detection: returns linux/macos/windows/unknown
|
|
6
|
+
# Uses uname -s (POSIX) as primary, ${OSTYPE-} as fallback
|
|
7
|
+
detect_os_env() {
|
|
8
|
+
local os
|
|
9
|
+
os=$(uname -s 2>/dev/null || echo "unknown")
|
|
10
|
+
case "$os" in
|
|
11
|
+
Linux*) echo "linux";;
|
|
12
|
+
Darwin*) echo "macos";;
|
|
13
|
+
MINGW*|MSYS*|CYGWIN*) echo "windows";;
|
|
14
|
+
*)
|
|
15
|
+
# Fallback: OSTYPE (bash built-in, not always available)
|
|
16
|
+
if [ -n "${OSTYPE-}" ]; then
|
|
17
|
+
case "${OSTYPE-}" in
|
|
18
|
+
linux*) echo "linux";;
|
|
19
|
+
darwin*) echo "macos";;
|
|
20
|
+
msys*|cygwin*) echo "windows";;
|
|
21
|
+
*) echo "unknown";;
|
|
22
|
+
esac
|
|
23
|
+
else
|
|
24
|
+
echo "unknown"
|
|
25
|
+
fi
|
|
26
|
+
;;
|
|
27
|
+
esac
|
|
28
|
+
}
|
|
29
|
+
|
|
5
30
|
detect_project_lang() {
|
|
6
|
-
if [
|
|
31
|
+
if [ -f "tsconfig.json" ]; then
|
|
7
32
|
echo "typescript"
|
|
8
|
-
elif [
|
|
33
|
+
elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ] || [ -f "setup.py" ]; then
|
|
9
34
|
echo "python"
|
|
10
|
-
elif [
|
|
35
|
+
elif [ -f "go.mod" ]; then
|
|
11
36
|
echo "go"
|
|
12
|
-
elif [
|
|
13
|
-
if [
|
|
37
|
+
elif [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
|
38
|
+
if [ -n "$(find . -name "*.kt" -type f | sed -n '1p; 1q')" ]; then
|
|
14
39
|
echo "kotlin"
|
|
15
40
|
else
|
|
16
41
|
echo "java"
|
|
17
42
|
fi
|
|
18
|
-
elif [
|
|
43
|
+
elif [ -f "pom.xml" ]; then
|
|
19
44
|
echo "java"
|
|
20
|
-
elif [
|
|
21
|
-
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [
|
|
45
|
+
elif [ -f "pubspec.yaml" ]; then
|
|
46
|
+
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [ -f ".metadata" ]; then
|
|
22
47
|
echo "flutter"
|
|
23
48
|
else
|
|
24
49
|
echo "dart"
|
|
25
50
|
fi
|
|
26
|
-
elif [
|
|
51
|
+
elif [ -n "$(find . -name "*.ps1" -type f | sed -n '1p; 1q')" ]; then
|
|
27
52
|
echo "powershell"
|
|
28
|
-
elif [
|
|
53
|
+
elif [ -f "Package.swift" ]; then
|
|
29
54
|
echo "swift"
|
|
30
|
-
elif [
|
|
55
|
+
elif [ -f "CMakeLists.txt" ] || [ -n "$(find . -name "*.cpp" -o -name "*.cc" -type f | sed -n '1p; 1q')" ]; then
|
|
31
56
|
echo "cpp"
|
|
32
|
-
elif [
|
|
57
|
+
elif [ -n "$(find . -name "*.m" -o -name "*.mm" -type f | sed -n '1p; 1q')" ]; then
|
|
33
58
|
echo "objectivec"
|
|
34
|
-
elif [
|
|
59
|
+
elif [ -n "$(find . -name "*.sh" -type f | sed -n '1p; 1q')" ]; then
|
|
35
60
|
echo "shell"
|
|
36
|
-
elif [
|
|
61
|
+
elif [ -n "$(find . -name "*.ps1" -type f -not -path "./.git/*" | sed -n '1p; 1q')" ]; then
|
|
37
62
|
echo "powershell"
|
|
38
63
|
else
|
|
39
|
-
if [
|
|
64
|
+
if [ -n "$(find . -name "*.ts" -o -name "*.tsx" -type f | sed -n '1p; 1q')" ]; then
|
|
40
65
|
echo "typescript"
|
|
41
|
-
elif [
|
|
66
|
+
elif [ -n "$(find . -name "*.py" -type f | sed -n '1p; 1q')" ]; then
|
|
42
67
|
echo "python"
|
|
43
|
-
elif [
|
|
68
|
+
elif [ -n "$(find . -name "*.go" -type f | sed -n '1p; 1q')" ]; then
|
|
44
69
|
echo "go"
|
|
45
|
-
elif [
|
|
70
|
+
elif [ -n "$(find . -name "*.kt" -type f | sed -n '1p; 1q')" ]; then
|
|
46
71
|
echo "kotlin"
|
|
47
|
-
elif [
|
|
72
|
+
elif [ -n "$(find . -name "*.java" -type f | sed -n '1p; 1q')" ]; then
|
|
48
73
|
echo "java"
|
|
49
|
-
elif [
|
|
50
|
-
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [
|
|
74
|
+
elif [ -n "$(find . -name "*.dart" -type f | sed -n '1p; 1q')" ]; then
|
|
75
|
+
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [ -f ".flutter" ]; then
|
|
51
76
|
echo "flutter"
|
|
52
77
|
else
|
|
53
78
|
echo "dart"
|
|
54
79
|
fi
|
|
55
|
-
elif [
|
|
80
|
+
elif [ -n "$(find . -name "*.swift" -type f | sed -n '1p; 1q')" ]; then
|
|
56
81
|
echo "swift"
|
|
57
|
-
elif [
|
|
82
|
+
elif [ -n "$(find . -name "*.cpp" -o -name "*.cc" -o -name "*.c" -o -name "*.h" -type f | sed -n '1p; 1q')" ]; then
|
|
58
83
|
echo "cpp"
|
|
59
|
-
elif [
|
|
84
|
+
elif [ -n "$(find . -name "*.m" -o -name "*.mm" -type f | sed -n '1p; 1q')" ]; then
|
|
60
85
|
echo "objectivec"
|
|
61
|
-
elif [
|
|
86
|
+
elif [ -n "$(find . -name "*.sh" -type f | sed -n '1p; 1q')" ]; then
|
|
62
87
|
echo "shell"
|
|
63
|
-
elif [
|
|
88
|
+
elif [ -n "$(find . -name "*.ps1" -type f -not -path "./.git/*" | sed -n '1p; 1q')" ]; then
|
|
64
89
|
echo "powershell"
|
|
65
90
|
else
|
|
66
91
|
echo "unknown"
|
|
@@ -73,23 +98,22 @@ route_to_adapter() {
|
|
|
73
98
|
local lang
|
|
74
99
|
lang=$(detect_project_lang)
|
|
75
100
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
source "./githooks/adapters/${lang}.sh"
|
|
101
|
+
local adapter_file=""
|
|
102
|
+
|
|
103
|
+
# 3-tier resolution matching pre-commit ADAPTER_DIR logic
|
|
104
|
+
# Tier 1: Global flat layout (~/.config/xp-gate/adapters/lang.sh)
|
|
105
|
+
if [ -f "$HOME/.config/xp-gate/adapters/${lang}.sh" ]; then
|
|
106
|
+
adapter_file="$HOME/.config/xp-gate/adapters/${lang}.sh"
|
|
107
|
+
# Tier 2: Project nested layout (githooks/adapters/lang.sh)
|
|
108
|
+
elif [ -f "githooks/adapters/${lang}.sh" ]; then
|
|
109
|
+
adapter_file="githooks/adapters/${lang}.sh"
|
|
110
|
+
elif [ -f "./githooks/adapters/${lang}.sh" ]; then
|
|
111
|
+
adapter_file="./githooks/adapters/${lang}.sh"
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if [ -n "$adapter_file" ]; then
|
|
115
|
+
# shellcheck source=./githooks/adapters/lang.sh
|
|
116
|
+
source "$adapter_file"
|
|
93
117
|
|
|
94
118
|
# Execute the requested action
|
|
95
119
|
case "$action" in
|
|
@@ -100,7 +124,7 @@ route_to_adapter() {
|
|
|
100
124
|
*) return 1 ;;
|
|
101
125
|
esac
|
|
102
126
|
else
|
|
103
|
-
echo "No adapter found for language: $lang"
|
|
127
|
+
echo "No adapter found for language: $lang (searched: ~/.config/xp-gate/adapters/, githooks/adapters/)"
|
|
104
128
|
return 1
|
|
105
129
|
fi
|
|
106
130
|
}
|
|
@@ -130,7 +154,7 @@ require_tool() {
|
|
|
130
154
|
fi
|
|
131
155
|
|
|
132
156
|
echo "❌ BLOCKED - Required tool '$tool_name' not available for $gate_name"
|
|
133
|
-
if [
|
|
157
|
+
if [ -n "$install_hint" ]; then
|
|
134
158
|
echo " Install: $install_hint"
|
|
135
159
|
fi
|
|
136
160
|
echo " Per QUALITY-GATES-CODE-OF-CONDUCT.md: tool unavailable = BLOCK, not SKIP"
|
|
@@ -142,20 +166,20 @@ detect_iac_project() {
|
|
|
142
166
|
local has_iac=false
|
|
143
167
|
|
|
144
168
|
# Check for Terraform files
|
|
145
|
-
if [
|
|
169
|
+
if [ -n "$(find . -maxdepth 2 -name "*.tf" -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')" ]; then
|
|
146
170
|
has_iac=true
|
|
147
171
|
fi
|
|
148
172
|
|
|
149
173
|
# Check for Kubernetes manifests (YAML with apiVersion/kind)
|
|
150
|
-
if [
|
|
151
|
-
local yaml_file=$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null |
|
|
174
|
+
if [ -n "$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')" ]; then
|
|
175
|
+
local yaml_file=$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')
|
|
152
176
|
if grep -qE "^(apiVersion|kind):" "$yaml_file" 2>/dev/null; then
|
|
153
177
|
has_iac=true
|
|
154
178
|
fi
|
|
155
179
|
fi
|
|
156
180
|
|
|
157
181
|
# Check for Dockerfiles
|
|
158
|
-
if [
|
|
182
|
+
if [ -n "$(find . -maxdepth 2 -name "Dockerfile" -o -name "*.dockerfile" -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')" ]; then
|
|
159
183
|
has_iac=true
|
|
160
184
|
fi
|
|
161
185
|
|
|
@@ -168,9 +192,9 @@ detect_iac_project() {
|
|
|
168
192
|
|
|
169
193
|
# Stryker 9.x config files (new format, takes priority)
|
|
170
194
|
detect_mutation_testable() {
|
|
171
|
-
if [
|
|
172
|
-
[
|
|
173
|
-
if [
|
|
195
|
+
if [ -f "stryker.config.mjs" ] || [ -f "stryker.config.js" ] || \
|
|
196
|
+
[ -f "stryker.config.cjs" ] || [ -f "stryker.config.json" ]; then
|
|
197
|
+
if [ -f "package.json" ] && grep -qE '"@stryker-mutator[^"]*"' package.json 2>/dev/null; then
|
|
174
198
|
return 0
|
|
175
199
|
fi
|
|
176
200
|
if command -v npx >/dev/null 2>&1 && npx --no-install stryker --version >/dev/null 2>&1; then
|
|
@@ -179,8 +203,8 @@ detect_mutation_testable() {
|
|
|
179
203
|
fi
|
|
180
204
|
|
|
181
205
|
# Legacy Stryker config files (backwards compatibility)
|
|
182
|
-
if [
|
|
183
|
-
if [
|
|
206
|
+
if [ -f "stryker.conf.json" ] || [ -f "stryker.prepush.conf.json" ]; then
|
|
207
|
+
if [ -f "package.json" ] && grep -qE '"@stryker-mutator[^"]*"' package.json 2>/dev/null; then
|
|
184
208
|
return 0
|
|
185
209
|
fi
|
|
186
210
|
if command -v npx >/dev/null 2>&1 && npx --no-install stryker --version >/dev/null 2>&1; then
|
|
@@ -189,4 +213,60 @@ detect_mutation_testable() {
|
|
|
189
213
|
fi
|
|
190
214
|
|
|
191
215
|
return 1
|
|
192
|
-
}
|
|
216
|
+
}
|
|
217
|
+
# Detect if a Python project has mutmut installed and configured
|
|
218
|
+
detect_python_mutation_testable() {
|
|
219
|
+
# Check for mutmut installation
|
|
220
|
+
if command -v mutmut >/dev/null 2>&1; then
|
|
221
|
+
return 0
|
|
222
|
+
fi
|
|
223
|
+
# Check for pip-installed mutmut in current venv
|
|
224
|
+
if command -v pip >/dev/null 2>&1 || command -v pip3 >/dev/null 2>&1; then
|
|
225
|
+
if pip show mutmut >/dev/null 2>&1; then
|
|
226
|
+
return 0
|
|
227
|
+
fi
|
|
228
|
+
if pip3 show mutmut >/dev/null 2>&1; then
|
|
229
|
+
return 0
|
|
230
|
+
fi
|
|
231
|
+
fi
|
|
232
|
+
return 1
|
|
233
|
+
}
|
|
234
|
+
# Detect if a Go project has gomutants installed and configured
|
|
235
|
+
detect_go_mutation_testable() {
|
|
236
|
+
# Check for gomutants CLI
|
|
237
|
+
if command -v gomutants >/dev/null 2>&1; then
|
|
238
|
+
return 0
|
|
239
|
+
fi
|
|
240
|
+
# Check GOPATH/bin/gomutants if go.mod exists (default GOPATH via go env when unset)
|
|
241
|
+
if [ -f "go.mod" ]; then
|
|
242
|
+
local go_gopath="${GOPATH:-$(go env GOPATH 2>/dev/null)}"
|
|
243
|
+
if [ -n "$go_gopath" ] && [ -x "$go_gopath/bin/gomutants" ]; then
|
|
244
|
+
return 0
|
|
245
|
+
fi
|
|
246
|
+
fi
|
|
247
|
+
return 1
|
|
248
|
+
}
|
|
249
|
+
# Detect if a Java/Kotlin project has PITest (pitest-maven or pitest-gradle) configured
|
|
250
|
+
detect_pitest_testable() {
|
|
251
|
+
# Check for Maven + pitest-maven plugin
|
|
252
|
+
if command -v mvn >/dev/null 2>&1 && [ -f "pom.xml" ]; then
|
|
253
|
+
if grep -q "pitest-maven" pom.xml 2>/dev/null; then
|
|
254
|
+
return 0
|
|
255
|
+
fi
|
|
256
|
+
fi
|
|
257
|
+
# Check for Gradle + pitest plugin
|
|
258
|
+
if [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
|
259
|
+
local gradle_cmd=""
|
|
260
|
+
if [ -f "gradlew" ] && [ -x "gradlew" ]; then
|
|
261
|
+
gradle_cmd="./gradlew"
|
|
262
|
+
elif command -v gradle >/dev/null 2>&1; then
|
|
263
|
+
gradle_cmd="gradle"
|
|
264
|
+
fi
|
|
265
|
+
if [ -n "$gradle_cmd" ]; then
|
|
266
|
+
if grep -qE "info\.solidsoft\.pitest|info\.solidsoft\.gradle\.pitest" build.gradle build.gradle.kts 2>/dev/null; then
|
|
267
|
+
return 0
|
|
268
|
+
fi
|
|
269
|
+
fi
|
|
270
|
+
fi
|
|
271
|
+
return 1
|
|
272
|
+
}
|
package/hooks/adapter-common.sh
CHANGED
|
@@ -2,65 +2,90 @@
|
|
|
2
2
|
|
|
3
3
|
# Common adapter functions for language detection and routing
|
|
4
4
|
|
|
5
|
+
# OS detection: returns linux/macos/windows/unknown
|
|
6
|
+
# Uses uname -s (POSIX) as primary, ${OSTYPE-} as fallback
|
|
7
|
+
detect_os_env() {
|
|
8
|
+
local os
|
|
9
|
+
os=$(uname -s 2>/dev/null || echo "unknown")
|
|
10
|
+
case "$os" in
|
|
11
|
+
Linux*) echo "linux";;
|
|
12
|
+
Darwin*) echo "macos";;
|
|
13
|
+
MINGW*|MSYS*|CYGWIN*) echo "windows";;
|
|
14
|
+
*)
|
|
15
|
+
# Fallback: OSTYPE (bash built-in, not always available)
|
|
16
|
+
if [ -n "${OSTYPE-}" ]; then
|
|
17
|
+
case "${OSTYPE-}" in
|
|
18
|
+
linux*) echo "linux";;
|
|
19
|
+
darwin*) echo "macos";;
|
|
20
|
+
msys*|cygwin*) echo "windows";;
|
|
21
|
+
*) echo "unknown";;
|
|
22
|
+
esac
|
|
23
|
+
else
|
|
24
|
+
echo "unknown"
|
|
25
|
+
fi
|
|
26
|
+
;;
|
|
27
|
+
esac
|
|
28
|
+
}
|
|
29
|
+
|
|
5
30
|
detect_project_lang() {
|
|
6
|
-
if [
|
|
31
|
+
if [ -f "tsconfig.json" ]; then
|
|
7
32
|
echo "typescript"
|
|
8
|
-
elif [
|
|
33
|
+
elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ] || [ -f "setup.py" ]; then
|
|
9
34
|
echo "python"
|
|
10
|
-
elif [
|
|
35
|
+
elif [ -f "go.mod" ]; then
|
|
11
36
|
echo "go"
|
|
12
|
-
elif [
|
|
13
|
-
if [
|
|
37
|
+
elif [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
|
38
|
+
if [ -n "$(find . -name "*.kt" -type f | sed -n '1p; 1q')" ]; then
|
|
14
39
|
echo "kotlin"
|
|
15
40
|
else
|
|
16
41
|
echo "java"
|
|
17
42
|
fi
|
|
18
|
-
elif [
|
|
43
|
+
elif [ -f "pom.xml" ]; then
|
|
19
44
|
echo "java"
|
|
20
|
-
elif [
|
|
21
|
-
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [
|
|
45
|
+
elif [ -f "pubspec.yaml" ]; then
|
|
46
|
+
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [ -f ".metadata" ]; then
|
|
22
47
|
echo "flutter"
|
|
23
48
|
else
|
|
24
49
|
echo "dart"
|
|
25
50
|
fi
|
|
26
|
-
elif [
|
|
51
|
+
elif [ -n "$(find . -name "*.ps1" -type f | sed -n '1p; 1q')" ]; then
|
|
27
52
|
echo "powershell"
|
|
28
|
-
elif [
|
|
53
|
+
elif [ -f "Package.swift" ]; then
|
|
29
54
|
echo "swift"
|
|
30
|
-
elif [
|
|
55
|
+
elif [ -f "CMakeLists.txt" ] || [ -n "$(find . -name "*.cpp" -o -name "*.cc" -type f | sed -n '1p; 1q')" ]; then
|
|
31
56
|
echo "cpp"
|
|
32
|
-
elif [
|
|
57
|
+
elif [ -n "$(find . -name "*.m" -o -name "*.mm" -type f | sed -n '1p; 1q')" ]; then
|
|
33
58
|
echo "objectivec"
|
|
34
|
-
elif [
|
|
59
|
+
elif [ -n "$(find . -name "*.sh" -type f | sed -n '1p; 1q')" ]; then
|
|
35
60
|
echo "shell"
|
|
36
|
-
elif [
|
|
61
|
+
elif [ -n "$(find . -name "*.ps1" -type f -not -path "./.git/*" | sed -n '1p; 1q')" ]; then
|
|
37
62
|
echo "powershell"
|
|
38
63
|
else
|
|
39
|
-
if [
|
|
64
|
+
if [ -n "$(find . -name "*.ts" -o -name "*.tsx" -type f | sed -n '1p; 1q')" ]; then
|
|
40
65
|
echo "typescript"
|
|
41
|
-
elif [
|
|
66
|
+
elif [ -n "$(find . -name "*.py" -type f | sed -n '1p; 1q')" ]; then
|
|
42
67
|
echo "python"
|
|
43
|
-
elif [
|
|
68
|
+
elif [ -n "$(find . -name "*.go" -type f | sed -n '1p; 1q')" ]; then
|
|
44
69
|
echo "go"
|
|
45
|
-
elif [
|
|
70
|
+
elif [ -n "$(find . -name "*.kt" -type f | sed -n '1p; 1q')" ]; then
|
|
46
71
|
echo "kotlin"
|
|
47
|
-
elif [
|
|
72
|
+
elif [ -n "$(find . -name "*.java" -type f | sed -n '1p; 1q')" ]; then
|
|
48
73
|
echo "java"
|
|
49
|
-
elif [
|
|
50
|
-
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [
|
|
74
|
+
elif [ -n "$(find . -name "*.dart" -type f | sed -n '1p; 1q')" ]; then
|
|
75
|
+
if grep -q "flutter:" "pubspec.yaml" 2>/dev/null || [ -f ".flutter" ]; then
|
|
51
76
|
echo "flutter"
|
|
52
77
|
else
|
|
53
78
|
echo "dart"
|
|
54
79
|
fi
|
|
55
|
-
elif [
|
|
80
|
+
elif [ -n "$(find . -name "*.swift" -type f | sed -n '1p; 1q')" ]; then
|
|
56
81
|
echo "swift"
|
|
57
|
-
elif [
|
|
82
|
+
elif [ -n "$(find . -name "*.cpp" -o -name "*.cc" -o -name "*.c" -o -name "*.h" -type f | sed -n '1p; 1q')" ]; then
|
|
58
83
|
echo "cpp"
|
|
59
|
-
elif [
|
|
84
|
+
elif [ -n "$(find . -name "*.m" -o -name "*.mm" -type f | sed -n '1p; 1q')" ]; then
|
|
60
85
|
echo "objectivec"
|
|
61
|
-
elif [
|
|
86
|
+
elif [ -n "$(find . -name "*.sh" -type f | sed -n '1p; 1q')" ]; then
|
|
62
87
|
echo "shell"
|
|
63
|
-
elif [
|
|
88
|
+
elif [ -n "$(find . -name "*.ps1" -type f -not -path "./.git/*" | sed -n '1p; 1q')" ]; then
|
|
64
89
|
echo "powershell"
|
|
65
90
|
else
|
|
66
91
|
echo "unknown"
|
|
@@ -73,23 +98,22 @@ route_to_adapter() {
|
|
|
73
98
|
local lang
|
|
74
99
|
lang=$(detect_project_lang)
|
|
75
100
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
source "./githooks/adapters/${lang}.sh"
|
|
101
|
+
local adapter_file=""
|
|
102
|
+
|
|
103
|
+
# 3-tier resolution matching pre-commit ADAPTER_DIR logic
|
|
104
|
+
# Tier 1: Global flat layout (~/.config/xp-gate/adapters/lang.sh)
|
|
105
|
+
if [ -f "$HOME/.config/xp-gate/adapters/${lang}.sh" ]; then
|
|
106
|
+
adapter_file="$HOME/.config/xp-gate/adapters/${lang}.sh"
|
|
107
|
+
# Tier 2: Project nested layout (githooks/adapters/lang.sh)
|
|
108
|
+
elif [ -f "githooks/adapters/${lang}.sh" ]; then
|
|
109
|
+
adapter_file="githooks/adapters/${lang}.sh"
|
|
110
|
+
elif [ -f "./githooks/adapters/${lang}.sh" ]; then
|
|
111
|
+
adapter_file="./githooks/adapters/${lang}.sh"
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if [ -n "$adapter_file" ]; then
|
|
115
|
+
# shellcheck source=./githooks/adapters/lang.sh
|
|
116
|
+
source "$adapter_file"
|
|
93
117
|
|
|
94
118
|
# Execute the requested action
|
|
95
119
|
case "$action" in
|
|
@@ -100,7 +124,7 @@ route_to_adapter() {
|
|
|
100
124
|
*) return 1 ;;
|
|
101
125
|
esac
|
|
102
126
|
else
|
|
103
|
-
echo "No adapter found for language: $lang"
|
|
127
|
+
echo "No adapter found for language: $lang (searched: ~/.config/xp-gate/adapters/, githooks/adapters/)"
|
|
104
128
|
return 1
|
|
105
129
|
fi
|
|
106
130
|
}
|
|
@@ -130,7 +154,7 @@ require_tool() {
|
|
|
130
154
|
fi
|
|
131
155
|
|
|
132
156
|
echo "❌ BLOCKED - Required tool '$tool_name' not available for $gate_name"
|
|
133
|
-
if [
|
|
157
|
+
if [ -n "$install_hint" ]; then
|
|
134
158
|
echo " Install: $install_hint"
|
|
135
159
|
fi
|
|
136
160
|
echo " Per QUALITY-GATES-CODE-OF-CONDUCT.md: tool unavailable = BLOCK, not SKIP"
|
|
@@ -142,20 +166,20 @@ detect_iac_project() {
|
|
|
142
166
|
local has_iac=false
|
|
143
167
|
|
|
144
168
|
# Check for Terraform files
|
|
145
|
-
if [
|
|
169
|
+
if [ -n "$(find . -maxdepth 2 -name "*.tf" -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')" ]; then
|
|
146
170
|
has_iac=true
|
|
147
171
|
fi
|
|
148
172
|
|
|
149
173
|
# Check for Kubernetes manifests (YAML with apiVersion/kind)
|
|
150
|
-
if [
|
|
151
|
-
local yaml_file=$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null |
|
|
174
|
+
if [ -n "$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')" ]; then
|
|
175
|
+
local yaml_file=$(find . -maxdepth 2 \( -name "*.yaml" -o -name "*.yml" \) -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')
|
|
152
176
|
if grep -qE "^(apiVersion|kind):" "$yaml_file" 2>/dev/null; then
|
|
153
177
|
has_iac=true
|
|
154
178
|
fi
|
|
155
179
|
fi
|
|
156
180
|
|
|
157
181
|
# Check for Dockerfiles
|
|
158
|
-
if [
|
|
182
|
+
if [ -n "$(find . -maxdepth 2 -name "Dockerfile" -o -name "*.dockerfile" -not -path "./.git/*" 2>/dev/null | sed -n '1p; 1q')" ]; then
|
|
159
183
|
has_iac=true
|
|
160
184
|
fi
|
|
161
185
|
|
|
@@ -168,9 +192,9 @@ detect_iac_project() {
|
|
|
168
192
|
|
|
169
193
|
# Stryker 9.x config files (new format, takes priority)
|
|
170
194
|
detect_mutation_testable() {
|
|
171
|
-
if [
|
|
172
|
-
[
|
|
173
|
-
if [
|
|
195
|
+
if [ -f "stryker.config.mjs" ] || [ -f "stryker.config.js" ] || \
|
|
196
|
+
[ -f "stryker.config.cjs" ] || [ -f "stryker.config.json" ]; then
|
|
197
|
+
if [ -f "package.json" ] && grep -qE '"@stryker-mutator[^"]*"' package.json 2>/dev/null; then
|
|
174
198
|
return 0
|
|
175
199
|
fi
|
|
176
200
|
if command -v npx >/dev/null 2>&1 && npx --no-install stryker --version >/dev/null 2>&1; then
|
|
@@ -179,8 +203,8 @@ detect_mutation_testable() {
|
|
|
179
203
|
fi
|
|
180
204
|
|
|
181
205
|
# Legacy Stryker config files (backwards compatibility)
|
|
182
|
-
if [
|
|
183
|
-
if [
|
|
206
|
+
if [ -f "stryker.conf.json" ] || [ -f "stryker.prepush.conf.json" ]; then
|
|
207
|
+
if [ -f "package.json" ] && grep -qE '"@stryker-mutator[^"]*"' package.json 2>/dev/null; then
|
|
184
208
|
return 0
|
|
185
209
|
fi
|
|
186
210
|
if command -v npx >/dev/null 2>&1 && npx --no-install stryker --version >/dev/null 2>&1; then
|
|
@@ -189,4 +213,60 @@ detect_mutation_testable() {
|
|
|
189
213
|
fi
|
|
190
214
|
|
|
191
215
|
return 1
|
|
192
|
-
}
|
|
216
|
+
}
|
|
217
|
+
# Detect if a Python project has mutmut installed and configured
|
|
218
|
+
detect_python_mutation_testable() {
|
|
219
|
+
# Check for mutmut installation
|
|
220
|
+
if command -v mutmut >/dev/null 2>&1; then
|
|
221
|
+
return 0
|
|
222
|
+
fi
|
|
223
|
+
# Check for pip-installed mutmut in current venv
|
|
224
|
+
if command -v pip >/dev/null 2>&1 || command -v pip3 >/dev/null 2>&1; then
|
|
225
|
+
if pip show mutmut >/dev/null 2>&1; then
|
|
226
|
+
return 0
|
|
227
|
+
fi
|
|
228
|
+
if pip3 show mutmut >/dev/null 2>&1; then
|
|
229
|
+
return 0
|
|
230
|
+
fi
|
|
231
|
+
fi
|
|
232
|
+
return 1
|
|
233
|
+
}
|
|
234
|
+
# Detect if a Go project has gomutants installed and configured
|
|
235
|
+
detect_go_mutation_testable() {
|
|
236
|
+
# Check for gomutants CLI
|
|
237
|
+
if command -v gomutants >/dev/null 2>&1; then
|
|
238
|
+
return 0
|
|
239
|
+
fi
|
|
240
|
+
# Check GOPATH/bin/gomutants if go.mod exists (default GOPATH via go env when unset)
|
|
241
|
+
if [ -f "go.mod" ]; then
|
|
242
|
+
local go_gopath="${GOPATH:-$(go env GOPATH 2>/dev/null)}"
|
|
243
|
+
if [ -n "$go_gopath" ] && [ -x "$go_gopath/bin/gomutants" ]; then
|
|
244
|
+
return 0
|
|
245
|
+
fi
|
|
246
|
+
fi
|
|
247
|
+
return 1
|
|
248
|
+
}
|
|
249
|
+
# Detect if a Java/Kotlin project has PITest (pitest-maven or pitest-gradle) configured
|
|
250
|
+
detect_pitest_testable() {
|
|
251
|
+
# Check for Maven + pitest-maven plugin
|
|
252
|
+
if command -v mvn >/dev/null 2>&1 && [ -f "pom.xml" ]; then
|
|
253
|
+
if grep -q "pitest-maven" pom.xml 2>/dev/null; then
|
|
254
|
+
return 0
|
|
255
|
+
fi
|
|
256
|
+
fi
|
|
257
|
+
# Check for Gradle + pitest plugin
|
|
258
|
+
if [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
|
259
|
+
local gradle_cmd=""
|
|
260
|
+
if [ -f "gradlew" ] && [ -x "gradlew" ]; then
|
|
261
|
+
gradle_cmd="./gradlew"
|
|
262
|
+
elif command -v gradle >/dev/null 2>&1; then
|
|
263
|
+
gradle_cmd="gradle"
|
|
264
|
+
fi
|
|
265
|
+
if [ -n "$gradle_cmd" ]; then
|
|
266
|
+
if grep -qE "info\.solidsoft\.pitest|info\.solidsoft\.gradle\.pitest" build.gradle build.gradle.kts 2>/dev/null; then
|
|
267
|
+
return 0
|
|
268
|
+
fi
|
|
269
|
+
fi
|
|
270
|
+
fi
|
|
271
|
+
return 1
|
|
272
|
+
}
|
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.11.
|
|
3
|
+
**Generated:** 2026-07-01
|
|
4
|
+
**Commit:** a5ef11d
|
|
5
|
+
**Branch:** sprint/2026-06-30-01
|
|
6
|
+
**Version:** 0.11.4.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-
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.11.
|
|
3
|
+
**Generated:** 2026-07-01
|
|
4
|
+
**Commit:** a5ef11d
|
|
5
|
+
**Branch:** sprint/2026-06-30-01
|
|
6
|
+
**Version:** 0.11.4.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.
|