#!/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()