@boyingliu01/xp-gate 0.6.0 → 0.7.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.
@@ -0,0 +1,172 @@
1
+ <style>
2
+ :root {
3
+ --sd-bg: var(--vscode-editor-background, #1e1e1e);
4
+ --sd-fg: var(--vscode-editor-foreground, #d4d4d4);
5
+ --sd-border: var(--vscode-panel-border, #333);
6
+ --sd-pass: var(--vscode-testing-iconPassed, #73c991);
7
+ --sd-fail: var(--vscode-testing-iconFailed, #f14c4c);
8
+ --sd-skip: var(--vscode-descriptionForeground, #888);
9
+ --sd-accent: var(--vscode-focusBorder, #007acc);
10
+ --sd-card-bg: var(--vscode-editor-widget-background, #252526);
11
+ --sd-active: var(--vscode-charts-yellow, #e5c07b);
12
+ }
13
+ * { box-sizing: border-box; margin: 0; padding: 0; }
14
+ body { font-family: var(--vscode-font-family, 'Segoe UI', sans-serif); color: var(--sd-fg); background: var(--sd-bg); padding: 16px; }
15
+ .sd-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
16
+ .sd-header h2 { font-size: 16px; font-weight: 600; }
17
+ .sd-status-badge { padding: 4px 12px; border-radius: 4px; font-size: 12px; font-weight: 600; text-transform: uppercase; }
18
+ .sd-status-badge.running { background: color-mix(in srgb, var(--sd-accent) 20%, transparent); color: var(--sd-accent); border: 1px solid var(--sd-accent); }
19
+ .sd-status-badge.paused { background: color-mix(in srgb, var(--sd-active) 20%, transparent); color: var(--sd-active); border: 1px solid var(--sd-active); }
20
+ .sd-status-badge.completed, .sd-status-badge.merged { background: color-mix(in srgb, var(--sd-pass) 20%, transparent); color: var(--sd-pass); border: 1px solid var(--sd-pass); }
21
+ .sd-meta { font-size: 12px; color: var(--sd-skip); margin-bottom: 16px; }
22
+ .sd-phase-track { display: flex; align-items: center; gap: 4px; margin-bottom: 20px; overflow-x: auto; padding-bottom: 4px; }
23
+ .sd-phase { display: flex; flex-direction: column; align-items: center; min-width: 72px; }
24
+ .sd-phase-dot { width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; border: 2px solid var(--sd-border); color: var(--sd-skip); background: var(--sd-bg); }
25
+ .sd-phase-dot.done { background: color-mix(in srgb, var(--sd-pass) 20%, transparent); border-color: var(--sd-pass); color: var(--sd-pass); }
26
+ .sd-phase-dot.active { background: color-mix(in srgb, var(--sd-accent) 25%, transparent); border-color: var(--sd-accent); color: var(--sd-accent); animation: pulse 1.5s infinite; }
27
+ .sd-phase-dot.future { border-color: var(--sd-border); color: var(--sd-skip); }
28
+ .sd-phase-label { font-size: 10px; margin-top: 4px; color: var(--sd-skip); text-align: center; white-space: nowrap; }
29
+ .sd-phase-label.active { color: var(--sd-accent); font-weight: 600; }
30
+ .sd-phase-label.done { color: var(--sd-pass); }
31
+ .sd-phase-line { width: 16px; height: 2px; background: var(--sd-border); margin-bottom: 20px; }
32
+ .sd-phase-line.done { background: var(--sd-pass); }
33
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }
34
+ .sd-section { margin-bottom: 16px; }
35
+ .sd-section h3 { font-size: 14px; font-weight: 600; margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--sd-border); }
36
+ .sd-progress-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
37
+ .sd-progress-row .label { font-size: 13px; min-width: 100px; }
38
+ .sd-progress-row .bar-track { flex: 1; height: 10px; background: var(--sd-border); border-radius: 5px; overflow: hidden; }
39
+ .sd-progress-row .bar-fill { height: 100%; border-radius: 5px; background: var(--sd-accent); transition: width 0.4s ease; }
40
+ .sd-progress-row .count { font-size: 13px; font-weight: 600; min-width: 60px; text-align: right; }
41
+ .sd-outputs { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px; }
42
+ .sd-output-item { background: var(--sd-card-bg); border: 1px solid var(--sd-border); border-radius: 4px; padding: 8px 10px; font-size: 12px; }
43
+ .sd-output-item .key { color: var(--sd-skip); font-size: 11px; }
44
+ .sd-output-item .val { margin-top: 2px; font-weight: 500; word-break: break-all; }
45
+ .sd-metrics { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
46
+ .sd-metric-card { background: var(--sd-card-bg); border: 1px solid var(--sd-border); border-radius: 6px; padding: 10px 14px; text-align: center; min-width: 100px; }
47
+ .sd-metric-card .value { font-size: 22px; font-weight: 700; color: var(--sd-accent); }
48
+ .sd-metric-card .label { font-size: 11px; color: var(--sd-skip); margin-top: 2px; }
49
+ .sd-learnings { list-style: none; }
50
+ .sd-learnings li { padding: 6px 0; font-size: 12px; border-bottom: 1px solid var(--sd-border); }
51
+ .sd-learnings li:last-child { border-bottom: none; }
52
+ .sd-learnings .cat { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 600; background: var(--sd-card-bg); border: 1px solid var(--sd-border); margin-right: 6px; }
53
+ .sd-empty { text-align: center; padding: 32px; color: var(--sd-skip); font-size: 13px; }
54
+ </style>
55
+
56
+ <div id="sd-root"></div>
57
+
58
+ <script>
59
+ (function() {
60
+ const data = window.__WIDGET_DATA__ || {};
61
+ const root = document.getElementById('sd-root');
62
+
63
+ if (!data || (!data.phase && !data.id && !data.status)) {
64
+ root.innerHTML = '<div class="sd-empty">No sprint state data available.<br>Start a sprint with /sprint-flow to see the dashboard.</div>';
65
+ return;
66
+ }
67
+
68
+ const PHASES = [
69
+ { num: -1, name: 'ISOLATE' },
70
+ { num: 0, name: 'THINK' },
71
+ { num: 1, name: 'PLAN' },
72
+ { num: 2, name: 'BUILD' },
73
+ { num: 3, name: 'REVIEW' },
74
+ { num: 4, name: 'UAT' },
75
+ { num: 5, name: 'FEEDBACK' },
76
+ { num: 6, name: 'SHIP' },
77
+ { num: 7, name: 'LAND' },
78
+ { num: 8, name: 'CLEANUP' }
79
+ ];
80
+
81
+ const currentPhase = data.phase !== undefined ? data.phase : -2;
82
+ const status = data.status || 'unknown';
83
+ const outputs = data.outputs || {};
84
+ const metrics = data.metrics || {};
85
+ const learnings = data.learnings || [];
86
+
87
+ let html = '';
88
+
89
+ // Header
90
+ html += '<div class="sd-header">';
91
+ html += '<h2>Sprint' + (data.id ? ' — ' + esc(data.id) : '') + '</h2>';
92
+ const statusCls = ['running', 'paused', 'completed', 'merged'].includes(status) ? status : 'running';
93
+ html += '<span class="sd-status-badge ' + statusCls + '">' + esc(status) + '</span>';
94
+ html += '</div>';
95
+
96
+ // Phase progress track
97
+ html += '<div class="sd-phase-track">';
98
+ for (let i = 0; i < PHASES.length; i++) {
99
+ const p = PHASES[i];
100
+ if (i > 0) {
101
+ const lineCls = p.num <= currentPhase ? 'done' : '';
102
+ html += '<div class="sd-phase-line ' + lineCls + '"></div>';
103
+ }
104
+ let dotCls = 'future';
105
+ if (p.num < currentPhase) dotCls = 'done';
106
+ else if (p.num === currentPhase) dotCls = 'active';
107
+ const lblCls = p.num < currentPhase ? 'done' : p.num === currentPhase ? 'active' : '';
108
+ const icon = p.num < currentPhase ? '✓' : p.num === currentPhase ? '▶' : String(p.num);
109
+ html += '<div class="sd-phase">';
110
+ html += '<div class="sd-phase-dot ' + dotCls + '">' + icon + '</div>';
111
+ html += '<div class="sd-phase-label ' + lblCls + '">' + esc(p.name) + '</div>';
112
+ html += '</div>';
113
+ }
114
+ html += '</div>';
115
+
116
+ // Metrics cards
117
+ if (metrics.tests_passed !== undefined || metrics.coverage_pct !== undefined || metrics.tests_failed !== undefined) {
118
+ html += '<div class="sd-metrics">';
119
+ if (metrics.tests_passed !== undefined) {
120
+ html += '<div class="sd-metric-card"><div class="value">' + metrics.tests_passed + '</div><div class="label">Tests Passed</div></div>';
121
+ }
122
+ if (metrics.tests_failed !== undefined) {
123
+ html += '<div class="sd-metric-card"><div class="value" style="color:' + (metrics.tests_failed > 0 ? 'var(--sd-fail)' : 'var(--sd-pass)') + '">' + metrics.tests_failed + '</div><div class="label">Tests Failed</div></div>';
124
+ }
125
+ if (metrics.coverage_pct !== undefined) {
126
+ html += '<div class="sd-metric-card"><div class="value" style="color:' + (metrics.coverage_pct >= 80 ? 'var(--sd-pass)' : 'var(--sd-fail)') + '">' + metrics.coverage_pct + '%</div><div class="label">Coverage</div></div>';
127
+ }
128
+ html += '</div>';
129
+ }
130
+
131
+ // REQ progress
132
+ if (data.req_progress || data.reqs) {
133
+ const rp = data.req_progress || {};
134
+ const done = rp.done || 0;
135
+ const totalReqs = rp.total || (data.reqs ? data.reqs.length : 0);
136
+ const pct = totalReqs > 0 ? Math.round((done / totalReqs) * 100) : 0;
137
+ html += '<div class="sd-section"><h3>REQ Progress</h3>';
138
+ html += '<div class="sd-progress-row">';
139
+ html += '<span class="label">Completed</span>';
140
+ html += '<div class="bar-track"><div class="bar-fill" style="width:' + pct + '%"></div></div>';
141
+ html += '<span class="count">' + done + '/' + totalReqs + '</span>';
142
+ html += '</div></div>';
143
+ }
144
+
145
+ // Phase outputs
146
+ const outputKeys = Object.keys(outputs);
147
+ if (outputKeys.length > 0) {
148
+ html += '<div class="sd-section"><h3>Phase Outputs</h3>';
149
+ html += '<div class="sd-outputs">';
150
+ for (const key of outputKeys) {
151
+ html += '<div class="sd-output-item"><div class="key">' + esc(key) + '</div><div class="val">' + esc(outputs[key]) + '</div></div>';
152
+ }
153
+ html += '</div></div>';
154
+ }
155
+
156
+ // Learnings
157
+ if (learnings.length > 0) {
158
+ html += '<div class="sd-section"><h3>Recent Learnings</h3>';
159
+ html += '<ul class="sd-learnings">';
160
+ const recent = learnings.slice(-5).reverse();
161
+ for (const l of recent) {
162
+ const cat = l.category || 'general';
163
+ html += '<li><span class="cat">' + esc(cat) + '</span>' + esc(l.summary || l.text || JSON.stringify(l)) + '</li>';
164
+ }
165
+ html += '</ul></div>';
166
+ }
167
+
168
+ root.innerHTML = html;
169
+
170
+ function esc(s) { const d = document.createElement('div'); d.textContent = String(s); return d.innerHTML; }
171
+ })();
172
+ </script>
@@ -316,6 +316,54 @@ Every review round output MUST follow this exact JSON structure:
316
316
 
317
317
  ---
318
318
 
319
+ ## Qoder 平台适配
320
+
321
+ 在 Qoder IDE 中,delphi-review 的多专家评审通过以下方式实现:
322
+
323
+ ### 多模型评审(替代 OpenCode 的多 agent 配置)
324
+
325
+ 利用 Qoder 的多模型访问能力(类似 coding plan),通过 Agent subagent 派发不同模型完成 Expert A/B/C 评审:
326
+
327
+ | 专家 | 角色 | Qoder Subagent 映射 | 说明 |
328
+ |------|------|---------------------|------|
329
+ | Expert A (架构) | 架构审查 | **plan-agent** subagent | 适合架构级分析 |
330
+ | Expert B (技术) | 实现审查 | **CodeReview** subagent | 代码审查天然适合 |
331
+ | Expert C (可行性) | 可行性仲裁 | **plan-agent** subagent(不同 prompt) | 与 Expert A 使用不同的评审 prompt |
332
+
333
+ **执行流程**:
334
+ 1. orchestrator 准备评审材料(设计文档/代码变更)
335
+ 2. 分别派发 2-3 个 Agent subagent,每个 subagent 携带对应专家的 system prompt
336
+ 3. 收集各专家评审结果 → 合并为共识报告
337
+ 4. 如未达成共识 → 迭代(携带其他专家意见重新评审)
338
+
339
+ ### 专家配置
340
+
341
+ 专家→模型映射通过 `.qoder/delphi-config.json` 配置:
342
+
343
+ ```json
344
+ {
345
+ "experts": {
346
+ "A": { "role": "architecture", "model_hint": "deepseek-v4-pro" },
347
+ "B": { "role": "implementation", "model_hint": "kimi-k2.6" },
348
+ "C": { "role": "feasibility", "model_hint": "qwen3.6-plus" }
349
+ },
350
+ "consensus_threshold": 0.95,
351
+ "max_rounds": 5
352
+ }
353
+ ```
354
+
355
+ > **注意**:`model_hint` 是建议模型,实际使用的模型取决于 Qoder 的模型调度策略。
356
+
357
+ ### 降级方案
358
+
359
+ 如果多模型 subagent 调用不可用,降级为**单模型多角色模式**:
360
+ - 同一模型分别扮演 Expert A/B/C(不同 system prompt)
361
+ - 明确标注降级警告:`[DEGRADED] 单模型多角色模式,失去跨 provider 匿名性保护`
362
+
363
+ 详细配置和执行指南参见 `references/qoder-multi-model.md`。
364
+
365
+ ---
366
+
319
367
  ## Anti-Patterns
320
368
 
321
369
  | ❌ 错误 | ✅ 正确 |
@@ -0,0 +1,191 @@
1
+ # Qoder Multi-Model Review Guide for Delphi Review
2
+
3
+ **Version:** v0.6.0
4
+ **Platform:** Qoder IDE
5
+ **Status:** Active
6
+
7
+ ---
8
+
9
+ ## 1. Overview
10
+
11
+ Delphi Review requires multi-expert anonymous consensus review using at least 2 different LLM providers. In Qoder, this is achieved through Agent subagent dispatch, leveraging Qoder's built-in multi-model capability.
12
+
13
+ ---
14
+
15
+ ## 2. Expert Configuration
16
+
17
+ ### 2.1 Configuration File
18
+
19
+ Create `.qoder/delphi-config.json` in project root:
20
+
21
+ ```json
22
+ {
23
+ "experts": {
24
+ "A": {
25
+ "role": "architecture",
26
+ "focus": "System design, scalability, maintainability, SOLID principles",
27
+ "model_hint": "deepseek-v4-pro"
28
+ },
29
+ "B": {
30
+ "role": "implementation",
31
+ "focus": "Code quality, testing strategy, error handling, performance",
32
+ "model_hint": "kimi-k2.6"
33
+ },
34
+ "C": {
35
+ "role": "feasibility",
36
+ "focus": "Practical constraints, timeline, team capability, risk assessment",
37
+ "model_hint": "qwen3.6-plus"
38
+ }
39
+ },
40
+ "consensus_threshold": 0.95,
41
+ "max_rounds": 5,
42
+ "providers_required": 2
43
+ }
44
+ ```
45
+
46
+ ### 2.2 Model Selection Rules
47
+
48
+ - Experts MUST come from **at least 2 different providers**
49
+ - **Forbidden**: Anthropic, OpenAI, Google (foreign models)
50
+ - **Recommended domestic providers**: DeepSeek, Qwen (Alibaba), Kimi (Moonshot), GLM (Zhipu), MiniMax
51
+
52
+ ---
53
+
54
+ ## 3. Execution Flow in Qoder
55
+
56
+ ### 3.1 Round 1: Independent Anonymous Review
57
+
58
+ For each expert, dispatch an Agent subagent with the expert's specific prompt:
59
+
60
+ **Expert A (Architecture) — plan-agent**:
61
+ ```
62
+ Agent(subagent_type="plan-agent", prompt="""
63
+ You are Expert A in a Delphi consensus review. Your role: Architecture Reviewer.
64
+ Focus: System design, scalability, maintainability, SOLID principles.
65
+
66
+ Review the following design/code and provide your assessment:
67
+ [REVIEW MATERIAL]
68
+
69
+ Output format:
70
+ {
71
+ "expert_id": "A",
72
+ "verdict": "APPROVED|REQUEST_CHANGES|REJECTED",
73
+ "issues": [...],
74
+ "strengths": [...],
75
+ "suggestions": [...]
76
+ }
77
+ """)
78
+ ```
79
+
80
+ **Expert B (Implementation) — CodeReview subagent**:
81
+ ```
82
+ Agent(subagent_type="CodeReview", prompt="""
83
+ You are Expert B in a Delphi consensus review. Your role: Implementation Reviewer.
84
+ Focus: Code quality, testing strategy, error handling, performance.
85
+
86
+ Review the following code changes:
87
+ [CHANGED FILES]
88
+ """)
89
+ ```
90
+
91
+ **Expert C (Feasibility) — plan-agent**:
92
+ ```
93
+ Agent(subagent_type="plan-agent", prompt="""
94
+ You are Expert C in a Delphi consensus review. Your role: Feasibility Arbiter.
95
+ Focus: Practical constraints, timeline, team capability, risk assessment.
96
+
97
+ Review the following design/code and provide your assessment:
98
+ [REVIEW MATERIAL]
99
+
100
+ Output format:
101
+ {
102
+ "expert_id": "C",
103
+ "verdict": "APPROVED|REQUEST_CHANGES|REJECTED",
104
+ ...
105
+ }
106
+ """)
107
+ ```
108
+
109
+ ### 3.2 Consensus Aggregation
110
+
111
+ After all experts respond:
112
+ 1. Parse each expert's JSON output
113
+ 2. Compare verdicts:
114
+ - All APPROVED → **Consensus: APPROVED**
115
+ - All REQUEST_CHANGES → Merge issues, present to user
116
+ - Mixed verdicts → **No consensus**, proceed to Round 2
117
+ 3. Calculate issue consensus ratio: issues agreed by ≥95% of experts → resolved
118
+
119
+ ### 3.3 Round 2+: Controlled Feedback
120
+
121
+ In subsequent rounds, each expert receives other experts' anonymized opinions:
122
+ ```
123
+ Agent(subagent_type="plan-agent", prompt="""
124
+ You are Expert A. In Round 1, your verdict was: REQUEST_CHANGES.
125
+ Other experts' anonymized feedback:
126
+ - Expert X: APPROVED, noted [strengths]
127
+ - Expert Y: REQUEST_CHANGES, noted [issues]
128
+
129
+ Review your assessment in light of others' feedback. Maintain your independence.
130
+ [REVIEW MATERIAL]
131
+ """)
132
+ ```
133
+
134
+ ### 3.4 Terminal States
135
+
136
+ | Condition | Action |
137
+ |-----------|--------|
138
+ | All experts APPROVED + ≥95% issue consensus | **APPROVED** — write `.sprint-state/delphi-reviewed.json` |
139
+ | Max rounds reached without consensus | **REJECTED** — present disagreement summary |
140
+ | Any expert REJECTED with critical issues | **REQUEST_CHANGES** — user must fix and re-review |
141
+
142
+ ---
143
+
144
+ ## 4. Degraded Mode
145
+
146
+ When multi-model subagent dispatch is unavailable:
147
+
148
+ ### 4.1 Single-Model Multi-Role Mode
149
+
150
+ The orchestrator plays all expert roles sequentially with different prompts:
151
+
152
+ ```
153
+ ⚠️ [DEGRADED] 单模型多角色模式
154
+ 失去跨 provider 匿名性保护,但保留多视角评审结构。
155
+ 建议:在条件允许时恢复多模型模式重新评审。
156
+ ```
157
+
158
+ ### 4.2 Degraded Output Format
159
+
160
+ ```json
161
+ {
162
+ "mode": "design",
163
+ "verdict": "APPROVED",
164
+ "degraded": true,
165
+ "degradation_reason": "Multi-model subagent unavailable",
166
+ "experts": ["A", "B", "C"],
167
+ "model": "single"
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## 5. Integration with Sprint Flow
174
+
175
+ ### 5.1 Phase 1 (Design Review)
176
+
177
+ - Default: 2 experts (A + B)
178
+ - Complex designs: 3 experts (A + B + C)
179
+ - Output: `.sprint-state/delphi-reviewed.json` + `specification.yaml`
180
+
181
+ ### 5.2 Phase 3 (Code Walkthrough)
182
+
183
+ - Default: 2 experts (A + B)
184
+ - Use `CodeReview` subagent for Expert B
185
+ - Output: `.code-walkthrough-result.json`
186
+
187
+ ### 5.3 HARD-GATE Enforcement
188
+
189
+ - Phase 2 BUILD cannot start until delphi-review verdict is APPROVED
190
+ - In Qoder: Pre-Edit Gate checks `.sprint-state/delphi-reviewed.json`
191
+ - See sprint-flow SKILL.md for Pre-Edit Gate details
@@ -297,6 +297,46 @@ Phase 0, 1, 3-6 行为完全不变。
297
297
 
298
298
  ---
299
299
 
300
+ ## Qoder 平台适配
301
+
302
+ ### Subagent Dispatch(替代 OpenCode 的 `task()` API)
303
+
304
+ 在 Qoder 环境中,ralph-loop 的 subagent 派发使用以下方式:
305
+
306
+ | 原调用 | Qoder 替代 | 说明 |
307
+ |---------|------------|------|
308
+ | `task(category="unspecified-high", load_skills=["test-driven-development"])` | **orchestrator 直接执行** | ralph-loop 逐 REQ 迭代,每个 REQ 在干净上下文中执行,不需要独立 subagent |
309
+ | `gstack/learn` | **Qoder Memory 系统** | permanent learnings → `UpdateMemory`;contextual learnings → 会话上下文 |
310
+
311
+ ### Learnings 持久化(替代 gstack/learn)
312
+
313
+ ralph-loop 的 learnings 分类机制在 Qoder 中通过 Memory 系统实现更优雅的持久化:
314
+
315
+ | Learnings 类型 | 原方案 | Qoder 替代 |
316
+ |---------------|--------|------------|
317
+ | **permanent** | progress.log + AGENTS.md | `UpdateMemory`(project_introduction / expert_experience / development_practice_specification 类型) |
318
+ | **contextual** | progress.log(最近 3 条) | 当前会话上下文传递,不持久化 |
319
+ | **Sprint retro** | gstack/learn | Phase 5 结束时 `UpdateMemory` 写入 |
320
+
321
+ **执行方式**:每个 REQ 完成后,orchestrator 调用 `UpdateMemory` 存储 permanent learnings:
322
+ - 架构决策 → `expert_experience` 类型
323
+ - 接口约定/全局规范 → `development_practice_specification` 类型
324
+ - 项目结构发现 → `project_introduction` 类型
325
+
326
+ ### 三层验证 Gate 增强(替代 PostToolUse Hook)
327
+
328
+ 在 Qoder 中,三层验证 Gate 增加 principles 检查步骤:
329
+
330
+ | 层级 | 原验证 | Qoder 增强 |
331
+ |------|--------|------------|
332
+ | L1 | typecheck + lint | + **principles check**(`npx -y tsx src/principles/index.ts --files <changed> --format console`) |
333
+ | L2 | 全量测试 | 无变化 |
334
+ | L3 | coverage ≥ 80% | 无变化 |
335
+
336
+ > **注意**:principles check 仅在 src/principles/ 存在时执行(非 xp-gate 项目跳过)。
337
+
338
+ ---
339
+
300
340
  ## Anti-Patterns
301
341
 
302
342
  | ❌ 错误 | ✅ 正确 |
@@ -263,6 +263,25 @@ Phase 2 第一步必须执行 DELPHI-GATE 检查。没有 delphi-review APPROVED
263
263
  3. 验证 `verdict` 字段 == `"APPROVED"` → 不等于 → 同上 BLOCK
264
264
  4. ✅ 通过 → 进入 BUILD 编码
265
265
 
266
+ **⚠️ Qoder Pre-Edit Gate(MANDATORY — 替代 Claude Code 的 delphi-review-guard.sh Hook)**:
267
+
268
+ 在 Qoder 环境中,由于没有 PreToolUse/PostToolUse 文件系统钩子,orchestrator **MUST** 在每次文件编辑/写入操作之前执行以下检查:
269
+
270
+ 1. 检查 `.sprint-state/` 目录是否存在 → 不存在 → 跳过检查(非 sprint 项目)
271
+ 2. 读取 `.sprint-state/delphi-reviewed.json` → 文件不存在 → **BLOCK**: 输出 `[DELPHI-GATE] delphi-review not APPROVED. 请先运行 /delphi-review`
272
+ 3. `verdict` != `"APPROVED"` → **BLOCK**
273
+ 4. `verdict` == `"APPROVED"` → 允许编辑
274
+
275
+ 此检查在 Phase 2 至 Phase 6 期间持续生效。orchestrator 不可绕过此检查。
276
+
277
+ **Post-REQ Principles Check(替代 Claude Code 的 PostToolUse xp-gate-check Hook)**:
278
+
279
+ 每个 REQ 完成后(ralph-loop 三层验证 Gate 之后),orchestrator **MUST** 运行:
280
+ ```bash
281
+ npx -y tsx src/principles/index.ts --files "<changed_files>" --format console
282
+ ```
283
+ 如果 src/principles/ 不存在(非 xp-gate 项目),则跳过此步骤。
284
+
266
285
  **输入**: `slices-manifest.json`(由 Phase 1 `/to-issues` 生成),按 `execution_order` 逐个执行。
267
286
 
268
287
  **默认模式**: `ralph-loop` — 逐 REQ/切片 迭代构建。每个切片(REQ)dispatch 独立 subagent,干净上下文,全量回归测试。Token 节约 40-67%。参见 `skills/ralph-loop/SKILL.md`。
@@ -425,6 +444,55 @@ Phase 2 第一步必须执行 DELPHI-GATE 检查。没有 delphi-review APPROVED
425
444
  | 7 | LAND | ✅ | `deep` | `["land-and-deploy"]` | subagent |
426
445
  | 8 | CLEANUP | ❌ | Bash(直接执行) | 无 | orchestrator |
427
446
 
447
+ ### Qoder Agent Dispatch Mapping(Qoder 平台替代方案)
448
+
449
+ 在 Qoder 环境中,OpenCode 的 `task()` API 和 superpowers/gstack 外部 skill 不可用。以下映射表说明每个 Phase 在 Qoder 中的执行方式:
450
+
451
+ | Phase | 原 task()/skill 调用 | Qoder 替代方案 | 说明 |
452
+ |-------|----------------------|--------------|------|
453
+ | -1 ISOLATE | Bash 直接执行 | **Bash 直接执行**(无变化) | git worktree 操作平台无关 |
454
+ | -0.5 AUTO-ESTIMATE | Bash 直接执行 | **Bash 直接执行**(无变化) | grep -rn 平台无关 |
455
+ | 0 THINK | `task(deep, brainstorming)` | **plan-agent subagent** | 需求探索与设计适合 plan-agent |
456
+ | 1 PLAN | `task(deep, autoplan+delphi+to-issues)` | **plan-agent subagent** | 规划类任务 |
457
+ | 2 BUILD | `ralph-loop` + 外部 skill | **orchestrator 直接执行** | ralph-loop 逐 REQ 迭代,不需要独立 subagent |
458
+ | 2 步骤 4 | `requesting-code-review` | **CodeReview subagent** | 代码盲评天然适合 CodeReview agent |
459
+ | 2 步骤 6 | `verification-before-completion` | **orchestrator 内联** | 运行测试 + lint + coverage + principles |
460
+ | 3 REVIEW | `task(deep, delphi+test-spec)` | **CodeReview subagent** + **browser-use MCP** | 代码走查 + 浏览器自动化 |
461
+ | 4 ACCEPT | 强制人工 | **强制人工**(无变化) | 必须人工验收 |
462
+ | 5 FEEDBACK | `task(quick, learn+retro+debug)` | **plan-agent** + **Memory 系统** | 回顾分析 + UpdateMemory 持久化 |
463
+ | 6 SHIP | `task(quick, finishing-branch+ship)` | **orchestrator 直接执行** | git + gh CLI 操作平台无关 |
464
+ | 7 LAND | `task(deep, land-and-deploy)` | **orchestrator 直接执行** | gh pr merge + CI polling |
465
+ | 8 CLEANUP | Bash 直接执行 | **Bash 直接执行**(无变化) | git worktree remove 平台无关 |
466
+
467
+ **Qoder 外部 Skill 降级表**(替代 superpowers/gstack 依赖):
468
+
469
+ | 外部 Skill | 来源 | Qoder 替代方案 |
470
+ |-----------|------|----------------|
471
+ | brainstorming | superpowers | orchestrator 内联需求探索对话 |
472
+ | autoplan | gstack | plan-agent 分析代码库生成计划 |
473
+ | freeze / unfreeze | gstack | Qoder Pre-Edit Gate 替代(见上方) |
474
+ | requesting-code-review | superpowers | **CodeReview subagent** |
475
+ | verification-before-completion | superpowers | orchestrator 运行测试+lint+coverage+principles |
476
+ | learn / retro | gstack | Qoder **Memory 系统**(UpdateMemory / SearchMemory) |
477
+ | browse | gstack | **browser-use MCP** 工具(navigate_page, click, fill, take_screenshot) |
478
+ | ship / finishing-a-development-branch | superpowers/gstack | orchestrator 执行 git + gh CLI |
479
+ | systematic-debugging | superpowers | orchestrator 内联分析错误日志 |
480
+ | land-and-deploy / canary | gstack | orchestrator 执行 gh + curl/Invoke-RestMethod |
481
+ | dispatching-parallel-agents | superpowers | orchestrator 按 dependency_graph 顺序执行 |
482
+ | executing-plans | superpowers | orchestrator 直接执行 |
483
+
484
+ **Qoder genui Widget 集成**:
485
+
486
+ Phase 3 REVIEW 完成后,orchestrator **SHOULD** 使用 genui `show_widget` MCP 工具展示质量报告:
487
+ - Widget 模板:`plugins/qoder/widgets/quality-report.html`
488
+ - 数据源:读取项目根目录的 `quality-report.json`
489
+
490
+ Sprint 执行过程中,用户可通过 `/sprint-status` 触发 genui `show_widget` 展示 Sprint 仪表板:
491
+ - Widget 模板:`plugins/qoder/widgets/sprint-dashboard.html`
492
+ - 数据源:`.sprint-state/sprint-state.json`
493
+
494
+ 详细适配规则参见 `references/qoder-adaptation.md`。
495
+
428
496
  **上下文隔离原则**:
429
497
  - 每个 Subagent 在**独立 session** 中启动,不继承 orchestrator 的对话历史
430
498
  - orchestrator session 仅接收 subagent 的最终结果摘要(~13,000 tokens/sprint)