@boyingliu01/xp-gate 0.13.2 → 0.14.0

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 (34) hide show
  1. package/bin/xp-gate.js +8 -0
  2. package/gate-9.sh +13 -13
  3. package/hooks/gate-9.sh +13 -13
  4. package/lib/__tests__/bootstrap.test.js +78 -0
  5. package/lib/__tests__/detect-deps.test.js +88 -0
  6. package/lib/__tests__/doctor.test.js +28 -0
  7. package/lib/__tests__/install-cmd.test.js +41 -0
  8. package/lib/__tests__/uninstall.test.js +53 -0
  9. package/lib/detect-deps.js +2 -0
  10. package/lib/doctor.js +13 -0
  11. package/lib/gate-tools.js +87 -0
  12. package/lib/init.js +1 -36
  13. package/lib/install-cmd.js +57 -0
  14. package/lib/shared-utils.js +35 -1
  15. package/lib/uninstall.js +54 -9
  16. package/mock-policy/AGENTS.md +2 -2
  17. package/mutation/AGENTS.md +2 -2
  18. package/package.json +1 -1
  19. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  20. package/plugins/claude-code/skills/delphi-review/AGENTS.md +2 -2
  21. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +2 -2
  22. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +2 -2
  23. package/plugins/opencode/package.json +1 -1
  24. package/plugins/opencode/skills/delphi-review/AGENTS.md +2 -2
  25. package/plugins/opencode/skills/sprint-flow/AGENTS.md +2 -2
  26. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +2 -2
  27. package/plugins/qoder/plugin.json +1 -1
  28. package/plugins/qoder/skills/delphi-review/AGENTS.md +2 -2
  29. package/plugins/qoder/skills/sprint-flow/AGENTS.md +2 -2
  30. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +2 -2
  31. package/principles/AGENTS.md +2 -2
  32. package/skills/delphi-review/AGENTS.md +2 -2
  33. package/skills/sprint-flow/AGENTS.md +2 -2
  34. package/skills/test-specification-alignment/AGENTS.md +2 -2
package/bin/xp-gate.js CHANGED
@@ -157,6 +157,14 @@ const COMMANDS = {
157
157
  }
158
158
  },
159
159
  usage: 'xp-gate update-hooks [--global] [--force] [--dry-run] [--no-backup] [--scope hooks|adapters|all]'
160
+ },
161
+ 'install': {
162
+ description: 'One-step install (init + bootstrap + doctor)',
163
+ run: subargs => {
164
+ const { install } = require('../lib/install-cmd');
165
+ install(subargs).then(code => process.exit(code));
166
+ },
167
+ usage: 'xp-gate install [--global]'
160
168
  }
161
169
  };
162
170
 
package/gate-9.sh CHANGED
@@ -1,14 +1,14 @@
1
1
  # ============================================================================
2
- # GATE 10: Semgrep SAST Security Scan
2
+ # GATE 9: Semgrep SAST Security Scan
3
3
  # Detects security vulnerabilities (SQL injection, XSS, etc.) in staged files
4
4
  # Tool: semgrep -- https://semgrep.dev
5
5
  # ============================================================================
6
6
 
7
7
  2>&1 echo ""
8
- 2>&1 echo "→ Gate 10: Semgrep SAST Security Scan..."
9
- GATE_10_START=$(gate_start_ms)
8
+ 2>&1 echo "→ Gate 9: Semgrep SAST Security Scan..."
9
+ GATE_9_START=$(gate_start_ms)
10
10
 
11
- GATE_10_STATUS=""
11
+ GATE_9_STATUS=""
12
12
 
13
13
  # Semgrep availability check
14
14
  SEMGREP_CMD=""
@@ -22,15 +22,15 @@ if [ -z "$SEMGREP_CMD" ]; then
22
22
  echo " ⚠️ WARN - semgrep not installed — SAST scanning unavailable"
23
23
  echo " Install: brew install semgrep (macOS) | pip install semgrep (Linux) | pip install semgrep (Windows)"
24
24
  echo " Pre-cache rules: semgrep --config=p/security-audit"
25
- echo " Gate 10: SAST Security (WARN, semgrep not installed)"
26
- GATE_10_STATUS="WARN"
25
+ echo " Gate 9: SAST Security (WARN, semgrep not installed)"
26
+ GATE_9_STATUS="WARN"
27
27
  else
28
28
  # Get staged files filtered to Semgrep-supported languages
29
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
30
 
31
31
  if [ -z "$SEMGREP_FILES" ]; then
32
32
  echo " ⏭️ SKIPPED - SAST (no supported language files changed)"
33
- GATE_10_STATUS="SKIP"
33
+ GATE_9_STATUS="SKIP"
34
34
  else
35
35
  # Run semgrep with JSON output
36
36
  # --config=p/security-audit: explicit security ruleset
@@ -41,7 +41,7 @@ else
41
41
 
42
42
  if [ "$SEMGREP_EXIT" -eq 0 ]; then
43
43
  echo " ✅ PASSED - No security vulnerabilities found."
44
- GATE_10_STATUS="PASS"
44
+ GATE_9_STATUS="PASS"
45
45
  elif [ "$SEMGREP_EXIT" -eq 1 ]; then
46
46
  # Findings detected - parse JSON to categorize
47
47
  CRITICAL_HIGH=$(echo "$SEMGREP_OUTPUT" | python3 -c "
@@ -99,7 +99,7 @@ except:
99
99
  if [ "$CRITICAL_HIGH" -gt 0 ]; then
100
100
  echo ""
101
101
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
102
- echo " GATE 10: Semgrep Security Gate"
102
+ echo " GATE 9: Semgrep Security Gate"
103
103
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
104
104
  echo " CRITICAL/HIGH: ${CRITICAL_HIGH} ❌ BLOCKED"
105
105
  echo " MEDIUM/LOW: ${MEDIUM_LOW} ⚠️ warning"
@@ -108,7 +108,7 @@ except:
108
108
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
109
109
  echo "$FINDING_DETAILS"
110
110
  echo " Run 'semgrep scan --config=p/security-audit' to review all findings."
111
- GATE_10_STATUS="FAIL"
111
+ GATE_9_STATUS="FAIL"
112
112
  exit 1
113
113
  else
114
114
  echo ""
@@ -117,14 +117,14 @@ except:
117
117
  echo " ⚠️ ${MEDIUM_LOW} medium/low findings (warnings only)"
118
118
  echo "$FINDING_DETAILS"
119
119
  fi
120
- GATE_10_STATUS="PASS"
120
+ GATE_9_STATUS="PASS"
121
121
  fi
122
122
  else
123
123
  # semgrep runtime error (timeout, config error, etc.)
124
124
  echo " ⚠️ semgrep exited with code ${SEMGREP_EXIT} — skipping gate"
125
125
  echo " ⏭️ SKIPPED - SAST (semgrep runtime error)"
126
- GATE_10_STATUS="SKIP"
126
+ GATE_9_STATUS="SKIP"
127
127
  fi
128
128
  fi
129
129
  fi
130
- record_gate_audit "gate-10" "sast-security" "$GATE_10_STATUS" "0" "$GATE_10_START"
130
+ record_gate_audit "gate-9" "sast-security" "$GATE_9_STATUS" "0" "$GATE_9_START"
package/hooks/gate-9.sh CHANGED
@@ -1,14 +1,14 @@
1
1
  # ============================================================================
2
- # GATE 10: Semgrep SAST Security Scan
2
+ # GATE 9: Semgrep SAST Security Scan
3
3
  # Detects security vulnerabilities (SQL injection, XSS, etc.) in staged files
4
4
  # Tool: semgrep -- https://semgrep.dev
5
5
  # ============================================================================
6
6
 
7
7
  2>&1 echo ""
8
- 2>&1 echo "→ Gate 10: Semgrep SAST Security Scan..."
9
- GATE_10_START=$(gate_start_ms)
8
+ 2>&1 echo "→ Gate 9: Semgrep SAST Security Scan..."
9
+ GATE_9_START=$(gate_start_ms)
10
10
 
11
- GATE_10_STATUS=""
11
+ GATE_9_STATUS=""
12
12
 
13
13
  # Semgrep availability check
14
14
  SEMGREP_CMD=""
@@ -22,15 +22,15 @@ if [ -z "$SEMGREP_CMD" ]; then
22
22
  echo " ⚠️ WARN - semgrep not installed — SAST scanning unavailable"
23
23
  echo " Install: brew install semgrep (macOS) | pip install semgrep (Linux) | pip install semgrep (Windows)"
24
24
  echo " Pre-cache rules: semgrep --config=p/security-audit"
25
- echo " Gate 10: SAST Security (WARN, semgrep not installed)"
26
- GATE_10_STATUS="WARN"
25
+ echo " Gate 9: SAST Security (WARN, semgrep not installed)"
26
+ GATE_9_STATUS="WARN"
27
27
  else
28
28
  # Get staged files filtered to Semgrep-supported languages
29
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
30
 
31
31
  if [ -z "$SEMGREP_FILES" ]; then
32
32
  echo " ⏭️ SKIPPED - SAST (no supported language files changed)"
33
- GATE_10_STATUS="SKIP"
33
+ GATE_9_STATUS="SKIP"
34
34
  else
35
35
  # Run semgrep with JSON output
36
36
  # --config=p/security-audit: explicit security ruleset
@@ -41,7 +41,7 @@ else
41
41
 
42
42
  if [ "$SEMGREP_EXIT" -eq 0 ]; then
43
43
  echo " ✅ PASSED - No security vulnerabilities found."
44
- GATE_10_STATUS="PASS"
44
+ GATE_9_STATUS="PASS"
45
45
  elif [ "$SEMGREP_EXIT" -eq 1 ]; then
46
46
  # Findings detected - parse JSON to categorize
47
47
  CRITICAL_HIGH=$(echo "$SEMGREP_OUTPUT" | python3 -c "
@@ -99,7 +99,7 @@ except:
99
99
  if [ "$CRITICAL_HIGH" -gt 0 ]; then
100
100
  echo ""
101
101
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
102
- echo " GATE 10: Semgrep Security Gate"
102
+ echo " GATE 9: Semgrep Security Gate"
103
103
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
104
104
  echo " CRITICAL/HIGH: ${CRITICAL_HIGH} ❌ BLOCKED"
105
105
  echo " MEDIUM/LOW: ${MEDIUM_LOW} ⚠️ warning"
@@ -108,7 +108,7 @@ except:
108
108
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
109
109
  echo "$FINDING_DETAILS"
110
110
  echo " Run 'semgrep scan --config=p/security-audit' to review all findings."
111
- GATE_10_STATUS="FAIL"
111
+ GATE_9_STATUS="FAIL"
112
112
  exit 1
113
113
  else
114
114
  echo ""
@@ -117,14 +117,14 @@ except:
117
117
  echo " ⚠️ ${MEDIUM_LOW} medium/low findings (warnings only)"
118
118
  echo "$FINDING_DETAILS"
119
119
  fi
120
- GATE_10_STATUS="PASS"
120
+ GATE_9_STATUS="PASS"
121
121
  fi
122
122
  else
123
123
  # semgrep runtime error (timeout, config error, etc.)
124
124
  echo " ⚠️ semgrep exited with code ${SEMGREP_EXIT} — skipping gate"
125
125
  echo " ⏭️ SKIPPED - SAST (semgrep runtime error)"
126
- GATE_10_STATUS="SKIP"
126
+ GATE_9_STATUS="SKIP"
127
127
  fi
128
128
  fi
129
129
  fi
130
- record_gate_audit "gate-10" "sast-security" "$GATE_10_STATUS" "0" "$GATE_10_START"
130
+ record_gate_audit "gate-9" "sast-security" "$GATE_9_STATUS" "0" "$GATE_9_START"
@@ -0,0 +1,78 @@
1
+ const { bootstrap } = require('../bootstrap.js');
2
+
3
+ describe('bootstrap', () => {
4
+ let consoleLogSpy;
5
+
6
+ beforeEach(() => {
7
+ consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
8
+ });
9
+
10
+ afterEach(() => {
11
+ vi.restoreAllMocks();
12
+ });
13
+
14
+ it('returns 0 when --dry-run given with no missing tools', () => {
15
+ vi.mock('../detect-deps.js', () => ({
16
+ GATE_CLI_TOOLS: [],
17
+ checkCliTool: () => ({ available: true }),
18
+ getToolInstallCmd: () => 'echo done',
19
+ }));
20
+
21
+ const { bootstrap } = require('../bootstrap.js');
22
+ const code = bootstrap(['--dry-run']);
23
+ expect(code).toBe(0);
24
+ vi.restoreAllMocks();
25
+ });
26
+
27
+ it('returns 0 when all CLI tools are available', () => {
28
+ vi.mock('../detect-deps.js', () => ({
29
+ GATE_CLI_TOOLS: [{ tool: 'testtool', gates: ['Gate 1'], install: { linux: 'echo ok' } }],
30
+ checkCliTool: () => ({ available: true, version: '1.0' }),
31
+ getToolInstallCmd: () => 'echo ok',
32
+ }));
33
+
34
+ const { bootstrap } = require('../bootstrap.js');
35
+ const code = bootstrap([]);
36
+ expect(code).toBe(0);
37
+ vi.restoreAllMocks();
38
+ });
39
+
40
+ it('accepts --lang ts parameter', () => {
41
+ vi.mock('../detect-deps.js', () => ({
42
+ GATE_CLI_TOOLS: [],
43
+ checkCliTool: () => ({ available: true }),
44
+ getToolInstallCmd: () => 'echo done',
45
+ }));
46
+
47
+ const { bootstrap } = require('../bootstrap.js');
48
+ const code = bootstrap(['--lang', 'ts']);
49
+ expect(code).toBe(0);
50
+ vi.restoreAllMocks();
51
+ });
52
+
53
+ it('accepts --lang ts,py parameter', () => {
54
+ vi.mock('../detect-deps.js', () => ({
55
+ GATE_CLI_TOOLS: [],
56
+ checkCliTool: () => ({ available: true }),
57
+ getToolInstallCmd: () => 'echo done',
58
+ }));
59
+
60
+ const { bootstrap } = require('../bootstrap.js');
61
+ const code = bootstrap(['--lang', 'ts,py']);
62
+ expect(code).toBe(0);
63
+ vi.restoreAllMocks();
64
+ });
65
+
66
+ it('recognizes --verbose flag without error', () => {
67
+ vi.mock('../detect-deps.js', () => ({
68
+ GATE_CLI_TOOLS: [],
69
+ checkCliTool: () => ({ available: true }),
70
+ getToolInstallCmd: () => 'echo done',
71
+ }));
72
+
73
+ const { bootstrap } = require('../bootstrap.js');
74
+ const code = bootstrap(['--verbose']);
75
+ expect(code).toBe(0);
76
+ vi.restoreAllMocks();
77
+ });
78
+ });
@@ -413,6 +413,94 @@ describe('detect-deps', () => {
413
413
 
414
414
  // ── checkCliTool tests (Issue #299 — Windows cross-platform) ──
415
415
 
416
+ describe('GATE_TOOLS classification', () => {
417
+ it('exports GATE_TOOLS with required categories', () => {
418
+ const { GATE_TOOLS } = require('../detect-deps');
419
+ expect(GATE_TOOLS.PLATFORM).toEqual(expect.arrayContaining(['jscpd', 'lizard', 'semgrep', 'gitleaks', 'npx']));
420
+ expect(GATE_TOOLS.IAC).toEqual(expect.arrayContaining(['checkov', 'hadolint', 'kube-score', 'tflint']));
421
+ expect(GATE_TOOLS.LANG_MAP.ts).toBe('typescript');
422
+ expect(GATE_TOOLS.LANG_MAP.py).toBe('python');
423
+ });
424
+
425
+ it('has LINT entries for all 12 supported languages', () => {
426
+ const { GATE_TOOLS } = require('../detect-deps');
427
+ expect(Object.keys(GATE_TOOLS.LINT).sort()).toEqual([
428
+ 'cpp', 'dart', 'flutter', 'go', 'java', 'kotlin',
429
+ 'objectivec', 'powershell', 'python', 'shell', 'swift', 'typescript',
430
+ ]);
431
+ });
432
+
433
+ it('has TEST entries for major languages', () => {
434
+ const { GATE_TOOLS } = require('../detect-deps');
435
+ expect(GATE_TOOLS.TEST.typescript).toContain('vitest');
436
+ expect(GATE_TOOLS.TEST.python).toContain('pytest');
437
+ expect(GATE_TOOLS.TEST.go).toContain('go');
438
+ });
439
+
440
+ it('has MUTATION entries for languages with mutation support', () => {
441
+ const { GATE_TOOLS } = require('../detect-deps');
442
+ expect(GATE_TOOLS.MUTATION.typescript).toContain('stryker');
443
+ expect(GATE_TOOLS.MUTATION.python).toContain('mutmut');
444
+ expect(GATE_TOOLS.MUTATION.go).toContain('gomutants');
445
+ expect(GATE_TOOLS.MUTATION.java).toContain('pitest');
446
+ });
447
+
448
+ it('has SPECIAL with jq, tsx, node descriptors', () => {
449
+ const { GATE_TOOLS } = require('../detect-deps');
450
+ expect(GATE_TOOLS.SPECIAL.jq.gate).toBe('MW');
451
+ expect(GATE_TOOLS.SPECIAL.tsx.gate).toContain('M');
452
+ expect(GATE_TOOLS.SPECIAL.node.gate).toContain('0');
453
+ });
454
+
455
+ it('LANG_MAP values all exist as LINT keys', () => {
456
+ const { GATE_TOOLS } = require('../detect-deps');
457
+ const lintKeys = Object.keys(GATE_TOOLS.LINT);
458
+ for (const full of Object.values(GATE_TOOLS.LANG_MAP)) {
459
+ expect(lintKeys).toContain(full);
460
+ }
461
+ });
462
+ });
463
+
464
+ describe('detectProjectLang', () => {
465
+ it('returns empty array for project with no known markers', () => {
466
+ const { detectProjectLang } = require('../detect-deps');
467
+ expect(detectProjectLang(tmpHome)).toEqual([]);
468
+ });
469
+
470
+ it('detects typescript from tsconfig.json', () => {
471
+ fs.writeFileSync(path.join(tmpHome, 'tsconfig.json'), '{}');
472
+ const { detectProjectLang } = require('../detect-deps');
473
+ expect(detectProjectLang(tmpHome)).toContain('typescript');
474
+ });
475
+
476
+ it('detects python from pyproject.toml', () => {
477
+ fs.writeFileSync(path.join(tmpHome, 'pyproject.toml'), '[project]\n');
478
+ const { detectProjectLang } = require('../detect-deps');
479
+ expect(detectProjectLang(tmpHome)).toContain('python');
480
+ });
481
+
482
+ it('detects go from go.mod', () => {
483
+ fs.writeFileSync(path.join(tmpHome, 'go.mod'), 'module example.com/m\n');
484
+ const { detectProjectLang } = require('../detect-deps');
485
+ expect(detectProjectLang(tmpHome)).toContain('go');
486
+ });
487
+
488
+ it('detects java from pom.xml', () => {
489
+ fs.writeFileSync(path.join(tmpHome, 'pom.xml'), '<project></project>');
490
+ const { detectProjectLang } = require('../detect-deps');
491
+ expect(detectProjectLang(tmpHome)).toContain('java');
492
+ });
493
+
494
+ it('detects multiple languages in monorepo', () => {
495
+ fs.writeFileSync(path.join(tmpHome, 'package.json'), JSON.stringify({ devDependencies: { typescript: '^5.0.0' } }));
496
+ fs.writeFileSync(path.join(tmpHome, 'go.mod'), 'module example.com/m\n');
497
+ const { detectProjectLang } = require('../detect-deps');
498
+ const langs = detectProjectLang(tmpHome);
499
+ expect(langs).toContain('typescript');
500
+ expect(langs).toContain('go');
501
+ });
502
+ });
503
+
416
504
  describe('checkCliTool', () => {
417
505
  const { execSync: realExecSync } = require('child_process');
418
506
 
@@ -931,4 +931,32 @@ describe('doctor', () => {
931
931
  const currentContent = fs.readFileSync(path.join(projectAdaptersDir(), 'gate-3.sh'), 'utf8');
932
932
  expect(currentContent).toBe(originalContent);
933
933
  });
934
+
935
+ it('--format json returns valid JSON with tools field', async () => {
936
+ setupLocalInstall();
937
+ seedVersionCache();
938
+ mockExecSuccess();
939
+ const { doctor } = require('../doctor');
940
+ const { formatDoctorJson } = require('../doctor');
941
+
942
+ const checks = [
943
+ { name: 'CLI tool: jscpd (Gate 2)', status: 'PASS', detail: 'v0.3.5' },
944
+ { name: 'CLI tool: lizard (Gate 3)', status: 'WARN', detail: 'Not found' },
945
+ ];
946
+ const json = formatDoctorJson(checks, 1);
947
+ expect(json.ok).toBe(false);
948
+ expect(json.issues).toBe(1);
949
+ expect(json.checks).toHaveLength(2);
950
+ expect(json.missing_tools).toBeDefined();
951
+ });
952
+
953
+ it('--format json returns ok:true when no issues', async () => {
954
+ const { formatDoctorJson } = require('../doctor');
955
+ const checks = [
956
+ { name: 'CLI tool: jscpd (Gate 2)', status: 'PASS', detail: 'v0.3.5' },
957
+ ];
958
+ const json = formatDoctorJson(checks, 0);
959
+ expect(json.ok).toBe(true);
960
+ expect(json.issues).toBe(0);
961
+ });
934
962
  });
@@ -0,0 +1,41 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ describe('install-cmd', () => {
6
+ let tmpDir;
7
+ let consoleLogSpy;
8
+
9
+ beforeEach(() => {
10
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'xpgate-install-'));
11
+ consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
12
+ vi.resetModules();
13
+ });
14
+
15
+ afterEach(() => {
16
+ fs.rmSync(tmpDir, { recursive: true, force: true });
17
+ vi.restoreAllMocks();
18
+ });
19
+
20
+ it('exports install function', () => {
21
+ const { install } = require('../install-cmd');
22
+ expect(typeof install).toBe('function');
23
+ });
24
+
25
+ it('install accepts --global flag', async () => {
26
+ const { install } = require('../install-cmd');
27
+ const code = await install(['--global'], tmpDir);
28
+ expect(typeof code).toBe('number');
29
+ });
30
+
31
+ it('install runs without --global (local mode) in git repo', async () => {
32
+ // Simulate git repo
33
+ const gitDir = path.join(tmpDir, '.git');
34
+ fs.mkdirSync(gitDir, { recursive: true });
35
+ fs.mkdirSync(path.join(gitDir, 'hooks'), { recursive: true });
36
+
37
+ const { install } = require('../install-cmd');
38
+ const code = await install([], tmpDir);
39
+ expect(typeof code).toBe('number');
40
+ });
41
+ });
@@ -623,4 +623,57 @@ describe('uninstall', () => {
623
623
  // After successful uninstall, backup should be cleaned up
624
624
  expect(fs.existsSync(backupDir())).toBe(false);
625
625
  });
626
+
627
+ it('--purge in global mode removes ~/.xp-gate/ and ~/.config/xp-gate/ config dir', async () => {
628
+ setupGlobalInstall();
629
+ const expectedHooksPath = globalHooksDir();
630
+
631
+ const xpGateDir = path.join(tmpHome, '.xp-gate');
632
+ fs.mkdirSync(path.join(xpGateDir, 'reports', 'pre-commit'), { recursive: true });
633
+ fs.writeFileSync(path.join(xpGateDir, 'reports', 'pre-commit', 'test.json'), '{}');
634
+
635
+ mockExecGlobalHooksPath(expectedHooksPath);
636
+ const { uninstall } = require('../uninstall');
637
+
638
+ const result = await uninstall(['--purge']);
639
+
640
+ expect(result).toBe(0);
641
+ expect(fs.existsSync(xpGateDir)).toBe(false);
642
+ expect(fs.existsSync(path.join(tmpHome, '.config', 'xp-gate'))).toBe(false);
643
+ });
644
+
645
+ it('--purge in local mode removes project and global .xp-gate/ dirs', async () => {
646
+ setupLocalInstall();
647
+
648
+ const projectXpGate = path.join(tmpProject, '.xp-gate');
649
+ fs.mkdirSync(path.join(projectXpGate, 'quality-status'), { recursive: true });
650
+ fs.writeFileSync(path.join(projectXpGate, 'quality-status', 'main.json'), '{}');
651
+
652
+ const globalXpGate = path.join(tmpHome, '.xp-gate');
653
+ fs.mkdirSync(path.join(globalXpGate, 'reports', 'pre-commit'), { recursive: true });
654
+ fs.writeFileSync(path.join(globalXpGate, 'reports', 'pre-commit', 'test.json'), '{}');
655
+
656
+ mockExecSuccess();
657
+ const { uninstall } = require('../uninstall');
658
+
659
+ const result = await uninstall(['--purge']);
660
+
661
+ expect(result).toBe(0);
662
+ expect(fs.existsSync(projectXpGate)).toBe(false);
663
+ expect(fs.existsSync(globalXpGate)).toBe(false);
664
+ expect(fs.existsSync(path.join(tmpHome, '.config', 'xp-gate'))).toBe(false);
665
+ });
666
+
667
+ it('--purge --dry-run prints purge plan without deleting', async () => {
668
+ setupGlobalInstall();
669
+ mockExecGlobalHooksPath(globalHooksDir());
670
+ const { uninstall } = require('../uninstall');
671
+
672
+ const result = await uninstall(['--purge', '--dry-run']);
673
+
674
+ expect(result).toBe(0);
675
+ expect(fs.existsSync(globalHooksDir())).toBe(true);
676
+ expect(fs.existsSync(globalAdaptersDir())).toBe(true);
677
+ expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Purge'));
678
+ });
626
679
  });
@@ -518,4 +518,6 @@ module.exports = {
518
518
  GATE_CLI_TOOLS,
519
519
  checkCliTool,
520
520
  getToolInstallCmd,
521
+ GATE_TOOLS: require('./gate-tools.js').GATE_TOOLS,
522
+ detectProjectLang: require('./gate-tools.js').detectProjectLang,
521
523
  };
package/lib/doctor.js CHANGED
@@ -804,6 +804,18 @@ async function doctor(args) {
804
804
  return issues > 0 ? 1 : 0;
805
805
  }
806
806
 
807
+ function formatDoctorJson(checks, issues) {
808
+ const missing_tools = checks
809
+ .filter(c => c.status === 'WARN' || c.status === 'FAIL')
810
+ .map(c => ({ name: c.name, detail: c.detail }));
811
+ return {
812
+ ok: issues === 0,
813
+ issues,
814
+ checks: checks.map(c => ({ name: c.name, status: c.status, detail: c.detail })),
815
+ missing_tools,
816
+ };
817
+ }
818
+
807
819
  module.exports = {
808
820
  doctor, isXpGateFile, SIGNATURES,
809
821
  fixVersionMismatch,
@@ -815,4 +827,5 @@ module.exports = {
815
827
  fixTuiRegistration,
816
828
  ensureTuiRegistration,
817
829
  readTuiJson,
830
+ formatDoctorJson,
818
831
  };
@@ -0,0 +1,87 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const GATE_TOOLS = {
5
+ PLATFORM: ['jscpd', 'lizard', 'semgrep', 'gitleaks', 'npx'],
6
+ IAC: ['checkov', 'hadolint', 'kube-score', 'tflint'],
7
+
8
+ LANG_MAP: {
9
+ ts: 'typescript', py: 'python', go: 'go', java: 'java',
10
+ kt: 'kotlin', cpp: 'cpp', swift: 'swift', dart: 'dart',
11
+ flutter: 'flutter', sh: 'shell', ps: 'powershell', objc: 'objectivec',
12
+ },
13
+
14
+ LINT: {
15
+ typescript: ['biome', 'eslint', 'tsc'],
16
+ python: ['ruff', 'flake8', 'mypy', 'black', 'isort'],
17
+ go: ['golangci-lint', 'go'],
18
+ java: ['checkstyle', 'pmd'],
19
+ kotlin: ['ktlint', 'detekt'],
20
+ cpp: ['clang-tidy', 'cppcheck', 'cmake'],
21
+ swift: ['swiftlint', 'swift'],
22
+ dart: ['dart'],
23
+ flutter: ['flutter'],
24
+ shell: ['shellcheck'],
25
+ powershell: ['pwsh'],
26
+ objectivec: ['oclint'],
27
+ },
28
+
29
+ TEST: {
30
+ typescript: ['vitest', 'jest'],
31
+ python: ['pytest'],
32
+ go: ['go'],
33
+ java: ['mvn', 'gradle'],
34
+ kotlin: ['mvn', 'gradle'],
35
+ swift: ['swift'],
36
+ cpp: ['ctest', 'gcovr'],
37
+ dart: ['dart'],
38
+ flutter: ['flutter'],
39
+ },
40
+
41
+ MUTATION: {
42
+ typescript: ['stryker'],
43
+ python: ['mutmut'],
44
+ go: ['gomutants'],
45
+ java: ['pitest'],
46
+ },
47
+
48
+ SPECIAL: {
49
+ jq: { gate: 'MW', desc: 'code-walkthrough JSON parser (mandatory)' },
50
+ tsx: { gate: 'M/M3/4/6', desc: 'TypeScript executor (via npx)' },
51
+ node: { gate: '0/4/6/M/M3', desc: 'All TypeScript gate runtime' },
52
+ },
53
+ };
54
+
55
+ const LANG_MARKERS = [
56
+ { file: 'tsconfig.json', lang: 'typescript' },
57
+ { file: 'package.json', check: (p) => {
58
+ try {
59
+ const json = JSON.parse(fs.readFileSync(p, 'utf8'));
60
+ return !!(json.devDependencies && json.devDependencies.typescript)
61
+ || !!(json.dependencies && json.dependencies.typescript);
62
+ } catch { return false; }
63
+ }, lang: 'typescript' },
64
+ { file: 'go.mod', lang: 'go' },
65
+ { file: 'pyproject.toml', lang: 'python' },
66
+ { file: 'manage.py', lang: 'python' },
67
+ { file: 'requirements.txt', lang: 'python' },
68
+ { file: 'pom.xml', lang: 'java' },
69
+ { file: 'build.gradle', lang: 'java' },
70
+ { file: 'build.gradle.kts', lang: 'kotlin' },
71
+ { file: 'pubspec.yaml', lang: 'flutter' },
72
+ { file: 'CMakeLists.txt', lang: 'cpp' },
73
+ { file: 'Package.swift', lang: 'swift' },
74
+ ];
75
+
76
+ function detectProjectLang(projectRoot) {
77
+ const found = new Set();
78
+ const exists = (f) => fs.existsSync(path.join(projectRoot, f));
79
+ for (const marker of LANG_MARKERS) {
80
+ if (!exists(marker.file)) continue;
81
+ if (marker.check && !marker.check(path.join(projectRoot, marker.file))) continue;
82
+ found.add(marker.lang);
83
+ }
84
+ return [...found];
85
+ }
86
+
87
+ module.exports = { GATE_TOOLS, detectProjectLang };
package/lib/init.js CHANGED
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const crypto = require('crypto');
4
4
  const { checkDeps, checkBash, autoInstallDeps, detectPlatform, GATE_CLI_TOOLS, checkCliTool } = require('./detect-deps.js');
5
+ const { copyHooks, copyAdapters } = require('./shared-utils.js');
5
6
  const {
6
7
  HOME_DIR,
7
8
  CONFIG_DIR,
@@ -11,42 +12,6 @@ const {
11
12
  GLOBAL_ADAPTERS_DIR,
12
13
  } = require('./shared-paths.js');
13
14
 
14
- function copyHooks(srcDir, destDir) {
15
- ['pre-commit', 'pre-push'].forEach(hook => {
16
- const src = path.join(srcDir, 'hooks', hook);
17
- const dest = path.join(destDir, hook);
18
- if (fs.existsSync(src)) {
19
- fs.copyFileSync(src, dest);
20
- fs.chmodSync(dest, 0o755);
21
- }
22
- });
23
- }
24
-
25
- function copyAdapters(srcDir, destDir) {
26
- const adapterSrc = path.join(srcDir, 'adapter-common.sh');
27
- if (fs.existsSync(adapterSrc)) {
28
- fs.copyFileSync(adapterSrc, path.join(destDir, 'adapter-common.sh'));
29
- }
30
- const adaptersDir = path.join(srcDir, 'adapters');
31
- if (fs.existsSync(adaptersDir)) {
32
- fs.readdirSync(adaptersDir).forEach(f => {
33
- if (f.endsWith('.sh')) {
34
- fs.copyFileSync(path.join(adaptersDir, f), path.join(destDir, f));
35
- }
36
- });
37
- }
38
- // Copy gate scripts (gate-*.sh) from githooks/ source-of-truth to destDir.
39
- // These are sourced by pre-commit via GATE_DIR which resolves to the adapter dir.
40
- const githooksDir = path.resolve(srcDir, '..', '..', '..', 'githooks');
41
- if (fs.existsSync(githooksDir)) {
42
- fs.readdirSync(githooksDir).forEach(f => {
43
- if (f.startsWith('gate-') && f.endsWith('.sh')) {
44
- fs.copyFileSync(path.join(githooksDir, f), path.join(destDir, f));
45
- }
46
- });
47
- }
48
- }
49
-
50
15
  function copyRecursive(src, dest) {
51
16
  const stat = fs.statSync(src);
52
17
  if (stat.isDirectory()) {
@@ -0,0 +1,57 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { execSync } = require('child_process');
4
+ const { copyHooks, copyAdapters } = require('./shared-utils');
5
+
6
+ async function install(args = [], cwd = process.cwd()) {
7
+ const isGlobal = args.includes('--global');
8
+
9
+ if (isGlobal) {
10
+ return setupGlobal(cwd);
11
+ }
12
+ return setupLocal(cwd);
13
+ }
14
+
15
+ function setupGlobal(cwd) {
16
+ const srcDir = path.dirname(__dirname);
17
+
18
+ const globalHooksDir = path.join(require('os').homedir(), '.config', 'xp-gate', 'hooks');
19
+ const globalAdaptersDir = path.join(require('os').homedir(), '.config', 'xp-gate', 'adapters');
20
+
21
+ fs.mkdirSync(globalHooksDir, { recursive: true });
22
+ fs.mkdirSync(globalAdaptersDir, { recursive: true });
23
+
24
+ copyHooks(srcDir, globalHooksDir);
25
+ copyAdapters(srcDir, globalAdaptersDir);
26
+
27
+ try {
28
+ execSync(`git config --global core.hooksPath "${globalHooksDir}"`, { stdio: 'pipe' });
29
+ } catch (err) {
30
+ console.warn(` Warning: Could not set global core.hooksPath: ${err.message}`);
31
+ }
32
+
33
+ console.log('Global installation complete.');
34
+ return 0;
35
+ }
36
+
37
+ function setupLocal(projectRoot) {
38
+ const gitDir = path.join(projectRoot, '.git');
39
+ if (!fs.existsSync(gitDir)) {
40
+ console.error('Error: Not a git repository');
41
+ return 1;
42
+ }
43
+
44
+ const srcDir = path.dirname(__dirname);
45
+ const hooksDir = path.join(gitDir, 'hooks');
46
+ const githooksDir = path.join(projectRoot, 'githooks');
47
+
48
+ copyHooks(srcDir, hooksDir);
49
+
50
+ fs.mkdirSync(path.join(githooksDir, 'adapters'), { recursive: true });
51
+ copyAdapters(srcDir, githooksDir);
52
+
53
+ console.log('Local installation complete.');
54
+ return 0;
55
+ }
56
+
57
+ module.exports = { install };
@@ -33,4 +33,38 @@ function readXpGateConfig() {
33
33
  }
34
34
  }
35
35
 
36
- module.exports = { copyDirRecursive, readXpGateConfig };
36
+ function copyHooks(srcDir, destDir) {
37
+ ['pre-commit', 'pre-push'].forEach(hook => {
38
+ const src = path.join(srcDir, 'hooks', hook);
39
+ const dest = path.join(destDir, hook);
40
+ if (fs.existsSync(src)) {
41
+ fs.copyFileSync(src, dest);
42
+ fs.chmodSync(dest, 0o755);
43
+ }
44
+ });
45
+ }
46
+
47
+ function copyAdapters(srcDir, destDir) {
48
+ const adaptersDir = path.join(srcDir, 'adapters');
49
+ const adapterCommon = path.join(srcDir, 'adapter-common.sh');
50
+ if (fs.existsSync(adapterCommon)) {
51
+ fs.copyFileSync(adapterCommon, path.join(destDir, 'adapter-common.sh'));
52
+ }
53
+ if (fs.existsSync(adaptersDir)) {
54
+ fs.readdirSync(adaptersDir).forEach(f => {
55
+ if (f.endsWith('.sh')) {
56
+ fs.copyFileSync(path.join(adaptersDir, f), path.join(destDir, f));
57
+ }
58
+ });
59
+ }
60
+ const githooksDir = path.resolve(srcDir, '..', '..', '..', 'githooks');
61
+ if (fs.existsSync(githooksDir)) {
62
+ fs.readdirSync(githooksDir).forEach(f => {
63
+ if (f.startsWith('gate-') && f.endsWith('.sh')) {
64
+ fs.copyFileSync(path.join(githooksDir, f), path.join(destDir, f));
65
+ }
66
+ });
67
+ }
68
+ }
69
+
70
+ module.exports = { copyDirRecursive, readXpGateConfig, copyHooks, copyAdapters };
package/lib/uninstall.js CHANGED
@@ -331,7 +331,8 @@ async function uninstall(args) {
331
331
  dryRun: args.includes('--dry-run'),
332
332
  force: args.includes('--force'),
333
333
  forceLocal: args.includes('--local'),
334
- forceGlobal: args.includes('--global')
334
+ forceGlobal: args.includes('--global'),
335
+ purge: args.includes('--purge'),
335
336
  };
336
337
 
337
338
  // §4.3 Step 1: Read config
@@ -362,7 +363,23 @@ async function uninstall(args) {
362
363
  // §4.3 Step 3: Build uninstall plan
363
364
  const plan = buildPlan(mode);
364
365
 
365
- if (plan.length === 0) {
366
+ // §4.3 Step 3b: Add purge items if --purge
367
+ const purgeDirs = [];
368
+ if (options.purge) {
369
+ const configDir = CONFIG_DIR;
370
+ const xpGateDir = path.join(HOME_DIR, '.xp-gate');
371
+ purgeDirs.push({ label: '~/.xp-gate/', path: xpGateDir });
372
+ purgeDirs.push({ label: '~/.config/xp-gate/', path: configDir });
373
+ if (mode === 'local') {
374
+ const gitDir = getGitDir();
375
+ if (gitDir) {
376
+ const projectXpGate = path.join(path.dirname(gitDir), '.xp-gate');
377
+ purgeDirs.push({ label: '.xp-gate/ (project)', path: projectXpGate });
378
+ }
379
+ }
380
+ }
381
+
382
+ if (plan.length === 0 && purgeDirs.length === 0) {
366
383
  console.log('Nothing to uninstall');
367
384
  // Still update config to uninstalled
368
385
  saveConfig({ ...config, mode: 'uninstalled', uninstalled: new Date().toISOString() });
@@ -377,6 +394,12 @@ async function uninstall(args) {
377
394
  for (const item of plan) {
378
395
  console.log(` • ${item.label}`);
379
396
  }
397
+ if (options.purge) {
398
+ console.log('\nPurge mode — additional cleanup:');
399
+ for (const d of purgeDirs) {
400
+ console.log(` • ${d.label}`);
401
+ }
402
+ }
380
403
 
381
404
  // §4.3 Step 5: Dry-run → exit
382
405
  if (options.dryRun) {
@@ -406,14 +429,36 @@ async function uninstall(args) {
406
429
  }
407
430
  }
408
431
 
432
+ if (options.purge) {
433
+ for (const d of purgeDirs) {
434
+ if (options.dryRun) {
435
+ console.log(` • ${d.label}`);
436
+ continue;
437
+ }
438
+ if (!fs.existsSync(d.path)) continue;
439
+ try {
440
+ fs.rmSync(d.path, { recursive: true, force: true });
441
+ console.log(` Removed ${d.label}`);
442
+ } catch (e) {
443
+ console.warn(` Warning: Could not remove ${d.label}: ${e.message}`);
444
+ hadErrors = true;
445
+ }
446
+ }
447
+ }
448
+
409
449
  // §4.8 State machine: uninstalling → uninstalled
410
- saveConfig({
411
- ...getConfig() || config,
412
- mode: 'uninstalled',
413
- uninstalled: new Date().toISOString(),
414
- // Clean up manifest after successful uninstall
415
- manifest: undefined
416
- });
450
+ try {
451
+ saveConfig({
452
+ ...getConfig() || config,
453
+ mode: 'uninstalled',
454
+ uninstalled: new Date().toISOString(),
455
+ manifest: undefined,
456
+ });
457
+ } catch (e) {
458
+ // purge mode: config dir has been deleted, save is non-critical
459
+ if (!options.purge) throw e;
460
+ console.warn(` Warning: Could not save config: ${e.message}`);
461
+ }
417
462
 
418
463
  // §4.12 Step 11: Clean up backup on success
419
464
  if (!hadErrors) {
@@ -1,9 +1,9 @@
1
1
  # SRC/MOCK-POLICY KNOWLEDGE BASE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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.
@@ -1,9 +1,9 @@
1
1
  # SRC/MUTATION KNOWLEDGE BASE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **Gate M** (incremental mutation testing) + **Gate M2** helpers (test-layer detection used by `src/mock-policy/`). Pre-push quality gate. TypeScript-only; uses Stryker.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/xp-gate",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "description": "AI-driven development workflow: 6 quality gates + Delphi review + Sprint Flow",
5
5
  "bin": {
6
6
  "xp-gate": "./bin/xp-gate.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xp-gate",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "displayName": "XP-Gate",
5
5
  "description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 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-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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": "@boyingliu01/opencode-plugin",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "XP-Gate quality gates + AI workflow skills + Sprint Flow TUI sidebar for OpenCode",
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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.13.2",
3
+ "version": "0.14.0",
4
4
  "displayName": "XP-Gate",
5
5
  "description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 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-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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
  # PRINCIPLES CHECKER MODULE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
3
  **Generated:** 2026-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.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-07-08
4
- **Commit:** 509be7b
4
+ **Commit:** 229cf7d
5
5
  **Branch:** main
6
- **Version:** 0.13.2.0
6
+ **Version:** 0.14.0.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.