@boyingliu01/xp-gate 0.12.2 → 0.12.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/cpp.sh +0 -0
- package/adapters/dart.sh +0 -0
- package/adapters/flutter.sh +0 -0
- package/adapters/go.sh +0 -0
- package/adapters/java.sh +0 -0
- package/adapters/kotlin.sh +0 -0
- package/adapters/objectivec.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 +19 -5
- 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/lib/__tests__/update-hooks.test.js +573 -0
- package/lib/init.js +9 -6
- package/lib/sprint-status.js +35 -1
- package/lib/update-hooks.js +288 -0
- package/mock-policy/AGENTS.md +3 -3
- package/mutation/AGENTS.md +3 -3
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +6 -6
- package/plugins/claude-code/skills/delphi-review/SKILL.md +34 -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 +6 -6
- package/plugins/opencode/skills/delphi-review/SKILL.md +34 -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/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +6 -6
- package/plugins/qoder/skills/delphi-review/SKILL.md +198 -264
- 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/skills/delphi-review/AGENTS.md +6 -6
- package/skills/delphi-review/SKILL.md +34 -12
- package/skills/sprint-flow/AGENTS.md +3 -3
- package/skills/test-specification-alignment/AGENTS.md +3 -3
- package/lib/__tests__/next-sprint.test.js +0 -231
- package/lib/next-sprint.js +0 -129
- package/lib/shared-phase-constants.d.ts +0 -17
- package/lib/shared-phase-constants.js +0 -77
- package/plugins/opencode/__tests__/tui-plugin.test.ts +0 -543
- package/plugins/opencode/__tests__/xp-gate-e2e-upgrade.test.ts +0 -562
- package/plugins/opencode/__tests__/xp-gate-update.test.ts +0 -518
- package/plugins/opencode/tui-plugin.ts +0 -414
- package/plugins/opencode/tui-plugin.tsx +0 -306
package/lib/sprint-status.js
CHANGED
|
@@ -9,9 +9,43 @@
|
|
|
9
9
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
|
-
const { PHASE_NAMES, PHASE_ORDER, getLatestTimestamp, isStale } = require('./shared-phase-constants');
|
|
13
12
|
const { discoverActiveSprints } = require('./sprint-discovery');
|
|
14
13
|
|
|
14
|
+
// Phase constants (inlined; was shared-phase-constants.js, removed in v0.13.0 slimming)
|
|
15
|
+
const PHASE_NAMES = {
|
|
16
|
+
'-1': 'ISOLATE', '-0.5': 'AUTO-ESTIMATE',
|
|
17
|
+
'0': 'THINK', '1': 'PLAN', '2': 'BUILD', '3': 'REVIEW',
|
|
18
|
+
'4': 'USER ACCEPTANCE', '5': 'FEEDBACK', '6': 'SHIP', '7': 'LAND', '8': 'CLEANUP',
|
|
19
|
+
};
|
|
20
|
+
const PHASE_ORDER = ['-1', '-0.5', '0', '1', '2', '3', '4', '5', '6', '7', '8'];
|
|
21
|
+
|
|
22
|
+
function parseTime(value) {
|
|
23
|
+
if (!value) return 0;
|
|
24
|
+
const t = new Date(value).getTime();
|
|
25
|
+
return isNaN(t) ? 0 : t;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getLatestTimestamp(state) {
|
|
29
|
+
if (!state || !state.started_at) return 0;
|
|
30
|
+
const started = parseTime(state.started_at);
|
|
31
|
+
if (!started) return 0;
|
|
32
|
+
const timestamps = [started];
|
|
33
|
+
if (Array.isArray(state.phase_history)) {
|
|
34
|
+
for (const ph of state.phase_history) {
|
|
35
|
+
timestamps.push(parseTime(ph.completed_at));
|
|
36
|
+
timestamps.push(parseTime(ph.started_at));
|
|
37
|
+
timestamps.push(parseTime(ph.timestamp));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return Math.max(...timestamps);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isStale(state) {
|
|
44
|
+
if (!state || !state.started_at) return false;
|
|
45
|
+
const latest = getLatestTimestamp(state);
|
|
46
|
+
return latest > 0 && Date.now() - latest > 3600000;
|
|
47
|
+
}
|
|
48
|
+
|
|
15
49
|
/**
|
|
16
50
|
* Read and parse sprint-state.json from a project directory.
|
|
17
51
|
* @param {string} dir - Project root directory
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @test REQ-265 update-hooks command
|
|
3
|
+
* @intent Sync latest hook versions from xp-gate package to project or global directory
|
|
4
|
+
* @covers AC-265-01, AC-265-02, AC-265-03, AC-265-04
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { GLOBAL_HOOKS_DIR, GLOBAL_ADAPTERS_DIR } = require('./shared-paths.js');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get the xp-gate package root directory (src/npm-package/).
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
14
|
+
function getPackageRoot() {
|
|
15
|
+
return path.resolve(__dirname, '..');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get the project's git hooks directory.
|
|
20
|
+
* @throws {Error} If not in a git repository
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
function getProjectHooksDir() {
|
|
24
|
+
const gitDir = path.join(process.cwd(), '.git');
|
|
25
|
+
if (!fs.existsSync(gitDir)) {
|
|
26
|
+
throw new Error('Not a Git repository: .git directory not found');
|
|
27
|
+
}
|
|
28
|
+
return path.join(gitDir, 'hooks');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Detect locally modified hook files by comparing source and destination contents.
|
|
33
|
+
* @param {string} srcDir - Package root directory
|
|
34
|
+
* @param {string} hooksDestDir - Destination hooks directory
|
|
35
|
+
* @param {string} adaptersDestDir - Destination adapters directory
|
|
36
|
+
* @returns {string[]} List of locally modified file names
|
|
37
|
+
*/
|
|
38
|
+
function detectLocalModifications(srcDir, hooksDestDir, adaptersDestDir) {
|
|
39
|
+
const modified = [];
|
|
40
|
+
|
|
41
|
+
// Check hook files: pre-commit, pre-push
|
|
42
|
+
['pre-commit', 'pre-push'].forEach(hook => {
|
|
43
|
+
const srcPath = path.join(srcDir, 'hooks', hook);
|
|
44
|
+
const destPath = path.join(hooksDestDir, hook);
|
|
45
|
+
if (fs.existsSync(destPath) && fs.existsSync(srcPath)) {
|
|
46
|
+
const srcContent = fs.readFileSync(srcPath, 'utf8');
|
|
47
|
+
const destContent = fs.readFileSync(destPath, 'utf8');
|
|
48
|
+
if (srcContent !== destContent) {
|
|
49
|
+
modified.push(hook);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Check adapter-common.sh
|
|
55
|
+
const adapterCommonSrc = path.join(srcDir, 'adapter-common.sh');
|
|
56
|
+
const adapterCommonDest = path.join(adaptersDestDir, 'adapter-common.sh');
|
|
57
|
+
if (fs.existsSync(adapterCommonDest) && fs.existsSync(adapterCommonSrc)) {
|
|
58
|
+
const srcContent = fs.readFileSync(adapterCommonSrc, 'utf8');
|
|
59
|
+
const destContent = fs.readFileSync(adapterCommonDest, 'utf8');
|
|
60
|
+
if (srcContent !== destContent) {
|
|
61
|
+
modified.push('adapter-common.sh');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check adapters/*.sh
|
|
66
|
+
const srcAdaptersDir = path.join(srcDir, 'adapters');
|
|
67
|
+
if (fs.existsSync(srcAdaptersDir)) {
|
|
68
|
+
fs.readdirSync(srcAdaptersDir).forEach(f => {
|
|
69
|
+
if (f.endsWith('.sh')) {
|
|
70
|
+
const srcPath = path.join(srcAdaptersDir, f);
|
|
71
|
+
const destPath = path.join(adaptersDestDir, 'adapters', f);
|
|
72
|
+
if (fs.existsSync(destPath) && fs.existsSync(srcPath)) {
|
|
73
|
+
const srcContent = fs.readFileSync(srcPath, 'utf8');
|
|
74
|
+
const destContent = fs.readFileSync(destPath, 'utf8');
|
|
75
|
+
if (srcContent !== destContent) {
|
|
76
|
+
modified.push(`adapters/${f}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check gate-*.sh scripts
|
|
84
|
+
if (fs.existsSync(srcDir)) {
|
|
85
|
+
fs.readdirSync(srcDir).forEach(f => {
|
|
86
|
+
if (f.startsWith('gate-') && f.endsWith('.sh')) {
|
|
87
|
+
const srcPath = path.join(srcDir, f);
|
|
88
|
+
const destPath = path.join(adaptersDestDir, f);
|
|
89
|
+
if (fs.existsSync(destPath) && fs.existsSync(srcPath)) {
|
|
90
|
+
const srcContent = fs.readFileSync(srcPath, 'utf8');
|
|
91
|
+
const destContent = fs.readFileSync(destPath, 'utf8');
|
|
92
|
+
if (srcContent !== destContent) {
|
|
93
|
+
modified.push(f);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return modified;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Atomically copy a file: write to .tmp then rename. Create .bak backup if enabled.
|
|
105
|
+
* @param {string} src - Source file path
|
|
106
|
+
* @param {string} dest - Destination file path
|
|
107
|
+
* @param {boolean} dryRun - If true, only log what would happen
|
|
108
|
+
* @param {boolean} noBackup - If true, skip backup creation
|
|
109
|
+
* @param {string} label - Human-readable label for logging
|
|
110
|
+
* @returns {boolean} Whether the file was copied
|
|
111
|
+
*/
|
|
112
|
+
function atomicCopyFile(src, dest, dryRun, noBackup, label) {
|
|
113
|
+
if (!fs.existsSync(src)) {
|
|
114
|
+
console.warn(` ⚠ ${label} not found, skipping`);
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (dryRun) {
|
|
119
|
+
console.log(` would update: ${label}`);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Ensure destination directory exists
|
|
124
|
+
const destDir = path.dirname(dest);
|
|
125
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
126
|
+
|
|
127
|
+
// Create backup if enabled
|
|
128
|
+
if (!noBackup && fs.existsSync(dest)) {
|
|
129
|
+
fs.copyFileSync(dest, `${dest}.bak`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Atomic write: temp file + rename
|
|
133
|
+
const tmpDest = `${dest}.tmp`;
|
|
134
|
+
fs.copyFileSync(src, tmpDest);
|
|
135
|
+
fs.renameSync(tmpDest, dest);
|
|
136
|
+
fs.chmodSync(dest, 0o755);
|
|
137
|
+
console.log(` ✓ ${label}`);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Copy hook files (pre-commit, pre-push) from package to destination.
|
|
143
|
+
* @param {string} srcDir - Package root directory
|
|
144
|
+
* @param {string} destDir - Destination hooks directory
|
|
145
|
+
* @param {boolean} dryRun
|
|
146
|
+
* @param {boolean} noBackup
|
|
147
|
+
*/
|
|
148
|
+
function copyHooks(srcDir, destDir, dryRun, noBackup) {
|
|
149
|
+
const hooksSrcDir = path.join(srcDir, 'hooks');
|
|
150
|
+
['pre-commit', 'pre-push'].forEach(hook => {
|
|
151
|
+
const src = path.join(hooksSrcDir, hook);
|
|
152
|
+
const dest = path.join(destDir, hook);
|
|
153
|
+
atomicCopyFile(src, dest, dryRun, noBackup, hook);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Copy adapter files (adapter-common.sh + adapters/*.sh) from package to destination.
|
|
159
|
+
* @param {string} srcDir - Package root directory
|
|
160
|
+
* @param {string} destDir - Destination directory (githooks/ for local, adapters/ for global)
|
|
161
|
+
* @param {boolean} dryRun
|
|
162
|
+
* @param {boolean} noBackup
|
|
163
|
+
*/
|
|
164
|
+
function copyAdapters(srcDir, destDir, dryRun, noBackup) {
|
|
165
|
+
// Copy adapter-common.sh from package root
|
|
166
|
+
const adapterCommonSrc = path.join(srcDir, 'adapter-common.sh');
|
|
167
|
+
const adapterCommonDest = path.join(destDir, 'adapter-common.sh');
|
|
168
|
+
atomicCopyFile(adapterCommonSrc, adapterCommonDest, dryRun, noBackup, 'adapter-common.sh');
|
|
169
|
+
|
|
170
|
+
// Copy adapters/*.sh
|
|
171
|
+
const srcAdaptersDir = path.join(srcDir, 'adapters');
|
|
172
|
+
if (fs.existsSync(srcAdaptersDir)) {
|
|
173
|
+
fs.readdirSync(srcAdaptersDir).forEach(f => {
|
|
174
|
+
if (f.endsWith('.sh')) {
|
|
175
|
+
const src = path.join(srcAdaptersDir, f);
|
|
176
|
+
const dest = path.join(destDir, 'adapters', f);
|
|
177
|
+
atomicCopyFile(src, dest, dryRun, noBackup, `adapters/${f}`);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Copy gate-*.sh scripts from package root to destination.
|
|
185
|
+
* @param {string} srcDir - Package root directory
|
|
186
|
+
* @param {string} destDir - Destination directory
|
|
187
|
+
* @param {boolean} dryRun
|
|
188
|
+
* @param {boolean} noBackup
|
|
189
|
+
*/
|
|
190
|
+
function copyGateScripts(srcDir, destDir, dryRun, noBackup) {
|
|
191
|
+
if (!fs.existsSync(srcDir)) return;
|
|
192
|
+
fs.readdirSync(srcDir).forEach(f => {
|
|
193
|
+
if (f.startsWith('gate-') && f.endsWith('.sh')) {
|
|
194
|
+
const src = path.join(srcDir, f);
|
|
195
|
+
const dest = path.join(destDir, f);
|
|
196
|
+
atomicCopyFile(src, dest, dryRun, noBackup, f);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function resolveSrcDir() {
|
|
202
|
+
return (module.exports && module.exports.getPackageRoot)
|
|
203
|
+
? module.exports.getPackageRoot()
|
|
204
|
+
: getPackageRoot();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function resolveDirs(global) {
|
|
208
|
+
if (global) return { hooksDestDir: GLOBAL_HOOKS_DIR, adaptersDestDir: GLOBAL_ADAPTERS_DIR };
|
|
209
|
+
return { hooksDestDir: getProjectHooksDir(), adaptersDestDir: path.join(process.cwd(), 'githooks') };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function ensureDirsExist(adaptersDestDir, hooksDestDir) {
|
|
213
|
+
fs.mkdirSync(hooksDestDir, { recursive: true });
|
|
214
|
+
fs.mkdirSync(adaptersDestDir, { recursive: true });
|
|
215
|
+
fs.mkdirSync(path.join(adaptersDestDir, 'adapters'), { recursive: true });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function printUpdateHeader(opts) {
|
|
219
|
+
const { global, srcDir, hooksDestDir, adaptersDestDir, scope, dryRun } = opts;
|
|
220
|
+
console.log(`XP-Gate Update Hooks`);
|
|
221
|
+
console.log(`====================`);
|
|
222
|
+
console.log(`Mode: ${global ? 'Global' : 'Local'}`);
|
|
223
|
+
console.log(`Source: ${srcDir}`);
|
|
224
|
+
console.log(`Hooks destination: ${hooksDestDir}`);
|
|
225
|
+
console.log(`Adapters destination: ${adaptersDestDir}`);
|
|
226
|
+
console.log(`Scope: ${scope}`);
|
|
227
|
+
if (dryRun) console.log(`Dry run: yes (no files will be modified)`);
|
|
228
|
+
console.log('');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function checkLocalModifications(srcDir, hooksDestDir, adaptersDestDir, force, dryRun) {
|
|
232
|
+
if (force || dryRun) return 0;
|
|
233
|
+
const localMods = detectLocalModifications(srcDir, hooksDestDir, adaptersDestDir);
|
|
234
|
+
if (localMods.length === 0) return 0;
|
|
235
|
+
console.warn(`[WARN] Detected ${localMods.length} locally modified file(s):`);
|
|
236
|
+
localMods.forEach(f => console.warn(` - ${f}`));
|
|
237
|
+
console.warn('Use --force to overwrite, or manually backup first.');
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function copyByScope(opts) {
|
|
242
|
+
const { scope, srcDir, hooksDestDir, adaptersDestDir, dryRun, noBackup } = opts;
|
|
243
|
+
if (scope === 'all' || scope === 'hooks') {
|
|
244
|
+
printInfo('hooks');
|
|
245
|
+
copyHooks(srcDir, hooksDestDir, dryRun, noBackup);
|
|
246
|
+
}
|
|
247
|
+
if (scope === 'all' || scope === 'adapters') {
|
|
248
|
+
printInfo('adapters');
|
|
249
|
+
copyAdapters(srcDir, adaptersDestDir, dryRun, noBackup);
|
|
250
|
+
}
|
|
251
|
+
if (scope === 'all') {
|
|
252
|
+
printInfo('gate scripts');
|
|
253
|
+
copyGateScripts(srcDir, adaptersDestDir, dryRun, noBackup);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function printInfo(label) { console.log(`Updating ${label}...`); }
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Main entry point: sync latest hook versions from xp-gate package to project or global directory.
|
|
261
|
+
*/
|
|
262
|
+
function updateHooks(options = {}) {
|
|
263
|
+
const { global = false, force = false, dryRun = false, noBackup = false, scope = 'all' } = options;
|
|
264
|
+
const srcDir = resolveSrcDir();
|
|
265
|
+
const { hooksDestDir, adaptersDestDir } = resolveDirs(global);
|
|
266
|
+
|
|
267
|
+
ensureDirsExist(adaptersDestDir, hooksDestDir);
|
|
268
|
+
printUpdateHeader({ global, srcDir, hooksDestDir, adaptersDestDir, scope, dryRun });
|
|
269
|
+
|
|
270
|
+
const modCheck = checkLocalModifications(srcDir, hooksDestDir, adaptersDestDir, force, dryRun);
|
|
271
|
+
if (modCheck !== 0) return modCheck;
|
|
272
|
+
|
|
273
|
+
copyByScope({ scope, srcDir, hooksDestDir, adaptersDestDir, dryRun, noBackup });
|
|
274
|
+
|
|
275
|
+
if (!dryRun) console.log('\nUpdate complete!');
|
|
276
|
+
return 0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
module.exports = {
|
|
280
|
+
updateHooks,
|
|
281
|
+
detectLocalModifications,
|
|
282
|
+
copyHooks,
|
|
283
|
+
copyAdapters,
|
|
284
|
+
copyGateScripts,
|
|
285
|
+
atomicCopyFile,
|
|
286
|
+
getPackageRoot,
|
|
287
|
+
getProjectHooksDir,
|
|
288
|
+
};
|
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Mock layering policy enforcement — Gate M3 of pre-push hook. Ensures integration tests use real implementations for internal dependencies, mock external dependencies, and annotate pending mocks with removal plans. Combines project scope scanning, mock decision engine, and per-file validation into a single pipeline.
|
package/mutation/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MUTATION KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**Gate M** (incremental mutation testing) + **Gate M2** helpers (test-layer detection used by `src/mock-policy/`). Pre-push quality gate. TypeScript-only; uses Stryker.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.4",
|
|
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
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.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.
|
|
@@ -32,9 +32,9 @@ skills/delphi-review/
|
|
|
32
32
|
- 3 experts anonymous in Round 1 (no cross-expert bias)
|
|
33
33
|
- ≥90% consensus threshold (was 95%, now unified to 90%)
|
|
34
34
|
- Max 5 rounds before forcing decision
|
|
35
|
-
- Cross-provider required: experts from ≥2 different providers
|
|
36
|
-
-
|
|
37
|
-
-
|
|
35
|
+
- Cross-provider required: experts from ≥2 different providers (model list read from `opencode.json` agent config, not hardcoded)
|
|
36
|
+
- Model selection: reads `delphi-reviewer-*` agent `model` fields from `opencode.json`
|
|
37
|
+
- No hardcoded model lists — models defined by user's `opencode.json` configuration
|
|
38
38
|
- Code-walkthrough mode: triggered on git push, stores result in .code-walkthrough-result.json
|
|
39
39
|
- Code-walkthrough skipped on main/master pushes (by design)
|
|
40
40
|
|
|
@@ -88,22 +88,44 @@ Permitted variants (all satisfy L1 trigger):
|
|
|
88
88
|
| 2 专家(默认) | A(架构) + B(实现) | 代码变更、小型设计 |
|
|
89
89
|
| 3 专家 | A(架构) + B(实现) + C(可行性) | 架构决策、需求文档 |
|
|
90
90
|
|
|
91
|
-
###
|
|
91
|
+
### 模型选择策略(强制 — 从 opencode.json 读取)
|
|
92
92
|
|
|
93
|
-
**MUST
|
|
93
|
+
**MUST 从 `opencode.json` 的 agent 配置中读取模型**,**严禁** hardcode 模型名称。
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| 阿里 Qwen | `qwen3.6-plus`, `qwen3.5-plus` |
|
|
100
|
-
| 智谱 GLM | `glm-5.1`, `glm-5.0` |
|
|
101
|
-
| MiniMax | `minimax-m2.7`, `minimax-m2.5` |
|
|
95
|
+
模型选择流程:
|
|
96
|
+
1. 读取 `opencode.json` 中 `agent` 字段下 `delphi-reviewer-architecture`、`delphi-reviewer-technical`、`delphi-reviewer-feasibility` 三个 agent 定义
|
|
97
|
+
2. 提取每个 agent 的 `model` 字段(格式:`provider/model-name`)
|
|
98
|
+
3. 分别作为 Expert A(架构)、Expert B(技术)、Expert C(可行性) 的模型
|
|
102
99
|
|
|
103
100
|
**关键原则**:
|
|
104
|
-
- ✅ 三个专家必须来自 **至少 2
|
|
105
|
-
- ❌
|
|
106
|
-
- ❌
|
|
101
|
+
- ✅ 三个专家必须来自 **至少 2 家不同 provider**(通过 `model` 字段的 `provider/` 前缀判断)
|
|
102
|
+
- ❌ 禁止 hardcode 模型名称(模型列表以 `opencode.json` 为准)
|
|
103
|
+
- ❌ 禁止三个专家全部使用同一 provider 的模型
|
|
104
|
+
|
|
105
|
+
**`opencode.json` agent 配置示例**(参考 `opencode.json.delphi.example`):
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"agent": {
|
|
109
|
+
"delphi-reviewer-architecture": {
|
|
110
|
+
"description": "...",
|
|
111
|
+
"mode": "subagent",
|
|
112
|
+
"model": "deepseek/deepseek-chat",
|
|
113
|
+
"tools": { "read": true, "bash": true, "write": false, "edit": false }
|
|
114
|
+
},
|
|
115
|
+
"delphi-reviewer-technical": {
|
|
116
|
+
"mode": "subagent",
|
|
117
|
+
"model": "bailian-coding-plan/qwen3.6-plus",
|
|
118
|
+
"tools": { "read": true, "bash": true, "write": false, "edit": false }
|
|
119
|
+
},
|
|
120
|
+
"delphi-reviewer-feasibility": {
|
|
121
|
+
"mode": "subagent",
|
|
122
|
+
"model": "deepseek/deepseek-chat",
|
|
123
|
+
"tools": { "read": true, "bash": true, "write": false, "edit": false }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
> 上例中 3 个专家使用了 2 个不同 provider(deepseek + bailian-coding-plan),满足跨 provider 要求。**实际模型名称以你的 `opencode.json` 配置为准,无需在 SKILL.md 维护模型列表。**
|
|
107
129
|
|
|
108
130
|
### 共识阈值
|
|
109
131
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → SHIP → LAND → USER ACCEPTANCE → FEEDBACK → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: 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
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.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
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.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.
|
|
@@ -32,9 +32,9 @@ skills/delphi-review/
|
|
|
32
32
|
- 3 experts anonymous in Round 1 (no cross-expert bias)
|
|
33
33
|
- ≥90% consensus threshold (was 95%, now unified to 90%)
|
|
34
34
|
- Max 5 rounds before forcing decision
|
|
35
|
-
- Cross-provider required: experts from ≥2 different providers
|
|
36
|
-
-
|
|
37
|
-
-
|
|
35
|
+
- Cross-provider required: experts from ≥2 different providers (model list read from `opencode.json` agent config, not hardcoded)
|
|
36
|
+
- Model selection: reads `delphi-reviewer-*` agent `model` fields from `opencode.json`
|
|
37
|
+
- No hardcoded model lists — models defined by user's `opencode.json` configuration
|
|
38
38
|
- Code-walkthrough mode: triggered on git push, stores result in .code-walkthrough-result.json
|
|
39
39
|
- Code-walkthrough skipped on main/master pushes (by design)
|
|
40
40
|
|
|
@@ -88,22 +88,44 @@ Permitted variants (all satisfy L1 trigger):
|
|
|
88
88
|
| 2 专家(默认) | A(架构) + B(实现) | 代码变更、小型设计 |
|
|
89
89
|
| 3 专家 | A(架构) + B(实现) + C(可行性) | 架构决策、需求文档 |
|
|
90
90
|
|
|
91
|
-
###
|
|
91
|
+
### 模型选择策略(强制 — 从 opencode.json 读取)
|
|
92
92
|
|
|
93
|
-
**MUST
|
|
93
|
+
**MUST 从 `opencode.json` 的 agent 配置中读取模型**,**严禁** hardcode 模型名称。
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| 阿里 Qwen | `qwen3.6-plus`, `qwen3.5-plus` |
|
|
100
|
-
| 智谱 GLM | `glm-5.1`, `glm-5.0` |
|
|
101
|
-
| MiniMax | `minimax-m2.7`, `minimax-m2.5` |
|
|
95
|
+
模型选择流程:
|
|
96
|
+
1. 读取 `opencode.json` 中 `agent` 字段下 `delphi-reviewer-architecture`、`delphi-reviewer-technical`、`delphi-reviewer-feasibility` 三个 agent 定义
|
|
97
|
+
2. 提取每个 agent 的 `model` 字段(格式:`provider/model-name`)
|
|
98
|
+
3. 分别作为 Expert A(架构)、Expert B(技术)、Expert C(可行性) 的模型
|
|
102
99
|
|
|
103
100
|
**关键原则**:
|
|
104
|
-
- ✅ 三个专家必须来自 **至少 2
|
|
105
|
-
- ❌
|
|
106
|
-
- ❌
|
|
101
|
+
- ✅ 三个专家必须来自 **至少 2 家不同 provider**(通过 `model` 字段的 `provider/` 前缀判断)
|
|
102
|
+
- ❌ 禁止 hardcode 模型名称(模型列表以 `opencode.json` 为准)
|
|
103
|
+
- ❌ 禁止三个专家全部使用同一 provider 的模型
|
|
104
|
+
|
|
105
|
+
**`opencode.json` agent 配置示例**(参考 `opencode.json.delphi.example`):
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"agent": {
|
|
109
|
+
"delphi-reviewer-architecture": {
|
|
110
|
+
"description": "...",
|
|
111
|
+
"mode": "subagent",
|
|
112
|
+
"model": "deepseek/deepseek-chat",
|
|
113
|
+
"tools": { "read": true, "bash": true, "write": false, "edit": false }
|
|
114
|
+
},
|
|
115
|
+
"delphi-reviewer-technical": {
|
|
116
|
+
"mode": "subagent",
|
|
117
|
+
"model": "bailian-coding-plan/qwen3.6-plus",
|
|
118
|
+
"tools": { "read": true, "bash": true, "write": false, "edit": false }
|
|
119
|
+
},
|
|
120
|
+
"delphi-reviewer-feasibility": {
|
|
121
|
+
"mode": "subagent",
|
|
122
|
+
"model": "deepseek/deepseek-chat",
|
|
123
|
+
"tools": { "read": true, "bash": true, "write": false, "edit": false }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
> 上例中 3 个专家使用了 2 个不同 provider(deepseek + bailian-coding-plan),满足跨 provider 要求。**实际模型名称以你的 `opencode.json` 配置为准,无需在 SKILL.md 维护模型列表。**
|
|
107
129
|
|
|
108
130
|
### 共识阈值
|
|
109
131
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → SHIP → LAND → USER ACCEPTANCE → FEEDBACK → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: 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
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.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.12.
|
|
3
|
+
"version": "0.12.4",
|
|
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
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-03
|
|
4
|
+
**Commit:** c3ed581
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.4.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.
|
|
@@ -32,9 +32,9 @@ skills/delphi-review/
|
|
|
32
32
|
- 3 experts anonymous in Round 1 (no cross-expert bias)
|
|
33
33
|
- ≥90% consensus threshold (was 95%, now unified to 90%)
|
|
34
34
|
- Max 5 rounds before forcing decision
|
|
35
|
-
- Cross-provider required: experts from ≥2 different providers
|
|
36
|
-
-
|
|
37
|
-
-
|
|
35
|
+
- Cross-provider required: experts from ≥2 different providers (model list read from `opencode.json` agent config, not hardcoded)
|
|
36
|
+
- Model selection: reads `delphi-reviewer-*` agent `model` fields from `opencode.json`
|
|
37
|
+
- No hardcoded model lists — models defined by user's `opencode.json` configuration
|
|
38
38
|
- Code-walkthrough mode: triggered on git push, stores result in .code-walkthrough-result.json
|
|
39
39
|
- Code-walkthrough skipped on main/master pushes (by design)
|
|
40
40
|
|