@boyingliu01/xp-gate 0.12.1 → 0.12.3

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.
Files changed (31) hide show
  1. package/bin/xp-gate.js +22 -0
  2. package/gate-3.sh +68 -0
  3. package/gate-4.sh +80 -0
  4. package/gate-7.sh +45 -0
  5. package/gate-8.sh +56 -0
  6. package/gate-9.sh +130 -0
  7. package/lib/__tests__/update-hooks.test.js +573 -0
  8. package/lib/update-hooks.js +288 -0
  9. package/mock-policy/AGENTS.md +3 -3
  10. package/mutation/AGENTS.md +3 -3
  11. package/package.json +7 -2
  12. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  13. package/plugins/claude-code/skills/delphi-review/AGENTS.md +6 -6
  14. package/plugins/claude-code/skills/delphi-review/SKILL.md +34 -12
  15. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
  16. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
  17. package/plugins/opencode/package.json +1 -1
  18. package/plugins/opencode/skills/delphi-review/AGENTS.md +6 -6
  19. package/plugins/opencode/skills/delphi-review/SKILL.md +34 -12
  20. package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
  21. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
  22. package/plugins/qoder/plugin.json +1 -1
  23. package/plugins/qoder/skills/delphi-review/AGENTS.md +6 -6
  24. package/plugins/qoder/skills/delphi-review/SKILL.md +198 -264
  25. package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
  26. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
  27. package/principles/AGENTS.md +3 -3
  28. package/skills/delphi-review/AGENTS.md +6 -6
  29. package/skills/delphi-review/SKILL.md +34 -12
  30. package/skills/sprint-flow/AGENTS.md +3 -3
  31. package/skills/test-specification-alignment/AGENTS.md +3 -3
package/bin/xp-gate.js CHANGED
@@ -13,6 +13,7 @@ const { principles } = require('../lib/principles.js');
13
13
  const { arch } = require('../lib/arch.js');
14
14
  const { upgrade } = require('../lib/upgrade.js');
15
15
  const { bootstrap } = require('../lib/bootstrap.js');
16
+ const { updateHooks } = require('../lib/update-hooks.js');
16
17
 
17
18
  function handleUIReview() {
18
19
  const { execSync } = require('child_process');
@@ -143,6 +144,27 @@ const COMMANDS = {
143
144
  handleNextSprint(subargs).then(code => process.exit(code));
144
145
  },
145
146
  usage: 'xp-gate next-sprint [--json] [--plan] [--dir <path>]'
147
+ },
148
+ 'update-hooks': {
149
+ description: 'Sync latest hooks from xp-gate package to project',
150
+ run: subargs => {
151
+ const scopeArg = subargs.find(a => a.startsWith('--scope='));
152
+ const scopeVal = scopeArg ? scopeArg.split('=')[1] : 'all';
153
+ const options = {
154
+ global: subargs.includes('--global'),
155
+ force: subargs.includes('--force'),
156
+ dryRun: subargs.includes('--dry-run'),
157
+ noBackup: subargs.includes('--no-backup'),
158
+ scope: scopeVal,
159
+ };
160
+ try {
161
+ process.exit(updateHooks(options));
162
+ } catch (err) {
163
+ console.error(`Error: ${err.message}`);
164
+ process.exit(1);
165
+ }
166
+ },
167
+ usage: 'xp-gate update-hooks [--global] [--force] [--dry-run] [--no-backup] [--scope hooks|adapters|all]'
146
168
  }
147
169
  };
148
170
 
package/gate-3.sh ADDED
@@ -0,0 +1,68 @@
1
+ # ============================================================================
2
+ # GATE 3: Cyclomatic Complexity Check
3
+ # Uses lizard - checks cyclomatic complexity of changed source files
4
+ # ============================================================================
5
+
6
+ 2>&1 echo ""
7
+ 2>&1 echo "→ Gate 3: Cyclomatic complexity..."
8
+ GATE_3_START=$(gate_start_ms)
9
+
10
+ if [ "$PROJECT_LANG" = "documentation-only" ]; then
11
+ echo "⏭️ SKIPPED - Complexity (documentation project)."
12
+ GATE_3_STATUS="SKIP"
13
+
14
+ elif [ "$PROJECT_LANG" = "powershell" ]; then
15
+ echo "ℹ️ No PowerShell Clean Code / SOLID tool available"
16
+ echo "⏭️ SKIPPED - Complexity (no PowerShell tool)"
17
+ GATE_3_STATUS="SKIP"
18
+
19
+ else
20
+ CCN_THRESHOLD=5
21
+
22
+ # Check lizard availability
23
+ LIZARD_CMD=""
24
+ if command -v lizard > /dev/null 2>&1; then
25
+ LIZARD_CMD=lizard
26
+ elif [ -f ~/.local/bin/lizard ]; then
27
+ LIZARD_CMD=~/.local/bin/lizard
28
+ fi
29
+
30
+ if [ -n "$LIZARD_CMD" ]; then
31
+ LIZARD_PATH=$(eval echo "$LIZARD_CMD")
32
+
33
+ # Get changed source files for complexity check
34
+ CC_FILES=$(echo "$CHANGED_FILES" | grep -E '\.(ts|tsx|js|jsx|py|go|java|swift|cpp|c|hpp|h|m|mm|kt)$' || true)
35
+
36
+ if [ -n "$CC_FILES" ]; then
37
+ echo "Checking complexity for source files..."
38
+
39
+ # Run lizard with CCN threshold
40
+ CC_OUTPUT=$($LIZARD_PATH -C $CCN_THRESHOLD $CC_FILES 2>&1 || true)
41
+
42
+ # Parse warning count from the summary table: "Warning cnt 8"
43
+ # Use anchored grep to avoid matching lizard table headers (e.g. "Rt" column)
44
+ CC_WARNINGS=$(echo "$CC_OUTPUT" | grep "^Warning cnt" | awk '{print $NF}' | tr -d '[:space:]' | sed 's/[^0-9]//g' || true)
45
+ CC_WARNINGS=${CC_WARNINGS:-0}
46
+
47
+ if [ "$CC_WARNINGS" -gt 0 ]; then
48
+ echo "$CC_OUTPUT"
49
+ echo ""
50
+ echo "❌ BLOCKED - $CC_WARNINGS functions with CCN > $CCN_THRESHOLD found."
51
+ echo "Refactor high-complexity functions to keep below $CCN_THRESHOLD complexity."
52
+ exit 1
53
+ else
54
+ echo "✅ PASSED - All functions within complexity threshold ($CCN_THRESHOLD)."
55
+ GATE_3_STATUS="PASS"
56
+ fi
57
+ else
58
+ echo "⏭️ SKIPPED - Complexity (no source files to check)."
59
+ GATE_3_STATUS="SKIP"
60
+ fi
61
+ else
62
+ echo "⚠️ WARN - lizard not installed, complexity check not performed"
63
+ echo " Install with: pip install --user lizard"
64
+ echo " Gate 3: Complexity check (WARN, tool not available)"
65
+ GATE_3_STATUS="WARN"
66
+ fi
67
+ fi
68
+ record_gate_audit "gate-3" "complexity" "$GATE_3_STATUS" "${CC_WARNINGS:-0}" "$GATE_3_START"
package/gate-4.sh ADDED
@@ -0,0 +1,80 @@
1
+ # ============================================================================
2
+ # GATE 4: Principles Checker (Clean Code + SOLID)
3
+ # Reuses existing principles checker logic
4
+ # ============================================================================
5
+
6
+ 2>&1 echo ""
7
+ 2>&1 echo "→ Gate 4: Principles checker (Clean Code + SOLID)..."
8
+ GATE_4_START=$(gate_start_ms)
9
+
10
+ GATE_4_STATUS=""
11
+
12
+ if [ "$PROJECT_LANG" = "documentation-only" ]; then
13
+ echo "⏭️ SKIPPED - Principles check (documentation project)."
14
+ GATE_4_STATUS="SKIP"
15
+
16
+ else
17
+ # Get source files to check against principles
18
+ PRINCIPLES_FILES=$(echo "$CHANGED_FILES" | grep -E '\.(ts|tsx|js|jsx|py|go|java|kt|dart|swift|cpp|c|hpp|h|m|mm)$' || true)
19
+
20
+ if [ -n "$PRINCIPLES_FILES" ]; then
21
+ # Check for principles checker in installed modules first, then project src/
22
+ PRINCIPLES_DIR=""
23
+ if [ -d ".xp-gate/modules/principles" ]; then
24
+ PRINCIPLES_DIR=".xp-gate/modules/principles"
25
+ elif [ -f "src/principles/index.ts" ]; then
26
+ PRINCIPLES_DIR="src/principles"
27
+ elif [ -d "$HOME/.config/xp-gate/modules/principles" ]; then
28
+ PRINCIPLES_DIR="$HOME/.config/xp-gate/modules/principles"
29
+ fi
30
+
31
+ if [ -n "$PRINCIPLES_DIR" ]; then
32
+ echo "Checking Clean Code + SOLID principles..."
33
+
34
+ if command -v npx > /dev/null 2>&1; then
35
+ # Run principles checker and store results
36
+ if npx tsx $PRINCIPLES_DIR/index.ts --files $PRINCIPLES_FILES --format json > /tmp/principles-output.json 2>/dev/null; then
37
+ # Check severity levels
38
+ ERROR_COUNT=$(grep -c '"severity":"error"' /tmp/principles-output.json 2>/dev/null || true)
39
+ ERROR_COUNT=${ERROR_COUNT:-0}
40
+ WARNING_COUNT=$(grep -c '"severity":"warning"' /tmp/principles-output.json 2>/dev/null || true)
41
+ WARNING_COUNT=${WARNING_COUNT:-0}
42
+
43
+ if [ "$ERROR_COUNT" -gt 0 ]; then
44
+ echo ""
45
+ echo "❌ BLOCKED - $ERROR_COUNT principle ERROR(S) found"
46
+ echo "Critical violations must be fixed before commit:"
47
+ echo " - error-handling violations"
48
+ echo " - SOLID principle violations"
49
+ echo " - architectural violations"
50
+ npx tsx $PRINCIPLES_DIR/index.ts --files $PRINCIPLES_FILES --format console
51
+ GATE_4_STATUS="FAIL"
52
+ exit 1
53
+ fi
54
+
55
+ echo "✅ PASSED - Principles checker (no errors found)."
56
+ GATE_4_STATUS="PASS"
57
+ if [ "$WARNING_COUNT" -gt 0 ]; then
58
+ echo "ℹ️ $WARNING_COUNT warnings found (will be handled by Boy Scout Rule)."
59
+ fi
60
+ else
61
+ echo "⚠️ Warning: Principles checker execution failed"
62
+ echo "⏭️ SKIPPED - Principles check (execution issue)"
63
+ GATE_4_STATUS="SKIP"
64
+ fi
65
+ else
66
+ echo "ℹ️ npx not available - skipping principles check"
67
+ echo "⏭️ SKIPPED - Principles check (no Node.js/npx)"
68
+ GATE_4_STATUS="SKIP"
69
+ fi
70
+ else
71
+ echo "ℹ️ Principles checker not found in project - skipping"
72
+ echo "⏭️ SKIPPED - Principles check (checker not in project)"
73
+ GATE_4_STATUS="SKIP"
74
+ fi
75
+ else
76
+ echo "⏭️ SKIPPED - Principles check (no matching source files changed)"
77
+ GATE_4_STATUS="SKIP"
78
+ fi
79
+ fi
80
+ record_gate_audit "gate-4" "principles" "$GATE_4_STATUS" "${WARNING_COUNT:-0}" "$GATE_4_START"
package/gate-7.sh ADDED
@@ -0,0 +1,45 @@
1
+ # ============================================================================
2
+ # GATE 7: IaC Security Scanning (Terraform, Kubernetes, Docker)
3
+ # Detects security issues in Infrastructure as Code files
4
+ # Tools: checkov (recommended), hadolint, kube-score, tflint
5
+ # ============================================================================
6
+
7
+ 2>&1 echo ""
8
+ 2>&1 echo "→ Gate 7: IaC Security Scanning (Terraform, Kubernetes, Docker)..."
9
+ GATE_7_START=$(gate_start_ms)
10
+
11
+ # Check if any IaC files are changed
12
+ IAC_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -E "\.(tf|yaml|yml)$|Dockerfile" || true)
13
+ if [ -z "$IAC_FILES" ]; then
14
+ echo "✅ PASSED - No IaC files detected in changes."
15
+ GATE_7_STATUS="PASS"
16
+ else
17
+ # Run IaC adapter
18
+ if [ -f "githooks/adapters/iac.sh" ]; then
19
+ # shellcheck source=githooks/adapters/iac.sh
20
+ source "githooks/adapters/iac.sh"
21
+
22
+ # Run static analysis for IaC files
23
+ IAC_OUTPUT=$(run_static_analysis "$IAC_FILES" 2>&1)
24
+ IAC_EXIT=$?
25
+
26
+ echo "$IAC_OUTPUT"
27
+
28
+ if [ $IAC_EXIT -eq 0 ]; then
29
+ echo "✅ PASSED - IaC security scan."
30
+ GATE_7_STATUS="PASS"
31
+ else
32
+ echo ""
33
+ echo "❌ BLOCKED - IaC security issues detected"
34
+ echo "Fix the security issues above before committing."
35
+ echo "Tip: Install checkov for comprehensive IaC scanning: pip install checkov"
36
+ GATE_7_STATUS="FAIL"
37
+ exit 1
38
+ fi
39
+ else
40
+ echo "ℹ️ SKIP - IaC adapter not found"
41
+ echo "⏭️ SKIPPED - IaC security (no IaC adapter found)"
42
+ GATE_7_STATUS="SKIP"
43
+ fi
44
+ fi
45
+ record_gate_audit "gate-7" "iac-security" "$GATE_7_STATUS" "0" "$GATE_7_START"
package/gate-8.sh ADDED
@@ -0,0 +1,56 @@
1
+ # ============================================================================
2
+ # GATE 8: Secret Scanning (gitleaks)
3
+ # Detects secrets (API keys, passwords, tokens) in staged files
4
+ # Tool: gitleaks -- https://github.com/gitleaks/gitleaks
5
+ # ============================================================================
6
+
7
+ 2>&1 echo ""
8
+ 2>&1 echo "→ Gate 8: Secret scanning (gitleaks)..."
9
+ GATE_8_START=$(gate_start_ms)
10
+
11
+ # Gitleaks availability check
12
+ GITLEAKS_CMD=""
13
+ if command -v gitleaks >/dev/null 2>&1; then
14
+ GITLEAKS_CMD="gitleaks"
15
+ elif [ -f "$HOME/.local/bin/gitleaks" ]; then
16
+ GIBLEAKS_CMD="$HOME/.local/bin/gitleaks"
17
+ fi
18
+
19
+ if [ -n "$GITLEAKS_CMD" ]; then
20
+ GITLEAKS_CONFIG=""
21
+ if [ -f ".gitleaks.toml" ]; then
22
+ GITLEAKS_CONFIG="--config=.gitleaks.toml"
23
+ fi
24
+
25
+ # Run gitleaks on staged changes only (pre-commit mode for speed)
26
+ GITLEAKS_OUTPUT=$($GITLEAKS_CMD git --pre-commit --redact --no-banner $GITLEAKS_CONFIG --report-format=json --report-path=/tmp/gitleaks-report.json 2>&1)
27
+ GITLEAKS_EXIT=$?
28
+
29
+ if [ "$GITLEAKS_EXIT" -eq 0 ]; then
30
+ echo " ✅ PASSED - No secrets detected."
31
+ GATE_8_STATUS="PASS"
32
+ elif [ "$GITLEAKS_EXIT" -eq 1 ]; then
33
+ # Secrets found — output details
34
+ echo "$GITLEAKS_OUTPUT"
35
+ echo ""
36
+ echo "❌ BLOCKED - Secrets detected in staged files."
37
+ echo ""
38
+ echo "Remediation options:"
39
+ echo " 1. Remove the secret and use environment variables instead"
40
+ echo " 2. Add a false positive to .gitleaks.toml allowlist"
41
+ echo " 3. Use git secret or vault for sensitive data"
42
+ echo ""
43
+ echo "See: https://github.com/gitleaks/gitleaks"
44
+ exit 1
45
+ else
46
+ echo " ⚠️ gitleaks exited with code $GITLEAKS_EXIT - skipping gate"
47
+ echo " ✅ Secret Scanning (SKIP, gitleaks error)"
48
+ GATE_8_STATUS="SKIP"
49
+ fi
50
+ else
51
+ echo " ℹ️ gitleaks not installed — secret scanning unavailable"
52
+ echo " Install: brew install gitleaks (macOS) | winget install gitleaks (Windows) | scripts/install-gitleaks.sh (Linux)"
53
+ echo " ⏭️ SKIPPED - Secret scanning (gitleaks not installed)"
54
+ GATE_8_STATUS="SKIP"
55
+ fi
56
+ record_gate_audit "gate-8" "secret-scanning" "$GATE_8_STATUS" "0" "$GATE_8_START"
package/gate-9.sh ADDED
@@ -0,0 +1,130 @@
1
+ # ============================================================================
2
+ # GATE 9: Semgrep SAST Security Scan
3
+ # Detects security vulnerabilities (SQL injection, XSS, etc.) in staged files
4
+ # Tool: semgrep -- https://semgrep.dev
5
+ # ============================================================================
6
+
7
+ 2>&1 echo ""
8
+ 2>&1 echo "→ Gate 9: Semgrep SAST Security Scan..."
9
+ GATE_9_START=$(gate_start_ms)
10
+
11
+ GATE_9_STATUS=""
12
+
13
+ # Semgrep availability check
14
+ SEMGREP_CMD=""
15
+ if command -v semgrep >/dev/null 2>&1; then
16
+ SEMGREP_CMD="semgrep"
17
+ elif [ -f "$HOME/.local/bin/semgrep" ]; then
18
+ SEMGREP_CMD="$HOME/.local/bin/semgrep"
19
+ fi
20
+
21
+ if [ -z "$SEMGREP_CMD" ]; then
22
+ echo " ⚠️ WARN - semgrep not installed — SAST scanning unavailable"
23
+ echo " Install: brew install semgrep (macOS) | pip install semgrep (Linux) | pip install semgrep (Windows)"
24
+ echo " Pre-cache rules: semgrep --config=p/security-audit"
25
+ echo " Gate 9: SAST Security (WARN, semgrep not installed)"
26
+ GATE_9_STATUS="WARN"
27
+ else
28
+ # Get staged files filtered to Semgrep-supported languages
29
+ SEMGREP_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -E '\.(ts|tsx|js|jsx|py|go|java|c|cpp|cs|rb|php|scala|swift)$' || true)
30
+
31
+ if [ -z "$SEMGREP_FILES" ]; then
32
+ echo " ⏭️ SKIPPED - SAST (no supported language files changed)"
33
+ GATE_9_STATUS="SKIP"
34
+ else
35
+ # Run semgrep with JSON output
36
+ # --config=p/security-audit: explicit security ruleset
37
+ # --json: machine-readable output
38
+ # --disable-version-check: skip network call
39
+ SEMGREP_OUTPUT=$($SEMGREP_CMD scan --config=p/security-audit --json --disable-version-check $SEMGREP_FILES 2>&1)
40
+ SEMGREP_EXIT=$?
41
+
42
+ if [ "$SEMGREP_EXIT" -eq 0 ]; then
43
+ echo " ✅ PASSED - No security vulnerabilities found."
44
+ GATE_9_STATUS="PASS"
45
+ elif [ "$SEMGREP_EXIT" -eq 1 ]; then
46
+ # Findings detected - parse JSON to categorize
47
+ CRITICAL_HIGH=$(echo "$SEMGREP_OUTPUT" | python3 -c "
48
+ import sys, json
49
+ try:
50
+ data = json.load(sys.stdin)
51
+ results = data.get('results', [])
52
+ count = 0
53
+ for r in results:
54
+ extra = r.get('extra', {})
55
+ severity = extra.get('severity', '').upper()
56
+ if severity in ('CRITICAL', 'HIGH'):
57
+ count += 1
58
+ print(count)
59
+ except:
60
+ print('0')
61
+ " 2>/dev/null || echo "0")
62
+
63
+ MEDIUM_LOW=$(echo "$SEMGREP_OUTPUT" | python3 -c "
64
+ import sys, json
65
+ try:
66
+ data = json.load(sys.stdin)
67
+ results = data.get('results', [])
68
+ count = 0
69
+ for r in results:
70
+ extra = r.get('extra', {})
71
+ severity = extra.get('severity', '').upper()
72
+ if severity in ('MEDIUM', 'LOW'):
73
+ count += 1
74
+ print(count)
75
+ except:
76
+ print('0')
77
+ " 2>/dev/null || echo "0")
78
+
79
+ # Extract top finding details
80
+ FINDING_DETAILS=$(echo "$SEMGREP_OUTPUT" | python3 -c "
81
+ import sys, json
82
+ try:
83
+ data = json.load(sys.stdin)
84
+ results = data.get('results', [])
85
+ for r in results[:5]: # Show top 5
86
+ extra = r.get('extra', {})
87
+ severity = extra.get('severity', 'UNKNOWN').upper()
88
+ rule_id = r.get('check_id', 'unknown')
89
+ path = r.get('path', 'unknown')
90
+ start_line = r.get('start', {}).get('line', '?')
91
+ message = extra.get('message', '')[:80]
92
+ print(f' [{severity}] {rule_id}')
93
+ print(f' {path}:{start_line} → {message}')
94
+ print()
95
+ except:
96
+ print(' (Failed to parse semgrep output)')
97
+ " 2>/dev/null || echo " (Failed to parse semgrep output)")
98
+
99
+ if [ "$CRITICAL_HIGH" -gt 0 ]; then
100
+ echo ""
101
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
102
+ echo " GATE 9: Semgrep Security Gate"
103
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
104
+ echo " CRITICAL/HIGH: ${CRITICAL_HIGH} ❌ BLOCKED"
105
+ echo " MEDIUM/LOW: ${MEDIUM_LOW} ⚠️ warning"
106
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
107
+ echo " ❌ BLOCKED — Critical/High vulnerability found"
108
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
109
+ echo "$FINDING_DETAILS"
110
+ echo " Run 'semgrep scan --config=p/security-audit' to review all findings."
111
+ GATE_9_STATUS="FAIL"
112
+ exit 1
113
+ else
114
+ echo ""
115
+ echo " ✅ PASSED - No critical/high vulnerabilities"
116
+ if [ "$MEDIUM_LOW" -gt 0 ]; then
117
+ echo " ⚠️ ${MEDIUM_LOW} medium/low findings (warnings only)"
118
+ echo "$FINDING_DETAILS"
119
+ fi
120
+ GATE_9_STATUS="PASS"
121
+ fi
122
+ else
123
+ # semgrep runtime error (timeout, config error, etc.)
124
+ echo " ⚠️ semgrep exited with code ${SEMGREP_EXIT} — skipping gate"
125
+ echo " ⏭️ SKIPPED - SAST (semgrep runtime error)"
126
+ GATE_9_STATUS="SKIP"
127
+ fi
128
+ fi
129
+ fi
130
+ record_gate_audit "gate-9" "sast-security" "$GATE_9_STATUS" "0" "$GATE_9_START"