This repository has been archived on 2026-03-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
AIMisc/code-quality-system/hooks/requirements-tracker.py
T
2026-01-30 00:42:33 +08:00

155 lines
4.4 KiB
Python

#!/usr/bin/env python3
"""
需求追踪器
从对话历史和计划文件中提取需求,生成检查清单
"""
import json
import sys
import os
import re
from pathlib import Path
def load_input():
"""加载 Hook 输入数据"""
try:
return json.load(sys.stdin)
except json.JSONDecodeError:
return {}
def extract_requirements_from_conversation(conversation_text):
"""从对话中提取需求"""
requirements = []
# 需求关键词模式
patterns = {
'功能需求': r'(需要|实现|添加|创建|开发)\s*([^,。;\n]{5,50})',
'技术栈': r'(使用|基于|框架)\s*([^,。;\n]{2,30})',
'约束条件': r'(必须|应该|不能|禁止)\s*([^,。;\n]{5,50})',
}
for category, pattern in patterns.items():
matches = re.findall(pattern, conversation_text)
for match in matches:
if isinstance(match, tuple):
requirements.append({
'category': category,
'description': match[-1].strip(),
'verified': False
})
return requirements
def read_plan_files(project_root):
"""读取项目计划文件"""
plan_files = []
docs_path = Path(project_root) / 'docs' / 'plans'
if docs_path.exists():
for plan_file in docs_path.glob('*.md'):
try:
with open(plan_file, 'r', encoding='utf-8') as f:
content = f.read()
plan_files.append({
'path': str(plan_file),
'content': content
})
except Exception as e:
pass
return plan_files
def parse_plan_to_checklist(plan_content):
"""解析计划文件为检查清单"""
checklist = []
# 提取任务/功能项
lines = plan_content.split('\n')
for line in lines:
line = line.strip()
# 匹配 markdown 列表项
if line.startswith('- ') or line.startswith('* '):
item = line[2:].strip()
# 移除 [ ] 或 [x] 标记
item = re.sub(r'^\[[ x]\]\s*', '', item)
if item:
checklist.append({
'description': item,
'verified': False,
'source': 'plan_file'
})
return checklist
def generate_requirement_checklist(project_root, conversation_context=''):
"""生成需求检查清单"""
checklist = {
'requirements': [],
'source': 'unknown'
}
# 1. 尝试从计划文件读取
plan_files = read_plan_files(project_root)
if plan_files:
for plan in plan_files:
items = parse_plan_to_checklist(plan['content'])
checklist['requirements'].extend(items)
checklist['source'] = 'plan_files'
checklist['plan_files'] = [p['path'] for p in plan_files]
# 2. 如果没有计划文件,从对话提取
if not checklist['requirements'] and conversation_context:
items = extract_requirements_from_conversation(conversation_context)
checklist['requirements'] = items
checklist['source'] = 'conversation'
return checklist
def save_checklist(checklist, task_id, project_root):
"""保存检查清单到临时文件"""
cache_dir = Path(project_root) / '.claude' / 'cache'
cache_dir.mkdir(parents=True, exist_ok=True)
checklist_file = cache_dir / f'requirements_{task_id}.json'
with open(checklist_file, 'w', encoding='utf-8') as f:
json.dump(checklist, f, ensure_ascii=False, indent=2)
return str(checklist_file)
def main():
"""主函数"""
input_data = load_input()
# 获取项目根目录
project_root = input_data.get('projectRoot', os.getcwd())
# 获取对话上下文(如果有)
conversation_context = input_data.get('conversationContext', '')
# 生成检查清单
checklist = generate_requirement_checklist(project_root, conversation_context)
# 保存到缓存
task_id = input_data.get('taskId', 'default')
checklist_file = save_checklist(checklist, task_id, project_root)
# 输出结果
output = {
'checklist_generated': True,
'requirements_count': len(checklist['requirements']),
'source': checklist['source'],
'checklist_file': checklist_file
}
print(json.dumps(output, ensure_ascii=False))
if __name__ == '__main__':
main()