| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- #!/usr/bin/env python3
- """
- Cursor任务执行触发器
- 这个脚本会读取pending_tasks.json,并以明确格式输出任务信息,
- 供Cursor识别并自动执行。
- 支持两种模式:
- 1. 单次执行:python scripts/trigger_cursor_execution.py --once
- 2. 定期执行:python scripts/trigger_cursor_execution.py --interval 300
- 定期执行模式下,脚本会:
- - 定期检查processing任务
- - 自动生成执行指令文件(.cursor/task_execute_instructions.md)
- - 输出任务信息供Cursor识别
- """
- import json
- import sys
- import time
- import argparse
- import logging
- from pathlib import Path
- from datetime import datetime
- # 配置日志
- logging.basicConfig(
- level=logging.INFO,
- format='%(asctime)s - %(levelname)s - %(message)s'
- )
- logger = logging.getLogger('CursorTaskTrigger')
- def get_task_file_path(task, workspace):
- """获取任务文件路径"""
- import os
- import re
-
- task_file = task.get('task_file')
- if not task_file and task.get('code_path'):
- # 从任务名称生成文件名
- task_name = task['task_name']
- safe_name = re.sub(r'[^\w\u4e00-\u9fff]+', '_', task_name)
- safe_name = re.sub(r'_+', '_', safe_name).strip('_')
- code_path = task.get('code_path', 'app/core/data_flow')
- task_file = os.path.join(workspace, code_path, f"{safe_name}.py")
- if not os.path.exists(task_file):
- task_file = None
- return task_file
- def create_execute_instructions_file(workspace, processing_tasks):
- """
- 创建任务执行指令文件,供Cursor自动读取
-
- Args:
- workspace: 工作区路径
- processing_tasks: 待处理任务列表
- """
- instructions_file = workspace / '.cursor' / 'task_execute_instructions.md'
- instructions_file.parent.mkdir(parents=True, exist_ok=True)
-
- with open(instructions_file, 'w', encoding='utf-8') as f:
- f.write(f"# 🤖 Cursor自动任务执行指令\n\n")
- f.write(f"**⚠️ 重要:Cursor AI请立即执行此文件中的任务!**\n\n")
- f.write(f"**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
- f.write(f"**待执行任务数量**: {len(processing_tasks)}\n\n")
- f.write(f"**执行状态**: ⏳ 等待执行\n\n")
- f.write("---\n\n")
- f.write(f"## 📋 执行指令\n\n")
- f.write(f"**Cursor AI:请按照以下步骤执行任务:**\n\n")
- f.write(f"1. 依次处理每个任务\n")
- f.write(f"2. 打开任务文件并实现功能\n")
- f.write(f"3. 完成后调用MCP工具更新状态\n\n")
- f.write("---\n\n")
-
- for idx, task in enumerate(processing_tasks, 1):
- task_file = get_task_file_path(task, workspace)
-
- f.write(f"## 🔴 任务 {idx}/{len(processing_tasks)}: [{task['task_id']}] {task['task_name']}\n\n")
- f.write(f"**执行状态**: ⏳ 待执行\n\n")
- f.write(f"**任务文件**: `{task_file or '未创建'}`\n\n")
- f.write(f"### 📝 任务描述\n\n{task['task_description']}\n\n")
- f.write(f"### ✅ 执行步骤(Cursor AI请按此执行)\n\n")
- f.write(f"#### 步骤1:打开任务文件\n")
- f.write(f"- 文件路径: `{task_file or 'N/A'}`\n")
- f.write(f"- 如果文件不存在,需要先创建\n\n")
- f.write(f"#### 步骤2:实现功能\n")
- f.write(f"- 仔细阅读上述任务描述\n")
- f.write(f"- 根据描述实现完整的功能\n")
- f.write(f"- 确保代码符合项目规范(PEP 8)\n")
- f.write(f"- 添加必要的错误处理和日志记录\n\n")
- f.write(f"#### 步骤3:验证代码\n")
- f.write(f"- 确保代码可以正常运行\n")
- f.write(f"- 检查代码逻辑是否正确\n\n")
- f.write(f"#### 步骤4:更新任务状态\n")
- f.write(f"- 调用MCP工具 `update_task_status`\n")
- f.write(f"- 使用以下参数:\n\n")
- f.write(f"```json\n")
- f.write(f"{{\n")
- f.write(f" \"tool\": \"update_task_status\",\n")
- f.write(f" \"task_id\": {task['task_id']},\n")
- if task_file:
- import os
- file_name = os.path.basename(task_file)
- file_dir = os.path.dirname(task_file).replace(str(workspace), '').strip('\\').strip('/').replace('\\', '/')
- f.write(f" \"code_name\": \"{file_name}\",\n")
- f.write(f" \"code_path\": \"{file_dir}\",\n")
- f.write(f" \"status\": \"completed\"\n")
- f.write(f"}}\n")
- f.write(f"```\n\n")
- f.write(f"**⚠️ 重要:必须完成上述所有步骤!**\n\n")
- f.write("---\n\n")
-
- logger.info(f"✅ 任务执行指令文件已创建: {instructions_file}")
-
- # 创建触发器文件,更新时间戳
- trigger_file = workspace / '.cursor' / 'task_trigger.txt'
- with open(trigger_file, 'w', encoding='utf-8') as f:
- f.write(f"CURSOR_AUTO_EXECUTE_TASK_TRIGGER\n")
- f.write(f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
- f.write(f"状态: 有 {len(processing_tasks)} 个任务待执行\n\n")
- f.write(f"此文件用于触发Cursor自动执行任务。\n")
- f.write(f"当此文件更新时间在5分钟内时,Cursor应该检查 .cursor/task_execute_instructions.md 并执行其中的任务。\n")
-
- logger.info(f"✅ 触发器文件已更新: {trigger_file}")
- def execute_tasks_once():
- """
- 执行一次任务检查和触发
-
- Returns:
- 找到的任务数量
- """
- workspace = Path(__file__).parent.parent
- pending_tasks_file = workspace / '.cursor' / 'pending_tasks.json'
-
- if not pending_tasks_file.exists():
- logger.info("⚠️ 没有找到pending任务文件")
- return 0
-
- try:
- with open(pending_tasks_file, 'r', encoding='utf-8') as f:
- pending_tasks = json.load(f)
-
- if not pending_tasks:
- logger.info("✅ 没有pending任务")
- return 0
-
- # 处理所有任务(如果没有status字段,默认为processing)
- # 只处理状态为processing或没有status的任务
- processing_tasks = [
- t for t in pending_tasks
- if t.get('status', 'processing') == 'processing' or 'status' not in t
- ]
-
- if not processing_tasks:
- logger.info("✅ 没有processing状态的任务")
- return 0
-
- logger.info(f"📋 找到 {len(processing_tasks)} 个processing任务,需要执行")
-
- # 创建执行指令文件
- create_execute_instructions_file(workspace, processing_tasks)
-
- # 输出任务信息供Cursor识别
- print("\n" + "=" * 80)
- print(f"🤖 [CURSOR-AUTO-EXECUTE] 发现 {len(processing_tasks)} 个待执行任务")
- print("=" * 80 + "\n")
-
- for task in processing_tasks:
- task_file = get_task_file_path(task, workspace)
-
- print(f"\n🤖 [CURSOR-EXECUTE-TASK]")
- print(f"任务ID: {task['task_id']}")
- print(f"任务名称: {task['task_name']}")
- print(f"任务文件: {task_file or '未创建'}")
- print(f"\n任务描述:\n{task['task_description']}")
- print(f"\n执行指令:")
- print(f"1. 打开任务文件: {task_file or task.get('code_path', 'app/core/data_flow') + '/' + task['task_name'] + '.py'}")
- print(f"2. 根据任务描述实现功能")
- print(f"3. 调用MCP工具更新状态:")
- print(f" 工具: update_task_status")
- print(f" 参数: {{")
- print(f" \"task_id\": {task['task_id']},")
- if task_file:
- import os
- file_path = task_file
- file_name = os.path.basename(file_path)
- file_dir = os.path.dirname(file_path).replace(str(workspace), '').strip('\\').strip('/').replace('\\', '/')
- print(f" \"code_name\": \"{file_name}\",")
- print(f" \"code_path\": \"{file_dir}\",")
- print(f" \"status\": \"completed\"")
- print(f" }}")
- print(f"\n🔚 [END-CURSOR-EXECUTE-TASK]\n")
- print("=" * 80)
-
- print(f"\n💡 提示:任务执行指令已保存到 .cursor/task_execute_instructions.md")
- print(f"💡 Cursor可以自动读取此文件并执行任务\n")
-
- return len(processing_tasks)
-
- except Exception as e:
- logger.error(f"❌ 读取任务文件失败: {e}")
- return 0
- def execute_tasks_loop(interval=300):
- """
- 循环执行任务检查和触发
-
- Args:
- interval: 检查间隔(秒),默认300秒(5分钟)
- """
- logger.info("=" * 80)
- logger.info("🚀 Cursor任务执行触发器已启动(定期模式)")
- logger.info(f"⏰ 检查间隔: {interval}秒 ({interval//60}分钟)")
- logger.info("按 Ctrl+C 停止服务")
- logger.info("=" * 80 + "\n")
-
- try:
- while True:
- try:
- count = execute_tasks_once()
-
- if count > 0:
- logger.info(f"\n✅ 已触发 {count} 个任务执行")
- logger.info(f"💡 任务指令已保存到 .cursor/task_execute_instructions.md")
- logger.info(f"💡 Cursor将自动读取并执行任务\n")
-
- logger.info(f"\n⏳ 下次检查时间: {interval}秒后...")
- time.sleep(interval)
-
- except KeyboardInterrupt:
- raise
- except Exception as e:
- logger.error(f"❌ 执行出错: {e}")
- logger.info(f"⏳ {interval}秒后重试...")
- time.sleep(interval)
-
- except KeyboardInterrupt:
- logger.info("\n" + "=" * 80)
- logger.info("⛔ 用户停止了Cursor任务执行触发器")
- logger.info("=" * 80)
- def main():
- """
- 主函数
- """
- parser = argparse.ArgumentParser(
- description='Cursor任务执行触发器 - 定期检查并触发任务执行'
- )
- parser.add_argument(
- '--once',
- action='store_true',
- help='只执行一次检查,不持续运行'
- )
- parser.add_argument(
- '--interval',
- type=int,
- default=300,
- help='检查间隔(秒),默认300秒(5分钟)'
- )
-
- args = parser.parse_args()
-
- if args.once:
- # 执行一次
- count = execute_tasks_once()
- logger.info(f"\n✅ 完成!找到 {count} 个待执行任务")
- else:
- # 循环执行
- execute_tasks_loop(interval=args.interval)
- if __name__ == '__main__':
- main()
|