@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.
Files changed (54) hide show
  1. package/adapters/cpp.sh +0 -0
  2. package/adapters/dart.sh +0 -0
  3. package/adapters/flutter.sh +0 -0
  4. package/adapters/go.sh +0 -0
  5. package/adapters/java.sh +0 -0
  6. package/adapters/kotlin.sh +0 -0
  7. package/adapters/objectivec.sh +0 -0
  8. package/adapters/powershell.sh +0 -0
  9. package/adapters/python.sh +0 -0
  10. package/adapters/shell.sh +0 -0
  11. package/adapters/swift.sh +0 -0
  12. package/adapters/typescript.sh +0 -0
  13. package/bin/xp-gate.js +19 -5
  14. package/gate-3.sh +0 -0
  15. package/gate-4.sh +0 -0
  16. package/gate-7.sh +0 -0
  17. package/gate-8.sh +0 -0
  18. package/gate-9.sh +0 -0
  19. package/lib/__tests__/update-hooks.test.js +573 -0
  20. package/lib/init.js +9 -6
  21. package/lib/sprint-status.js +35 -1
  22. package/lib/update-hooks.js +288 -0
  23. package/mock-policy/AGENTS.md +3 -3
  24. package/mutation/AGENTS.md +3 -3
  25. package/package.json +1 -1
  26. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  27. package/plugins/claude-code/skills/delphi-review/AGENTS.md +6 -6
  28. package/plugins/claude-code/skills/delphi-review/SKILL.md +34 -12
  29. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
  30. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
  31. package/plugins/opencode/package.json +1 -1
  32. package/plugins/opencode/skills/delphi-review/AGENTS.md +6 -6
  33. package/plugins/opencode/skills/delphi-review/SKILL.md +34 -12
  34. package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
  35. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
  36. package/plugins/qoder/plugin.json +1 -1
  37. package/plugins/qoder/skills/delphi-review/AGENTS.md +6 -6
  38. package/plugins/qoder/skills/delphi-review/SKILL.md +198 -264
  39. package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
  40. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
  41. package/principles/AGENTS.md +3 -3
  42. package/skills/delphi-review/AGENTS.md +6 -6
  43. package/skills/delphi-review/SKILL.md +34 -12
  44. package/skills/sprint-flow/AGENTS.md +3 -3
  45. package/skills/test-specification-alignment/AGENTS.md +3 -3
  46. package/lib/__tests__/next-sprint.test.js +0 -231
  47. package/lib/next-sprint.js +0 -129
  48. package/lib/shared-phase-constants.d.ts +0 -17
  49. package/lib/shared-phase-constants.js +0 -77
  50. package/plugins/opencode/__tests__/tui-plugin.test.ts +0 -543
  51. package/plugins/opencode/__tests__/xp-gate-e2e-upgrade.test.ts +0 -562
  52. package/plugins/opencode/__tests__/xp-gate-update.test.ts +0 -518
  53. package/plugins/opencode/tui-plugin.ts +0 -414
  54. package/plugins/opencode/tui-plugin.tsx +0 -306
@@ -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
+ };
@@ -1,9 +1,9 @@
1
1
  # SRC/MOCK-POLICY KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-07-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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.
@@ -1,9 +1,9 @@
1
1
  # SRC/MUTATION KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-07-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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": "@boyingliu01/xp-gate",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
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.12.2",
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-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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
- - Domestic models only: glm, kimi, minimax, qwen, deepseek
37
- - Foreign models forbidden: Anthropic, OpenAI, Google
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 使用国产开源模型**,**严禁** Anthropic/GPT/Gemini 等国外模型。
93
+ **MUST `opencode.json` 的 agent 配置中读取模型**,**严禁** hardcode 模型名称。
94
94
 
95
- | 厂家 | 可用模型 |
96
- |------|---------|
97
- | 深度求索 DeepSeek | `deepseek-v4-pro`, `deepseek-v4-lite` |
98
- | 月之暗面 Kimi | `kimi-k2.6`, `kimi-k2.5` |
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
- - ❌ 禁止使用 Anthropic、OpenAI、Google 等国外模型
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-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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": "@boyingliu01/opencode-plugin",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
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
- **Generated:** 2026-07-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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
- - Domestic models only: glm, kimi, minimax, qwen, deepseek
37
- - Foreign models forbidden: Anthropic, OpenAI, Google
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 使用国产开源模型**,**严禁** Anthropic/GPT/Gemini 等国外模型。
93
+ **MUST `opencode.json` 的 agent 配置中读取模型**,**严禁** hardcode 模型名称。
94
94
 
95
- | 厂家 | 可用模型 |
96
- |------|---------|
97
- | 深度求索 DeepSeek | `deepseek-v4-pro`, `deepseek-v4-lite` |
98
- | 月之暗面 Kimi | `kimi-k2.6`, `kimi-k2.5` |
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
- - ❌ 禁止使用 Anthropic、OpenAI、Google 等国外模型
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-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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.2",
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-01
4
- **Commit:** 58ec6df
3
+ **Generated:** 2026-07-03
4
+ **Commit:** c3ed581
5
5
  **Branch:** main
6
- **Version:** 0.12.2.0
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
- - Domestic models only: glm, kimi, minimax, qwen, deepseek
37
- - Foreign models forbidden: Anthropic, OpenAI, Google
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