@zhuan-ai/zhuanspec 2.2.4 → 2.4.8
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/bin/zhuanspec-hook.js +3 -0
- package/dist/cli/hooks.d.ts +14 -0
- package/dist/cli/hooks.js +465 -0
- package/dist/cli/index.js +100 -0
- package/dist/commands/artifact-workflow.js +15 -34
- package/dist/commands/design.d.ts +42 -0
- package/dist/commands/design.js +337 -0
- package/dist/commands/progress.d.ts +32 -0
- package/dist/commands/progress.js +278 -0
- package/dist/commands/review.d.ts +32 -0
- package/dist/commands/review.js +472 -0
- package/dist/commands/validate.d.ts +14 -0
- package/dist/commands/validate.js +161 -10
- package/dist/core/archive.d.ts +1 -0
- package/dist/core/archive.js +45 -3
- package/dist/core/completions/command-registry.js +67 -0
- package/dist/core/configurators/slash/amazon-q.js +32 -2
- package/dist/core/configurators/slash/antigravity.js +8 -2
- package/dist/core/configurators/slash/auggie.js +16 -1
- package/dist/core/configurators/slash/base.js +1 -1
- package/dist/core/configurators/slash/claude.d.ts +4 -0
- package/dist/core/configurators/slash/claude.js +56 -1
- package/dist/core/configurators/slash/cline.js +8 -2
- package/dist/core/configurators/slash/codebuddy.js +22 -1
- package/dist/core/configurators/slash/codex.js +21 -0
- package/dist/core/configurators/slash/costrict.js +15 -0
- package/dist/core/configurators/slash/crush.js +22 -1
- package/dist/core/configurators/slash/cursor.js +22 -1
- package/dist/core/configurators/slash/factory.js +16 -1
- package/dist/core/configurators/slash/gemini.js +8 -2
- package/dist/core/configurators/slash/github-copilot.js +19 -1
- package/dist/core/configurators/slash/iflow.js +22 -1
- package/dist/core/configurators/slash/kilocode.js +4 -1
- package/dist/core/configurators/slash/opencode.js +27 -0
- package/dist/core/configurators/slash/qoder.d.ts +4 -0
- package/dist/core/configurators/slash/qoder.js +59 -1
- package/dist/core/configurators/slash/qwen.js +8 -2
- package/dist/core/configurators/slash/roocode.js +8 -2
- package/dist/core/configurators/slash/windsurf.js +8 -2
- package/dist/core/dashboard/metrics.d.ts +33 -0
- package/dist/core/dashboard/metrics.js +114 -0
- package/dist/core/hooks/collect-knowledge.d.ts +16 -0
- package/dist/core/hooks/collect-knowledge.js +203 -0
- package/dist/core/hooks/context-load-hook.d.ts +25 -0
- package/dist/core/hooks/context-load-hook.js +159 -0
- package/dist/core/hooks/deviation-check.d.ts +27 -0
- package/dist/core/hooks/deviation-check.js +403 -0
- package/dist/core/hooks/deviation-handler.d.ts +43 -0
- package/dist/core/hooks/deviation-handler.js +98 -0
- package/dist/core/hooks/init.d.ts +14 -0
- package/dist/core/hooks/init.js +244 -0
- package/dist/core/hooks/notify-milestone.d.ts +14 -0
- package/dist/core/hooks/notify-milestone.js +170 -0
- package/dist/core/hooks/post-apply.d.ts +29 -0
- package/dist/core/hooks/post-apply.js +173 -0
- package/dist/core/hooks/post-archive.d.ts +7 -0
- package/dist/core/hooks/post-archive.js +208 -0
- package/dist/core/hooks/pre-apply.d.ts +34 -0
- package/dist/core/hooks/pre-apply.js +139 -0
- package/dist/core/hooks/pre-archive.d.ts +7 -0
- package/dist/core/hooks/pre-archive.js +50 -0
- package/dist/core/hooks/record-progress.d.ts +49 -0
- package/dist/core/hooks/record-progress.js +494 -0
- package/dist/core/hooks/review-hooks.d.ts +89 -0
- package/dist/core/hooks/review-hooks.js +345 -0
- package/dist/core/hooks/review-orchestrator.d.ts +40 -0
- package/dist/core/hooks/review-orchestrator.js +146 -0
- package/dist/core/hooks/summarize.d.ts +15 -0
- package/dist/core/hooks/summarize.js +282 -0
- package/dist/core/hooks/user-input-hook.d.ts +25 -0
- package/dist/core/hooks/user-input-hook.js +179 -0
- package/dist/core/init.d.ts +8 -0
- package/dist/core/init.js +251 -23
- package/dist/core/parsers/requirement-blocks.js +13 -10
- package/dist/core/templates/agents-template.d.ts +1 -1
- package/dist/core/templates/agents-template.js +510 -243
- package/dist/core/templates/index.d.ts +1 -0
- package/dist/core/templates/index.js +1 -0
- package/dist/core/templates/skill-templates.js +46 -152
- package/dist/core/templates/slash-command-templates.d.ts +1 -1
- package/dist/core/templates/slash-command-templates.js +352 -20
- package/dist/core/templates/tasks-template.d.ts +7 -0
- package/dist/core/templates/tasks-template.js +130 -24
- package/dist/core/templates/tdd-tasks-template.d.ts +3 -0
- package/dist/core/templates/tdd-tasks-template.js +91 -38
- package/dist/core/templates/test-cases-template.d.ts +41 -0
- package/dist/core/templates/test-cases-template.js +128 -0
- package/dist/core/validation/strict-rules.d.ts +44 -5
- package/dist/core/validation/strict-rules.js +302 -8
- package/dist/core/validation/validator.js +52 -2
- package/dist/core/view.d.ts +1 -0
- package/dist/core/view.js +60 -2
- package/dist/mcp/index.d.ts +28 -0
- package/dist/mcp/index.js +31 -0
- package/dist/utils/file-system.d.ts +1 -0
- package/dist/utils/file-system.js +11 -0
- package/dist/utils/item-discovery.js +24 -2
- package/dist/utils/phase-utils.d.ts +36 -0
- package/dist/utils/phase-utils.js +117 -0
- package/package.json +22 -23
- package/schemas/spec-driven/schema.yaml +45 -31
- package/schemas/spec-driven/templates/spec.md +142 -5
- package/schemas/spec-driven/templates/tasks.md +73 -9
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review Hooks - Result Checkers for Review Phase
|
|
3
|
+
*
|
|
4
|
+
* Three independent hooks for Review phase (Phase 3):
|
|
5
|
+
* 1. code-review-result: Check code-review-expert skill output
|
|
6
|
+
* 2. unit-test-result: Check generate-mockito-unit-test-skill output
|
|
7
|
+
* 3. spec-consistency-result: Check spec-code-consistency output
|
|
8
|
+
*
|
|
9
|
+
* Each hook:
|
|
10
|
+
* - Reads skill output file
|
|
11
|
+
* - Extracts key metrics (Critical count, coverage, consistency)
|
|
12
|
+
* - Decides if fix loop is needed
|
|
13
|
+
* - Controls loop count (max 3)
|
|
14
|
+
*/
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
17
|
+
import { getBeijingTime } from './record-progress.js';
|
|
18
|
+
// Output file paths for skill results
|
|
19
|
+
const SKILL_OUTPUT_DIR = 'zhuanspec/.skill-outputs';
|
|
20
|
+
const CODE_REVIEW_OUTPUT = 'code-review-result.json';
|
|
21
|
+
const UNIT_TEST_OUTPUT = 'unit-test-result.json';
|
|
22
|
+
const SPEC_CONSISTENCY_OUTPUT = 'spec-consistency-result.json';
|
|
23
|
+
// Loop control
|
|
24
|
+
const MAX_LOOP_COUNT = 3;
|
|
25
|
+
export async function codeReviewResultCheck(changeId, skillOutput) {
|
|
26
|
+
const output = skillOutput || await readSkillOutput(changeId, CODE_REVIEW_OUTPUT);
|
|
27
|
+
if (!output) {
|
|
28
|
+
return {
|
|
29
|
+
pass: false,
|
|
30
|
+
needFix: false,
|
|
31
|
+
loopCount: 0,
|
|
32
|
+
metrics: { error: 'No skill output found' },
|
|
33
|
+
nextAction: 'stop',
|
|
34
|
+
fixPrompt: 'Code review skill output not found. Please run code-review-expert skill first.',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const loopCount = (output.loopCount || 0) + 1;
|
|
38
|
+
// Check Critical issues
|
|
39
|
+
if (output.criticalCount > 0) {
|
|
40
|
+
if (loopCount > MAX_LOOP_COUNT) {
|
|
41
|
+
// Loop limit reached, stop and report
|
|
42
|
+
return {
|
|
43
|
+
pass: false,
|
|
44
|
+
needFix: true,
|
|
45
|
+
loopCount: loopCount,
|
|
46
|
+
metrics: {
|
|
47
|
+
criticalCount: output.criticalCount,
|
|
48
|
+
importantCount: output.importantCount,
|
|
49
|
+
loopExceeded: true,
|
|
50
|
+
},
|
|
51
|
+
nextAction: 'stop',
|
|
52
|
+
fixPrompt: formatFixPrompt(output.issues.filter(i => i.level === 'critical'), loopCount),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Need fix loop
|
|
56
|
+
return {
|
|
57
|
+
pass: false,
|
|
58
|
+
needFix: true,
|
|
59
|
+
loopCount: loopCount,
|
|
60
|
+
metrics: {
|
|
61
|
+
criticalCount: output.criticalCount,
|
|
62
|
+
importantCount: output.importantCount,
|
|
63
|
+
criticalIssues: output.issues.filter(i => i.level === 'critical'),
|
|
64
|
+
},
|
|
65
|
+
nextAction: 'fix',
|
|
66
|
+
fixPrompt: formatFixPrompt(output.issues.filter(i => i.level === 'critical'), loopCount),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// PASS: No critical issues
|
|
70
|
+
return {
|
|
71
|
+
pass: true,
|
|
72
|
+
needFix: false,
|
|
73
|
+
loopCount: loopCount,
|
|
74
|
+
metrics: {
|
|
75
|
+
criticalCount: 0,
|
|
76
|
+
importantCount: output.importantCount,
|
|
77
|
+
infoCount: output.infoCount,
|
|
78
|
+
sonarStatus: output.sonarStatus,
|
|
79
|
+
},
|
|
80
|
+
nextAction: 'continue',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export async function unitTestResultCheck(changeId, skillOutput) {
|
|
84
|
+
const output = skillOutput || await readSkillOutput(changeId, UNIT_TEST_OUTPUT);
|
|
85
|
+
if (!output) {
|
|
86
|
+
return {
|
|
87
|
+
pass: false,
|
|
88
|
+
needFix: false,
|
|
89
|
+
loopCount: 0,
|
|
90
|
+
metrics: { error: 'No skill output found' },
|
|
91
|
+
nextAction: 'stop',
|
|
92
|
+
fixPrompt: 'Unit test skill output not found. Please run generate-mockito-unit-test-skill first.',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const loopCount = (output.loopCount || 0) + 1;
|
|
96
|
+
// Check test pass and coverage
|
|
97
|
+
const testFailed = !output.testPassed || output.passRate < 100;
|
|
98
|
+
const coverageLow = output.coverage < output.coverageThreshold;
|
|
99
|
+
if (testFailed || coverageLow) {
|
|
100
|
+
if (loopCount > MAX_LOOP_COUNT) {
|
|
101
|
+
return {
|
|
102
|
+
pass: false,
|
|
103
|
+
needFix: true,
|
|
104
|
+
loopCount: loopCount,
|
|
105
|
+
metrics: {
|
|
106
|
+
testPassed: output.testPassed,
|
|
107
|
+
passRate: output.passRate,
|
|
108
|
+
coverage: output.coverage,
|
|
109
|
+
coverageThreshold: output.coverageThreshold,
|
|
110
|
+
loopExceeded: true,
|
|
111
|
+
},
|
|
112
|
+
nextAction: 'stop',
|
|
113
|
+
fixPrompt: formatUnitTestFixPrompt(output, loopCount),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
pass: false,
|
|
118
|
+
needFix: true,
|
|
119
|
+
loopCount: loopCount,
|
|
120
|
+
metrics: {
|
|
121
|
+
testPassed: output.testPassed,
|
|
122
|
+
passRate: output.passRate,
|
|
123
|
+
coverage: output.coverage,
|
|
124
|
+
coverageThreshold: output.coverageThreshold,
|
|
125
|
+
failedTests: output.failedTests,
|
|
126
|
+
},
|
|
127
|
+
nextAction: 'fix',
|
|
128
|
+
fixPrompt: formatUnitTestFixPrompt(output, loopCount),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// PASS: Tests passed and coverage meets threshold
|
|
132
|
+
return {
|
|
133
|
+
pass: true,
|
|
134
|
+
needFix: false,
|
|
135
|
+
loopCount: loopCount,
|
|
136
|
+
metrics: {
|
|
137
|
+
testPassed: true,
|
|
138
|
+
passRate: output.passRate,
|
|
139
|
+
coverage: output.coverage,
|
|
140
|
+
newTestsGenerated: output.newTestsGenerated,
|
|
141
|
+
},
|
|
142
|
+
nextAction: 'continue',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export async function specConsistencyResultCheck(changeId, skillOutput) {
|
|
146
|
+
const output = skillOutput || await readSkillOutput(changeId, SPEC_CONSISTENCY_OUTPUT);
|
|
147
|
+
if (!output) {
|
|
148
|
+
return {
|
|
149
|
+
pass: false,
|
|
150
|
+
needFix: false,
|
|
151
|
+
loopCount: 0,
|
|
152
|
+
metrics: { error: 'No skill output found' },
|
|
153
|
+
nextAction: 'stop',
|
|
154
|
+
fixPrompt: 'Spec-consistency skill output not found. Please run spec-code-consistency check first.',
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const loopCount = (output.loopCount || 0) + 1;
|
|
158
|
+
// Check consistency coverage
|
|
159
|
+
const hasUncovered = output.uncoveredScenarios.length > 0;
|
|
160
|
+
if (hasUncovered) {
|
|
161
|
+
if (loopCount > MAX_LOOP_COUNT) {
|
|
162
|
+
return {
|
|
163
|
+
pass: false,
|
|
164
|
+
needFix: true,
|
|
165
|
+
loopCount: loopCount,
|
|
166
|
+
metrics: {
|
|
167
|
+
consistencyRate: output.consistencyRate,
|
|
168
|
+
totalScenarios: output.totalScenarios,
|
|
169
|
+
coveredScenarios: output.coveredScenarios,
|
|
170
|
+
loopExceeded: true,
|
|
171
|
+
},
|
|
172
|
+
nextAction: 'stop',
|
|
173
|
+
fixPrompt: formatConsistencyFixPrompt(output, loopCount),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
pass: false,
|
|
178
|
+
needFix: true,
|
|
179
|
+
loopCount: loopCount,
|
|
180
|
+
metrics: {
|
|
181
|
+
consistencyRate: output.consistencyRate,
|
|
182
|
+
uncoveredScenarios: output.uncoveredScenarios,
|
|
183
|
+
},
|
|
184
|
+
nextAction: 'fix',
|
|
185
|
+
fixPrompt: formatConsistencyFixPrompt(output, loopCount),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
// PASS: All scenarios covered
|
|
189
|
+
return {
|
|
190
|
+
pass: true,
|
|
191
|
+
needFix: false,
|
|
192
|
+
loopCount: loopCount,
|
|
193
|
+
metrics: {
|
|
194
|
+
consistencyRate: 100,
|
|
195
|
+
totalRequirements: output.totalRequirements,
|
|
196
|
+
totalScenarios: output.totalScenarios,
|
|
197
|
+
coveredScenarios: output.coveredScenarios,
|
|
198
|
+
mapping: output.mapping,
|
|
199
|
+
},
|
|
200
|
+
nextAction: 'continue',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// ============================================================
|
|
204
|
+
// Helper Functions
|
|
205
|
+
// ============================================================
|
|
206
|
+
async function readSkillOutput(changeId, filename) {
|
|
207
|
+
const cwd = process.cwd();
|
|
208
|
+
const outputPath = path.join(cwd, SKILL_OUTPUT_DIR, changeId, filename);
|
|
209
|
+
try {
|
|
210
|
+
if (await FileSystemUtils.fileExists(outputPath)) {
|
|
211
|
+
const content = await FileSystemUtils.readFile(outputPath);
|
|
212
|
+
return JSON.parse(content);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// File not found or parse error
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
function formatFixPrompt(issues, loopCount) {
|
|
221
|
+
const issueList = issues.map(i => `- [${i.level.toUpperCase}] ${i.file}${i.line ? `:${i.line}` : ''}: ${i.message}`).join('\n');
|
|
222
|
+
return `
|
|
223
|
+
🔄 Code Review Fix Loop (${loopCount}/${MAX_LOOP_COUNT})
|
|
224
|
+
|
|
225
|
+
发现 ${issues.length} 个 Critical 问题需要修复:
|
|
226
|
+
|
|
227
|
+
${issueList}
|
|
228
|
+
|
|
229
|
+
请修复以上问题后,重新调用 code-review-expert skill 进行验证。
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
function formatUnitTestFixPrompt(output, loopCount) {
|
|
233
|
+
const failedList = output.failedTests.length > 0
|
|
234
|
+
? `\n失败的测试:\n${output.failedTests.map(t => `- ${t}`).join('\n')}`
|
|
235
|
+
: '';
|
|
236
|
+
return `
|
|
237
|
+
🔄 Unit Test Fix Loop (${loopCount}/${MAX_LOOP_COUNT})
|
|
238
|
+
|
|
239
|
+
测试状态:
|
|
240
|
+
- 通过率:${output.passRate}%
|
|
241
|
+
- 覆盖率:${output.coverage}%(阈值:${output.coverageThreshold}%)
|
|
242
|
+
${failedList}
|
|
243
|
+
|
|
244
|
+
请补充单元测试或修复失败的测试,然后重新调用 generate-mockito-unit-test-skill。
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
function formatConsistencyFixPrompt(output, loopCount) {
|
|
248
|
+
const uncoveredList = output.uncoveredScenarios.map(s => `- ${s.requirementId}/${s.scenarioId}: ${s.description}`).join('\n');
|
|
249
|
+
return `
|
|
250
|
+
🔄 Spec-Code Consistency Fix Loop (${loopCount}/${MAX_LOOP_COUNT})
|
|
251
|
+
|
|
252
|
+
发现 ${output.uncoveredScenarios.length} 个未覆盖的 Scenario:
|
|
253
|
+
|
|
254
|
+
${uncoveredList}
|
|
255
|
+
|
|
256
|
+
请选择修复方向:
|
|
257
|
+
1. 添加代码实现以覆盖这些 Scenario
|
|
258
|
+
2. 或更新 Spec 描述以反映当前实现状态
|
|
259
|
+
|
|
260
|
+
然后重新运行 spec-code-consistency 检查。
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
// ============================================================
|
|
264
|
+
// Write Skill Output (for skill to call)
|
|
265
|
+
// ============================================================
|
|
266
|
+
export async function writeCodeReviewOutput(changeId, output) {
|
|
267
|
+
await writeSkillOutput(changeId, CODE_REVIEW_OUTPUT, output);
|
|
268
|
+
}
|
|
269
|
+
export async function writeUnitTestOutput(changeId, output) {
|
|
270
|
+
await writeSkillOutput(changeId, UNIT_TEST_OUTPUT, output);
|
|
271
|
+
}
|
|
272
|
+
export async function writeSpecConsistencyOutput(changeId, output) {
|
|
273
|
+
await writeSkillOutput(changeId, SPEC_CONSISTENCY_OUTPUT, output);
|
|
274
|
+
}
|
|
275
|
+
// Export generic write function for subagent use
|
|
276
|
+
export { writeSkillOutput };
|
|
277
|
+
async function writeSkillOutput(changeId, filename, data) {
|
|
278
|
+
const cwd = process.cwd();
|
|
279
|
+
const outputDir = path.join(cwd, SKILL_OUTPUT_DIR, changeId);
|
|
280
|
+
await FileSystemUtils.createDirectory(outputDir);
|
|
281
|
+
const outputPath = path.join(outputDir, filename);
|
|
282
|
+
await FileSystemUtils.writeFile(outputPath, JSON.stringify(data, null, 2));
|
|
283
|
+
}
|
|
284
|
+
export async function generateReviewReport(changeId, results) {
|
|
285
|
+
const report = `# Review Report: ${changeId}
|
|
286
|
+
|
|
287
|
+
**执行时间**: ${getBeijingTime()}
|
|
288
|
+
**执行者**: AI
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 1. Code Review 结果
|
|
293
|
+
|
|
294
|
+
| 指标 | 结果 |
|
|
295
|
+
|------|------|
|
|
296
|
+
| Critical 问题 | ${results.codeReview.metrics.criticalCount || 0} |
|
|
297
|
+
| Important 问题 | ${results.codeReview.metrics.importantCount || 0} |
|
|
298
|
+
| Info 问题 | ${results.codeReview.metrics.infoCount || 0} |
|
|
299
|
+
| 循环次数 | ${results.codeReview.loopCount} |
|
|
300
|
+
| 状态 | ${results.codeReview.pass ? '✅ PASS' : '❌ FAIL'} |
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## 2. 单测验证结果
|
|
305
|
+
|
|
306
|
+
| 指标 | 结果 |
|
|
307
|
+
|------|------|
|
|
308
|
+
| 测试通过率 | ${results.unitTest.metrics.passRate || 0}% |
|
|
309
|
+
| 覆盖率 | ${results.unitTest.metrics.coverage || 0}% |
|
|
310
|
+
| 新增单测 | ${(results.unitTest.metrics.newTestsGenerated || []).length} 个 |
|
|
311
|
+
| 循环次数 | ${results.unitTest.loopCount} |
|
|
312
|
+
| 状态 | ${results.unitTest.pass ? '✅ PASS' : '❌ FAIL'} |
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## 3. Spec-Code 一致性认证
|
|
317
|
+
|
|
318
|
+
| 指标 | 结果 |
|
|
319
|
+
|------|------|
|
|
320
|
+
| Requirements 数量 | ${results.specConsistency.metrics.totalRequirements || 0} |
|
|
321
|
+
| Scenario 数量 | ${results.specConsistency.metrics.totalScenarios || 0} |
|
|
322
|
+
| 一致性覆盖率 | ${results.specConsistency.metrics.consistencyRate || 0}% |
|
|
323
|
+
| 循环次数 | ${results.specConsistency.loopCount} |
|
|
324
|
+
| 状态 | ${results.specConsistency.pass ? '✅ PASS' : '❌ FAIL'} |
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## 总体结论
|
|
329
|
+
|
|
330
|
+
**状态**: ${results.codeReview.pass && results.unitTest.pass && results.specConsistency.pass ? 'PASS' : 'FAIL'}
|
|
331
|
+
**可归档**: ${results.codeReview.pass && results.unitTest.pass && results.specConsistency.pass ? '是' : '否'}
|
|
332
|
+
|
|
333
|
+
${results.codeReview.pass && results.unitTest.pass && results.specConsistency.pass
|
|
334
|
+
? '**下一步**: 进入阶段 4(归档变更)'
|
|
335
|
+
: '**下一步**: 根据以上报告继续修复问题'}
|
|
336
|
+
`;
|
|
337
|
+
// Write report to change directory
|
|
338
|
+
const cwd = process.cwd();
|
|
339
|
+
const changeDir = path.join(cwd, 'zhuanspec', 'changes', changeId);
|
|
340
|
+
const reportPath = path.join(changeDir, 'review-report.md');
|
|
341
|
+
await FileSystemUtils.writeFile(reportPath, report);
|
|
342
|
+
return report;
|
|
343
|
+
}
|
|
344
|
+
export { MAX_LOOP_COUNT, };
|
|
345
|
+
//# sourceMappingURL=review-hooks.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review Orchestrator - 三轨并行 Review 调度
|
|
3
|
+
*
|
|
4
|
+
* 使用 Agent 工具启动 3 个 subagent 并行执行:
|
|
5
|
+
* 1. Code Review subagent - 调用 code-review-expert skill
|
|
6
|
+
* 2. Unit Test subagent - 调用 generate-mockito-unit-test skill
|
|
7
|
+
* 3. Spec-Code Consistency subagent - 执行一致性检查
|
|
8
|
+
*
|
|
9
|
+
* 每个 subagent 内部自闭环修复(最多3轮),最后汇总报告
|
|
10
|
+
*/
|
|
11
|
+
export interface ReviewOrchestratorOptions {
|
|
12
|
+
changeId: string;
|
|
13
|
+
parallel?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface SubagentReport {
|
|
16
|
+
track: 'code-review' | 'unit-test' | 'spec-consistency';
|
|
17
|
+
reportFile: string;
|
|
18
|
+
passed: boolean;
|
|
19
|
+
loopCount: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Orchestrate three-track parallel review
|
|
23
|
+
*
|
|
24
|
+
* Note: This function returns prompts for subagents.
|
|
25
|
+
* The actual parallel execution should be done using Agent tool in the main conversation.
|
|
26
|
+
*/
|
|
27
|
+
export declare function orchestrateReview(options: ReviewOrchestratorOptions): Promise<{
|
|
28
|
+
codeReviewPrompt: string;
|
|
29
|
+
unitTestPrompt: string;
|
|
30
|
+
specConsistencyPrompt: string;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Collect subagent reports and generate final review report
|
|
34
|
+
*/
|
|
35
|
+
export declare function collectReports(changeId: string, reports: SubagentReport[]): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Check if all three tracks passed
|
|
38
|
+
*/
|
|
39
|
+
export declare function allTracksPassed(reports: SubagentReport[]): boolean;
|
|
40
|
+
//# sourceMappingURL=review-orchestrator.d.ts.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review Orchestrator - 三轨并行 Review 调度
|
|
3
|
+
*
|
|
4
|
+
* 使用 Agent 工具启动 3 个 subagent 并行执行:
|
|
5
|
+
* 1. Code Review subagent - 调用 code-review-expert skill
|
|
6
|
+
* 2. Unit Test subagent - 调用 generate-mockito-unit-test skill
|
|
7
|
+
* 3. Spec-Code Consistency subagent - 执行一致性检查
|
|
8
|
+
*
|
|
9
|
+
* 每个 subagent 内部自闭环修复(最多3轮),最后汇总报告
|
|
10
|
+
*/
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
13
|
+
import { generateReviewReport } from './review-hooks.js';
|
|
14
|
+
/**
|
|
15
|
+
* Generate subagent prompts with self-contained loop instructions
|
|
16
|
+
*/
|
|
17
|
+
function generateCodeReviewPrompt(changeId) {
|
|
18
|
+
return `
|
|
19
|
+
执行 Code Review,发现 Critical 问题时启动修复循环:
|
|
20
|
+
|
|
21
|
+
## 任务目标
|
|
22
|
+
对 changeId=${changeId} 的代码变更进行生产级代码评审
|
|
23
|
+
|
|
24
|
+
## 自闭环指令
|
|
25
|
+
1. 执行 code-review-expert skill 进行代码审查
|
|
26
|
+
2. 如果发现 Critical 问题,立即修复
|
|
27
|
+
3. 修复后重新检查(最多3轮)
|
|
28
|
+
4. 输出 code-review-result.json 报告到 zhuanspec/.skill-outputs/${changeId}/
|
|
29
|
+
|
|
30
|
+
## 输出格式
|
|
31
|
+
{
|
|
32
|
+
"criticalCount": number,
|
|
33
|
+
"importantCount": number,
|
|
34
|
+
"infoCount": number,
|
|
35
|
+
"issues": [...],
|
|
36
|
+
"loopCount": number,
|
|
37
|
+
"finalStatus": "PASS" | "FAIL"
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
function generateUnitTestPrompt(changeId) {
|
|
42
|
+
return `
|
|
43
|
+
执行单元测试验证,失败时启动修复循环:
|
|
44
|
+
|
|
45
|
+
## 任务目标
|
|
46
|
+
为 changeId=${changeId} 的代码变更生成并验证单元测试
|
|
47
|
+
|
|
48
|
+
## 自闭环指令
|
|
49
|
+
1. 执行 generate-mockito-unit-test skill 生成单测
|
|
50
|
+
2. 运行单测,检查通过率和覆盖率
|
|
51
|
+
3. 如果失败或不达标,立即修复
|
|
52
|
+
4. 修复后重新测试(最多3轮)
|
|
53
|
+
5. 输出 unit-test-result.json 报告到 zhuanspec/.skill-outputs/${changeId}/
|
|
54
|
+
|
|
55
|
+
## 输出格式
|
|
56
|
+
{
|
|
57
|
+
"testPassed": boolean,
|
|
58
|
+
"passRate": number,
|
|
59
|
+
"coverage": number,
|
|
60
|
+
"newTestsGenerated": [...],
|
|
61
|
+
"failedTests": [...],
|
|
62
|
+
"loopCount": number,
|
|
63
|
+
"finalStatus": "PASS" | "FAIL"
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
67
|
+
function generateSpecConsistencyPrompt(changeId) {
|
|
68
|
+
return `
|
|
69
|
+
执行 Spec-Code 一致性检查,发现未覆盖 Scenario 时启动修复循环:
|
|
70
|
+
|
|
71
|
+
## 任务目标
|
|
72
|
+
验证 changeId=${changeId} 的代码实现与 Spec Requirement 一致
|
|
73
|
+
|
|
74
|
+
## 自闭环指令
|
|
75
|
+
1. 解析 specs/*.md 中的所有 Requirement 和 Scenario
|
|
76
|
+
2. 检查代码实现是否覆盖每个 Scenario
|
|
77
|
+
3. 如果发现未覆盖,立即补充代码或更新 Spec
|
|
78
|
+
4. 修复后重新检查(最多3轮)
|
|
79
|
+
5. 输出 spec-consistency-result.json 报告到 zhuanspec/.skill-outputs/${changeId}/
|
|
80
|
+
|
|
81
|
+
## 输出格式
|
|
82
|
+
{
|
|
83
|
+
"consistencyRate": number,
|
|
84
|
+
"totalRequirements": number,
|
|
85
|
+
"totalScenarios": number,
|
|
86
|
+
"coveredScenarios": number,
|
|
87
|
+
"uncoveredScenarios": [...],
|
|
88
|
+
"loopCount": number,
|
|
89
|
+
"finalStatus": "PASS" | "FAIL"
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Orchestrate three-track parallel review
|
|
95
|
+
*
|
|
96
|
+
* Note: This function returns prompts for subagents.
|
|
97
|
+
* The actual parallel execution should be done using Agent tool in the main conversation.
|
|
98
|
+
*/
|
|
99
|
+
export async function orchestrateReview(options) {
|
|
100
|
+
const { changeId } = options;
|
|
101
|
+
// Ensure output directory exists
|
|
102
|
+
const cwd = process.cwd();
|
|
103
|
+
const outputDir = path.join(cwd, 'zhuanspec', '.skill-outputs', changeId);
|
|
104
|
+
await FileSystemUtils.createDirectory(outputDir);
|
|
105
|
+
return {
|
|
106
|
+
codeReviewPrompt: generateCodeReviewPrompt(changeId),
|
|
107
|
+
unitTestPrompt: generateUnitTestPrompt(changeId),
|
|
108
|
+
specConsistencyPrompt: generateSpecConsistencyPrompt(changeId),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Collect subagent reports and generate final review report
|
|
113
|
+
*/
|
|
114
|
+
export async function collectReports(changeId, reports) {
|
|
115
|
+
const cwd = process.cwd();
|
|
116
|
+
const changeDir = path.join(cwd, 'zhuanspec', 'changes', changeId);
|
|
117
|
+
// Generate review report
|
|
118
|
+
const reportContent = await generateReviewReport(changeId, {
|
|
119
|
+
codeReview: {
|
|
120
|
+
pass: reports.find(r => r.track === 'code-review')?.passed ?? false,
|
|
121
|
+
needFix: false,
|
|
122
|
+
loopCount: reports.find(r => r.track === 'code-review')?.loopCount ?? 0,
|
|
123
|
+
metrics: {},
|
|
124
|
+
},
|
|
125
|
+
unitTest: {
|
|
126
|
+
pass: reports.find(r => r.track === 'unit-test')?.passed ?? false,
|
|
127
|
+
needFix: false,
|
|
128
|
+
loopCount: reports.find(r => r.track === 'unit-test')?.loopCount ?? 0,
|
|
129
|
+
metrics: {},
|
|
130
|
+
},
|
|
131
|
+
specConsistency: {
|
|
132
|
+
pass: reports.find(r => r.track === 'spec-consistency')?.passed ?? false,
|
|
133
|
+
needFix: false,
|
|
134
|
+
loopCount: reports.find(r => r.track === 'spec-consistency')?.loopCount ?? 0,
|
|
135
|
+
metrics: {},
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
return reportContent;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if all three tracks passed
|
|
142
|
+
*/
|
|
143
|
+
export function allTracksPassed(reports) {
|
|
144
|
+
return reports.every(r => r.passed);
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=review-orchestrator.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stop Hook - Summarize Session Progress
|
|
3
|
+
*
|
|
4
|
+
* This hook runs when Claude Code session stops or pauses:
|
|
5
|
+
* 1. Summarize current wave completion status
|
|
6
|
+
* 2. Update ZHUANSPEC_CURRENT_TASK for next task
|
|
7
|
+
* 3. Check if tasks.md is complete → trigger Review phase
|
|
8
|
+
* 4. Generate events.json entries for key events
|
|
9
|
+
*/
|
|
10
|
+
interface SummarizeOptions {
|
|
11
|
+
json?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function summarizeHook(options: SummarizeOptions): Promise<void>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=summarize.d.ts.map
|