kiro-spec-engine 1.2.3 → 1.3.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +172 -0
  3. package/bin/kiro-spec-engine.js +62 -0
  4. package/docs/agent-hooks-analysis.md +815 -0
  5. package/docs/cross-tool-guide.md +554 -0
  6. package/docs/manual-workflows-guide.md +417 -0
  7. package/docs/steering-strategy-guide.md +196 -0
  8. package/lib/adoption/detection-engine.js +14 -4
  9. package/lib/commands/adopt.js +117 -3
  10. package/lib/commands/context.js +99 -0
  11. package/lib/commands/prompt.js +105 -0
  12. package/lib/commands/status.js +225 -0
  13. package/lib/commands/task.js +199 -0
  14. package/lib/commands/watch.js +569 -0
  15. package/lib/commands/workflows.js +240 -0
  16. package/lib/commands/workspace.js +189 -0
  17. package/lib/context/context-exporter.js +378 -0
  18. package/lib/context/prompt-generator.js +482 -0
  19. package/lib/steering/adoption-config.js +164 -0
  20. package/lib/steering/steering-manager.js +289 -0
  21. package/lib/task/task-claimer.js +430 -0
  22. package/lib/utils/tool-detector.js +383 -0
  23. package/lib/watch/action-executor.js +458 -0
  24. package/lib/watch/event-debouncer.js +323 -0
  25. package/lib/watch/execution-logger.js +550 -0
  26. package/lib/watch/file-watcher.js +499 -0
  27. package/lib/watch/presets.js +266 -0
  28. package/lib/watch/watch-manager.js +533 -0
  29. package/lib/workspace/workspace-manager.js +370 -0
  30. package/lib/workspace/workspace-sync.js +356 -0
  31. package/package.json +3 -1
  32. package/template/.kiro/tools/backup_manager.py +295 -0
  33. package/template/.kiro/tools/configuration_manager.py +218 -0
  34. package/template/.kiro/tools/document_evaluator.py +550 -0
  35. package/template/.kiro/tools/enhancement_logger.py +168 -0
  36. package/template/.kiro/tools/error_handler.py +335 -0
  37. package/template/.kiro/tools/improvement_identifier.py +444 -0
  38. package/template/.kiro/tools/modification_applicator.py +737 -0
  39. package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
  40. package/template/.kiro/tools/quality_scorer.py +305 -0
  41. package/template/.kiro/tools/report_generator.py +154 -0
  42. package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
  43. package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
  44. package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
  45. package/template/.kiro/tools/workflow_quality_gate.py +100 -0
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Quality Gate Enforcer - 质量门控组件
4
+
5
+ 负责在 Spec 创建工作流中强制执行质量标准
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+ from typing import Optional
10
+ from ultrawork_enhancer_v3 import UltraworkEnhancerV3, EnhancementResult
11
+
12
+
13
+ @dataclass
14
+ class GateResult:
15
+ """质量门结果"""
16
+ passed: bool
17
+ score: float
18
+ threshold: float
19
+ enhancement_result: Optional[EnhancementResult] = None
20
+ message: str = ""
21
+
22
+
23
+ class QualityGateEnforcer:
24
+ """
25
+ 质量门控器 - 强制执行质量标准
26
+
27
+ 集成到 Spec 创建工作流,确保文档达到质量阈值
28
+ """
29
+
30
+ def __init__(self,
31
+ requirements_threshold: float = 9.0,
32
+ design_threshold: float = 9.0,
33
+ tasks_threshold: float = 8.0):
34
+ """
35
+ 初始化质量门控器
36
+
37
+ Args:
38
+ requirements_threshold: Requirements 质量阈值
39
+ design_threshold: Design 质量阈值
40
+ tasks_threshold: Tasks 质量阈值
41
+ """
42
+ self.requirements_threshold = requirements_threshold
43
+ self.design_threshold = design_threshold
44
+ self.tasks_threshold = tasks_threshold
45
+
46
+ # 创建增强器实例
47
+ self.enhancer = UltraworkEnhancerV3(
48
+ quality_threshold=requirements_threshold,
49
+ max_iterations=10,
50
+ plateau_iterations=3,
51
+ create_backups=True,
52
+ cleanup_backups_on_success=True
53
+ )
54
+
55
+ def check_requirements_gate(self, requirements_path: str) -> GateResult:
56
+ """
57
+ 检查 Requirements 质量门
58
+
59
+ Args:
60
+ requirements_path: Requirements 文档路径
61
+
62
+ Returns:
63
+ GateResult: 质量门结果
64
+ """
65
+ print(f"\n{'='*60}")
66
+ print(f"Quality Gate: Requirements")
67
+ print(f"Threshold: {self.requirements_threshold}/10")
68
+ print(f"{'='*60}\n")
69
+
70
+ # 设置阈值
71
+ self.enhancer.set_quality_threshold(self.requirements_threshold)
72
+
73
+ # 执行增强
74
+ result = self.enhancer.enhance_requirements_quality(requirements_path)
75
+
76
+ # 检查是否通过
77
+ passed = result.final_score >= self.requirements_threshold
78
+
79
+ if passed:
80
+ message = f"✓ Requirements quality gate PASSED ({result.final_score:.2f}/{self.requirements_threshold})"
81
+ else:
82
+ message = f"✗ Requirements quality gate FAILED ({result.final_score:.2f}/{self.requirements_threshold})"
83
+
84
+ print(f"\n{message}\n")
85
+
86
+ return GateResult(
87
+ passed=passed,
88
+ score=result.final_score,
89
+ threshold=self.requirements_threshold,
90
+ enhancement_result=result,
91
+ message=message
92
+ )
93
+
94
+ def check_design_gate(self, design_path: str, requirements_path: str) -> GateResult:
95
+ """
96
+ 检查 Design 质量门
97
+
98
+ Args:
99
+ design_path: Design 文档路径
100
+ requirements_path: Requirements 文档路径
101
+
102
+ Returns:
103
+ GateResult: 质量门结果
104
+ """
105
+ print(f"\n{'='*60}")
106
+ print(f"Quality Gate: Design")
107
+ print(f"Threshold: {self.design_threshold}/10")
108
+ print(f"{'='*60}\n")
109
+
110
+ # 设置阈值
111
+ self.enhancer.set_quality_threshold(self.design_threshold)
112
+
113
+ # 执行增强
114
+ result = self.enhancer.enhance_design_completeness(design_path, requirements_path)
115
+
116
+ # 检查是否通过
117
+ passed = result.final_score >= self.design_threshold
118
+
119
+ if passed:
120
+ message = f"✓ Design quality gate PASSED ({result.final_score:.2f}/{self.design_threshold})"
121
+ else:
122
+ message = f"✗ Design quality gate FAILED ({result.final_score:.2f}/{self.design_threshold})"
123
+
124
+ print(f"\n{message}\n")
125
+
126
+ return GateResult(
127
+ passed=passed,
128
+ score=result.final_score,
129
+ threshold=self.design_threshold,
130
+ enhancement_result=result,
131
+ message=message
132
+ )
133
+
134
+ def check_tasks_gate(self, tasks_path: str) -> GateResult:
135
+ """
136
+ 检查 Tasks 质量门
137
+
138
+ Args:
139
+ tasks_path: Tasks 文档路径
140
+
141
+ Returns:
142
+ GateResult: 质量门结果
143
+ """
144
+ print(f"\n{'='*60}")
145
+ print(f"Quality Gate: Tasks")
146
+ print(f"Threshold: {self.tasks_threshold}/10")
147
+ print(f"{'='*60}\n")
148
+
149
+ # 执行验证
150
+ result = self.enhancer.validate_tasks_completeness(tasks_path)
151
+
152
+ # 检查是否通过
153
+ passed = result.final_score >= self.tasks_threshold
154
+
155
+ if passed:
156
+ message = f"✓ Tasks quality gate PASSED ({result.final_score:.2f}/{self.tasks_threshold})"
157
+ else:
158
+ message = f"✗ Tasks quality gate FAILED ({result.final_score:.2f}/{self.tasks_threshold})"
159
+
160
+ print(f"\n{message}\n")
161
+
162
+ return GateResult(
163
+ passed=passed,
164
+ score=result.final_score,
165
+ threshold=self.tasks_threshold,
166
+ enhancement_result=result,
167
+ message=message
168
+ )
169
+
170
+
171
+ def main():
172
+ """命令行入口"""
173
+ import sys
174
+
175
+ if len(sys.argv) < 3:
176
+ print("Usage: python quality_gate_enforcer.py <gate> <path> [requirements_path]")
177
+ print("Gates:")
178
+ print(" requirements <path> - Check requirements quality gate")
179
+ print(" design <path> <requirements> - Check design quality gate")
180
+ print(" tasks <path> - Check tasks quality gate")
181
+ sys.exit(1)
182
+
183
+ gate = sys.argv[1]
184
+ path = sys.argv[2]
185
+
186
+ enforcer = QualityGateEnforcer()
187
+
188
+ if gate == 'requirements':
189
+ result = enforcer.check_requirements_gate(path)
190
+ elif gate == 'design':
191
+ if len(sys.argv) < 4:
192
+ print("Error: design gate requires requirements path")
193
+ sys.exit(1)
194
+ requirements_path = sys.argv[3]
195
+ result = enforcer.check_design_gate(path, requirements_path)
196
+ elif gate == 'tasks':
197
+ result = enforcer.check_tasks_gate(path)
198
+ else:
199
+ print(f"Error: Unknown gate '{gate}'")
200
+ sys.exit(1)
201
+
202
+ # 返回退出码:0 = 通过,1 = 失败
203
+ sys.exit(0 if result.passed else 1)
204
+
205
+
206
+ if __name__ == '__main__':
207
+ main()
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Quality Scorer - 质量评分组件
4
+
5
+ 负责计算文档质量分数,提供加权评分算法和详细评分分解
6
+ """
7
+
8
+ from typing import Dict, Optional
9
+ from dataclasses import dataclass, field
10
+ from document_evaluator import DocumentEvaluator, QualityAssessment
11
+
12
+
13
+ @dataclass
14
+ class CriterionScore:
15
+ """单项评分标准"""
16
+ name: str
17
+ score: float # 0-10
18
+ weight: float # 0-1
19
+ weighted_score: float # score * weight
20
+ max_score: float = 10.0
21
+ description: str = ""
22
+
23
+
24
+ @dataclass
25
+ class ScoringResult:
26
+ """评分结果"""
27
+ total_score: float # 0-10
28
+ criterion_scores: Dict[str, CriterionScore] = field(default_factory=dict)
29
+ language: str = 'en'
30
+ scoring_breakdown: str = ""
31
+ assessment: Optional[QualityAssessment] = None
32
+
33
+
34
+ class QualityScorer:
35
+ """
36
+ 质量评分器 - 计算文档质量分数
37
+
38
+ 支持加权评分算法和详细评分分解
39
+ """
40
+
41
+ # 默认权重配置
42
+ DEFAULT_REQUIREMENTS_WEIGHTS = {
43
+ 'structure': 0.20, # 20%
44
+ 'ears_format': 0.20, # 20%
45
+ 'user_stories': 0.20, # 20%
46
+ 'acceptance_criteria': 0.20, # 20%
47
+ 'nfr_coverage': 0.10, # 10%
48
+ 'constraints': 0.10 # 10%
49
+ }
50
+
51
+ DEFAULT_DESIGN_WEIGHTS = {
52
+ 'structure': 0.25, # 25%
53
+ 'traceability': 0.20, # 20%
54
+ 'component_detail': 0.20, # 20%
55
+ 'diagrams': 0.15, # 15%
56
+ 'technology': 0.10, # 10%
57
+ 'nfr_design': 0.05, # 5%
58
+ 'interfaces': 0.05 # 5%
59
+ }
60
+
61
+ def __init__(self):
62
+ self.evaluator = DocumentEvaluator()
63
+ self.requirements_weights = self.DEFAULT_REQUIREMENTS_WEIGHTS.copy()
64
+ self.design_weights = self.DEFAULT_DESIGN_WEIGHTS.copy()
65
+
66
+ def configure_weights(self, weights: Dict[str, float]):
67
+ """
68
+ 配置评分标准权重
69
+
70
+ Args:
71
+ weights: 权重字典,格式为 {'criterion_name': weight}
72
+ """
73
+ # 验证权重总和为 1.0
74
+ total_weight = sum(weights.values())
75
+ if abs(total_weight - 1.0) > 0.01:
76
+ raise ValueError(f"Weights must sum to 1.0, got {total_weight}")
77
+
78
+ # 更新权重
79
+ for criterion, weight in weights.items():
80
+ if criterion in self.requirements_weights:
81
+ self.requirements_weights[criterion] = weight
82
+ elif criterion in self.design_weights:
83
+ self.design_weights[criterion] = weight
84
+
85
+ def score_requirements(self, content: str, language: Optional[str] = None) -> ScoringResult:
86
+ """
87
+ 计算 Requirements 文档质量分数
88
+
89
+ Args:
90
+ content: 文档内容
91
+ language: 语言 ('zh' 或 'en'),None 则自动检测
92
+
93
+ Returns:
94
+ ScoringResult: 评分结果
95
+ """
96
+ # 使用 DocumentEvaluator 进行评估
97
+ assessment = self.evaluator.assess_requirements_quality(content, language)
98
+
99
+ # 计算加权分数
100
+ criterion_scores = {}
101
+ total_score = 0.0
102
+
103
+ for criterion, weight in self.requirements_weights.items():
104
+ raw_score = assessment.criteria_scores.get(criterion, 0.0)
105
+ weighted_score = raw_score * weight * 10.0 # 转换为 0-10 分制
106
+
107
+ criterion_scores[criterion] = CriterionScore(
108
+ name=criterion,
109
+ score=raw_score * 10.0, # 原始分数(0-10)
110
+ weight=weight,
111
+ weighted_score=weighted_score,
112
+ description=self._get_criterion_description(criterion, assessment.language)
113
+ )
114
+
115
+ total_score += weighted_score
116
+
117
+ # 生成评分分解说明
118
+ breakdown = self._generate_requirements_breakdown(
119
+ criterion_scores,
120
+ total_score,
121
+ assessment
122
+ )
123
+
124
+ return ScoringResult(
125
+ total_score=min(total_score, 10.0),
126
+ criterion_scores=criterion_scores,
127
+ language=assessment.language,
128
+ scoring_breakdown=breakdown,
129
+ assessment=assessment
130
+ )
131
+
132
+ def score_design(self, design_content: str, requirements_content: str, language: Optional[str] = None) -> ScoringResult:
133
+ """
134
+ 计算 Design 文档质量分数
135
+
136
+ Args:
137
+ design_content: 设计文档内容
138
+ requirements_content: 需求文档内容
139
+ language: 语言 ('zh' 或 'en'),None 则自动检测
140
+
141
+ Returns:
142
+ ScoringResult: 评分结果
143
+ """
144
+ # 使用 DocumentEvaluator 进行评估
145
+ assessment = self.evaluator.assess_design_quality(
146
+ design_content,
147
+ requirements_content,
148
+ language
149
+ )
150
+
151
+ # 计算加权分数
152
+ criterion_scores = {}
153
+ total_score = 0.0
154
+
155
+ for criterion, weight in self.design_weights.items():
156
+ raw_score = assessment.criteria_scores.get(criterion, 0.0)
157
+ weighted_score = raw_score * weight * 10.0 # 转换为 0-10 分制
158
+
159
+ criterion_scores[criterion] = CriterionScore(
160
+ name=criterion,
161
+ score=raw_score * 10.0, # 原始分数(0-10)
162
+ weight=weight,
163
+ weighted_score=weighted_score,
164
+ description=self._get_criterion_description(criterion, assessment.language)
165
+ )
166
+
167
+ total_score += weighted_score
168
+
169
+ # 生成评分分解说明
170
+ breakdown = self._generate_design_breakdown(
171
+ criterion_scores,
172
+ total_score,
173
+ assessment
174
+ )
175
+
176
+ return ScoringResult(
177
+ total_score=min(total_score, 10.0),
178
+ criterion_scores=criterion_scores,
179
+ language=assessment.language,
180
+ scoring_breakdown=breakdown,
181
+ assessment=assessment
182
+ )
183
+
184
+ def _get_criterion_description(self, criterion: str, language: str) -> str:
185
+ """获取评分标准描述"""
186
+ descriptions_zh = {
187
+ 'structure': '文档结构完整性',
188
+ 'ears_format': 'EARS 格式验收标准',
189
+ 'user_stories': '用户故事质量',
190
+ 'acceptance_criteria': '验收标准完整性',
191
+ 'nfr_coverage': '非功能需求覆盖',
192
+ 'constraints': '约束条件说明',
193
+ 'traceability': '需求追溯性',
194
+ 'component_detail': '组件详细度',
195
+ 'diagrams': '架构图和设计图',
196
+ 'technology': '技术选型说明',
197
+ 'nfr_design': '非功能需求设计',
198
+ 'interfaces': '接口定义完整性'
199
+ }
200
+
201
+ descriptions_en = {
202
+ 'structure': 'Document Structure Completeness',
203
+ 'ears_format': 'EARS Format Acceptance Criteria',
204
+ 'user_stories': 'User Story Quality',
205
+ 'acceptance_criteria': 'Acceptance Criteria Completeness',
206
+ 'nfr_coverage': 'Non-functional Requirements Coverage',
207
+ 'constraints': 'Constraints Description',
208
+ 'traceability': 'Requirements Traceability',
209
+ 'component_detail': 'Component Detail Level',
210
+ 'diagrams': 'Architecture and Design Diagrams',
211
+ 'technology': 'Technology Stack Explanation',
212
+ 'nfr_design': 'Non-functional Requirements Design',
213
+ 'interfaces': 'Interface Definition Completeness'
214
+ }
215
+
216
+ if language == 'zh':
217
+ return descriptions_zh.get(criterion, criterion)
218
+ else:
219
+ return descriptions_en.get(criterion, criterion)
220
+
221
+ def _generate_requirements_breakdown(self, criterion_scores: Dict[str, CriterionScore], total_score: float, assessment: QualityAssessment) -> str:
222
+ """生成 Requirements 评分分解说明"""
223
+ lang = assessment.language
224
+
225
+ if lang == 'zh':
226
+ breakdown = f"## 评分分解\n\n"
227
+ breakdown += f"**总分**: {total_score:.2f}/10\n\n"
228
+ breakdown += f"### 各项评分\n\n"
229
+
230
+ for criterion, score_obj in criterion_scores.items():
231
+ breakdown += f"- **{score_obj.description}** ({score_obj.weight*100:.0f}%): "
232
+ breakdown += f"{score_obj.score:.2f}/10 → 加权分 {score_obj.weighted_score:.2f}\n"
233
+
234
+ if assessment.missing_sections:
235
+ breakdown += f"\n### 缺失章节\n\n"
236
+ for section in assessment.missing_sections:
237
+ breakdown += f"- {section}\n"
238
+
239
+ if assessment.issues:
240
+ breakdown += f"\n### 改进建议\n\n"
241
+ for issue in assessment.issues[:5]: # 最多显示 5 个
242
+ breakdown += f"- {issue}\n"
243
+ else:
244
+ breakdown = f"## Scoring Breakdown\n\n"
245
+ breakdown += f"**Total Score**: {total_score:.2f}/10\n\n"
246
+ breakdown += f"### Criterion Scores\n\n"
247
+
248
+ for criterion, score_obj in criterion_scores.items():
249
+ breakdown += f"- **{score_obj.description}** ({score_obj.weight*100:.0f}%): "
250
+ breakdown += f"{score_obj.score:.2f}/10 → Weighted {score_obj.weighted_score:.2f}\n"
251
+
252
+ if assessment.missing_sections:
253
+ breakdown += f"\n### Missing Sections\n\n"
254
+ for section in assessment.missing_sections:
255
+ breakdown += f"- {section}\n"
256
+
257
+ if assessment.issues:
258
+ breakdown += f"\n### Improvement Suggestions\n\n"
259
+ for issue in assessment.issues[:5]: # Show max 5
260
+ breakdown += f"- {issue}\n"
261
+
262
+ return breakdown
263
+
264
+ def _generate_design_breakdown(self, criterion_scores: Dict[str, CriterionScore], total_score: float, assessment: QualityAssessment) -> str:
265
+ """生成 Design 评分分解说明"""
266
+ lang = assessment.language
267
+
268
+ if lang == 'zh':
269
+ breakdown = f"## 评分分解\n\n"
270
+ breakdown += f"**总分**: {total_score:.2f}/10\n\n"
271
+ breakdown += f"### 各项评分\n\n"
272
+
273
+ for criterion, score_obj in criterion_scores.items():
274
+ breakdown += f"- **{score_obj.description}** ({score_obj.weight*100:.0f}%): "
275
+ breakdown += f"{score_obj.score:.2f}/10 → 加权分 {score_obj.weighted_score:.2f}\n"
276
+
277
+ if assessment.missing_sections:
278
+ breakdown += f"\n### 缺失章节\n\n"
279
+ for section in assessment.missing_sections:
280
+ breakdown += f"- {section}\n"
281
+
282
+ if assessment.issues:
283
+ breakdown += f"\n### 改进建议\n\n"
284
+ for issue in assessment.issues[:5]:
285
+ breakdown += f"- {issue}\n"
286
+ else:
287
+ breakdown = f"## Scoring Breakdown\n\n"
288
+ breakdown += f"**Total Score**: {total_score:.2f}/10\n\n"
289
+ breakdown += f"### Criterion Scores\n\n"
290
+
291
+ for criterion, score_obj in criterion_scores.items():
292
+ breakdown += f"- **{score_obj.description}** ({score_obj.weight*100:.0f}%): "
293
+ breakdown += f"{score_obj.score:.2f}/10 → Weighted {score_obj.weighted_score:.2f}\n"
294
+
295
+ if assessment.missing_sections:
296
+ breakdown += f"\n### Missing Sections\n\n"
297
+ for section in assessment.missing_sections:
298
+ breakdown += f"- {section}\n"
299
+
300
+ if assessment.issues:
301
+ breakdown += f"\n### Improvement Suggestions\n\n"
302
+ for issue in assessment.issues[:5]:
303
+ breakdown += f"- {issue}\n"
304
+
305
+ return breakdown
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Report Generator - 报告生成器
4
+
5
+ 生成增强过程的详细报告
6
+ 注意:这是一个轻量级实现,基本报告功能已集成在 EnhancementResult 中
7
+ """
8
+
9
+ from dataclasses import dataclass
10
+ from typing import List, Dict, Optional
11
+ from datetime import datetime
12
+
13
+
14
+ @dataclass
15
+ class EnhancementReport:
16
+ """增强报告数据结构"""
17
+ document_type: str
18
+ document_path: str
19
+ initial_score: float
20
+ final_score: float
21
+ improvement: float
22
+ iterations: int
23
+ stopping_reason: str
24
+ improvements_applied: List[Dict]
25
+ timestamp: str
26
+ gate_passed: Optional[bool] = None
27
+ gate_threshold: Optional[float] = None
28
+
29
+
30
+ class ReportGenerator:
31
+ """
32
+ 报告生成器
33
+
34
+ 生成 Markdown 格式的增强报告和质量摘要
35
+ """
36
+
37
+ def generate_enhancement_report(self, report_data: EnhancementReport) -> str:
38
+ """
39
+ 生成增强报告
40
+
41
+ Args:
42
+ report_data: 报告数据
43
+
44
+ Returns:
45
+ Markdown 格式的报告
46
+ """
47
+ lines = []
48
+
49
+ # 标题
50
+ lines.append(f"# Enhancement Report: {report_data.document_type.upper()}")
51
+ lines.append(f"\n**Generated**: {report_data.timestamp}")
52
+ lines.append(f"**Document**: `{report_data.document_path}`\n")
53
+ lines.append("---\n")
54
+
55
+ # 摘要
56
+ lines.append("## Summary\n")
57
+ lines.append(f"- **Initial Score**: {report_data.initial_score:.2f}/10")
58
+ lines.append(f"- **Final Score**: {report_data.final_score:.2f}/10")
59
+ lines.append(f"- **Improvement**: +{report_data.improvement:.2f}")
60
+ lines.append(f"- **Iterations**: {report_data.iterations}")
61
+ lines.append(f"- **Stopping Reason**: {report_data.stopping_reason}\n")
62
+
63
+ # 质量门结果
64
+ if report_data.gate_passed is not None:
65
+ lines.append("## Quality Gate\n")
66
+ status = "✓ PASSED" if report_data.gate_passed else "✗ FAILED"
67
+ lines.append(f"- **Status**: {status}")
68
+ lines.append(f"- **Threshold**: {report_data.gate_threshold}/10")
69
+ lines.append(f"- **Final Score**: {report_data.final_score:.2f}/10\n")
70
+
71
+ # 改进详情
72
+ if report_data.improvements_applied:
73
+ lines.append("## Improvements Applied\n")
74
+ for i, imp in enumerate(report_data.improvements_applied, 1):
75
+ lines.append(f"{i}. **{imp.get('type', 'Unknown')}**")
76
+ lines.append(f" - Section: {imp.get('section', 'N/A')}")
77
+ lines.append(f" - Priority: {imp.get('priority', 'N/A')}")
78
+ if imp.get('description'):
79
+ lines.append(f" - Description: {imp['description']}")
80
+ lines.append("")
81
+
82
+ lines.append("---\n")
83
+ lines.append(f"*Report generated by Ultrawork Enhancement System*\n")
84
+
85
+ return '\n'.join(lines)
86
+
87
+ def generate_quality_summary(self, reports: List[EnhancementReport]) -> str:
88
+ """
89
+ 生成质量摘要(多个文档)
90
+
91
+ Args:
92
+ reports: 报告列表
93
+
94
+ Returns:
95
+ Markdown 格式的摘要
96
+ """
97
+ lines = []
98
+
99
+ # 标题
100
+ lines.append("# Quality Summary\n")
101
+ lines.append(f"**Generated**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
102
+ lines.append(f"**Documents**: {len(reports)}\n")
103
+ lines.append("---\n")
104
+
105
+ # 总体统计
106
+ total_improvement = sum(r.improvement for r in reports)
107
+ avg_iterations = sum(r.iterations for r in reports) / len(reports) if reports else 0
108
+ passed_gates = sum(1 for r in reports if r.gate_passed)
109
+
110
+ lines.append("## Overall Statistics\n")
111
+ lines.append(f"- **Total Improvement**: +{total_improvement:.2f}")
112
+ lines.append(f"- **Average Iterations**: {avg_iterations:.1f}")
113
+ if any(r.gate_passed is not None for r in reports):
114
+ lines.append(f"- **Quality Gates Passed**: {passed_gates}/{len(reports)}\n")
115
+ else:
116
+ lines.append("")
117
+
118
+ # 各文档详情
119
+ lines.append("## Document Details\n")
120
+ for report in reports:
121
+ lines.append(f"### {report.document_type.upper()}\n")
122
+ lines.append(f"- **Path**: `{report.document_path}`")
123
+ lines.append(f"- **Score**: {report.initial_score:.2f} → {report.final_score:.2f} (+{report.improvement:.2f})")
124
+ lines.append(f"- **Iterations**: {report.iterations}")
125
+
126
+ if report.gate_passed is not None:
127
+ status = "✓ PASSED" if report.gate_passed else "✗ FAILED"
128
+ lines.append(f"- **Quality Gate**: {status}")
129
+
130
+ lines.append("")
131
+
132
+ lines.append("---\n")
133
+ lines.append(f"*Summary generated by Ultrawork Enhancement System*\n")
134
+
135
+ return '\n'.join(lines)
136
+
137
+ def save_report(self, report: str, output_path: str):
138
+ """
139
+ 保存报告到文件
140
+
141
+ Args:
142
+ report: 报告内容
143
+ output_path: 输出路径
144
+ """
145
+ from pathlib import Path
146
+
147
+ Path(output_path).parent.mkdir(parents=True, exist_ok=True)
148
+
149
+ with open(output_path, 'w', encoding='utf-8') as f:
150
+ f.write(report)
151
+
152
+
153
+ # 注意:基本报告功能已集成在 ultrawork_enhancer_v3.py 的 EnhancementResult 中
154
+ # 本类提供更详细的 Markdown 格式报告生成,可选使用