194 lines
6.7 KiB
Python
194 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
自动完成检查 Hook
|
|
拦截任务结束,执行代码质量检查
|
|
"""
|
|
import json
|
|
import sys
|
|
import os
|
|
from pathlib import Path
|
|
|
|
|
|
# 导入模块
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
from requirements_tracker import generate_requirement_checklist, save_checklist
|
|
from code_analyzer import analyze_code_quality, calculate_completeness_score
|
|
from notification_sender import notify_check_result
|
|
|
|
|
|
def load_iteration_tracker(project_root):
|
|
"""加载迭代计数器"""
|
|
tracker_file = Path(project_root) / '.claude' / 'iteration-tracker.json'
|
|
|
|
if tracker_file.exists():
|
|
with open(tracker_file, 'r', encoding='utf-8') as f:
|
|
return json.load(f)
|
|
|
|
return {}
|
|
|
|
|
|
def update_iteration_count(project_root, task_id, increment=True):
|
|
"""更新迭代计数"""
|
|
tracker = load_iteration_tracker(project_root)
|
|
|
|
if task_id not in tracker:
|
|
tracker[task_id] = 0
|
|
|
|
if increment:
|
|
tracker[task_id] += 1
|
|
|
|
# 保存
|
|
tracker_file = Path(project_root) / '.claude' / 'iteration-tracker.json'
|
|
tracker_file.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(tracker_file, 'w', encoding='utf-8') as f:
|
|
json.dump(tracker, f, ensure_ascii=False, indent=2)
|
|
|
|
return tracker[task_id]
|
|
|
|
|
|
def reset_iteration_count(project_root, task_id):
|
|
"""重置迭代计数(任务完成时)"""
|
|
return update_iteration_count(project_root, task_id, increment=False)
|
|
|
|
|
|
def generate_fix_requirements(issues, requirements_checklist):
|
|
"""生成修复要求"""
|
|
fix_requirements = []
|
|
|
|
# 从代码问题生成修复要求
|
|
if issues['todo']:
|
|
fix_requirements.append(f"- 处理 {len(issues['todo'])} 个 TODO/FIXME 项")
|
|
|
|
if issues['empty_functions']:
|
|
fix_requirements.append(f"- 实现以下空函数: {', '.join([f'{i[\"file\"]}:{i[\"line\"]}' for i in issues['empty_functions'][:3]])}")
|
|
|
|
if issues['placeholders']:
|
|
fix_requirements.append(f"- 移除或实现占位符代码 ({len(issues['placeholders'])} 处)")
|
|
|
|
if issues['commented_code']:
|
|
fix_requirements.append(f"- 清理或取消注释代码 ({len(issues['commented_code'])} 处)")
|
|
|
|
# 从需求清单生成修复要求
|
|
unverified = [r for r in requirements_checklist.get('requirements', []) if not r.get('verified', False)]
|
|
if unverified:
|
|
fix_requirements.append(f"- 验证以下需求已完成:\n " + "\n ".join([f"{i+1}. {r['description']}" for i, r in enumerate(unverified[:5])]))
|
|
|
|
return "\n".join(fix_requirements) if fix_requirements else "未发现明显问题,建议人工审查"
|
|
|
|
|
|
def perform_quick_check(project_root, task_id, conversation_context=''):
|
|
"""执行快速检查"""
|
|
# 1. 生成需求检查清单
|
|
requirements_checklist = generate_requirement_checklist(project_root, conversation_context)
|
|
save_checklist(requirements_checklist, task_id, project_root)
|
|
|
|
# 2. 代码质量分析
|
|
analysis_result = analyze_code_quality(project_root)
|
|
score = analysis_result['score']
|
|
issues = analysis_result['issues']
|
|
|
|
# 3. 检查逻辑
|
|
passed = score >= 80
|
|
critical_issues = len(issues['empty_functions']) + len(issues['placeholders'])
|
|
|
|
# 4. 获取迭代计数
|
|
iteration_count = load_iteration_tracker(project_root).get(task_id, 0)
|
|
requires_review = iteration_count >= 3
|
|
|
|
# 5. 生成结果
|
|
result = {
|
|
'passed': passed,
|
|
'score': score,
|
|
'iteration_count': iteration_count,
|
|
'requires_review': requires_review,
|
|
'issues': analysis_result['summary'],
|
|
'total_issues': analysis_result['total_issues']
|
|
}
|
|
|
|
# 6. 决定是否阻止完成
|
|
if not passed and not requires_review:
|
|
# 增加迭代计数
|
|
new_count = update_iteration_count(project_root, task_id)
|
|
result['iteration_count'] = new_count
|
|
|
|
# 生成修复要求
|
|
fix_requirements = generate_fix_requirements(issues, requirements_checklist)
|
|
result['fix_requirements'] = fix_requirements
|
|
result['block_completion'] = True
|
|
result['message'] = f'代码质量检查未通过 (评分: {score}/100,迭代: {new_count}/3)'
|
|
|
|
elif requires_review:
|
|
result['block_completion'] = True
|
|
result['message'] = f'已达最大迭代次数 ({iteration_count}/3),需要深度审查'
|
|
result['trigger_review_agent'] = True
|
|
|
|
else:
|
|
# 通过,重置计数
|
|
reset_iteration_count(project_root, task_id)
|
|
result['block_completion'] = False
|
|
result['message'] = f'代码质量检查通过 (评分: {score}/100)'
|
|
|
|
return result
|
|
|
|
|
|
def main():
|
|
"""主函数"""
|
|
try:
|
|
# 加载输入
|
|
input_data = json.load(sys.stdin)
|
|
except json.JSONDecodeError:
|
|
input_data = {}
|
|
|
|
# 获取参数
|
|
project_root = input_data.get('projectRoot', os.getcwd())
|
|
task_id = input_data.get('taskId', 'default')
|
|
conversation_context = input_data.get('conversationContext', '')
|
|
|
|
# 执行快速检查
|
|
check_result = perform_quick_check(project_root, task_id, conversation_context)
|
|
|
|
# 发送通知(异步,不阻塞)
|
|
if check_result.get('passed') or check_result.get('requires_review'):
|
|
try:
|
|
notify_check_result(check_result)
|
|
except Exception:
|
|
pass # 通知失败不影响主流程
|
|
|
|
# 显示终端信息
|
|
if not check_result.get('passed'):
|
|
print(f"\n{'='*60}", file=sys.stderr)
|
|
print(f"⚠️ 代码质量检查未通过", file=sys.stderr)
|
|
print(f"{'='*60}", file=sys.stderr)
|
|
print(f"评分: {check_result['score']}/100", file=sys.stderr)
|
|
print(f"迭代次数: {check_result['iteration_count']}/3", file=sys.stderr)
|
|
print(f"\n发现的问题:", file=sys.stderr)
|
|
for key, count in check_result['issues'].items():
|
|
if count > 0:
|
|
print(f" - {key}: {count}", file=sys.stderr)
|
|
print(f"\n修复要求:", file=sys.stderr)
|
|
print(check_result.get('fix_requirements', ''), file=sys.stderr)
|
|
print(f"{'='*60}\n", file=sys.stderr)
|
|
|
|
# 构造 Hook 输出
|
|
output = {
|
|
'hookSpecificOutput': {
|
|
'hookEventName': 'TaskEnd',
|
|
'blockCompletion': check_result.get('block_completion', False),
|
|
'additionalContext': check_result.get('fix_requirements', ''),
|
|
'triggerReviewAgent': check_result.get('trigger_review_agent', False),
|
|
'checkResult': check_result
|
|
}
|
|
}
|
|
|
|
# 如果通过,添加成功消息
|
|
if check_result.get('passed'):
|
|
output['hookSpecificOutput']['message'] = f"✅ 代码质量检查通过 (评分: {check_result['score']}/100)"
|
|
|
|
# 输出 JSON
|
|
print(json.dumps(output, ensure_ascii=False))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|