@boyingliu01/xp-gate 0.15.5 → 0.18.1

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 (165) hide show
  1. package/adapter-common.sh +0 -0
  2. package/adapters/cpp.sh +0 -0
  3. package/adapters/dart.sh +0 -0
  4. package/adapters/flutter.sh +0 -0
  5. package/adapters/go.sh +0 -0
  6. package/adapters/iac.sh +0 -0
  7. package/adapters/java.sh +0 -0
  8. package/adapters/kotlin.sh +0 -0
  9. package/adapters/objectivec.sh +0 -0
  10. package/adapters/plugins/book299-20132-python/scripts/install-gradle.sh +0 -0
  11. package/adapters/plugins/book299-20132-python/scripts/install-maven.sh +0 -0
  12. package/adapters/plugins/book299-4081-c/scripts/install-gradle.sh +0 -0
  13. package/adapters/plugins/book299-4081-c/scripts/install-maven.sh +0 -0
  14. package/adapters/plugins/book299-4083-javascriptes5/scripts/install-gradle.sh +0 -0
  15. package/adapters/plugins/book299-4083-javascriptes5/scripts/install-maven.sh +0 -0
  16. package/adapters/powershell.sh +0 -0
  17. package/adapters/python.sh +0 -0
  18. package/adapters/shell.sh +0 -0
  19. package/adapters/swift.sh +0 -0
  20. package/adapters/typescript.sh +0 -0
  21. package/bin/xp-gate.js +29 -1
  22. package/gate-3.sh +0 -0
  23. package/gate-4.sh +0 -0
  24. package/gate-7.sh +0 -0
  25. package/gate-8.sh +0 -0
  26. package/gate-9.sh +0 -0
  27. package/hooks/adapter-common.sh +0 -0
  28. package/hooks/gate-3.sh +0 -0
  29. package/hooks/gate-4.sh +0 -0
  30. package/hooks/gate-7.sh +0 -0
  31. package/hooks/gate-8.sh +0 -0
  32. package/hooks/gate-9.sh +0 -0
  33. package/hooks/lib/now-ms.sh +33 -0
  34. package/hooks/pre-commit +63 -47
  35. package/hooks/pre-push +0 -0
  36. package/hooks/sprint-gate.sh +291 -0
  37. package/lib/__tests__/check-version.test.js +122 -0
  38. package/lib/__tests__/doctor.test.js +13 -15
  39. package/lib/__tests__/gate-audit.test.ts +38 -0
  40. package/lib/__tests__/phase-transition.test.js +512 -272
  41. package/lib/__tests__/retro.test.js +131 -0
  42. package/lib/__tests__/sprint-audit.test.js +207 -207
  43. package/lib/__tests__/sprint-status-rework.test.js +184 -0
  44. package/lib/check-version.js +9 -0
  45. package/lib/doctor-tui.js +268 -198
  46. package/lib/doctor.js +15 -3
  47. package/lib/gate-audit.ts +18 -7
  48. package/lib/gate-runner.js +77 -30
  49. package/lib/init.js +10 -0
  50. package/lib/language-tools.js +833 -833
  51. package/lib/mattpocock-license-verdict.json +7 -0
  52. package/lib/phase-transition.js +499 -249
  53. package/lib/retro.js +222 -0
  54. package/lib/shared-utils.js +7 -0
  55. package/lib/sprint-audit.js +235 -235
  56. package/lib/sprint-init.js +207 -0
  57. package/lib/sprint-state-migrator.js +1 -0
  58. package/lib/sprint-status.js +111 -0
  59. package/mock-policy/AGENTS.md +3 -3
  60. package/mutation/AGENTS.md +3 -3
  61. package/package.json +3 -2
  62. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  63. package/plugins/claude-code/bin/delphi-review-guard.sh +0 -0
  64. package/plugins/claude-code/bin/xp-gate-check +0 -0
  65. package/plugins/claude-code/skills/batch-grill-me/SKILL.md +15 -0
  66. package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
  67. package/plugins/claude-code/skills/delphi-review/SKILL.md +59 -4
  68. package/plugins/claude-code/skills/delphi-review/references/requirements.md +390 -0
  69. package/plugins/claude-code/skills/delphi-review/references/round-templates.md +67 -0
  70. package/plugins/claude-code/skills/domain-modeling/ADR-FORMAT.md +64 -0
  71. package/plugins/claude-code/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  72. package/plugins/claude-code/skills/domain-modeling/SKILL.md +74 -0
  73. package/plugins/claude-code/skills/grill-with-docs/SKILL.md +7 -0
  74. package/plugins/claude-code/skills/grilling/SKILL.md +12 -0
  75. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
  76. package/plugins/claude-code/skills/sprint-flow/SKILL.md +168 -43
  77. package/plugins/claude-code/skills/sprint-flow/references/components/memory.md +1 -1
  78. package/plugins/claude-code/skills/sprint-flow/references/components/middleware.md +1 -1
  79. package/plugins/claude-code/skills/sprint-flow/references/components/skill-invocations.md +21 -20
  80. package/plugins/claude-code/skills/sprint-flow/references/components/tool-descriptions.md +22 -23
  81. package/plugins/claude-code/skills/sprint-flow/references/orchestration-rules.md +14 -12
  82. package/plugins/claude-code/skills/sprint-flow/references/phase-2-design.md +145 -133
  83. package/plugins/claude-code/skills/sprint-flow/references/phase-3-build.md +69 -2
  84. package/plugins/claude-code/skills/sprint-flow/references/phase-4-verify.md +93 -31
  85. package/plugins/claude-code/skills/sprint-flow/references/phase-5-ship.md +99 -14
  86. package/plugins/claude-code/skills/sprint-flow/references/phase-6-close.md +37 -5
  87. package/plugins/claude-code/skills/sprint-flow/references/phase-overview.md +58 -53
  88. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
  89. package/plugins/claude-code/skills/test-specification-alignment/SKILL.md +8 -3
  90. package/plugins/claude-code/skills/to-issues/SKILL.md +1 -1
  91. package/plugins/opencode/index.ts +1 -0
  92. package/plugins/opencode/package.json +1 -1
  93. package/plugins/opencode/skills/batch-grill-me/SKILL.md +15 -0
  94. package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
  95. package/plugins/opencode/skills/delphi-review/SKILL.md +59 -4
  96. package/plugins/opencode/skills/delphi-review/references/requirements.md +390 -0
  97. package/plugins/opencode/skills/delphi-review/references/round-templates.md +67 -0
  98. package/plugins/opencode/skills/domain-modeling/ADR-FORMAT.md +64 -0
  99. package/plugins/opencode/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  100. package/plugins/opencode/skills/domain-modeling/SKILL.md +74 -0
  101. package/plugins/opencode/skills/grill-with-docs/SKILL.md +7 -0
  102. package/plugins/opencode/skills/grilling/SKILL.md +12 -0
  103. package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
  104. package/plugins/opencode/skills/sprint-flow/SKILL.md +168 -43
  105. package/plugins/opencode/skills/sprint-flow/references/components/memory.md +1 -1
  106. package/plugins/opencode/skills/sprint-flow/references/components/middleware.md +1 -1
  107. package/plugins/opencode/skills/sprint-flow/references/components/skill-invocations.md +21 -20
  108. package/plugins/opencode/skills/sprint-flow/references/components/tool-descriptions.md +22 -23
  109. package/plugins/opencode/skills/sprint-flow/references/orchestration-rules.md +14 -12
  110. package/plugins/opencode/skills/sprint-flow/references/phase-2-design.md +145 -133
  111. package/plugins/opencode/skills/sprint-flow/references/phase-3-build.md +69 -2
  112. package/plugins/opencode/skills/sprint-flow/references/phase-4-verify.md +93 -31
  113. package/plugins/opencode/skills/sprint-flow/references/phase-5-ship.md +99 -14
  114. package/plugins/opencode/skills/sprint-flow/references/phase-6-close.md +37 -5
  115. package/plugins/opencode/skills/sprint-flow/references/phase-overview.md +58 -53
  116. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
  117. package/plugins/opencode/skills/test-specification-alignment/SKILL.md +8 -3
  118. package/plugins/opencode/skills/to-issues/SKILL.md +1 -1
  119. package/plugins/qoder/agents/delphi-architecture.md +48 -48
  120. package/plugins/qoder/agents/delphi-feasibility.md +48 -48
  121. package/plugins/qoder/agents/delphi-technical.md +48 -48
  122. package/plugins/qoder/bin/sprint-flow-guard.sh +0 -0
  123. package/plugins/qoder/bin/xp-gate-check +0 -0
  124. package/plugins/qoder/plugin.json +1 -1
  125. package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
  126. package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
  127. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
  128. package/principles/AGENTS.md +3 -3
  129. package/scripts/__tests__/check-mattpocock-license.test.js +229 -0
  130. package/scripts/__tests__/sync-package-content.test.js +50 -0
  131. package/scripts/check-mattpocock-license.cjs +302 -0
  132. package/scripts/delphi-external-review.cjs +432 -432
  133. package/scripts/migrate-audit-anomalies.mjs +78 -0
  134. package/scripts/sync-package-content.js +52 -5
  135. package/skills/batch-grill-me/SKILL.md +15 -0
  136. package/skills/delphi-review/AGENTS.md +3 -3
  137. package/skills/delphi-review/SKILL.md +59 -4
  138. package/skills/delphi-review/references/requirements.md +390 -0
  139. package/skills/delphi-review/references/round-templates.md +67 -0
  140. package/skills/domain-modeling/ADR-FORMAT.md +64 -0
  141. package/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  142. package/skills/domain-modeling/SKILL.md +74 -0
  143. package/skills/grill-with-docs/SKILL.md +7 -0
  144. package/skills/grilling/SKILL.md +12 -0
  145. package/skills/sprint-flow/AGENTS.md +3 -3
  146. package/skills/sprint-flow/SKILL.md +168 -43
  147. package/skills/sprint-flow/references/components/memory.md +1 -1
  148. package/skills/sprint-flow/references/components/middleware.md +1 -1
  149. package/skills/sprint-flow/references/components/skill-invocations.md +21 -20
  150. package/skills/sprint-flow/references/components/tool-descriptions.md +22 -23
  151. package/skills/sprint-flow/references/orchestration-rules.md +14 -12
  152. package/skills/sprint-flow/references/phase-2-design.md +145 -133
  153. package/skills/sprint-flow/references/phase-3-build.md +69 -2
  154. package/skills/sprint-flow/references/phase-4-verify.md +93 -31
  155. package/skills/sprint-flow/references/phase-5-ship.md +99 -14
  156. package/skills/sprint-flow/references/phase-6-close.md +37 -5
  157. package/skills/sprint-flow/references/phase-overview.md +58 -53
  158. package/skills/test-specification-alignment/AGENTS.md +3 -3
  159. package/skills/test-specification-alignment/SKILL.md +8 -3
  160. package/skills/to-issues/SKILL.md +1 -1
  161. package/adapters/gate-3.sh +0 -68
  162. package/adapters/gate-4.sh +0 -80
  163. package/adapters/gate-7.sh +0 -45
  164. package/adapters/gate-8.sh +0 -56
  165. package/adapters/gate-9.sh +0 -104
package/lib/retro.js ADDED
@@ -0,0 +1,222 @@
1
+ /**
2
+ * xp-gate retro — Sprint engineering retrospective CLI (#369, design §8.1)
3
+ *
4
+ * Reads git log + .xp-gate/audit.jsonl + .quality-history.jsonl + .sprint-history/
5
+ * and generates a Markdown retrospective report with rework rate trend (#369)
6
+ * and --skip-evidence exposure (§8.4) sections.
7
+ *
8
+ * Zero npm dependencies (Node built-ins only).
9
+ * @module retro
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const { execSync } = require('child_process');
17
+
18
+ /**
19
+ * Get git commit subjects within a date window.
20
+ * @param {string} dir - Repository root
21
+ * @param {number} days - Lookback window in days
22
+ * @returns {Array<{hash: string, date: string, subject: string}>}
23
+ */
24
+ function getGitCommits(dir, days) {
25
+ try {
26
+ const out = execSync(
27
+ `git log --since="${days} days ago" --pretty=format:"%H|%ai|%s"`,
28
+ { cwd: dir, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
29
+ );
30
+ return out.split('\n').filter(Boolean).map(l => {
31
+ const [hash, date, ...rest] = l.split('|');
32
+ return { hash, date, subject: rest.join('|') };
33
+ });
34
+ } catch {
35
+ return [];
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Parse .xp-gate/audit.jsonl entries.
41
+ * @param {string} dir - Repository root
42
+ * @returns {object[]} Parsed audit entries
43
+ */
44
+ function readAuditEntries(dir) {
45
+ const p = path.join(dir, '.xp-gate', 'audit.jsonl');
46
+ if (!fs.existsSync(p)) return [];
47
+ return fs.readFileSync(p, 'utf8').split('\n')
48
+ .filter(l => l.trim())
49
+ .map(l => { try { return JSON.parse(l); } catch { return null; } })
50
+ .filter(Boolean);
51
+ }
52
+
53
+ /**
54
+ * Read last 10 entries from .quality-history.jsonl.
55
+ * @param {string} dir - Repository root
56
+ * @returns {object[]} Recent quality entries
57
+ */
58
+ function readQualityHistory(dir) {
59
+ const p = path.join(dir, '.quality-history.jsonl');
60
+ if (!fs.existsSync(p)) return [];
61
+ const entries = fs.readFileSync(p, 'utf8').split('\n')
62
+ .filter(l => l.trim())
63
+ .map(l => { try { return JSON.parse(l); } catch { return null; } })
64
+ .filter(Boolean);
65
+ return entries.slice(-10);
66
+ }
67
+
68
+ /**
69
+ * Read sprint history JSON files from .sprint-state/sprint-history/.
70
+ * @param {string} dir - Repository root
71
+ * @param {string|null} sprintFilter - Optional sprint ID filter
72
+ * @returns {object[]} Sprint state objects
73
+ */
74
+ function readSprintHistory(dir, sprintFilter) {
75
+ const histDir = path.join(dir, '.sprint-state', 'sprint-history');
76
+ const results = [];
77
+ if (fs.existsSync(histDir)) {
78
+ for (const f of fs.readdirSync(histDir).filter(f => f.endsWith('.json'))) {
79
+ try {
80
+ const s = JSON.parse(fs.readFileSync(path.join(histDir, f), 'utf8'));
81
+ if (!sprintFilter || s.id === sprintFilter) results.push(s);
82
+ } catch { /* skip */ }
83
+ }
84
+ }
85
+ return results;
86
+ }
87
+
88
+ /**
89
+ * Build the Markdown retrospective report.
90
+ * @param {object} opts - Report data
91
+ * @returns {string} Markdown report
92
+ */
93
+ function buildReport(opts) {
94
+ const { days, commits, audit, quality, sprints } = opts;
95
+ const now = new Date();
96
+ const start = new Date(now.getTime() - days * 86400000);
97
+ const L = [];
98
+
99
+ L.push('# Sprint Engineering Retrospective');
100
+ L.push('');
101
+ L.push(`Period: ${start.toISOString().slice(0, 10)} to ${now.toISOString().slice(0, 10)}`);
102
+ L.push('');
103
+
104
+ // Activity Summary
105
+ L.push('## Activity Summary');
106
+ const gateEntries = audit.filter(e => e.gate_id);
107
+ const passed = gateEntries.filter(e => e.passed).length;
108
+ const normal = gateEntries.filter(e => !e.duration_anomaly);
109
+ const anomalous = gateEntries.length - normal.length;
110
+ const avgMs = normal.length > 0
111
+ ? Math.round(normal.reduce((s, e) => s + (e.duration_ms || 0), 0) / normal.length)
112
+ : 0;
113
+ L.push(`- Total commits in window: ${commits.length}`);
114
+ L.push(`- Sprint transitions recorded: ${sprints.length}`);
115
+ L.push(`- Gate pass rate: ${gateEntries.length > 0 ? ((passed / gateEntries.length) * 100).toFixed(1) : '0.0'}% (${gateEntries.length} gates total, ${gateEntries.length - passed} failed)`);
116
+ if (gateEntries.length > 0) {
117
+ L.push(`- Avg gate duration: ${avgMs}ms (${anomalous} anomal${anomalous === 1 ? 'y' : 'ies'} excluded)`);
118
+ }
119
+ L.push('');
120
+
121
+ // Rework Rate Trend (#369)
122
+ L.push('## Rework Rate Trend (#369)');
123
+ const withRate = sprints.filter(s => s.metrics && s.metrics.rework_rate != null);
124
+ if (withRate.length === 0) {
125
+ L.push('No data');
126
+ } else {
127
+ L.push('| Sprint | Rework Rate | Fix Commits | Total Commits |');
128
+ L.push('|--------|-------------|-------------|---------------|');
129
+ for (const s of withRate) {
130
+ const pct = (s.metrics.rework_rate * 100).toFixed(1);
131
+ const fix = s.metrics.total_sprint_commits != null
132
+ ? Math.round(s.metrics.rework_rate * s.metrics.total_sprint_commits)
133
+ : '?';
134
+ L.push(`| ${s.id || 'unknown'} | ${pct}% | ${fix} | ${s.metrics.total_sprint_commits ?? '?'} |`);
135
+ if (s.metrics.rework_rate > 0.30) {
136
+ L.push(`⚠️ Sprint ${s.id || 'unknown'}: ${pct}% rework — exceeds 30% threshold`);
137
+ }
138
+ }
139
+ }
140
+ L.push('');
141
+
142
+ // Evidence Skip Exposure (§8.4)
143
+ L.push('## Evidence Skip Exposure (§8.4)');
144
+ const skipped = audit.filter(e => e.event === 'evidence_skipped');
145
+ if (skipped.length === 0) {
146
+ L.push('No data');
147
+ } else {
148
+ L.push('| Phase | Reason | Timestamp |');
149
+ L.push('|-------|--------|-----------|');
150
+ for (const e of skipped) {
151
+ L.push(`| ${e.phase || '?'} | ${e.reason || '?'} | ${(e.timestamp || '').slice(0, 19)} |`);
152
+ }
153
+ const bySprint = {};
154
+ for (const e of skipped) {
155
+ const k = e.sprint_id || 'unknown';
156
+ bySprint[k] = (bySprint[k] || 0) + 1;
157
+ }
158
+ for (const [sid, count] of Object.entries(bySprint)) {
159
+ if (count > 2) {
160
+ L.push(`⚠️ Sprint ${sid} used skip ${count} times`);
161
+ }
162
+ }
163
+ }
164
+ L.push('');
165
+
166
+ // Quality Trend
167
+ L.push('## Quality Trend');
168
+ if (quality.length === 0) {
169
+ L.push('No data');
170
+ } else {
171
+ for (const q of quality) {
172
+ L.push(`- ${(q.timestamp || '').slice(0, 10)}: score ${q.score ?? '?'}`);
173
+ }
174
+ }
175
+
176
+ return L.join('\n');
177
+ }
178
+
179
+ /**
180
+ * CLI entry point for xp-gate retro.
181
+ * @param {string[]} args - CLI subargs (without 'retro')
182
+ * @returns {Promise<number>} Exit code
183
+ */
184
+ async function handleRetro(args = []) {
185
+ const allFlag = args.includes('--all');
186
+ const jsonFlag = args.includes('--json');
187
+ const daysIdx = args.indexOf('--days');
188
+ const sprintIdx = args.indexOf('--sprint');
189
+
190
+ let days = allFlag ? 30 : 7;
191
+ if (daysIdx >= 0 && args[daysIdx + 1]) {
192
+ days = parseInt(args[daysIdx + 1], 10);
193
+ if (isNaN(days) || days < 1) days = 7;
194
+ }
195
+
196
+ const sprintFilter = (sprintIdx >= 0 && args[sprintIdx + 1]) ? args[sprintIdx + 1] : null;
197
+ const dir = process.cwd();
198
+
199
+ const commits = getGitCommits(dir, days);
200
+ const audit = readAuditEntries(dir);
201
+ const quality = readQualityHistory(dir);
202
+ const sprints = readSprintHistory(dir, sprintFilter);
203
+
204
+ if (jsonFlag) {
205
+ const gateEntries = audit.filter(e => e.gate_id);
206
+ const passed = gateEntries.filter(e => e.passed).length;
207
+ console.log(JSON.stringify({
208
+ period: { days, from: new Date(Date.now() - days * 86400000).toISOString(), to: new Date().toISOString() },
209
+ total_commits: commits.length,
210
+ gate_pass_rate: gateEntries.length > 0 ? passed / gateEntries.length : null,
211
+ rework_rates: sprints.filter(s => s.metrics?.rework_rate != null).map(s => ({ id: s.id, rate: s.metrics.rework_rate })),
212
+ evidence_skipped: audit.filter(e => e.event === 'evidence_skipped'),
213
+ quality: quality.map(q => ({ timestamp: q.timestamp, score: q.score })),
214
+ }, null, 2));
215
+ return 0;
216
+ }
217
+
218
+ console.log(buildReport({ days, commits, audit, quality, sprints }));
219
+ return 0;
220
+ }
221
+
222
+ module.exports = { handleRetro };
@@ -42,6 +42,13 @@ function copyHooks(srcDir, destDir) {
42
42
  fs.chmodSync(dest, 0o755);
43
43
  }
44
44
  });
45
+
46
+ // Copy lib/ directory (e.g. now-ms.sh) — sourced by pre-commit at runtime
47
+ const libSrc = path.join(srcDir, 'hooks', 'lib');
48
+ const libDest = path.join(destDir, 'lib');
49
+ if (fs.existsSync(libSrc)) {
50
+ copyDirRecursive(libSrc, libDest);
51
+ }
45
52
  }
46
53
 
47
54
  function copyAdapters(srcDir, destDir) {