@boyingliu01/xp-gate 0.18.2 → 0.18.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.
- package/adapter-common.sh +0 -0
- package/adapters/cpp.sh +0 -0
- package/adapters/dart.sh +0 -0
- package/adapters/flutter.sh +0 -0
- package/adapters/gate-9.sh +1 -0
- package/adapters/go.sh +0 -0
- package/adapters/iac.sh +0 -0
- package/adapters/java.sh +0 -0
- package/adapters/kotlin.sh +0 -0
- package/adapters/objectivec.sh +0 -0
- package/adapters/plugins/book299-20132-python/scripts/install-gradle.sh +0 -0
- package/adapters/plugins/book299-20132-python/scripts/install-maven.sh +0 -0
- package/adapters/plugins/book299-4081-c/scripts/install-gradle.sh +0 -0
- package/adapters/plugins/book299-4081-c/scripts/install-maven.sh +0 -0
- package/adapters/plugins/book299-4083-javascriptes5/scripts/install-gradle.sh +0 -0
- package/adapters/plugins/book299-4083-javascriptes5/scripts/install-maven.sh +0 -0
- package/adapters/powershell.sh +0 -0
- package/adapters/python.sh +0 -0
- package/adapters/shell.sh +0 -0
- package/adapters/swift.sh +0 -0
- package/adapters/typescript.sh +0 -0
- package/bin/xp-gate.js +45 -0
- package/gate-3.sh +0 -0
- package/gate-4.sh +0 -0
- package/gate-7.sh +0 -0
- package/gate-8.sh +0 -0
- package/gate-9.sh +0 -0
- package/hooks/adapter-common.sh +0 -0
- package/hooks/gate-3.sh +0 -0
- package/hooks/gate-4.sh +0 -0
- package/hooks/gate-7.sh +0 -0
- package/hooks/gate-8.sh +0 -0
- package/hooks/gate-9.sh +0 -0
- package/hooks/pre-commit +108 -9
- package/hooks/pre-push +63 -232
- package/hooks/sprint-gate.sh +0 -0
- package/lib/__tests__/install-skill.test.js +3 -3
- package/lib/__tests__/phase-transition.test.js +512 -512
- package/lib/__tests__/sprint-audit.test.js +207 -207
- package/lib/__tests__/test-alignment.test.ts +761 -0
- package/lib/install-skill.js +11 -3
- package/lib/language-tools.js +833 -833
- package/lib/mattpocock-license-verdict.json +1 -1
- package/lib/phase-transition.js +604 -499
- package/lib/sprint-audit.js +235 -235
- package/lib/sprint-init.js +248 -207
- package/lib/test-alignment.ts +651 -0
- package/mock-policy/AGENTS.md +3 -3
- package/mutation/AGENTS.md +3 -3
- package/mutation/gate-m.ts +18 -4
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/bin/delphi-review-guard.sh +0 -0
- package/plugins/claude-code/bin/xp-gate-check +0 -0
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/claude-code/skills/grilling/SKILL.md +12 -12
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/opencode/skills/grilling/SKILL.md +12 -12
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/qoder/agents/delphi-architecture.md +48 -48
- package/plugins/qoder/agents/delphi-feasibility.md +48 -48
- package/plugins/qoder/agents/delphi-technical.md +48 -48
- package/plugins/qoder/bin/sprint-flow-guard.sh +0 -0
- package/plugins/qoder/bin/xp-gate-check +0 -0
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
- package/principles/AGENTS.md +3 -3
- package/scripts/delphi-external-review.cjs +432 -432
- package/skills/delphi-review/AGENTS.md +3 -3
- package/skills/grilling/SKILL.md +12 -12
- package/skills/sprint-flow/AGENTS.md +3 -3
- package/skills/test-specification-alignment/AGENTS.md +3 -3
package/adapter-common.sh
CHANGED
|
File without changes
|
package/adapters/cpp.sh
CHANGED
|
File without changes
|
package/adapters/dart.sh
CHANGED
|
File without changes
|
package/adapters/flutter.sh
CHANGED
|
File without changes
|
package/adapters/gate-9.sh
CHANGED
package/adapters/go.sh
CHANGED
|
File without changes
|
package/adapters/iac.sh
CHANGED
|
File without changes
|
package/adapters/java.sh
CHANGED
|
File without changes
|
package/adapters/kotlin.sh
CHANGED
|
File without changes
|
package/adapters/objectivec.sh
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/adapters/powershell.sh
CHANGED
|
File without changes
|
package/adapters/python.sh
CHANGED
|
File without changes
|
package/adapters/shell.sh
CHANGED
|
File without changes
|
package/adapters/swift.sh
CHANGED
|
File without changes
|
package/adapters/typescript.sh
CHANGED
|
File without changes
|
package/bin/xp-gate.js
CHANGED
|
@@ -28,6 +28,46 @@ function handleUIReview() {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
async function runAlignmentCheck(subargs) {
|
|
32
|
+
const specIdx = subargs.indexOf('--spec');
|
|
33
|
+
const specPath = specIdx >= 0 ? subargs[specIdx + 1] : path.join(process.cwd(), 'specification.yaml');
|
|
34
|
+
|
|
35
|
+
const testsIdx = subargs.indexOf('--tests');
|
|
36
|
+
const testDirs = testsIdx >= 0 ? [subargs[testsIdx + 1]] : undefined;
|
|
37
|
+
|
|
38
|
+
const outputIdx = subargs.indexOf('--output');
|
|
39
|
+
const outputPath = outputIdx >= 0 ? subargs[outputIdx + 1] : undefined;
|
|
40
|
+
|
|
41
|
+
const jsonMode = subargs.includes('--json');
|
|
42
|
+
|
|
43
|
+
// Load TS module via tsx
|
|
44
|
+
const { execSync } = require('child_process');
|
|
45
|
+
const alignmentPath = path.join(__dirname, '..', 'lib', 'test-alignment.ts');
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
execSync(`npx tsx -e "
|
|
49
|
+
import { runFullAlignment } from '${alignmentPath}';
|
|
50
|
+
const report = runFullAlignment({
|
|
51
|
+
specPath: '${specPath}',
|
|
52
|
+
testDirs: ${JSON.stringify(testDirs || null)},
|
|
53
|
+
headCommit: require('child_process').execSync('git rev-parse HEAD 2>/dev/null || echo unknown').toString().trim(),
|
|
54
|
+
outputPath: ${outputPath ? `'${outputPath}'` : 'undefined'},
|
|
55
|
+
});
|
|
56
|
+
if (${jsonMode}) {
|
|
57
|
+
console.log(JSON.stringify(report, null, 2));
|
|
58
|
+
} else {
|
|
59
|
+
console.log('Status:', report.alignment_status);
|
|
60
|
+
console.log('Score:', report.score);
|
|
61
|
+
console.log('Misaligned:', report.misaligned_tests.length);
|
|
62
|
+
}
|
|
63
|
+
process.exit(report.alignment_status === 'PASS' ? 0 : 1);
|
|
64
|
+
"`, { stdio: 'inherit' });
|
|
65
|
+
} catch (err) {
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
31
71
|
const COMMANDS = {
|
|
32
72
|
'init': {
|
|
33
73
|
description: 'Initialize xp-gate (use --global for all projects)',
|
|
@@ -131,6 +171,11 @@ const COMMANDS = {
|
|
|
131
171
|
run: subargs => arch(subargs).then(code => process.exit(code)),
|
|
132
172
|
usage: 'xp-gate arch [--config <path>]'
|
|
133
173
|
},
|
|
174
|
+
'check-alignment': {
|
|
175
|
+
description: 'Run test-specification alignment check (deterministic, no LLM)',
|
|
176
|
+
run: subargs => runAlignmentCheck(subargs).then(code => process.exit(code)),
|
|
177
|
+
usage: 'xp-gate check-alignment [--spec <path>] [--tests <dir>] [--json] [--output <path>]'
|
|
178
|
+
},
|
|
134
179
|
'upgrade': {
|
|
135
180
|
description: 'Check for xp-gate updates (--preview for JSON, --apply to upgrade)',
|
|
136
181
|
run: subargs => upgrade(subargs).then(code => process.exit(code)),
|
package/gate-3.sh
CHANGED
|
File without changes
|
package/gate-4.sh
CHANGED
|
File without changes
|
package/gate-7.sh
CHANGED
|
File without changes
|
package/gate-8.sh
CHANGED
|
File without changes
|
package/gate-9.sh
CHANGED
|
File without changes
|
package/hooks/adapter-common.sh
CHANGED
|
File without changes
|
package/hooks/gate-3.sh
CHANGED
|
File without changes
|
package/hooks/gate-4.sh
CHANGED
|
File without changes
|
package/hooks/gate-7.sh
CHANGED
|
File without changes
|
package/hooks/gate-8.sh
CHANGED
|
File without changes
|
package/hooks/gate-9.sh
CHANGED
|
File without changes
|
package/hooks/pre-commit
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# OpenCode Quality Gates - Pre-Commit Hook -
|
|
2
|
+
# OpenCode Quality Gates - Pre-Commit Hook - 12 numbered gates (Gate 0–11)
|
|
3
3
|
#
|
|
4
|
-
# DESIGN PRINCIPLE:
|
|
5
|
-
#
|
|
4
|
+
# DESIGN PRINCIPLE: Tool unavailable = SKIP (graceful degradation), tool available + check fails = BLOCK
|
|
5
|
+
# Missing tools do NOT block the commit — the gate degrades to SKIP. Block fires only when
|
|
6
|
+
# the tool exists AND the check fails. This prevents broken toolchains from blocking work.
|
|
6
7
|
#
|
|
7
|
-
# Converts 9 sequential gates into 6 type-based comprehensive gates
|
|
8
8
|
# Sourced from adapter-common.sh and language-specific adapters
|
|
9
9
|
|
|
10
10
|
# Source the common adapter functions — 3-tier resolution:
|
|
@@ -1328,7 +1328,9 @@ source "$GATE_DIR/gate-4.sh"
|
|
|
1328
1328
|
# v0.14.3+ (Issue #312): Skip test run when no code files changed.
|
|
1329
1329
|
# Code files = src/**/*.ts, plugins/**/*.ts, *.ts, *.tsx, etc. (language-aware).
|
|
1330
1330
|
# VERSION, CHANGELOG, docs, config-only changes → SKIP test run entirely.
|
|
1331
|
-
# Gate 5a (new file pairing)
|
|
1331
|
+
# Gate 5a (new file pairing), 5b (mock density), and 5c (semantic annotation)
|
|
1332
|
+
# are lightweight and still run even when no code files changed.
|
|
1333
|
+
# Gate 5a (new file pairing) and Gate 5b (mock density) still run — they're lightweight.
|
|
1332
1334
|
# ============================================================================
|
|
1333
1335
|
2>&1 echo ""
|
|
1334
1336
|
2>&1 echo "→ Gate 5: Tests & coverage..."
|
|
@@ -1640,6 +1642,82 @@ else
|
|
|
1640
1642
|
done
|
|
1641
1643
|
fi
|
|
1642
1644
|
|
|
1645
|
+
# ============================================================================
|
|
1646
|
+
# Gate 5c: Semantic Annotation Check (v0.19.0+)
|
|
1647
|
+
# Validates @test REQ-XXX annotations against specification.yaml.
|
|
1648
|
+
#
|
|
1649
|
+
# Strategy: Reads pre-compiled req-ids.json (produced by xp-gate check-alignment).
|
|
1650
|
+
# If req-ids.json is absent or stale, degrades to SKIP.
|
|
1651
|
+
# If present: greps staged tests for @test REQ-XXX, cross-references against
|
|
1652
|
+
# the pre-compiled REQ ID list. BLOCKs if any REQ ID doesn't exist in spec.
|
|
1653
|
+
# If any REQ in spec has no annotated test, emits visible [FAIL] message
|
|
1654
|
+
# (exit 0, appears in hook summary) — full alignment check runs at CLI time.
|
|
1655
|
+
# ============================================================================
|
|
1656
|
+
REQ_IDS_FILE=".sprint-state/phase-outputs/req-ids.json"
|
|
1657
|
+
if [ -f "$REQ_IDS_FILE" ] && command -v jq >/dev/null 2>&1; then
|
|
1658
|
+
# Check staleness: req-ids.json must be newer than specification.yaml
|
|
1659
|
+
SPEC_FILE="specification.yaml"
|
|
1660
|
+
REQ_IDS_STALE=false
|
|
1661
|
+
if [ -f "$SPEC_FILE" ]; then
|
|
1662
|
+
if [ "$REQ_IDS_FILE" -ot "$SPEC_FILE" ]; then
|
|
1663
|
+
REQ_IDS_STALE=true
|
|
1664
|
+
fi
|
|
1665
|
+
fi
|
|
1666
|
+
|
|
1667
|
+
if [ "$REQ_IDS_STALE" = true ]; then
|
|
1668
|
+
echo "⚠️ Gate 5c: req-ids.json is stale (specification.yaml updated since last check-alignment)"
|
|
1669
|
+
echo " Run 'xp-gate check-alignment' to regenerate before next commit."
|
|
1670
|
+
else
|
|
1671
|
+
CHANGED_TEST_FILES_ANNOTATED=$(echo "$CHANGED_FILES" | grep -E '\.(test|spec)\.(ts|tsx|js|jsx)$' || true)
|
|
1672
|
+
if [ -n "$CHANGED_TEST_FILES_ANNOTATED" ]; then
|
|
1673
|
+
echo " → Checking @test REQ-XXX annotations..."
|
|
1674
|
+
ANNOTATION_ERRORS=0
|
|
1675
|
+
for tf in $CHANGED_TEST_FILES_ANNOTATED; do
|
|
1676
|
+
if [ -f "$tf" ]; then
|
|
1677
|
+
# Extract @test REQ-XXX annotations from staged test file (word-bounded)
|
|
1678
|
+
ANNOTATED_REQS=$(grep -oE '@test\s+REQ-[A-Z0-9-]+' "$tf" 2>/dev/null | sed 's/@test\s*//' | sort -u || true)
|
|
1679
|
+
for req_id in $ANNOTATED_REQS; do
|
|
1680
|
+
# Cross-reference against pre-compiled REQ ID list
|
|
1681
|
+
FOUND=$(jq -r --arg rid "$req_id" '.[] | select(. == $rid)' "$REQ_IDS_FILE" 2>/dev/null || true)
|
|
1682
|
+
if [ -z "$FOUND" ]; then
|
|
1683
|
+
echo "❌ Gate 5c: $tf — @test $req_id: REQ ID not found in specification.yaml"
|
|
1684
|
+
ANNOTATION_ERRORS=$((ANNOTATION_ERRORS + 1))
|
|
1685
|
+
fi
|
|
1686
|
+
done
|
|
1687
|
+
fi
|
|
1688
|
+
done
|
|
1689
|
+
|
|
1690
|
+
if [ "$ANNOTATION_ERRORS" -gt 0 ]; then
|
|
1691
|
+
echo ""
|
|
1692
|
+
echo "❌ $ANNOTATION_ERRORS test annotation(s) reference non-existent REQ IDs — commit BLOCKED"
|
|
1693
|
+
echo " Fix: Verify REQ IDs against specification.yaml, or run 'xp-gate check-alignment'"
|
|
1694
|
+
exit 1
|
|
1695
|
+
fi
|
|
1696
|
+
|
|
1697
|
+
# Check reverse: any REQ in spec with no annotated test → visible FAIL (non-blocking)
|
|
1698
|
+
ALL_SPEC_REQS=$(jq -r '.[]' "$REQ_IDS_FILE" 2>/dev/null)
|
|
1699
|
+
ANNOTATED_ALL=""
|
|
1700
|
+
for tf in $(echo "$CHANGED_FILES" | grep -E '\.(test|spec)\.(ts|tsx|js|jsx)$' || true); do
|
|
1701
|
+
if [ -f "$tf" ]; then
|
|
1702
|
+
ANNOTATED_ALL="$ANNOTATED_ALL $(grep -oE '@test\s+REQ-[A-Z0-9-]+' "$tf" 2>/dev/null | sed 's/@test\s*//' || true)"
|
|
1703
|
+
fi
|
|
1704
|
+
done
|
|
1705
|
+
UNTESTED_COUNT=0
|
|
1706
|
+
for spec_req in $ALL_SPEC_REQS; do
|
|
1707
|
+
if ! echo "$ANNOTATED_ALL" | grep -qF "$spec_req"; then
|
|
1708
|
+
UNTESTED_COUNT=$((UNTESTED_COUNT + 1))
|
|
1709
|
+
fi
|
|
1710
|
+
done
|
|
1711
|
+
if [ "$UNTESTED_COUNT" -gt 0 ]; then
|
|
1712
|
+
echo "⚠️ [FAIL] Gate 5c: $UNTESTED_COUNT REQ(s) in specification.yaml have no annotated tests"
|
|
1713
|
+
echo " This is non-blocking. Run 'xp-gate check-alignment' for full alignment report."
|
|
1714
|
+
fi
|
|
1715
|
+
|
|
1716
|
+
echo " ✅ @test annotation check complete."
|
|
1717
|
+
fi
|
|
1718
|
+
fi
|
|
1719
|
+
fi
|
|
1720
|
+
|
|
1643
1721
|
# ============================================================================
|
|
1644
1722
|
# v0.14.3+ (Issue #312): Early skip when no code files changed.
|
|
1645
1723
|
# If the commit only touches VERSION, CHANGELOG, docs, config, .gitignore,
|
|
@@ -2439,13 +2517,13 @@ generate_quality_report() {
|
|
|
2439
2517
|
local TIMESTAMP
|
|
2440
2518
|
local BRANCH
|
|
2441
2519
|
local PASSED_COUNT=0
|
|
2442
|
-
local TOTAL_GATES=
|
|
2520
|
+
local TOTAL_GATES=12
|
|
2443
2521
|
|
|
2444
2522
|
COMMIT_HASH=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
2445
2523
|
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
|
|
2446
2524
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
2447
2525
|
|
|
2448
|
-
for gate in 1 2 3 4 5 6 7 8 9 10 11; do
|
|
2526
|
+
for gate in 1 2 3 4 5 6 7 8 9 10 11 12; do
|
|
2449
2527
|
local status_var="GATE_${gate}_STATUS"
|
|
2450
2528
|
if [ "${!status_var}" = "PASS" ]; then
|
|
2451
2529
|
PASSED_COUNT=$((PASSED_COUNT + 1))
|
|
@@ -2558,6 +2636,11 @@ generate_quality_report() {
|
|
|
2558
2636
|
"name": "Sprint Flow Enforcement",
|
|
2559
2637
|
"status": "${GATE_11_STATUS:-PASS}",
|
|
2560
2638
|
"tool": "sprint-gate.sh"
|
|
2639
|
+
},
|
|
2640
|
+
"gate12_file_hygiene": {
|
|
2641
|
+
"name": "File Hygiene Check",
|
|
2642
|
+
"status": "${GATE_12_STATUS:-WARN}",
|
|
2643
|
+
"tool": "gate-12-file-hygiene.sh"
|
|
2561
2644
|
}
|
|
2562
2645
|
}
|
|
2563
2646
|
}
|
|
@@ -2583,8 +2666,8 @@ ENDJSON
|
|
|
2583
2666
|
GATES_JSON="${GATES_JSON}\"gate8\":{\"status\":\"${GATE_8_STATUS:-PASS}\",\"name\":\"Secret Scanning\"},"
|
|
2584
2667
|
GATES_JSON="${GATES_JSON}\"gate9\":{\"status\":\"${GATE_9_STATUS:-PASS}\",\"name\":\"Build Integrity\"},"
|
|
2585
2668
|
GATES_JSON="${GATES_JSON}\"gate10\":{\"status\":\"${GATE_10_STATUS:-PASS}\",\"name\":\"SAST Security\"},"
|
|
2586
|
-
GATES_JSON="${GATES_JSON}\"gate11\":{\"status\":\"${GATE_11_STATUS:-PASS}\",\"name\":\"Sprint Flow\"}
|
|
2587
|
-
GATES_JSON="${GATES_JSON}}"
|
|
2669
|
+
GATES_JSON="${GATES_JSON}\"gate11\":{\"status\":\"${GATE_11_STATUS:-PASS}\",\"name\":\"Sprint Flow\"},"
|
|
2670
|
+
GATES_JSON="${GATES_JSON}\"gate12\":{\"status\":\"${GATE_12_STATUS:-WARN}\",\"name\":\"File Hygiene\"}}"
|
|
2588
2671
|
|
|
2589
2672
|
echo "{\"timestamp\":\"$TIMESTAMP\",\"commit\":\"$COMMIT_HASH\",\"branch\":\"$BRANCH\",\"score\":$SCORE,\"passed\":$PASSED_COUNT,\"total\":$TOTAL_GATES,\"gates\":$GATES_JSON,\"coverage\":\"$COV_PCT\",\"complexityWarnings\":${CC_WARNINGS:-0},\"principleWarnings\":${WARNING_COUNT:-0},\"boyScoutBlocked\":${BS_BLOCKED}}" >> "$HISTORY_FILE"
|
|
2590
2673
|
|
|
@@ -2605,6 +2688,7 @@ ENDJSON
|
|
|
2605
2688
|
printf " %-45s %s\n" "Gate 9: Build Integrity" "${GATE_9_STATUS:-PASS}"
|
|
2606
2689
|
printf " %-45s %s\n" "Gate 10: SAST Security" "${GATE_10_STATUS:-PASS}"
|
|
2607
2690
|
printf " %-45s %s\n" "Gate 11: Sprint Flow" "${GATE_11_STATUS:-PASS}"
|
|
2691
|
+
printf " %-45s %s\n" "Gate 12: File Hygiene" "${GATE_12_STATUS:-WARN}"
|
|
2608
2692
|
echo ""
|
|
2609
2693
|
echo " Overall Score: $SCORE/10 | $PASSED_COUNT/$TOTAL_GATES gates passed"
|
|
2610
2694
|
echo " Branch status: $REPORT_FILE"
|
|
@@ -2612,8 +2696,23 @@ ENDJSON
|
|
|
2612
2696
|
echo " History saved: $HISTORY_FILE"
|
|
2613
2697
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
2614
2698
|
echo ""
|
|
2699
|
+
# AI-friendly common footer: tells LLM agents how to fix issues instead of bypassing
|
|
2700
|
+
echo " ── AI AGENT DIRECTIVE ──"
|
|
2701
|
+
echo " If any gate FAILED above:"
|
|
2702
|
+
echo " - Each error includes a file path and rule identifier"
|
|
2703
|
+
echo " - Fix each issue, then re-run: git commit"
|
|
2704
|
+
echo " - Do NOT use --no-verify — bypassed commits block sprint progression"
|
|
2705
|
+
echo " ─────────────────────────"
|
|
2706
|
+
echo ""
|
|
2615
2707
|
}
|
|
2616
2708
|
|
|
2709
|
+
# Post-commit bypass marker: write a sentinel file in .git/ directory
|
|
2710
|
+
# that the post-commit hook checks to detect --no-verify bypasses
|
|
2711
|
+
_wp_marker="$(git rev-parse --git-dir 2>/dev/null)/xp-gate-precommit-marker"
|
|
2712
|
+
if [ -n "$_wp_marker" ] && [ "$_wp_marker" != "/xp-gate-precommit-marker" ]; then
|
|
2713
|
+
echo "$(date +%s)" > "$_wp_marker"
|
|
2714
|
+
fi
|
|
2715
|
+
|
|
2617
2716
|
generate_quality_report
|
|
2618
2717
|
|
|
2619
2718
|
exit 0
|