├── .cursor └── rules ├── .gitignore ├── LICENSE ├── PROJECT_PROGRESS.md ├── QUICKSTART.md ├── README.md ├── README.zh.md ├── learning_notes ├── daily │ └── 2025-03-12.json ├── reviews │ └── review_20250312.json ├── stats.json └── topics │ ├── python │ └── 2025-03-12-0002.json │ └── test │ └── 2025-03-12-0001.json ├── learning_paths ├── current_path.json └── paths.json ├── pdm.lock ├── project_management ├── .task_count ├── actuals │ ├── decisions │ │ └── .gitkeep │ ├── reports │ │ ├── daily │ │ │ └── .gitkeep │ │ └── weekly │ │ │ └── .gitkeep │ └── tasks │ │ └── TASK-001_开发命令系统核心功能.md ├── control │ ├── MAIN_CONTROL.md │ └── REQUIREMENTS.md ├── scripts │ └── create_task.sh └── templates │ ├── daily_report_template.md │ ├── decision_template.md │ ├── main_control_template.md │ ├── project_progress_template.md │ ├── risk_template.md │ ├── task_template.md │ └── weekly_report_template.md ├── pyproject.toml ├── requirements.txt ├── scripts ├── create_report.sh ├── generate_timestamp.py ├── hooks │ └── pre-commit ├── init_project.sh ├── simple_timestamp.sh ├── timestamp.sh └── update_progress.sh ├── setup.py └── src └── cursormind ├── __init__.py ├── __main__.py ├── cli.py ├── config ├── __init__.py └── settings.py ├── core ├── __init__.py ├── achievement.py ├── code_review.py ├── command_handler.py ├── cursor_framework.py ├── learning_path.py ├── note_manager.py └── project_manager.py └── utils ├── __init__.py ├── helpers.py └── note_manager.py /.cursor/rules: -------------------------------------------------------------------------------- 1 | # Cursor Engineering Rules v2.0 2 | 3 | ## Project Management Structure 4 | - Use `project_management/control/MAIN_CONTROL.md` as the single source of truth for project status 5 | - Follow standardized naming conventions for all reports: 6 | - Daily: `project_management/actuals/reports/daily/daily_report_YYYYMMDD.md` 7 | - Weekly: `project_management/actuals/reports/weekly/weekly_report_YYYYWNN.md` 8 | - Decisions: `project_management/actuals/decisions/decision_DID.md` 9 | - Update `PROJECT_PROGRESS.md` for stakeholder-facing progress tracking 10 | - Always use `scripts/generate_timestamp.py` to generate consistent timestamps 11 | - Supported formats: full, date, datetime, compact, week 12 | - Never create or modify timestamps manually 13 | 14 | ## Code Development Standards 15 | - Implement complete, production-ready code with proper error handling 16 | - Maintain 80% code to 20% documentation ratio in implementation files 17 | - Follow language-specific best practices (PEP8 for Python, etc.) 18 | - Ensure unit test coverage for all new functionality (minimum 85%) 19 | - Document public APIs with standardized docstrings 20 | - Review code for security vulnerabilities before submission 21 | - Never reference non-existent files, functions, or features 22 | 23 | ## Workflow Optimization 24 | - Use [CODE NOW] when analysis exceeds 5 minutes without concrete progress 25 | - Implement [FOCUS] technique to establish clear context boundaries 26 | - Apply [RESET] command to break circular reasoning patterns 27 | - Use [DECISION] marker to document important engineering choices 28 | - Follow "implement, test, refactor" development cycle 29 | - Commit frequently with descriptive, atomic changes 30 | - Avoid thought loops: prioritize execution over excessive analysis 31 | - When uncertain, ask directly instead of making assumptions 32 | 33 | ## Task Execution Guidelines 34 | - Define tasks with SMART criteria (Specific, Measurable, Achievable, Relevant, Time-bound) 35 | - Break large tasks into sub-tasks of no more than 4 hours each 36 | - Include verification methods and acceptance criteria for each task 37 | - Link tasks to specific project requirements or objectives 38 | - Document blockers and dependencies explicitly 39 | - Set clear completion deadlines for all tasks 40 | - Provide clear progress updates during long-running tasks 41 | 42 | ## Quality Assurance Practices 43 | - Conduct peer code reviews for all significant changes 44 | - Run static analysis tools before committing (linters, type checkers) 45 | - Validate against performance benchmarks for critical components 46 | - Document edge cases and their handling mechanisms 47 | - Maintain backward compatibility unless explicitly specified otherwise 48 | - Create regression tests for all bug fixes 49 | 50 | ## Documentation Integrity 51 | - README files must accurately reflect actual project functionality 52 | - Never add descriptions of unimplemented features 53 | - Verify functionality exists before updating documentation 54 | - When referencing code, specify exact file paths and line numbers 55 | - Maintain consistent version numbers across all documents 56 | 57 | ## Memory and Context Management 58 | - Always reference current file contents before making changes 59 | - Review previous conversations to maintain context continuity 60 | - Keep track of project history and development decisions 61 | - Do not forget previous instructions or requirements 62 | - When context is unclear, review existing files before proceeding 63 | 64 | ## Error Handling Protocol 65 | - Acknowledge errors immediately without justification 66 | - Correct mistakes based on actual project content 67 | - When fabrication is detected, reset and respond with verified information 68 | - Provide concise, accurate responses without unnecessary elaboration 69 | - Document error patterns to prevent recurrence -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python虚拟环境 2 | .venv/ 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # 日报和周报文件 8 | project_management/actuals/reports/daily/*.md 9 | project_management/actuals/reports/weekly/*.md 10 | !project_management/actuals/reports/daily/.gitkeep 11 | !project_management/actuals/reports/weekly/.gitkeep 12 | 13 | # 决策记录 14 | project_management/actuals/decisions/*.md 15 | !project_management/actuals/decisions/.gitkeep 16 | 17 | # 临时文件 18 | temp_*.md 19 | 20 | # 系统文件 21 | .DS_Store 22 | Thumbs.db 23 | 24 | # 本地讨论文件 25 | project_management/ideaguide.md -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 yagami 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PROJECT_PROGRESS.md: -------------------------------------------------------------------------------- 1 | # 项目进度跟踪 2 | 3 | ## 项目信息 4 | - **项目名称**: CursorMind 5 | - **版本**: Beta 0.1 -> Beta 0.2.1 6 | - **开始日期**: 2025-03-07 7 | - **计划完成日期**: 2025-03-15 8 | - **当前状态**: 进行中 9 | - **当前进度**: 75% 10 | 11 | ## 里程碑 12 | | 里程碑 | 计划日期 | 实际日期 | 状态 | 负责人 | 13 | |-------|---------|---------|------|-------| 14 | | 项目启动 | 2025-03-07 | 2025-03-07 | 已完成 | Team | 15 | | Beta 0.1发布 | 2025-03-07 | 2025-03-07 | 已完成 | Team | 16 | | 核心功能重构 | 2025-03-12 | 2025-03-12 | 已完成 | Team | 17 | | Beta 0.2.1发布 | 2025-03-12 | 2025-03-12 | 已完成 | Team | 18 | | 文档完善 | 2025-03-13 | | 进行中 | Team | 19 | | 功能测试 | 2025-03-14 | | 未开始 | Team | 20 | | 正式版本发布 | 2025-03-15 | | 未开始 | Team | 21 | 22 | ## 进度更新历史 23 | | 日期 | 进度 | 更新内容 | 更新人 | 24 | |------|------|---------|-------| 25 | | 2025-03-07 | 15% | 项目初始化完成,基础框架搭建 | Team | 26 | | 2025-03-11 | 25% | Beta 0.1文档规范化完成,规划后续版本开发 | Team | 27 | | 2025-03-12 | 75% | 完成核心功能重构,发布Beta 0.2.1版本:
- 重构代码审查功能
- 优化性能检查逻辑
- 增强文件操作安全性
- 完善项目管理功能
- 添加学习路径功能
- 更新中英文文档 | Team | 28 | 29 | ## 已完成功能 30 | 1. **代码质量保证** 31 | - 代码风格检查 32 | - 性能分析系统 33 | - 安全检查机制 34 | - 最佳实践建议 35 | 36 | 2. **项目管理工具** 37 | - 进度追踪系统 38 | - 任务管理功能 39 | - 报告生成器 40 | - 团队协作功能 41 | 42 | 3. **学习与发展** 43 | - 学习路径管理 44 | - 最佳实践指南 45 | - 示例代码库 46 | - 技术文档系统 47 | 48 | ## 风险与问题 49 | | ID | 描述 | 影响程度 | 状态 | 解决方案 | 负责人 | 50 | |----|-----|---------|------|---------|-------| 51 | | R001 | 功能扩展与复杂度平衡 | 低 | 已解决 | 采用模块化设计,实现功能解耦 | Team | 52 | | R002 | 文档更新及时性 | 低 | 已解决 | 建立实时文档更新机制 | Team | 53 | | R003 | 用户体验一致性 | 中 | 开放 | 制定统一的UI/UX规范 | Team | 54 | | R004 | 跨平台兼容性 | 中 | 开放 | 增加平台特定的适配层 | Team | 55 | 56 | ## 下一步计划 57 | - [ ] 完善单元测试覆盖率 58 | - [ ] 添加更多实用示例 59 | - [ ] 优化错误处理机制 60 | - [ ] 改进命令行交互体验 61 | - [ ] 编写详细的API文档 62 | - [ ] 制作视频教程和演示 63 | - [ ] 建立用户反馈系统 64 | 65 | ## 版本规划 66 | ### 即将发布 (2025-03-15) 67 | - 完整的测试覆盖 68 | - 优化的错误处理 69 | - 改进的用户体验 70 | - 详细的API文档 71 | - 更多使用示例 72 | 73 | ### 未来规划 74 | - 集成更多IDE支持 75 | - 添加插件系统 76 | - 支持更多编程语言 77 | - 引入AI辅助功能 78 | - 添加可视化界面 79 | 80 | ## 备注 81 | Beta 0.2.1版本标志着项目的重要里程碑,核心功能已经完成重构,接下来将专注于提升用户体验和完善文档体系。项目进展顺利,预计能按期完成最终发布。 82 | 83 | --- 84 | *最后更新: 2025-03-11 23:37:45 PDT* -------------------------------------------------------------------------------- /QUICKSTART.md: -------------------------------------------------------------------------------- 1 | # CursorMind 快速入门指南 2 | 3 | ## 简介 4 | CursorMind (Beta 0.1.1) 是一个专为Cursor开发者设计的轻量级项目管理框架,帮助您在使用AI辅助编程的同时,培养良好的软件工程实践。 5 | 6 | ## 快速开始(5分钟上手) 7 | 8 | ### 1. 初始化项目 9 | ```bash 10 | # 克隆项目 11 | git clone [your-repo-url] 12 | cd your-project 13 | 14 | # 初始化项目结构 15 | ./project_management/scripts/init_project.sh "我的新项目" 16 | ``` 17 | 18 | ### 2. 日常工作流程 19 | 20 | #### 创建并更新日报 21 | ```bash 22 | # 创建今日工作报告 23 | ./project_management/scripts/create_daily_report.sh 24 | 25 | # 示例:更新今日工作内容 26 | vim project_management/actuals/reports/daily/daily_report_20250311.md 27 | 28 | # 更新项目进度(例:完成35%并添加说明) 29 | ./project_management/scripts/update_progress.sh 35 "完成用户认证模块开发" 30 | ``` 31 | 32 | #### 生成周报 33 | ```bash 34 | # 在每周结束时生成周报 35 | ./project_management/scripts/create_weekly_report.sh 36 | 37 | # 系统会自动汇总本周的日报内容 38 | ``` 39 | 40 | #### 创建新任务 41 | ```bash 42 | # 创建新任务 43 | ./project_management/scripts/create_task.sh "实现用户登录功能" 44 | 45 | # 更新任务状态 46 | ./project_management/scripts/update_task.sh TASK-001 "进行中" 47 | ``` 48 | 49 | ### 3. 项目管理最佳实践 50 | - 每日更新工作日报,记录具体进展 51 | ```markdown 52 | ## 今日工作内容 53 | 1. 完成用户认证模块 54 | - 实现JWT认证 55 | - 添加密码加密 56 | ``` 57 | - 及时更新项目进度文件 58 | ```markdown 59 | ## 项目进度 60 | - 版本: Beta 0.1.1 61 | - 进度: 35% 62 | - 说明: 完成核心功能开发 63 | ``` 64 | - 使用标准命令管理工作流 65 | ```bash 66 | # 当遇到问题需要重新规划时 67 | [RESET] ./project_management/scripts/reset_task.sh TASK-001 68 | 69 | # 当需要快速开始执行时 70 | [CODE NOW] ./project_management/scripts/start_task.sh TASK-001 71 | ``` 72 | 73 | ## 项目结构 74 | ``` 75 | project_management/ 76 | ├── control/ # 项目控制文档 77 | │ └── MAIN_CONTROL.md # 项目主控制文件 78 | ├── templates/ # 文档模板 79 | │ ├── daily_report_template.md 80 | │ ├── weekly_report_template.md 81 | │ └── task_template.md 82 | ├── actuals/ # 实际文档 83 | │ └── reports/ # 报告目录 84 | │ ├── daily/ # 日报 85 | │ └── weekly/ # 周报 86 | └── scripts/ # 工具脚本 87 | ├── init_project.sh 88 | ├── create_daily_report.sh 89 | └── update_progress.sh 90 | ``` 91 | 92 | ## 常见命令 93 | - `create_daily_report.sh`: 创建今日工作报告 94 | ```bash 95 | # 示例:创建带有特定说明的日报 96 | ./project_management/scripts/create_daily_report.sh "重要版本发布" 97 | ``` 98 | - `create_weekly_report.sh`: 生成本周工作报告 99 | ```bash 100 | # 示例:生成指定周的报告 101 | ./project_management/scripts/create_weekly_report.sh 2025W11 102 | ``` 103 | - `update_progress.sh`: 更新项目进度 104 | ```bash 105 | # 示例:更新进度并添加里程碑 106 | ./project_management/scripts/update_progress.sh 50 "完成MVP版本" 107 | ``` 108 | 109 | ## 注意事项 110 | 1. 所有时间戳使用PST时区 111 | ```markdown 112 | ## 时间 113 | 2025-03-11 20:02:41 PST 114 | ``` 115 | 2. 文档命名遵循规范 116 | ``` 117 | daily_report_20250311.md 118 | weekly_report_2025W11.md 119 | TASK-001_user_auth.md 120 | ``` 121 | 3. 确保Git忽略了正确的文件 122 | ```gitignore 123 | # .gitignore示例 124 | .DS_Store 125 | node_modules/ 126 | .env 127 | ``` 128 | 129 | ## 常见问题 130 | 131 | Q: 如何修改默认时区? 132 | A: 编辑project_management/scripts/config.sh: 133 | ```bash 134 | # 修改时区设置 135 | TIMEZONE="America/Los_Angeles" # PST时区 136 | ``` 137 | 138 | Q: 报告格式是否可以自定义? 139 | A: 可以修改templates/目录下的对应模板: 140 | ```markdown 141 | # 自定义日报模板示例 142 | ## 时间 143 | [TIMESTAMP] 144 | 145 | ## 自定义字段 146 | [YOUR_CONTENT] 147 | ``` 148 | 149 | Q: 如何处理任务依赖关系? 150 | A: 在任务模板中明确标注: 151 | ```markdown 152 | ## 依赖关系 153 | - 前置任务: TASK-001, TASK-002 154 | - 后续任务: TASK-004 155 | ``` 156 | 157 | ## 获取帮助 158 | 如有问题,请参考: 159 | 1. 项目文档(docs/) 160 | 2. 示例项目(examples/) 161 | 3. 提交Issue获取支持 162 | 163 | ## 命令速查表 164 | | 命令 | 说明 | 示例 | 165 | |-----|------|-----| 166 | | init_project.sh | 初始化项目 | ./scripts/init_project.sh "项目名" | 167 | | create_daily_report.sh | 创建日报 | ./scripts/create_daily_report.sh | 168 | | update_progress.sh | 更新进度 | ./scripts/update_progress.sh 35 "说明" | 169 | | create_task.sh | 创建任务 | ./scripts/create_task.sh "任务名" | 170 | 171 | --- 172 | *最后更新: 2025-03-11 20:02:41 PST* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ✨ CursorMind 2 | 3 |

4 | English Version | 5 | 中文版 6 |

7 | 8 |
9 |

CursorMind

10 |

Elevate Your Development Experience with AI-Powered Tools

11 |

Current Version: Beta 0.2.1

12 | 13 | ![License](https://img.shields.io/badge/License-MIT-blue.svg) 14 | ![Version](https://img.shields.io/badge/Version-Beta%200.2.1-brightgreen.svg) 15 | ![Status](https://img.shields.io/badge/Status-In%20Development-orange.svg) 16 | ![Language](https://img.shields.io/badge/Language-Python-yellow.svg) 17 | ![Python Version](https://img.shields.io/badge/Python-3.9--3.13-blue.svg) 18 |
19 | 20 | ## 📝 Update Log 21 | 22 | ### Beta 0.2.1 (2025-03-12 00:25:02 PDT) 23 | - 🔄 Enhanced core architecture for improved stability and performance 24 | - ✨ Introduced comprehensive code review system with multi-standard support 25 | - 🛡️ Strengthened file operation security mechanisms 26 | - ⚡️ Optimized performance analysis algorithms 27 | - 📊 Expanded project management capabilities 28 | - 📚 Launched interactive learning paths feature 29 | 30 | ### Beta 0.1 (2025-03-07) 31 | - 🎉 Initial release with foundational framework 32 | - ✅ Core functionality implementation 33 | 34 | --- 35 | 36 | ## 📖 Project Introduction 37 | 38 | 🌟 **CursorMind** is your intelligent companion for AI-assisted development, designed to serve developers 👨‍💻, project managers 👨‍💼, teams 👥, and students 👨‍🎓. Beyond traditional development tools, it integrates code quality assurance 🛠️, project management 📊, learning assistance 📚, and best practice guidelines 📝. For students beginning their programming journey, CursorMind provides an ideal platform 🎯 to develop proper software engineering mindset 🧠 from day one. 39 | 40 | ### 🎯 Core Values 41 | 42 | 1. **Educational Excellence** 43 | - Structured learning paths for programming beginners 44 | - Standardized teaching frameworks for educators 45 | - Hands-on projects for practical skill development 46 | 47 | 2. **Development Standards** 48 | - Industry-aligned coding guidelines 49 | - Best practice implementations 50 | - Quality-focused development approach 51 | 52 | 3. **Project Management** 53 | - Streamlined project workflows 54 | - Enhanced team collaboration 55 | - Quality-driven delivery process 56 | 57 | 4. **Automation Tools** 58 | - Intelligent code quality assessment 59 | - Performance optimization tools 60 | - Security vulnerability detection 61 | 62 | ## 🚀 Feature Details 63 | 64 | CursorMind offers comprehensive development support: 65 | 66 | ### 1. Code Quality Assurance ⚡️ 67 | - Smart code review with standard compliance 68 | - Performance analysis and optimization 69 | - Automated security vulnerability detection 70 | - Best practice guidance 71 | 72 | ### 2. Project Management Tools 📊 73 | - Project progress tracking 74 | - Team collaboration workflows 75 | - Automated reporting system 76 | - Quality metrics monitoring 77 | 78 | ### 3. Learning & Development 📚 79 | - Personalized learning paths 80 | - Rich resource library 81 | - Practical project exercises 82 | - Skill assessment tools 83 | 84 | ### 4. Development Tools Integration 🛠️ 85 | - Automated workflow configuration 86 | - Version control integration 87 | - CI/CD pipeline support 88 | - Development environment standardization 89 | 90 |
91 | View Detailed Feature List 👉 92 | 93 | - **Code Review** 94 | - Style Compliance: PEP8, Google Style, and other standard checks 95 | - Complexity Analysis: Cyclomatic complexity calculation and refactoring suggestions 96 | - Naming Conventions: Best practice validation for variables, functions, and classes 97 | - Documentation Coverage: Critical functionality documentation verification 98 | 99 | - **Performance Analysis** 100 | - Algorithm Complexity: Time and space complexity assessment 101 | - Memory Management: Leak detection and usage optimization 102 | - Performance Profiling: Bottleneck identification 103 | - Optimization Guide: Targeted improvement recommendations 104 | 105 | - **Project Management** 106 | - Progress Tracking: Milestone management and burndown analysis 107 | - Task Management: Smart task breakdown and workload assessment 108 | - Team Collaboration: Code review workflow and knowledge sharing 109 | - Quality Monitoring: Automated testing and performance tracking 110 | 111 | - **Learning Resources** 112 | - Skill Map: Personalized improvement pathways 113 | - Practice Projects: Curated exercise collection 114 | - Best Practices: Detailed coding standards and architecture guidelines 115 | - Reference Code: Common functionality implementations 116 | 117 | - **Tool Integration** 118 | - CI/CD: Pipeline configuration and automation 119 | - Git Integration: Version control and branch management 120 | - Environment Setup: Development environment automation 121 | - IDE Support: Popular development tool integration 122 |
123 | 124 | ## 🎯 Getting Started 125 | 126 | Choose your path with CursorMind: 127 | 128 | ### 1. Individual Developer 👨‍💻 129 | 130 | Quick start with code quality tools: 131 | ```bash 132 | # Install the toolkit 133 | pip install cursormind 134 | export PYTHONPATH=src # Unix/macOS 135 | set PYTHONPATH=src # Windows 136 | 137 | # Begin using 138 | cursormind review file your_code.py # Code review 139 | cursormind analyze dir your_project/ # Project analysis 140 | ``` 141 | 142 | ### 2. Learner 📚 143 | 144 | Start your learning journey: 145 | ```bash 146 | # Browse available learning paths 147 | cursormind path list 148 | 149 | # Begin a learning path (e.g., Python basics) 150 | cursormind path start python-beginner 151 | 152 | # Check progress and resources 153 | cursormind path status 154 | 155 | # Complete current task and get next steps 156 | cursormind path next 157 | ``` 158 | 159 | ### 3. Project Team 👥 160 | 161 | Structured project management workflow: 162 | ```bash 163 | # Step 1: Initialize new project 164 | ./project_management/scripts/init_project.sh "Project Name" 165 | 166 | # Step 2: Daily workflow management 167 | ./project_management/scripts/create_daily_report.sh # Daily report 168 | ./project_management/scripts/update_progress.sh 35 "Auth module complete" # Update progress 169 | ./project_management/scripts/create_task.sh "Implement login" # Create task 170 | ./project_management/scripts/update_task.sh TASK-001 "In Progress" # Update status 171 | 172 | # Step 3: Generate reports 173 | ./project_management/scripts/create_weekly_report.sh # Weekly summary 174 | ``` 175 | 176 |
177 | View Detailed Usage Guide 👉 178 | 179 | ### Developer Workflow 180 | 181 | 1. **Quality Management** 182 | - Use `cursormind review` for code analysis 183 | - Run `cursormind analyze` for project assessment 184 | - Apply recommended best practices 185 | - Address security vulnerabilities 186 | 187 | 2. **Documentation Management** 188 | - Use standardized templates (`project_management/templates/`) 189 | - Follow timestamp conventions (`scripts/generate_timestamp.py`) 190 | - Maintain progress tracking (`PROJECT_PROGRESS.md`) 191 | - Document technical decisions 192 | 193 | 3. **Engineering Standards** 194 | - Follow language-specific guidelines (e.g., PEP8 for Python) 195 | - Maintain code-to-documentation ratio (80:20) 196 | - Ensure test coverage (minimum 85%) 197 | - Regular security audits 198 | 199 | ### Learning Guide 200 | 201 | 1. **Path Selection** 202 | - Browse available paths (`learning_paths/`) 203 | - Choose appropriate skill level 204 | - Set learning objectives 205 | - Track progress 206 | 207 | 2. **Resource Utilization** 208 | - Access recommended materials 209 | - Complete milestone projects 210 | - Study example implementations 211 | - Document learning insights 212 | 213 | 3. **Practical Development** 214 | - Use project templates 215 | - Apply learned concepts 216 | - Get mentor feedback 217 | - Continuous improvement 218 | 219 | ### Team Collaboration 220 | 221 | 1. **Project Setup** 222 | ```bash 223 | # Create project structure 224 | ./project_management/scripts/init_project.sh "Project Name" 225 | 226 | # Configure workflow 227 | cp project_management/templates/* ./ 228 | ``` 229 | 230 | 2. **Daily Operations** 231 | ```bash 232 | # Create daily report 233 | ./project_management/scripts/create_daily_report.sh "Version Release" 234 | 235 | # Update progress 236 | ./project_management/scripts/update_progress.sh 50 "MVP Complete" 237 | 238 | # Task management 239 | ./project_management/scripts/create_task.sh "New Feature" 240 | ./project_management/scripts/update_task.sh TASK-001 "In Progress" 241 | ``` 242 | 243 | 3. **Quality Control** 244 | ```bash 245 | # Code review 246 | cursormind review file src/main.py 247 | 248 | # Project analysis 249 | cursormind analyze dir ./src 250 | 251 | # Quality report 252 | ./project_management/scripts/generate_quality_report.sh 253 | ``` 254 | 255 | ### Best Practices 256 | 257 | 1. **Individual Development** 258 | - Pre-commit code review 259 | - Real-time documentation updates 260 | - Coding standard compliance 261 | - Regular performance optimization 262 | 263 | 2. **Learning Enhancement** 264 | - Structured learning plan 265 | - Consistent practice 266 | - Regular reflection 267 | - Community engagement 268 | 269 | 3. **Team Collaboration** 270 | - Standard adherence 271 | - Effective communication 272 | - Knowledge sharing 273 | - Regular code reviews 274 | 275 |
276 | 277 | ## 💻 Installation Guide 278 | 279 | Quick Start: 280 | 1. Ensure Python 3.9-3.13 is installed 281 | 2. Run installation commands: 282 | ```bash 283 | pip install cursormind 284 | export PYTHONPATH=src # Unix/macOS 285 | set PYTHONPATH=src # Windows 286 | ``` 287 | 288 |
289 | View Complete Installation Guide 👉 290 | 291 | ### System Requirements 292 | 293 | - Python 3.9-3.13 (3.13 recommended) 294 | - pip package manager 295 | - Git (optional, for version control) 296 | 297 | ### Windows Installation 298 | 299 | 1. **Install Python** 300 | ```powershell 301 | # Download Python 3.13 from https://www.python.org/downloads/ 302 | # Enable "Add Python to PATH" during installation 303 | ``` 304 | 305 | 2. **Setup Environment** 306 | ```powershell 307 | # Create and activate virtual environment 308 | python -m venv .venv 309 | .\.venv\Scripts\Activate.ps1 310 | ``` 311 | 312 | 3. **Install CursorMind** 313 | ```powershell 314 | pip install --upgrade pip 315 | pip install cursormind 316 | $env:PYTHONPATH = "src" 317 | ``` 318 | 319 | ### macOS/Linux Installation 320 | 321 | 1. **Create Environment** 322 | ```bash 323 | python3.13 -m venv .venv 324 | source .venv/bin/activate 325 | ``` 326 | 327 | 2. **Install CursorMind** 328 | ```bash 329 | pip install --upgrade pip 330 | pip install cursormind 331 | export PYTHONPATH=src 332 | ``` 333 | 334 | ### Verify Installation 335 | 336 | Run these commands: 337 | ```bash 338 | cursormind --version 339 | cursormind review file your_code.py 340 | ``` 341 | 342 | For issues, refer to the troubleshooting guide below. 343 |
344 | 345 | ### ❗ Common Issues 346 | 347 | Quick solutions for common problems: 348 | 349 | 1. Verify Python version compatibility (3.9-3.13) 350 | 2. Check PYTHONPATH environment variable 351 | 3. Confirm virtual environment activation 352 | 353 |
354 | View Complete Troubleshooting Guide 👉 355 | 356 | ### Windows Troubleshooting 357 | 358 | 1. **Python PATH Issues** 359 | ```powershell 360 | # Check Python installation 361 | python --version 362 | 363 | # Manual PATH addition if needed 364 | # System Properties -> Environment Variables -> Path 365 | # Add: C:\Users\username\AppData\Local\Programs\Python\Python313 366 | ``` 367 | 368 | 2. **Virtual Environment Problems** 369 | ```powershell 370 | # Fix permission issues 371 | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 372 | 373 | # Reactivate environment 374 | .\.venv\Scripts\Activate.ps1 375 | ``` 376 | 377 | 3. **Module Import Errors** 378 | ```powershell 379 | # Verify PYTHONPATH 380 | echo $env:PYTHONPATH 381 | 382 | # Reset if needed 383 | $env:PYTHONPATH = "src" 384 | ``` 385 | 386 | ### macOS Troubleshooting 387 | 388 | 1. **Python Version Issues** 389 | ```bash 390 | # Version check 391 | python3 --version 392 | 393 | # Use specific version 394 | python3.13 -m pip install cursormind 395 | ``` 396 | 397 | 2. **Permission Problems** 398 | ```bash 399 | # Fix permissions 400 | sudo chown -R $USER ~/.local 401 | chmod +x ~/.local/bin/cursormind 402 | ``` 403 | 404 | 3. **Environment Variables** 405 | ```bash 406 | # Add to shell profile 407 | echo 'export PYTHONPATH=src' >> ~/.zshrc 408 | source ~/.zshrc 409 | ``` 410 | 411 | ### Ubuntu/Debian Troubleshooting 412 | 413 | 1. **PPA Issues** 414 | ```bash 415 | # Install prerequisites 416 | sudo apt install software-properties-common 417 | 418 | # Add PPA 419 | sudo add-apt-repository ppa:deadsnakes/ppa 420 | ``` 421 | 422 | 2. **Dependency Problems** 423 | ```bash 424 | # Install build requirements 425 | sudo apt install build-essential libssl-dev libffi-dev python3.13-dev 426 | ``` 427 | 428 | 3. **Permission Issues** 429 | ```bash 430 | # Fix permissions 431 | sudo chown -R $USER ~/.local 432 | sudo chmod +x ~/.local/bin/cursormind 433 | ``` 434 |
435 | 436 |
437 | 🕒 Timestamp Standards 438 | 439 | Ensure consistency in project documentation with our timestamp tools. 440 | 441 | ### Using Timestamp Tools 442 | 443 | ```bash 444 | # Generate full timestamp (default) 445 | python3 scripts/generate_timestamp.py full 446 | # Output: 2025-03-11 23:37:45 PDT 447 | 448 | # Date only 449 | python3 scripts/generate_timestamp.py date 450 | # Output: 2025-03-11 451 | 452 | # Date and time (no timezone) 453 | python3 scripts/generate_timestamp.py datetime 454 | # Output: 2025-03-11 23:37:45 455 | 456 | # Compact format 457 | python3 scripts/generate_timestamp.py compact 458 | # Output: 20250311 459 | 460 | # Year and week 461 | python3 scripts/generate_timestamp.py week 462 | # Output: 2025W11 463 | ``` 464 | 465 | ### Timestamp Guidelines 466 | 467 | 1. **Requirements** 468 | - Use `scripts/generate_timestamp.py` for all timestamps 469 | - No manual timestamp modifications 470 | - Maintain consistent timezone (default: US Pacific Time PST/PDT) 471 | - Configure timezone in `.env` file if needed 472 | 473 | 2. **Git Hook Setup** 474 | ```bash 475 | # Copy pre-commit hook 476 | cp scripts/hooks/pre-commit .git/hooks/ 477 | 478 | # Set permissions 479 | chmod +x .git/hooks/pre-commit 480 | ``` 481 |
482 | 483 | ### 📢 Manifesto 484 | 485 | We believe: 486 | - Technology should be accessible to everyone 487 | - Cursor is more than an IDE; it's a gateway to smarter programming 488 | - CursorMind empowers developers with AI-assisted programming 489 | - Open source drives technological progress - fork and contribute! 490 | 491 | ### 🤝 Community Participation 492 | 493 | Join our vibrant community: 494 | - 🌟 Star us if you find CursorMind helpful 495 | - 🐛 Report bugs via [Issues](https://github.com/yourusername/cursormind/issues) 496 | - 💡 Submit [Pull Requests](https://github.com/yourusername/cursormind/pulls) 497 | - 📝 Help improve documentation 498 | - 💬 Share your experience and suggestions 499 | 500 | Let's build better AI programming tools together! 501 | 502 | #### 📜 MIT License 503 | 504 | CursorMind is released under the MIT License, which means: 505 | - ✅ You can freely use, modify, and distribute this software 506 | - ✅ You can use it for commercial projects 507 | - ✅ You can make and distribute closed source versions 508 | - ℹ️ The only requirement is to include the original copyright notice and license 509 | 510 | We encourage individuals and organizations to: 511 | - 🔄 Fork and modify the project for your specific needs 512 | - 🌱 Share your improvements back with the community 513 | - 🤝 Collaborate on making AI-assisted development more accessible 514 | 515 | For full license details, see the [LICENSE](LICENSE) file. 516 | 517 |
518 | 519 | *Cursor empowers efficiency, while your vision creates the future.* 520 | 521 |
522 | 523 | --- 524 | *Last updated: 2025-03-12 02:37:42 PDT* 525 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # ✨ CursorMind 2 | 3 |

4 | English Version | 5 | 中文版 6 |

7 | 8 |
9 |

CursorMind

10 |

提升您的 Cursor 开发效率与项目管理质量

11 |

当前版本:Beta 0.2.1

12 | 13 | ![许可证](https://img.shields.io/badge/许可证-MIT-blue.svg) 14 | ![版本](https://img.shields.io/badge/版本-Beta%200.2.1-brightgreen.svg) 15 | ![状态](https://img.shields.io/badge/状态-开发中-orange.svg) 16 | ![语言](https://img.shields.io/badge/语言-Python-yellow.svg) 17 | ![Python版本](https://img.shields.io/badge/Python-3.9--3.13-blue.svg) 18 |
19 | 20 | ## 📝 更新日志 21 | 22 | ### Beta 0.2.1 (2025-03-12 00:25:02 PDT) 23 | - 🔄 重构核心代码结构,提升系统稳定性 24 | - ✨ 新增代码审查功能,支持多种编码规范 25 | - 🛡️ 增强文件操作安全性,防止潜在风险 26 | - ⚡️ 优化性能检查逻辑,提升分析效率 27 | - 📊 改进项目管理功能,支持更多场景 28 | - 📚 添加学习路径功能,助力编程教育 29 | 30 | ### Beta 0.1 (2025-03-07) 31 | - 🎉 发布初始项目结构 32 | - ✅ 实现基础功能模块 33 | 34 | --- 35 | 36 | ## 📖 项目简介 37 | 38 | 🌟 **CursorMind** 是一个面向开发者 👨‍💻、项目经理 👨‍💼、团队 👥 和学生 👨‍🎓 的综合性开发工具集。它不仅提供了代码质量保证工具 🛠️,还包含了项目管理 📊、学习辅助 📚 和最佳实践指南 📝 等功能模块。对于正在学习编程的中小学生来说,CursorMind 提供了一个理想的学习平台 🎯,帮助他们在编程启蒙阶段就建立正确的软件工程思维 🧠。 39 | 40 | ### 🎯 核心价值 41 | 42 | 1. **教育赋能** 43 | - 为编程初学者提供循序渐进的学习路径 44 | - 帮助教育工作者建立标准化的教学体系 45 | - 通过实践项目培养工程思维 46 | 47 | 2. **开发规范** 48 | - 提供业界认可的编码标准 49 | - 实施最佳开发实践 50 | - 保证代码质量和一致性 51 | 52 | 3. **项目管理** 53 | - 标准化项目流程 54 | - 提高团队协作效率 55 | - 确保项目交付质量 56 | 57 | 4. **自动化工具** 58 | - 代码质量自动检查 59 | - 性能分析和优化 60 | - 安全漏洞检测 61 | 62 | ## 🚀 功能详情 63 | 64 | CursorMind 为您提供全方位的开发支持: 65 | 66 | ### 1. 代码质量保证 ⚡️ 67 | - 智能代码审查,确保编码规范 68 | - 性能分析与优化建议 69 | - 安全漏洞自动检测 70 | - 最佳实践指导 71 | 72 | ### 2. 项目管理工具 📊 73 | - 项目进度追踪与管理 74 | - 团队协作流程规范 75 | - 自动化报告生成 76 | - 质量指标监控 77 | 78 | ### 3. 学习与发展 📚 79 | - 个性化学习路径规划 80 | - 丰富的学习资源库 81 | - 实战项目练习 82 | - 技术能力评估 83 | 84 | ### 4. 开发工具集成 🛠️ 85 | - 自动化工作流配置 86 | - 代码版本控制集成 87 | - 持续集成/部署支持 88 | - 开发环境标准化 89 | 90 |
91 | 查看详细功能列表 👉 92 | 93 | - **代码审查** 94 | - 风格检查:确保代码符合 PEP8、Google Style 等主流编码规范 95 | - 复杂度分析:计算圈复杂度,识别需要重构的代码块 96 | - 命名规范:检查变量、函数、类的命名是否符合最佳实践 97 | - 注释完整性:验证关键功能是否有充分的文档说明 98 | 99 | - **性能分析** 100 | - 算法复杂度评估:分析时间和空间复杂度 101 | - 内存使用监控:识别内存泄漏和过度内存使用 102 | - 性能瓶颈定位:通过性能分析找出耗时操作 103 | - 优化建议:提供具体的性能优化方案 104 | 105 | - **项目管理** 106 | - 进度追踪:里程碑管理和燃尽图分析 107 | - 任务分配:智能任务分解和工作量评估 108 | - 团队协作:代码评审流程和知识共享 109 | - 质量监控:自动化测试和性能监测 110 | 111 | - **学习资源** 112 | - 技能图谱:个性化的技能提升路线 113 | - 实战项目:配套的练习项目集 114 | - 最佳实践:详细的编码规范和架构指南 115 | - 示例代码:常用功能的参考实现 116 | 117 | - **工具集成** 118 | - CI/CD:持续集成和部署流程配置 119 | - Git集成:版本控制和分支管理 120 | - 环境配置:开发环境自动化设置 121 | - 扩展支持:主流IDE和工具链集成 122 |
123 | 124 | ## 🎯 使用方式选择 125 | 126 | CursorMind 提供三种主要使用场景,选择最适合您的方式开始: 127 | 128 | ### 1. 个人开发者 👨‍💻 129 | 130 | 快速开始使用代码质量工具: 131 | ```bash 132 | # 安装工具 133 | pip install cursormind 134 | export PYTHONPATH=src # Unix/macOS 135 | set PYTHONPATH=src # Windows 136 | 137 | # 开始使用 138 | cursormind review file your_code.py # 代码审查 139 | cursormind analyze dir your_project/ # 项目分析 140 | ``` 141 | 142 | ### 2. 学习者 📚 143 | 144 | 开始您的学习之旅: 145 | ```bash 146 | # 查看可用的学习路径 147 | cursormind path list 148 | 149 | # 选择并开始一个学习路径(如:Python入门) 150 | cursormind path start python-beginner 151 | 152 | # 查看当前进度和推荐资源 153 | cursormind path status 154 | 155 | # 完成当前任务并获取下一步建议 156 | cursormind path next 157 | ``` 158 | 159 | ### 3. 项目团队 👥 160 | 161 | 规范化的项目管理流程: 162 | ```bash 163 | # 第1步:初始化新项目 164 | ./project_management/scripts/init_project.sh "项目名称" 165 | 166 | # 第2步:日常工作管理 167 | ./project_management/scripts/create_daily_report.sh # 创建日报 168 | ./project_management/scripts/update_progress.sh 35 "完成用户认证模块" # 更新进度 169 | ./project_management/scripts/create_task.sh "实现登录功能" # 创建新任务 170 | ./project_management/scripts/update_task.sh TASK-001 "进行中" # 更新任务状态 171 | 172 | # 第3步:生成工作报告 173 | ./project_management/scripts/create_weekly_report.sh # 生成周报 174 | ``` 175 | 176 |
177 | 查看详细使用指南 👉 178 | 179 | ### 开发者工作流 180 | 181 | 1. **代码质量管理** 182 | - 使用 `cursormind review` 进行代码审查 183 | - 运行 `cursormind analyze` 进行项目分析 184 | - 应用推荐的最佳实践和优化建议 185 | - 检查并修复潜在的安全漏洞 186 | 187 | 2. **项目文档管理** 188 | - 使用标准化的文档模板(位于 `project_management/templates/`) 189 | - 遵循时间戳规范记录更新(使用 `scripts/generate_timestamp.py`) 190 | - 维护项目进度文件(`PROJECT_PROGRESS.md`) 191 | - 记录技术决策和设计方案 192 | 193 | 3. **工程实践规范** 194 | - 遵循语言特定的编码标准(如 Python 的 PEP8) 195 | - 保持代码文档比例(80:20) 196 | - 确保单元测试覆盖率(最低 85%) 197 | - 定期进行安全漏洞检查 198 | 199 | ### 学习路径指南 200 | 201 | 1. **选择学习路径** 202 | - 浏览可用的学习路径(`learning_paths/`) 203 | - 根据个人水平选择合适的路径 204 | - 设置学习目标和计划 205 | - 跟踪学习进度 206 | 207 | 2. **使用学习资源** 208 | - 查看推荐的学习资源和文档 209 | - 完成阶段性练习项目 210 | - 参考示例代码和最佳实践 211 | - 记录学习心得和问题 212 | 213 | 3. **实践项目开发** 214 | - 使用项目模板快速启动 215 | - 应用所学知识解决实际问题 216 | - 获取导师反馈和建议 217 | - 持续改进和优化 218 | 219 | ### 团队协作流程 220 | 221 | 1. **项目初始化** 222 | ```bash 223 | # 创建标准项目结构 224 | ./project_management/scripts/init_project.sh "项目名称" 225 | 226 | # 配置工作流程 227 | cp project_management/templates/* ./ 228 | ``` 229 | 230 | 2. **日常工作管理** 231 | ```bash 232 | # 创建今日工作报告 233 | ./project_management/scripts/create_daily_report.sh "重要版本发布" 234 | 235 | # 更新项目进度 236 | ./project_management/scripts/update_progress.sh 50 "完成MVP版本" 237 | 238 | # 创建和更新任务 239 | ./project_management/scripts/create_task.sh "新功能开发" 240 | ./project_management/scripts/update_task.sh TASK-001 "进行中" 241 | ``` 242 | 243 | 3. **质量控制** 244 | ```bash 245 | # 代码审查 246 | cursormind review file src/main.py 247 | 248 | # 项目分析 249 | cursormind analyze dir ./src 250 | 251 | # 生成质量报告 252 | ./project_management/scripts/generate_quality_report.sh 253 | ``` 254 | 255 | ### 最佳实践建议 256 | 257 | 1. **个人开发** 258 | - 每次提交前进行代码审查 259 | - 保持文档的实时更新 260 | - 遵循项目编码规范 261 | - 定期进行性能优化 262 | 263 | 2. **学习提升** 264 | - 制定合理的学习计划 265 | - 保持练习的连续性 266 | - 及时记录和总结 267 | - 参与社区讨论和分享 268 | 269 | 3. **团队协作** 270 | - 严格遵循项目规范 271 | - 保持良好的沟通习惯 272 | - 注重知识的沉淀和共享 273 | - 定期进行团队代码评审 274 | 275 |
276 | 277 | ## 💻 安装指南 278 | 279 | 快速开始: 280 | 1. 确保安装 Python 3.9-3.13 281 | 2. 运行安装命令: 282 | ```bash 283 | pip install cursormind 284 | export PYTHONPATH=src # Unix/macOS 285 | set PYTHONPATH=src # Windows 286 | ``` 287 | 288 |
289 | 查看完整安装说明 👉 290 | 291 | ### 系统要求 292 | 293 | - Python 3.9-3.13(推荐使用 Python 3.13) 294 | - pip 包管理器 295 | - Git(可选,用于版本控制) 296 | 297 | ### Windows 安装步骤 298 | 299 | 1. **安装 Python** 300 | ```powershell 301 | # 从 https://www.python.org/downloads/ 下载并安装 Python 3.13 302 | # 安装时必须勾选 "Add Python to PATH" 303 | ``` 304 | 305 | 2. **打开 PowerShell 并创建虚拟环境** 306 | ```powershell 307 | # 创建并激活虚拟环境 308 | python -m venv .venv 309 | .\.venv\Scripts\Activate.ps1 310 | ``` 311 | 312 | 3. **安装 CursorMind** 313 | ```powershell 314 | pip install --upgrade pip 315 | pip install cursormind 316 | $env:PYTHONPATH = "src" 317 | ``` 318 | 319 | ### macOS/Linux 安装步骤 320 | 321 | 1. **创建虚拟环境** 322 | ```bash 323 | python3.13 -m venv .venv 324 | source .venv/bin/activate 325 | ``` 326 | 327 | 2. **安装 CursorMind** 328 | ```bash 329 | pip install --upgrade pip 330 | pip install cursormind 331 | export PYTHONPATH=src 332 | ``` 333 | 334 | ### 验证安装 335 | 336 | 运行以下命令确认安装成功: 337 | ```bash 338 | cursormind --version 339 | cursormind review file your_code.py 340 | ``` 341 | 342 | 如果遇到问题,请参考下方的故障排除指南。 343 |
344 | 345 | ### ❗ 常见问题 346 | 347 | 遇到问题?以下是一些快速解决方案: 348 | 349 | 1. 确保 Python 版本兼容(3.9-3.13) 350 | 2. 检查 PYTHONPATH 环境变量设置 351 | 3. 验证虚拟环境是否正确激活 352 | 353 |
354 | 查看完整故障排除指南 👉 355 | 356 | ### Windows 常见问题 357 | 358 | 1. **Python 未添加到 PATH** 359 | ```powershell 360 | # 检查 Python 是否在 PATH 中 361 | python --version 362 | 363 | # 如果未找到,手动添加到 PATH 364 | # 打开系统属性 -> 环境变量 -> Path -> 添加 Python 安装路径 365 | # 通常在:C:\Users\用户名\AppData\Local\Programs\Python\Python313 366 | ``` 367 | 368 | 2. **虚拟环境激活失败** 369 | ```powershell 370 | # 如果出现权限错误 371 | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 372 | 373 | # 重新激活虚拟环境 374 | .\.venv\Scripts\Activate.ps1 375 | ``` 376 | 377 | 3. **模块未找到** 378 | ```powershell 379 | # 确保 PYTHONPATH 正确设置 380 | echo $env:PYTHONPATH 381 | 382 | # 如果需要,重新设置 383 | $env:PYTHONPATH = "src" 384 | ``` 385 | 386 | ### macOS 常见问题 387 | 388 | 1. **Python 版本冲突** 389 | ```bash 390 | # 检查 Python 版本 391 | python3 --version 392 | 393 | # 使用特定版本 394 | python3.13 -m pip install cursormind 395 | ``` 396 | 397 | 2. **权限问题** 398 | ```bash 399 | # 修复权限 400 | sudo chown -R $USER ~/.local 401 | chmod +x ~/.local/bin/cursormind 402 | ``` 403 | 404 | 3. **环境变量持久化** 405 | ```bash 406 | # 添加到 .zshrc 或 .bash_profile 407 | echo 'export PYTHONPATH=src' >> ~/.zshrc 408 | source ~/.zshrc 409 | ``` 410 | 411 | ### Ubuntu/Debian 常见问题 412 | 413 | 1. **PPA 添加失败** 414 | ```bash 415 | # 安装必要工具 416 | sudo apt install software-properties-common 417 | 418 | # 重试添加 PPA 419 | sudo add-apt-repository ppa:deadsnakes/ppa 420 | ``` 421 | 422 | 2. **依赖问题** 423 | ```bash 424 | # 安装编译依赖 425 | sudo apt install build-essential libssl-dev libffi-dev python3.13-dev 426 | ``` 427 | 428 | 3. **权限问题** 429 | ```bash 430 | # 修复权限 431 | sudo chown -R $USER ~/.local 432 | sudo chmod +x ~/.local/bin/cursormind 433 | ``` 434 |
435 | 436 |
437 | 🕒 时间戳规范 438 | 439 | 为确保项目文档中的时间戳保持一致性和准确性,我们提供了专门的时间戳生成工具。 440 | 441 | ### 时间戳工具使用 442 | 443 | ```bash 444 | # 生成完整格式的时间戳(默认) 445 | python3 scripts/generate_timestamp.py full 446 | # 输出示例:2025-03-11 23:37:45 PDT 447 | 448 | # 仅生成日期 449 | python3 scripts/generate_timestamp.py date 450 | # 输出示例:2025-03-11 451 | 452 | # 生成日期和时间(不含时区) 453 | python3 scripts/generate_timestamp.py datetime 454 | # 输出示例:2025-03-11 23:37:45 455 | 456 | # 生成紧凑格式 457 | python3 scripts/generate_timestamp.py compact 458 | # 输出示例:20250311 459 | 460 | # 生成年份和周数 461 | python3 scripts/generate_timestamp.py week 462 | # 输出示例:2025W11 463 | ``` 464 | 465 | ### 时间戳规范说明 466 | 467 | 1. **强制要求** 468 | - 所有文档中的时间戳必须使用 `scripts/generate_timestamp.py` 生成 469 | - 禁止手动编写或修改时间戳 470 | - 时区必须保持一致(默认使用美国太平洋时区 PST/PDT) 471 | - 如需使用其他时区,请在项目根目录的 `.env` 文件中设置 `TZ` 环境变量,并确保所有团队成员使用相同配置 472 | 473 | 2. **Git Hook 配置** 474 | ```bash 475 | # 复制 pre-commit hook 到 Git hooks 目录 476 | cp scripts/hooks/pre-commit .git/hooks/ 477 | 478 | # 设置执行权限 479 | chmod +x .git/hooks/pre-commit 480 | ``` 481 |
482 | 483 | ### 📢 宣言 484 | 485 | 我们坚信: 486 | - 技术应该是平等的,每个人都应该有机会学习和使用AI编程 487 | - Cursor不仅是一个IDE,更是一个让编程变得更简单、更智能的工具 488 | - 通过CursorMind,我们致力于让每个开发者都能享受到AI辅助编程的便利 489 | - 开源精神是技术进步的基石,欢迎大家fork项目,共同建设AI编程生态 490 | 491 | ### 🤝 参与贡献 492 | 493 | 我们热烈欢迎社区的每一位成员参与到CursorMind的开发中来: 494 | - 🌟 如果您觉得这个项目有帮助,请给我们一个star 495 | - 🐛 发现bug?请提交 [Issues](https://github.com/yourusername/cursormind/issues) 496 | - 💡 有新想法?欢迎提交 [Pull Requests](https://github.com/yourusername/cursormind/pulls) 497 | - 📝 帮助改进文档?这对初学者来说非常重要 498 | - 💬 分享您的使用经验和建议 499 | 500 | 让我们一起打造更好的AI编程工具! 501 | 502 | #### 📜 MIT 开源许可 503 | 504 | CursorMind 采用 MIT 许可证开源,这意味着: 505 | - ✅ 您可以自由使用、修改和分发本软件 506 | - ✅ 您可以将其用于商业项目 507 | - ✅ 您可以创建和分发闭源版本 508 | - ℹ️ 唯一的要求是包含原始版权声明和许可证 509 | 510 | 我们鼓励个人和组织: 511 | - 🔄 根据特定需求分支(Fork)和修改项目 512 | - 🌱 将改进分享回社区 513 | - 🤝 共同推进 AI 辅助开发的普及 514 | 515 | 完整许可证详情,请查看 [LICENSE](LICENSE) 文件。 516 | 517 |
518 | 519 | *Cursor赋能开发效率,而你的愿景能创造未来。* 520 | 521 |
522 | 523 | --- 524 | *最后更新:2025-03-12 02:37:42 PDT* 525 | -------------------------------------------------------------------------------- /learning_notes/daily/2025-03-12.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "2025-03-12-0001", 4 | "content": "测试笔记", 5 | "topic": "test", 6 | "tags": [], 7 | "created_at": "2025-03-11 21:25:03 PDT", 8 | "updated_at": "2025-03-11 21:25:03 PDT" 9 | }, 10 | { 11 | "id": "2025-03-12-0002", 12 | "content": "学习了Python的基本语法,包括变量定义、数据类型等", 13 | "topic": "python", 14 | "tags": [], 15 | "created_at": "2025-03-11 21:28:10 PDT", 16 | "updated_at": "2025-03-11 21:28:10 PDT" 17 | } 18 | ] -------------------------------------------------------------------------------- /learning_notes/reviews/review_20250312.json: -------------------------------------------------------------------------------- 1 | { 2 | "period": "2025-03-06 至 2025-03-12", 3 | "total_notes": 2, 4 | "total_words": 2, 5 | "topics": { 6 | "test": 1, 7 | "python": 1 8 | }, 9 | "tags": {}, 10 | "daily_notes": [ 11 | { 12 | "date": "2025-03-12", 13 | "notes": [ 14 | { 15 | "id": "2025-03-12-0001", 16 | "content": "测试笔记", 17 | "topic": "test", 18 | "tags": [], 19 | "created_at": "2025-03-11 21:25:03 PDT", 20 | "updated_at": "2025-03-11 21:25:03 PDT" 21 | }, 22 | { 23 | "id": "2025-03-12-0002", 24 | "content": "学习了Python的基本语法,包括变量定义、数据类型等", 25 | "topic": "python", 26 | "tags": [], 27 | "created_at": "2025-03-11 21:28:10 PDT", 28 | "updated_at": "2025-03-11 21:28:10 PDT" 29 | } 30 | ] 31 | }, 32 | { 33 | "date": "2025-03-12", 34 | "notes": [ 35 | { 36 | "id": "2025-03-12-0001", 37 | "content": "测试笔记", 38 | "topic": "test", 39 | "tags": [], 40 | "created_at": "2025-03-11 21:25:03 PDT", 41 | "updated_at": "2025-03-11 21:25:03 PDT" 42 | }, 43 | { 44 | "id": "2025-03-12-0002", 45 | "content": "学习了Python的基本语法,包括变量定义、数据类型等", 46 | "topic": "python", 47 | "tags": [], 48 | "created_at": "2025-03-11 21:28:10 PDT", 49 | "updated_at": "2025-03-11 21:28:10 PDT" 50 | } 51 | ] 52 | } 53 | ], 54 | "highlights": [] 55 | } -------------------------------------------------------------------------------- /learning_notes/stats.json: -------------------------------------------------------------------------------- 1 | { 2 | "total_notes": 2, 3 | "total_words": 2, 4 | "topics": { 5 | "test": 1, 6 | "python": 1 7 | }, 8 | "tags": {}, 9 | "daily_streak": 1, 10 | "last_note_date": "2025-03-12T12:28:10.643288", 11 | "last_updated": "2025-03-11 21:28:10 PDT" 12 | } -------------------------------------------------------------------------------- /learning_notes/topics/python/2025-03-12-0002.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2025-03-12-0002", 3 | "content": "学习了Python的基本语法,包括变量定义、数据类型等", 4 | "topic": "python", 5 | "tags": [], 6 | "created_at": "2025-03-11 21:28:10 PDT", 7 | "updated_at": "2025-03-11 21:28:10 PDT" 8 | } -------------------------------------------------------------------------------- /learning_notes/topics/test/2025-03-12-0001.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2025-03-12-0001", 3 | "content": "测试笔记", 4 | "topic": "test", 5 | "tags": [], 6 | "created_at": "2025-03-11 21:25:03 PDT", 7 | "updated_at": "2025-03-11 21:25:03 PDT" 8 | } -------------------------------------------------------------------------------- /learning_paths/current_path.json: -------------------------------------------------------------------------------- 1 | { 2 | "path_id": "python-beginner", 3 | "current_stage": 0, 4 | "current_step": 1, 5 | "started_at": "2025-03-11 21:27:30 PDT", 6 | "last_updated": "2025-03-11 21:27:46 PDT" 7 | } -------------------------------------------------------------------------------- /learning_paths/paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": [ 3 | { 4 | "id": "python-beginner", 5 | "name": "Python入门之路", 6 | "description": "从零开始学习Python编程", 7 | "difficulty": "初级", 8 | "estimated_time": "3个月", 9 | "stages": [ 10 | { 11 | "name": "基础语法", 12 | "steps": [ 13 | "变量和数据类型", 14 | "控制流程", 15 | "函数定义和使用" 16 | ], 17 | "resources": [ 18 | { 19 | "type": "文档", 20 | "name": "Python官方教程", 21 | "url": "https://docs.python.org/zh-cn/3/tutorial/" 22 | } 23 | ], 24 | "projects": [ 25 | { 26 | "name": "计算器程序", 27 | "description": "创建一个简单的命令行计算器" 28 | } 29 | ] 30 | } 31 | ] 32 | }, 33 | { 34 | "id": "web-beginner", 35 | "name": "网页设计入门", 36 | "description": "学习HTML、CSS和JavaScript基础", 37 | "difficulty": "初级", 38 | "estimated_time": "2个月", 39 | "stages": [] 40 | }, 41 | { 42 | "id": "pm-beginner", 43 | "name": "项目管理入门", 44 | "description": "学习基本的项目管理概念和工具", 45 | "difficulty": "初级", 46 | "estimated_time": "1个月", 47 | "stages": [] 48 | } 49 | ] 50 | } -------------------------------------------------------------------------------- /pdm.lock: -------------------------------------------------------------------------------- 1 | # This file is @generated by PDM. 2 | # It is not intended for manual editing. 3 | 4 | [metadata] 5 | groups = ["default"] 6 | strategy = ["inherit_metadata"] 7 | lock_version = "4.5.0" 8 | content_hash = "sha256:03ae8673a9bbb0a0081cd7d3a90791153502b7cb3feb4e1fc1d3efdf9cc8ad54" 9 | 10 | [[metadata.targets]] 11 | requires_python = ">=3.9" 12 | 13 | [[package]] 14 | name = "click" 15 | version = "8.1.8" 16 | requires_python = ">=3.7" 17 | summary = "Composable command line interface toolkit" 18 | groups = ["default"] 19 | dependencies = [ 20 | "colorama; platform_system == \"Windows\"", 21 | "importlib-metadata; python_version < \"3.8\"", 22 | ] 23 | files = [ 24 | {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, 25 | {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, 26 | ] 27 | 28 | [[package]] 29 | name = "colorama" 30 | version = "0.4.6" 31 | requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 32 | summary = "Cross-platform colored terminal text." 33 | groups = ["default"] 34 | marker = "platform_system == \"Windows\"" 35 | files = [ 36 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 37 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 38 | ] 39 | 40 | [[package]] 41 | name = "markdown-it-py" 42 | version = "3.0.0" 43 | requires_python = ">=3.8" 44 | summary = "Python port of markdown-it. Markdown parsing, done right!" 45 | groups = ["default"] 46 | dependencies = [ 47 | "mdurl~=0.1", 48 | ] 49 | files = [ 50 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, 51 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, 52 | ] 53 | 54 | [[package]] 55 | name = "mdurl" 56 | version = "0.1.2" 57 | requires_python = ">=3.7" 58 | summary = "Markdown URL utilities" 59 | groups = ["default"] 60 | files = [ 61 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, 62 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, 63 | ] 64 | 65 | [[package]] 66 | name = "pygments" 67 | version = "2.19.1" 68 | requires_python = ">=3.8" 69 | summary = "Pygments is a syntax highlighting package written in Python." 70 | groups = ["default"] 71 | files = [ 72 | {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, 73 | {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, 74 | ] 75 | 76 | [[package]] 77 | name = "python-dateutil" 78 | version = "2.9.0.post0" 79 | requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 80 | summary = "Extensions to the standard Python datetime module" 81 | groups = ["default"] 82 | dependencies = [ 83 | "six>=1.5", 84 | ] 85 | files = [ 86 | {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, 87 | {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, 88 | ] 89 | 90 | [[package]] 91 | name = "pytz" 92 | version = "2025.1" 93 | summary = "World timezone definitions, modern and historical" 94 | groups = ["default"] 95 | files = [ 96 | {file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"}, 97 | {file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"}, 98 | ] 99 | 100 | [[package]] 101 | name = "rich" 102 | version = "13.9.4" 103 | requires_python = ">=3.8.0" 104 | summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" 105 | groups = ["default"] 106 | dependencies = [ 107 | "markdown-it-py>=2.2.0", 108 | "pygments<3.0.0,>=2.13.0", 109 | "typing-extensions<5.0,>=4.0.0; python_version < \"3.11\"", 110 | ] 111 | files = [ 112 | {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, 113 | {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, 114 | ] 115 | 116 | [[package]] 117 | name = "six" 118 | version = "1.17.0" 119 | requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 120 | summary = "Python 2 and 3 compatibility utilities" 121 | groups = ["default"] 122 | files = [ 123 | {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, 124 | {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, 125 | ] 126 | 127 | [[package]] 128 | name = "typing-extensions" 129 | version = "4.12.2" 130 | requires_python = ">=3.8" 131 | summary = "Backported and Experimental Type Hints for Python 3.8+" 132 | groups = ["default"] 133 | marker = "python_version < \"3.11\"" 134 | files = [ 135 | {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, 136 | {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, 137 | ] 138 | -------------------------------------------------------------------------------- /project_management/.task_count: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /project_management/actuals/decisions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagami1997/CursorMind/c85ceaa15e0371c4ec4ca426fdd9f2609287efe7/project_management/actuals/decisions/.gitkeep -------------------------------------------------------------------------------- /project_management/actuals/reports/daily/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagami1997/CursorMind/c85ceaa15e0371c4ec4ca426fdd9f2609287efe7/project_management/actuals/reports/daily/.gitkeep -------------------------------------------------------------------------------- /project_management/actuals/reports/weekly/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagami1997/CursorMind/c85ceaa15e0371c4ec4ca426fdd9f2609287efe7/project_management/actuals/reports/weekly/.gitkeep -------------------------------------------------------------------------------- /project_management/actuals/tasks/TASK-001_开发命令系统核心功能.md: -------------------------------------------------------------------------------- 1 | # 任务模板 2 | 3 | 16 | 17 | ## 任务信息 18 | 31 | 32 | - **任务ID**: TASK-001 33 | - **任务名称**: 开发命令系统核心功能 34 | - **创建时间**: 2025-03-11 20:27:36 PDT 35 | - **优先级**: 高 36 | - **状态**: 未开始 37 | 38 | ## 任务描述 39 | 53 | 54 | 开发CursorMind项目的命令系统核心功能,实现项目管理和文档生成的自动化处理。具体包括: 55 | 56 | 1. 实现基础命令解析器 57 | - 支持命令行参数解析 58 | - 实现命令注册和路由系统 59 | - 添加帮助信息生成功能 60 | 61 | 2. 开发核心命令集 62 | - 项目初始化命令 63 | - 任务管理命令(创建、更新、查询) 64 | - 报告生成命令(日报、周报) 65 | - 模板管理命令 66 | 67 | 3. 实现命令执行环境 68 | - 配置文件加载和验证 69 | - 环境变量管理 70 | - 错误处理和日志记录 71 | 72 | 4. 开发命令扩展机制 73 | - 插件系统设计 74 | - 自定义命令支持 75 | - 命令别名功能 76 | 77 | ## 验收标准 78 | 91 | 92 | 1. [ ] 命令解析器能够正确处理各类参数和选项 93 | 2. [ ] 核心命令集功能完整且稳定运行 94 | 3. [ ] 命令执行环境配置灵活,错误处理完善 95 | 4. [ ] 扩展机制设计合理,支持插件开发 96 | 5. [ ] 完成命令系统技术文档编写 97 | 6. [ ] 通过单元测试和集成测试 98 | 7. [ ] 提供详细的使用示例和最佳实践 99 | 100 | ## 时间规划 101 | 114 | 115 | - **计划开始**: 2025-03-11 116 | - **预计完成**: 2025-03-15 117 | - **实际耗时**: 0小时 118 | - **检查点**: 119 | - 2025-03-12: 完成基础命令解析器 120 | - 2025-03-13: 完成核心命令集开发 121 | - 2025-03-14: 完成执行环境和扩展机制 122 | - 2025-03-15: 完成测试和文档 123 | 124 | ## 依赖关系 125 | 137 | 138 | - **前置任务**: 无 139 | - **后续任务**: 待定 140 | - **关键路径**: 是(作为Beta 0.1.1版本的核心功能) 141 | 142 | ## 资源需求 143 | 156 | 157 | - Python 3.8+ 158 | - Click库(命令行工具开发) 159 | - PyTest(测试框架) 160 | - 1人/5天开发时间 161 | - Git版本控制 162 | - VSCode开发环境 163 | 164 | ## 进展记录 165 | 176 | 177 | | 日期 | 进展 | 备注 | 178 | |------|------|------| 179 | | 2025-03-11 | 任务创建和规划 | 初始化任务,完成详细设计 | 180 | 181 | ## 备注 182 | 195 | 196 | 1. 性能考虑:命令执行效率要求小于1秒 197 | 2. 可维护性:遵循SOLID原则,确保代码质量 198 | 3. 建议:考虑添加命令执行历史记录功能 199 | 4. 风险:需要确保向后兼容性 200 | 201 | --- 202 | *最后更新: 2025-03-11 20:27:36 PDT* 203 | 204 | -------------------------------------------------------------------------------- /project_management/control/MAIN_CONTROL.md: -------------------------------------------------------------------------------- 1 | # 项目主控制文档 2 | 3 | ## 基本信息 4 | - 项目名称:CursorMind 5 | - 版本:Beta 0.2.1 6 | - 状态:进行中 7 | - 进度:75% 8 | - 最后更新:2025-03-11 23:37:45 PDT 9 | 10 | ## 项目目标 11 | 开发一个全面的Cursor开发工具集,提供代码质量检查、项目管理、学习辅助和最佳实践指导功能。 12 | 13 | ## 当前阶段 14 | - 阶段名称:Beta 0.2.1优化阶段 15 | - 开始时间:2025-03-12 16 | - 计划完成:2025-03-19 17 | - 主要任务:代码质量优化和安全性增强 18 | 19 | ## 开发计划 20 | 21 | ### 已完成任务 22 | 1. 核心功能开发 23 | - 代码审查模块 24 | - 性能检查功能 25 | - 安全检查机制 26 | - Python 3.9+支持 27 | 28 | 2. 文档体系建设 29 | - README.zh.md更新 30 | - 配置文件优化 31 | - 文档格式规范 32 | 33 | ### 进行中任务 34 | 1. 代码质量优化 35 | - 函数复杂度重构 36 | - 局部变量优化 37 | - 代码风格统一 38 | 39 | 2. 安全性增强 40 | - 文件访问安全评估 41 | - 安全措施实施 42 | - 测试用例完善 43 | 44 | ### 待开始任务 45 | 1. 文档完善 46 | - API文档更新 47 | - 开发指南完善 48 | - 示例代码补充 49 | 50 | ## 里程碑 51 | 1. [已完成] Beta 0.1 - 2025-03-10 52 | 2. [已完成] Beta 0.2 - 2025-03-11 53 | 3. [进行中] Beta 0.2.1 - 2025-03-19 54 | 4. [计划中] Beta 0.3 - 2025-03-26 55 | 56 | ## 团队成员 57 | - 项目负责人:@kinglee 58 | - 开发团队:@dev-team 59 | - 测试团队:@test-team 60 | 61 | ## 关键决策记录 62 | 1. 2025-03-12 - 提升Python版本要求至3.9+ 63 | 2. 2025-03-12 - 确定代码质量优化优先级 64 | 65 | ## 风险追踪 66 | 1. [中] 代码复杂度超标 67 | - 影响:性能和可维护性 68 | - 措施:计划重构高复杂度函数 69 | 70 | 2. [中] 安全性问题 71 | - 影响:文件访问安全 72 | - 措施:进行安全评估和加固 73 | 74 | 3. [低] 文档更新延迟 75 | - 影响:开发效率 76 | - 措施:建立文档更新机制 77 | 78 | ## 质量控制 79 | 1. 代码质量指标 80 | - 函数复杂度 ≤ 10 81 | - 局部变量数量 ≤ 15 82 | - 行长度 ≤ 88字符 83 | 84 | 2. 测试覆盖率要求 85 | - 单元测试:90%+ 86 | - 集成测试:85%+ 87 | 88 | ## 依赖关系 89 | 1. 外部依赖 90 | - Python 3.9+ 91 | - click >= 8.0.0 92 | - rich >= 10.0.0 93 | 94 | 2. 内部依赖 95 | - 代码审查模块 96 | - 性能检查模块 97 | - 安全检查模块 98 | 99 | ## 文档链接 100 | 1. [README.zh.md](../../README.zh.md) 101 | 2. [REQUIREMENTS.md](./REQUIREMENTS.md) 102 | 3. [API文档](../docs/api/) 103 | 104 | ## 工具使用规范 105 | 1. 时间戳生成 106 | - 所有文档中的时间戳必须使用 `scripts/generate_timestamp.py` 生成 107 | - 支持的格式: 108 | * `full`: YYYY-MM-DD HH:MM:SS PST/PDT(默认) 109 | * `date`: YYYY-MM-DD 110 | * `datetime`: YYYY-MM-DD HH:MM:SS 111 | * `compact`: YYYYMMDD 112 | * `week`: YYYYWNN 113 | - 使用示例:`python3 scripts/generate_timestamp.py full` 114 | 115 | ## 命令参考 116 | - **[CODE NOW]**: 立即开始编码任务 117 | - **[FOCUS]**: 专注于当前最重要的任务 118 | - **[RESET]**: 重置当前工作状态 119 | - **[DECISION]**: 记录重要决策 120 | 121 | --- 122 | *最后更新: 2025-03-11 23:37:45 PDT* -------------------------------------------------------------------------------- /project_management/control/REQUIREMENTS.md: -------------------------------------------------------------------------------- 1 | # 项目需求文档 2 | 3 | ## 项目信息 4 | - **项目名称**: CursorMind 5 | - **版本**: Beta 0.2.1 6 | - **最后更新**: 2025-03-12 7 | - **状态**: 已确认 8 | 9 | ## 1. 概述 10 | ### 1.1 目的 11 | 开发一个综合性的 Cursor 开发工具集,提供代码质量保证、项目管理、学习辅助和最佳实践指南等功能,帮助开发者提升开发效率和项目质量。 12 | 13 | ### 1.2 项目背景 14 | 随着软件开发复杂度的增加,开发者需要一个集成的工具来管理代码质量、项目进度和学习成长。CursorMind 旨在提供这样一个综合解决方案。 15 | 16 | ### 1.3 目标用户 17 | - 专业开发人员 18 | - 项目经理 19 | - 团队领导 20 | - 初学者 21 | - 学生(大学生、中学生、小学生) 22 | 23 | ## 2. 功能需求 24 | ### 2.1 核心功能 25 | | 需求ID | 优先级 | 描述 | 验收标准 | 状态 | 26 | |-------|-------|------|---------|------| 27 | | FR001 | 高 | 代码风格检查 | 支持多种编码规范,提供详细报告 | 已完成 | 28 | | FR002 | 高 | 性能分析 | 识别性能瓶颈,提供优化建议 | 已完成 | 29 | | FR003 | 高 | 安全检查 | 发现潜在安全隐患,提供修复方案 | 已完成 | 30 | | FR004 | 高 | 项目管理 | 支持任务跟踪和进度管理 | 已完成 | 31 | | FR005 | 高 | 学习路径 | 提供个性化学习计划 | 已完成 | 32 | 33 | ### 2.2 扩展功能 34 | | 需求ID | 优先级 | 描述 | 验收标准 | 状态 | 35 | |-------|-------|------|---------|------| 36 | | FR101 | 中 | 团队协作 | 支持多人协作和代码评审 | 进行中 | 37 | | FR102 | 中 | 插件系统 | 支持自定义扩展 | 计划中 | 38 | | FR103 | 低 | AI 辅助 | 提供智能代码建议 | 计划中 | 39 | 40 | ## 3. 非功能需求 41 | ### 3.1 性能需求 42 | | 需求ID | 优先级 | 描述 | 验收标准 | 状态 | 43 | |-------|-------|------|---------|------| 44 | | NFR001 | 高 | 响应时间 | 命令执行时间 < 1s | 已完成 | 45 | | NFR002 | 高 | 资源占用 | 内存使用 < 500MB | 已完成 | 46 | | NFR003 | 中 | 并发处理 | 支持多任务并行执行 | 进行中 | 47 | 48 | ### 3.2 安全需求 49 | | 需求ID | 优先级 | 描述 | 验收标准 | 状态 | 50 | |-------|-------|------|---------|------| 51 | | NFR101 | 高 | 文件访问安全 | 安全的文件操作机制 | 已完成 | 52 | | NFR102 | 高 | 配置文件保护 | 加密存储敏感信息 | 已完成 | 53 | | NFR103 | 中 | 用户认证 | 支持多种认证方式 | 计划中 | 54 | 55 | ### 3.3 可用性需求 56 | | 需求ID | 优先级 | 描述 | 验收标准 | 状态 | 57 | |-------|-------|------|---------|------| 58 | | NFR201 | 高 | 命令行界面 | 清晰的命令结构和帮助信息 | 已完成 | 59 | | NFR202 | 中 | 多语言支持 | 支持中英文界面 | 已完成 | 60 | | NFR203 | 中 | 错误处理 | 友好的错误提示 | 已完成 | 61 | 62 | ## 4. 约束条件 63 | - Python 版本要求:>= 3.9 64 | - 保持轻量级设计 65 | - 跨平台兼容性 66 | - 模块化架构 67 | 68 | ## 5. 假设和依赖 69 | ### 假设 70 | - 用户具备基本的命令行操作能力 71 | - 用户了解基本的编程概念 72 | - 用户有稳定的网络连接 73 | 74 | ### 依赖 75 | - Python 运行时环境 76 | - pip 包管理器 77 | - Git(可选) 78 | 79 | ## 6. 需求变更历史 80 | | 变更ID | 日期 | 描述 | 影响 | 提出人 | 状态 | 81 | |-------|------|------|------|-------|------| 82 | | CH001 | 2025-03-07 | 初始需求确定 | 项目范围定义 | Team | 已批准 | 83 | | CH002 | 2025-03-12 | 增加学习路径功能 | 扩展项目范围 | Team | 已批准 | 84 | 85 | ## 7. 附录 86 | ### 7.1 术语表 87 | | 术语 | 定义 | 88 | |------|------| 89 | | 代码审查 | 对代码质量、性能和安全性的综合检查 | 90 | | 学习路径 | 个性化的学习计划和进度追踪 | 91 | | 项目管理 | 任务分配、进度跟踪和团队协作 | 92 | 93 | ### 7.2 相关文档 94 | - [项目主控制文档](MAIN_CONTROL.md) 95 | - [项目进度文档](../../PROJECT_PROGRESS.md) 96 | - [API文档](../../docs/api/README.md) 97 | 98 | --- 99 | *最后更新: 2025-03-12 15:30:00 PST* -------------------------------------------------------------------------------- /project_management/scripts/create_task.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 设置时区为PST 4 | export TZ="America/Los_Angeles" 5 | 6 | # 检查参数 7 | if [ $# -lt 1 ]; then 8 | echo "用法: $0 <任务名称> [优先级(高/中/低)]" 9 | exit 1 10 | fi 11 | 12 | # 获取参数 13 | TASK_NAME="$1" 14 | PRIORITY="${2:-中}" # 默认优先级为"中" 15 | 16 | # 生成任务ID(格式:TASK-XXX) 17 | TASK_COUNT_FILE="project_management/.task_count" 18 | if [ ! -f "$TASK_COUNT_FILE" ]; then 19 | echo "1" > "$TASK_COUNT_FILE" 20 | fi 21 | TASK_NUM=$(cat "$TASK_COUNT_FILE") 22 | TASK_ID="TASK-$(printf "%03d" $TASK_NUM)" 23 | 24 | # 更新任务计数 25 | echo $((TASK_NUM + 1)) > "$TASK_COUNT_FILE" 26 | 27 | # 获取当前时间戳 28 | TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S %Z") 29 | 30 | # 创建任务文件 31 | TASK_FILE="project_management/actuals/tasks/${TASK_ID}_$(echo "$TASK_NAME" | tr ' ' '_').md" 32 | mkdir -p "project_management/actuals/tasks" 33 | 34 | # 从模板创建任务文件 35 | sed -e "s/\[TASK-ID\]/$TASK_ID/g" \ 36 | -e "s/\[任务名称\]/$TASK_NAME/g" \ 37 | -e "s/\[TIMESTAMP\]/$TIMESTAMP/g" \ 38 | -e "s/\[高\/中\/低\]/$PRIORITY/g" \ 39 | -e "s/\[未开始\/进行中\/已完成\/已暂停\]/未开始/g" \ 40 | "project_management/templates/task_template.md" > "$TASK_FILE" 41 | 42 | echo "已创建任务:$TASK_ID" 43 | echo "任务文件:$TASK_FILE" -------------------------------------------------------------------------------- /project_management/templates/daily_report_template.md: -------------------------------------------------------------------------------- 1 | # 日报模板 2 | 3 | 10 | 11 | ## 时间 12 | 13 | [TIMESTAMP] 14 | 15 | ## 今日工作内容 16 | 22 | 23 | 1. [工作项1] 24 | - [具体内容] 25 | - [完成度] 26 | 27 | 2. [工作项2] 28 | - [具体内容] 29 | - [完成度] 30 | 31 | ## 明日计划 32 | 39 | 40 | 1. [计划项1] 41 | - [具体内容] 42 | - [预期目标] 43 | 44 | ## 问题与解决方案 45 | 52 | 53 | - 问题:[描述] 54 | - 解决方案:[方案] 55 | 56 | ## 项目进度 57 | 63 | 64 | - 版本: [VERSION] 65 | - 进度: [PROGRESS]% 66 | 67 | ## 备注 68 | 75 | 76 | [备注内容] 77 | 78 | --- 79 | *使用 [CODE NOW] 命令立即开始编码,避免过度分析* -------------------------------------------------------------------------------- /project_management/templates/decision_template.md: -------------------------------------------------------------------------------- 1 | # 决策记录 2 | 3 | ## 基本信息 4 | - **决策ID**: {{DECISION_ID}} 5 | - **标题**: {{DECISION_TITLE}} 6 | - **日期**: {{DECISION_DATE}} 7 | - **时间戳**: {{TIMESTAMP}} 8 | - **状态**: {{STATUS}} (提议/已批准/已拒绝/已实施) 9 | - **决策者**: {{DECIDER}} 10 | - **相关领域**: {{DOMAIN}} 11 | 12 | ## 背景 13 | {{BACKGROUND}} 14 | 15 | ## 问题陈述 16 | {{PROBLEM_STATEMENT}} 17 | 18 | ## 决策驱动因素 19 | - {{DRIVER_1}} 20 | - {{DRIVER_2}} 21 | - {{DRIVER_3}} 22 | 23 | ## 考虑的选项 24 | ### 选项1: {{OPTION_1}} 25 | - **描述**: {{DESCRIPTION_1}} 26 | - **优点**: 27 | - {{PRO_1_1}} 28 | - {{PRO_1_2}} 29 | - **缺点**: 30 | - {{CON_1_1}} 31 | - {{CON_1_2}} 32 | 33 | ### 选项2: {{OPTION_2}} 34 | - **描述**: {{DESCRIPTION_2}} 35 | - **优点**: 36 | - {{PRO_2_1}} 37 | - {{PRO_2_2}} 38 | - **缺点**: 39 | - {{CON_2_1}} 40 | - {{CON_2_2}} 41 | 42 | ## 决策结果 43 | **选择的选项**: {{CHOSEN_OPTION}} 44 | 45 | **理由**: 46 | {{RATIONALE}} 47 | 48 | ## 影响 49 | - **技术影响**: {{TECHNICAL_IMPACT}} 50 | - **业务影响**: {{BUSINESS_IMPACT}} 51 | - **资源影响**: {{RESOURCE_IMPACT}} 52 | - **风险**: {{RISKS}} 53 | 54 | ## 实施计划 55 | 1. {{IMPLEMENTATION_STEP_1}} 56 | 2. {{IMPLEMENTATION_STEP_2}} 57 | 3. {{IMPLEMENTATION_STEP_3}} 58 | 59 | ## 验证方法 60 | {{VALIDATION_METHOD}} 61 | 62 | ## 相关决策 63 | - {{RELATED_DECISION_1}} 64 | - {{RELATED_DECISION_2}} 65 | 66 | ## 参考资料 67 | - {{REFERENCE_1}} 68 | - {{REFERENCE_2}} 69 | 70 | ## 备注 71 | {{NOTES}} 72 | 73 | --- 74 | *使用 [FOCUS] 命令限制上下文到指定范围,防止分心* -------------------------------------------------------------------------------- /project_management/templates/main_control_template.md: -------------------------------------------------------------------------------- 1 | # 项目主控制文档模板 2 | 3 | 10 | 11 | ## 项目信息 12 | 19 | 20 | - **项目名称**: [PROJECT_NAME] 21 | - **版本**: [VERSION] 22 | - **开始日期**: [START_DATE] 23 | - **计划完成日期**: [END_DATE] 24 | 25 | ## 项目目标 26 | 33 | 34 | [项目目标描述] 35 | 36 | ## 当前阶段 37 | 44 | 45 | - 阶段:[PHASE_NAME] 46 | - 状态:[STATUS] 47 | - 进度:[PROGRESS]% 48 | 49 | ## 开发计划 50 | 57 | 58 | ### 第一阶段:[阶段名称]([时间估计]) 59 | 1. [任务1] 60 | 2. [任务2] 61 | 3. [任务3] 62 | 63 | ### 第二阶段:[阶段名称]([时间估计]) 64 | 1. [任务1] 65 | 2. [任务2] 66 | 3. [任务3] 67 | 68 | ## 关键里程碑 69 | 76 | 77 | 1. [ ] [里程碑1] 78 | 2. [ ] [里程碑2] 79 | 3. [ ] [里程碑3] 80 | 81 | ## 风险管理 82 | 89 | 90 | 1. [风险1] 91 | - 影响:[描述] 92 | - 对策:[措施] 93 | 94 | ## 质量控制 95 | 102 | 103 | - [质量控制项1] 104 | - [质量控制项2] 105 | - [质量控制项3] 106 | 107 | ## 下一步行动 108 | 115 | 116 | 1. [行动项1] 117 | 2. [行动项2] 118 | 3. [行动项3] 119 | 120 | --- 121 | *最后更新: [TIMESTAMP]* 122 | 123 | -------------------------------------------------------------------------------- /project_management/templates/project_progress_template.md: -------------------------------------------------------------------------------- 1 | # 项目进度跟踪模板 2 | 3 | 10 | 11 | ## 项目信息 12 | 19 | 20 | - **项目名称**: [PROJECT_NAME] 21 | - **版本**: [VERSION] 22 | - **开始日期**: [START_DATE] 23 | - **计划完成日期**: [END_DATE] 24 | - **当前状态**: [STATUS] 25 | - **当前进度**: [PROGRESS]% 26 | 27 | ## 里程碑 28 | 35 | 36 | | 里程碑 | 计划日期 | 实际日期 | 状态 | 负责人 | 37 | |-------|---------|---------|------|-------| 38 | | [里程碑1] | [计划日期] | [实际日期] | [状态] | [负责人] | 39 | | [里程碑2] | [计划日期] | [实际日期] | [状态] | [负责人] | 40 | 41 | ## 进度更新历史 42 | 49 | 50 | | 日期 | 进度 | 更新内容 | 更新人 | 51 | |------|------|---------|-------| 52 | | [日期] | [进度]% | [更新说明] | [更新人] | 53 | 54 | ## 风险与问题 55 | 62 | 63 | | ID | 描述 | 影响程度 | 状态 | 解决方案 | 负责人 | 64 | |----|-----|---------|------|---------|-------| 65 | | [ID] | [描述] | 高/中/低 | 开放/已解决 | [方案] | [负责人] | 66 | 67 | ## 下一步计划 68 | 75 | 76 | - [ ] [任务1] 77 | - [ ] [任务2] 78 | - [ ] [任务3] 79 | 80 | ## 备注 81 | 88 | 89 | [备注内容] 90 | 91 | --- 92 | *最后更新: [TIMESTAMP]* 93 | 94 | -------------------------------------------------------------------------------- /project_management/templates/risk_template.md: -------------------------------------------------------------------------------- 1 | # 风险评估 2 | 3 | ## 基本信息 4 | - **风险ID**: {{RISK_ID}} 5 | - **风险名称**: {{RISK_NAME}} 6 | - **创建日期**: {{CREATION_DATE}} 7 | - **最后更新**: {{LAST_UPDATED}} 8 | - **时间戳**: {{TIMESTAMP}} 9 | - **状态**: {{STATUS}} (已识别/已分析/已缓解/已关闭) 10 | - **负责人**: {{OWNER}} 11 | 12 | ## 风险描述 13 | {{RISK_DESCRIPTION}} 14 | 15 | ## 风险评估 16 | - **可能性**: {{PROBABILITY}} (高/中/低) 17 | - **影响程度**: {{IMPACT}} (高/中/低) 18 | - **风险等级**: {{RISK_LEVEL}} (高/中/低) 19 | - **触发条件**: {{TRIGGER_CONDITIONS}} 20 | 21 | ## 影响分析 22 | - **项目进度影响**: {{SCHEDULE_IMPACT}} 23 | - **项目成本影响**: {{COST_IMPACT}} 24 | - **项目质量影响**: {{QUALITY_IMPACT}} 25 | - **其他影响**: {{OTHER_IMPACT}} 26 | 27 | ## 缓解策略 28 | ### 预防措施 29 | 1. {{PREVENTION_MEASURE_1}} 30 | 2. {{PREVENTION_MEASURE_2}} 31 | 32 | ### 应对计划 33 | 1. {{RESPONSE_PLAN_1}} 34 | 2. {{RESPONSE_PLAN_2}} 35 | 36 | ### 应急计划 37 | {{CONTINGENCY_PLAN}} 38 | 39 | ## 监控指标 40 | - **指标1**: {{METRIC_1}} 41 | - **指标2**: {{METRIC_2}} 42 | - **监控频率**: {{MONITORING_FREQUENCY}} 43 | - **预警阈值**: {{WARNING_THRESHOLD}} 44 | 45 | ## 相关风险 46 | - {{RELATED_RISK_1}} 47 | - {{RELATED_RISK_2}} 48 | 49 | ## 风险状态历史 50 | | 日期 | 状态 | 更新人 | 备注 | 51 | |------|------|-------|------| 52 | | {{DATE_1}} | {{STATUS_1}} | {{UPDATER_1}} | {{NOTE_1}} | 53 | | {{DATE_2}} | {{STATUS_2}} | {{UPDATER_2}} | {{NOTE_2}} | 54 | 55 | ## 经验教训 56 | {{LESSONS_LEARNED}} 57 | 58 | ## 附件和参考 59 | - {{ATTACHMENT_1}} 60 | - {{REFERENCE_1}} 61 | 62 | --- 63 | *使用 [CODE NOW] 命令立即停止分析并开始编写代码* -------------------------------------------------------------------------------- /project_management/templates/task_template.md: -------------------------------------------------------------------------------- 1 | # 任务模板 2 | 3 | 16 | 17 | ## 任务信息 18 | 31 | 32 | - **任务ID**: [TASK-ID] 33 | - **任务名称**: [任务名称] 34 | - **创建时间**: [TIMESTAMP] 35 | - **优先级**: [高/中/低] 36 | - **状态**: [未开始/进行中/已完成/已暂停] 37 | 38 | ## 任务描述 39 | 53 | 54 | [详细描述任务内容和目标] 55 | 56 | ## 验收标准 57 | 70 | 71 | 1. [ ] [标准1] 72 | 2. [ ] [标准2] 73 | 3. [ ] [标准3] 74 | 75 | ## 时间规划 76 | 89 | 90 | - **计划开始**: [START_DATE] 91 | - **预计完成**: [END_DATE] 92 | - **实际耗时**: [ACTUAL_HOURS]小时 93 | 94 | ## 依赖关系 95 | 107 | 108 | - **前置任务**: [依赖的任务ID] 109 | - **后续任务**: [被依赖的任务ID] 110 | 111 | ## 资源需求 112 | 125 | 126 | - [所需资源1] 127 | - [所需资源2] 128 | 129 | ## 进展记录 130 | 141 | 142 | | 日期 | 进展 | 备注 | 143 | |------|------|------| 144 | | [日期] | [进展说明] | [备注] | 145 | 146 | ## 备注 147 | 159 | 160 | [补充说明] 161 | 162 | --- 163 | *最后更新: [TIMESTAMP]* 164 | 165 | -------------------------------------------------------------------------------- /project_management/templates/weekly_report_template.md: -------------------------------------------------------------------------------- 1 | # 周报模板 2 | 3 | 10 | 11 | ## 时间 12 | 13 | [TIMESTAMP] 14 | 15 | ## 本周主要工作 16 | 23 | 24 | 1. [重要工作1] 25 | - [具体成果] 26 | - [完成情况] 27 | 28 | 2. [重要工作2] 29 | - [具体成果] 30 | - [完成情况] 31 | 32 | ## 下周工作计划 33 | 40 | 41 | 1. [计划项1] 42 | - [具体目标] 43 | - [验收标准] 44 | 45 | 2. [计划项2] 46 | - [具体目标] 47 | - [验收标准] 48 | 49 | ## 存在的问题和风险 50 | 57 | 58 | 1. [问题1] 59 | - 影响:[描述] 60 | - 对策:[方案] 61 | 62 | 2. [风险1] 63 | - 等级:[高/中/低] 64 | - 缓解:[措施] 65 | 66 | ## 项目状态 67 | 74 | 75 | - 版本: [VERSION] 76 | - 总体进度: [PROGRESS]% 77 | - 计划完成时间: [DEADLINE] 78 | 79 | ## 其他说明 80 | 87 | 88 | [补充说明] 89 | 90 | --- 91 | *最后更新: [TIMESTAMP]* -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["pdm-backend"] 3 | build-backend = "pdm.backend" 4 | 5 | [project] 6 | name = "cursormind" 7 | version = "0.2.1" 8 | authors = [ 9 | {name = "Yagami"}, 10 | ] 11 | description = "A project management framework for Cursor developers" 12 | readme = "README.md" 13 | requires-python = ">=3.9" 14 | classifiers = [ 15 | "Programming Language :: Python :: 3", 16 | "Programming Language :: Python :: 3.9", 17 | "Programming Language :: Python :: 3.10", 18 | "Programming Language :: Python :: 3.11", 19 | "Programming Language :: Python :: 3.12", 20 | "Programming Language :: Python :: 3.13", 21 | "License :: OSI Approved :: MIT License", 22 | "Operating System :: OS Independent", 23 | ] 24 | dependencies = [ 25 | "click>=8.0.0", 26 | "rich>=10.0.0", 27 | "python-dateutil>=2.8.2", 28 | "pytz>=2021.3", 29 | ] 30 | 31 | [project.scripts] 32 | cursormind = "cursormind.cli:main" 33 | 34 | [tool.pdm] 35 | package-dir = "src" -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | click>=8.0.0 2 | pytz>=2021.1 3 | pytest>=7.0.0 4 | pytest-cov>=3.0.0 5 | black>=22.0.0 6 | flake8>=4.0.0 7 | mypy>=0.900 -------------------------------------------------------------------------------- /scripts/create_report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CursorMind 报告创建脚本 4 | # 用法: ./create_report.sh [daily|weekly] 5 | 6 | set -e 7 | 8 | # 颜色定义 9 | RED='\033[0;31m' 10 | GREEN='\033[0;32m' 11 | YELLOW='\033[0;33m' 12 | BLUE='\033[0;34m' 13 | NC='\033[0m' # No Color 14 | 15 | # 检查参数 16 | if [ $# -lt 1 ]; then 17 | echo -e "${RED}错误: 缺少报告类型参数${NC}" 18 | echo -e "用法: $0 [daily|weekly]" 19 | exit 1 20 | fi 21 | 22 | REPORT_TYPE="$1" 23 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 24 | PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" 25 | 26 | # 获取太平洋时间戳 27 | # 尝试使用Python时间戳脚本,如果失败则使用简单时间戳脚本 28 | CURRENT_DATE=$("$SCRIPT_DIR/timestamp.sh" date 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" date) 29 | FULL_TIMESTAMP=$("$SCRIPT_DIR/timestamp.sh" full 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" full) 30 | COMPACT_DATE=$("$SCRIPT_DIR/timestamp.sh" compact 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" compact) 31 | WEEK_NUMBER=$("$SCRIPT_DIR/timestamp.sh" week 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" week) 32 | 33 | # 检查是否使用了简单时间戳脚本 34 | if ! "$SCRIPT_DIR/timestamp.sh" full &>/dev/null; then 35 | echo -e "${YELLOW}警告: 使用本地时间而非太平洋时间${NC}" 36 | echo -e "${YELLOW}如需使用太平洋时间,请确保已安装Python 3.6+和pytz库${NC}" 37 | fi 38 | 39 | # 获取项目名称 40 | PROJECT_NAME=$(grep "项目名称" "$PROJECT_ROOT/PROJECT_PROGRESS.md" | head -n 1 | cut -d ":" -f 2 | sed 's/^ *//' | sed 's/ *$//') 41 | if [ -z "$PROJECT_NAME" ] || [ "$PROJECT_NAME" = "[项目名称]" ]; then 42 | PROJECT_NAME="未命名项目" 43 | fi 44 | 45 | # 创建日报 46 | create_daily_report() { 47 | REPORT_FILE="$PROJECT_ROOT/project_management/actuals/reports/daily/daily_report_$COMPACT_DATE.md" 48 | TEMPLATE_FILE="$PROJECT_ROOT/project_management/templates/daily_report_template.md" 49 | 50 | echo -e "${BLUE}=== 创建日报: $COMPACT_DATE ===${NC}" 51 | echo -e "${BLUE}=== 时间戳: $FULL_TIMESTAMP ===${NC}" 52 | 53 | # 检查是否已存在 54 | if [ -f "$REPORT_FILE" ]; then 55 | echo -e "${YELLOW}警告: 今日日报已存在${NC}" 56 | read -p "是否覆盖? (y/n): " -n 1 -r 57 | echo 58 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then 59 | echo -e "${RED}已取消${NC}" 60 | return 61 | fi 62 | fi 63 | 64 | # 复制模板并替换占位符 65 | cp "$TEMPLATE_FILE" "$REPORT_FILE" 66 | sed -i '' "s/{{DATE}}/$CURRENT_DATE/g" "$REPORT_FILE" 67 | sed -i '' "s/{{PROJECT_NAME}}/$PROJECT_NAME/g" "$REPORT_FILE" 68 | sed -i '' "s/{{AUTHOR}}/$(whoami)/g" "$REPORT_FILE" 69 | sed -i '' "s/{{TIMESTAMP}}/$FULL_TIMESTAMP/g" "$REPORT_FILE" 70 | 71 | echo -e "${GREEN}日报已创建: $REPORT_FILE${NC}" 72 | } 73 | 74 | # 创建周报 75 | create_weekly_report() { 76 | # 使用太平洋时间的年份和周数 77 | YEAR_WEEK=$WEEK_NUMBER 78 | REPORT_FILE="$PROJECT_ROOT/project_management/actuals/reports/weekly/weekly_report_$YEAR_WEEK.md" 79 | TEMPLATE_FILE="$PROJECT_ROOT/project_management/templates/weekly_report_template.md" 80 | 81 | # 计算本周的开始和结束日期 82 | # 尝试使用Python脚本,如果失败则使用简单方法 83 | if "$SCRIPT_DIR/timestamp.sh" full &>/dev/null; then 84 | # 使用Python脚本计算 85 | WEEK_START=$(python3 -c " 86 | import datetime, pytz 87 | pacific = pytz.timezone('America/Los_Angeles') 88 | now = datetime.datetime.now(pacific) 89 | start = now - datetime.timedelta(days=now.weekday()) 90 | print(start.strftime('%Y-%m-%d')) 91 | " 2>/dev/null || date -v-$(date +%u)d +"%Y-%m-%d") 92 | 93 | WEEK_END=$(python3 -c " 94 | import datetime, pytz 95 | pacific = pytz.timezone('America/Los_Angeles') 96 | now = datetime.datetime.now(pacific) 97 | start = now - datetime.timedelta(days=now.weekday()) 98 | end = start + datetime.timedelta(days=6) 99 | print(end.strftime('%Y-%m-%d')) 100 | " 2>/dev/null || date -v-$(date +%u)d -v+6d +"%Y-%m-%d") 101 | else 102 | # 使用简单方法计算 103 | WEEK_START=$(date -v-$(date +%u)d +"%Y-%m-%d") 104 | WEEK_END=$(date -v-$(date +%u)d -v+6d +"%Y-%m-%d") 105 | fi 106 | 107 | # 提取周数 108 | WEEK_NUM=$(echo $YEAR_WEEK | cut -d 'W' -f 2) 109 | 110 | echo -e "${BLUE}=== 创建周报: 第$WEEK_NUM周 ($WEEK_START 至 $WEEK_END) ===${NC}" 111 | echo -e "${BLUE}=== 时间戳: $FULL_TIMESTAMP ===${NC}" 112 | 113 | # 检查是否已存在 114 | if [ -f "$REPORT_FILE" ]; then 115 | echo -e "${YELLOW}警告: 本周周报已存在${NC}" 116 | read -p "是否覆盖? (y/n): " -n 1 -r 117 | echo 118 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then 119 | echo -e "${RED}已取消${NC}" 120 | return 121 | fi 122 | fi 123 | 124 | # 复制模板并替换占位符 125 | cp "$TEMPLATE_FILE" "$REPORT_FILE" 126 | sed -i '' "s/{{WEEK_NUMBER}}/$WEEK_NUM/g" "$REPORT_FILE" 127 | sed -i '' "s/{{PROJECT_NAME}}/$PROJECT_NAME/g" "$REPORT_FILE" 128 | sed -i '' "s/{{START_DATE}}/$WEEK_START/g" "$REPORT_FILE" 129 | sed -i '' "s/{{END_DATE}}/$WEEK_END/g" "$REPORT_FILE" 130 | sed -i '' "s/{{AUTHOR}}/$(whoami)/g" "$REPORT_FILE" 131 | sed -i '' "s/{{TIMESTAMP}}/$FULL_TIMESTAMP/g" "$REPORT_FILE" 132 | 133 | echo -e "${GREEN}周报已创建: $REPORT_FILE${NC}" 134 | } 135 | 136 | # 根据报告类型执行相应的函数 137 | case "$REPORT_TYPE" in 138 | daily) 139 | create_daily_report 140 | ;; 141 | weekly) 142 | create_weekly_report 143 | ;; 144 | *) 145 | echo -e "${RED}错误: 无效的报告类型 '$REPORT_TYPE'${NC}" 146 | echo -e "有效的报告类型: daily, weekly" 147 | exit 1 148 | ;; 149 | esac -------------------------------------------------------------------------------- /scripts/generate_timestamp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | CursorMind 时间戳生成脚本 6 | 生成美国太平洋时间的时间戳 7 | """ 8 | 9 | import datetime 10 | import pytz 11 | import sys 12 | 13 | def get_pacific_timestamp(format_type='full'): 14 | """ 15 | 获取美国太平洋时间的时间戳 16 | 17 | 参数: 18 | format_type (str): 时间戳格式类型 19 | - 'full': 完整格式 YYYY-MM-DD HH:MM:SS PST/PDT 20 | - 'date': 仅日期 YYYY-MM-DD 21 | - 'datetime': 日期和时间 YYYY-MM-DD HH:MM:SS 22 | - 'compact': 紧凑格式 YYYYMMDD 23 | - 'week': 年份和周数 YYYYWNN 24 | 25 | 返回: 26 | str: 格式化的时间戳 27 | """ 28 | # 获取太平洋时区的当前时间 29 | pacific_tz = pytz.timezone('America/Los_Angeles') 30 | now = datetime.datetime.now(pacific_tz) 31 | 32 | # 确定是PST还是PDT 33 | timezone_name = now.strftime('%Z') 34 | 35 | if format_type == 'full': 36 | # 完整格式: YYYY-MM-DD HH:MM:SS PST/PDT 37 | return now.strftime('%Y-%m-%d %H:%M:%S') + f" {timezone_name}" 38 | elif format_type == 'date': 39 | # 仅日期: YYYY-MM-DD 40 | return now.strftime('%Y-%m-%d') 41 | elif format_type == 'datetime': 42 | # 日期和时间: YYYY-MM-DD HH:MM:SS 43 | return now.strftime('%Y-%m-%d %H:%M:%S') 44 | elif format_type == 'compact': 45 | # 紧凑格式: YYYYMMDD 46 | return now.strftime('%Y%m%d') 47 | elif format_type == 'week': 48 | # 年份和周数: YYYYWNN 49 | year = now.strftime('%Y') 50 | week = now.strftime('%U') 51 | return f"{year}W{week}" 52 | else: 53 | raise ValueError(f"不支持的格式类型: {format_type}") 54 | 55 | if __name__ == "__main__": 56 | # 如果有命令行参数,使用它作为格式类型 57 | format_type = 'full' 58 | if len(sys.argv) > 1: 59 | format_type = sys.argv[1] 60 | 61 | try: 62 | timestamp = get_pacific_timestamp(format_type) 63 | print(timestamp) 64 | except ValueError as e: 65 | print(f"错误: {e}", file=sys.stderr) 66 | print("支持的格式类型: full, date, datetime, compact, week", file=sys.stderr) 67 | sys.exit(1) -------------------------------------------------------------------------------- /scripts/hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 检查时间戳格式的 pre-commit hook 4 | 5 | # 获取当前的太平洋时间戳格式 6 | CORRECT_FORMAT=$(python3 scripts/generate_timestamp.py full) 7 | TIMEZONE=$(echo $CORRECT_FORMAT | awk '{print $NF}') 8 | 9 | # 检查文档中的时间戳格式 10 | check_timestamps() { 11 | local file="$1" 12 | if grep -E "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} (PST|PDT)" "$file" | grep -v "$TIMEZONE"; then 13 | echo "错误: $file 中存在不正确的时区格式,请使用 scripts/generate_timestamp.py 生成时间戳" 14 | return 1 15 | fi 16 | return 0 17 | } 18 | 19 | # 获取待提交的 Markdown 文件 20 | files=$(git diff --cached --name-only --diff-filter=ACM | grep "\.md$") 21 | 22 | # 检查每个文件 23 | for file in $files; do 24 | if [ -f "$file" ]; then 25 | if ! check_timestamps "$file"; then 26 | exit 1 27 | fi 28 | fi 29 | done 30 | 31 | exit 0 -------------------------------------------------------------------------------- /scripts/init_project.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CursorMind 项目初始化脚本 4 | # 用法: ./init_project.sh "项目名称" 5 | 6 | set -e 7 | 8 | # 颜色定义 9 | RED='\033[0;31m' 10 | GREEN='\033[0;32m' 11 | YELLOW='\033[0;33m' 12 | BLUE='\033[0;34m' 13 | NC='\033[0m' # No Color 14 | 15 | # 检查参数 16 | if [ $# -lt 1 ]; then 17 | echo -e "${RED}错误: 缺少项目名称参数${NC}" 18 | echo -e "用法: $0 \"项目名称\"" 19 | exit 1 20 | fi 21 | 22 | PROJECT_NAME="$1" 23 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 24 | PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" 25 | 26 | # 获取太平洋时间戳 27 | # 尝试使用Python时间戳脚本,如果失败则使用简单时间戳脚本 28 | CURRENT_DATE=$("$SCRIPT_DIR/timestamp.sh" date 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" date) 29 | FULL_TIMESTAMP=$("$SCRIPT_DIR/timestamp.sh" full 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" full) 30 | 31 | # 检查是否使用了简单时间戳脚本 32 | if ! "$SCRIPT_DIR/timestamp.sh" full &>/dev/null; then 33 | echo -e "${YELLOW}警告: 使用本地时间而非太平洋时间${NC}" 34 | echo -e "${YELLOW}如需使用太平洋时间,请确保已安装Python 3.6+和pytz库${NC}" 35 | fi 36 | 37 | echo -e "${BLUE}=== 初始化项目: $PROJECT_NAME ===${NC}" 38 | echo -e "${BLUE}=== 时间戳: $FULL_TIMESTAMP ===${NC}" 39 | 40 | # 更新 PROJECT_PROGRESS.md 41 | echo -e "${YELLOW}更新项目进度文件...${NC}" 42 | sed -i '' "s/\[项目名称\]/$PROJECT_NAME/g" "$PROJECT_ROOT/PROJECT_PROGRESS.md" 43 | sed -i '' "s/\[YYYY-MM-DD\]/$CURRENT_DATE/g" "$PROJECT_ROOT/PROJECT_PROGRESS.md" 44 | sed -i '' "s/最后更新: YYYY-MM-DD/最后更新: $FULL_TIMESTAMP/g" "$PROJECT_ROOT/PROJECT_PROGRESS.md" 45 | 46 | # 更新 MAIN_CONTROL.md 47 | echo -e "${YELLOW}更新中央控制文档...${NC}" 48 | sed -i '' "s/\[项目名称\]/$PROJECT_NAME/g" "$PROJECT_ROOT/project_management/control/MAIN_CONTROL.md" 49 | sed -i '' "s/\[YYYY-MM-DD\]/$CURRENT_DATE/g" "$PROJECT_ROOT/project_management/control/MAIN_CONTROL.md" 50 | sed -i '' "s/- \*\*最后更新\*\*: \[YYYY-MM-DD\]/- **最后更新**: $FULL_TIMESTAMP/g" "$PROJECT_ROOT/project_management/control/MAIN_CONTROL.md" 51 | 52 | # 更新 REQUIREMENTS.md 53 | echo -e "${YELLOW}更新需求文档...${NC}" 54 | sed -i '' "s/\[项目名称\]/$PROJECT_NAME/g" "$PROJECT_ROOT/project_management/control/REQUIREMENTS.md" 55 | sed -i '' "s/\[YYYY-MM-DD\]/$CURRENT_DATE/g" "$PROJECT_ROOT/project_management/control/REQUIREMENTS.md" 56 | sed -i '' "s/- \*\*最后更新\*\*: \[YYYY-MM-DD\]/- **最后更新**: $FULL_TIMESTAMP/g" "$PROJECT_ROOT/project_management/control/REQUIREMENTS.md" 57 | 58 | # 创建初始日报 59 | echo -e "${YELLOW}创建今日日报...${NC}" 60 | "$SCRIPT_DIR/create_report.sh" daily 61 | 62 | # 创建初始周报 63 | echo -e "${YELLOW}创建本周周报...${NC}" 64 | "$SCRIPT_DIR/create_report.sh" weekly 65 | 66 | # 设置脚本权限 67 | echo -e "${YELLOW}设置脚本执行权限...${NC}" 68 | chmod +x "$SCRIPT_DIR"/*.sh 69 | chmod +x "$SCRIPT_DIR"/*.py 70 | 71 | echo -e "${GREEN}=== 项目初始化完成! ===${NC}" 72 | echo -e "项目名称: ${BLUE}$PROJECT_NAME${NC}" 73 | echo -e "初始化时间: ${BLUE}$FULL_TIMESTAMP${NC}" 74 | echo -e "\n${YELLOW}接下来您可以:${NC}" 75 | echo -e "1. 查看和编辑 ${BLUE}PROJECT_PROGRESS.md${NC} 文件" 76 | echo -e "2. 查看和编辑 ${BLUE}project_management/control/MAIN_CONTROL.md${NC} 文件" 77 | echo -e "3. 查看今日创建的日报和周报" 78 | echo -e "\n${GREEN}祝您项目顺利!${NC}" -------------------------------------------------------------------------------- /scripts/simple_timestamp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CursorMind 简单时间戳生成脚本 4 | # 用法: ./simple_timestamp.sh [format_type] 5 | # format_type 可以是: full, date, datetime, compact, week 6 | 7 | # 注意: 此脚本使用系统时间,不是太平洋时间 8 | # 如果需要太平洋时间,请使用timestamp.sh脚本 9 | 10 | format_type="${1:-full}" 11 | 12 | case "$format_type" in 13 | full) 14 | # 完整格式: YYYY-MM-DD HH:MM:SS TZ 15 | date "+%Y-%m-%d %H:%M:%S %Z" 16 | ;; 17 | date) 18 | # 仅日期: YYYY-MM-DD 19 | date "+%Y-%m-%d" 20 | ;; 21 | datetime) 22 | # 日期和时间: YYYY-MM-DD HH:MM:SS 23 | date "+%Y-%m-%d %H:%M:%S" 24 | ;; 25 | compact) 26 | # 紧凑格式: YYYYMMDD 27 | date "+%Y%m%d" 28 | ;; 29 | week) 30 | # 年份和周数: YYYYWNN 31 | date "+%YW%U" 32 | ;; 33 | *) 34 | echo "错误: 不支持的格式类型: $format_type" >&2 35 | echo "支持的格式类型: full, date, datetime, compact, week" >&2 36 | exit 1 37 | ;; 38 | esac -------------------------------------------------------------------------------- /scripts/timestamp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CursorMind 时间戳生成脚本包装器 4 | # 用法: ./timestamp.sh [format_type] 5 | # format_type 可以是: full, date, datetime, compact, week 6 | 7 | set -e 8 | 9 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 10 | PYTHON_SCRIPT="$SCRIPT_DIR/generate_timestamp.py" 11 | VENV_DIR="$SCRIPT_DIR/.venv" 12 | 13 | # 检查Python脚本是否存在 14 | if [ ! -f "$PYTHON_SCRIPT" ]; then 15 | echo "错误: 找不到Python时间戳脚本: $PYTHON_SCRIPT" >&2 16 | exit 1 17 | fi 18 | 19 | # 如果虚拟环境不存在,创建一个 20 | if [ ! -d "$VENV_DIR" ]; then 21 | echo "创建Python虚拟环境..." >&2 22 | python3 -m venv "$VENV_DIR" || { 23 | echo "错误: 无法创建虚拟环境,请确保已安装Python 3.6+" >&2 24 | 25 | # 回退方案:直接使用系统Python,但可能会失败 26 | echo "尝试使用系统Python..." >&2 27 | if ! python3 -c "import pytz" &>/dev/null; then 28 | echo "错误: 未安装pytz模块,请手动安装: pip3 install pytz" >&2 29 | 30 | # 生成一个基本的时间戳作为回退 31 | date "+%Y-%m-%d %H:%M:%S" 32 | exit 1 33 | fi 34 | 35 | python3 "$PYTHON_SCRIPT" "$@" 36 | exit $? 37 | } 38 | 39 | # 安装依赖 40 | "$VENV_DIR/bin/pip" install pytz || { 41 | echo "错误: 无法安装pytz模块" >&2 42 | exit 1 43 | } 44 | fi 45 | 46 | # 使用虚拟环境中的Python运行脚本 47 | "$VENV_DIR/bin/python" "$PYTHON_SCRIPT" "$@" || { 48 | # 如果失败,尝试使用系统Python 49 | echo "警告: 虚拟环境执行失败,尝试使用系统Python..." >&2 50 | python3 "$PYTHON_SCRIPT" "$@" || { 51 | # 如果仍然失败,使用系统日期命令作为回退 52 | echo "错误: 无法执行Python脚本,使用系统日期命令作为回退" >&2 53 | if [ "$1" = "full" ]; then 54 | date "+%Y-%m-%d %H:%M:%S" 55 | elif [ "$1" = "date" ]; then 56 | date "+%Y-%m-%d" 57 | elif [ "$1" = "compact" ]; then 58 | date "+%Y%m%d" 59 | elif [ "$1" = "week" ]; then 60 | date "+%YW%U" 61 | else 62 | date "+%Y-%m-%d %H:%M:%S" 63 | fi 64 | } 65 | } -------------------------------------------------------------------------------- /scripts/update_progress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CursorMind 项目进度更新脚本 4 | # 用法: ./update_progress.sh <进度百分比> ["更新内容"] 5 | 6 | set -e 7 | 8 | # 颜色定义 9 | RED='\033[0;31m' 10 | GREEN='\033[0;32m' 11 | YELLOW='\033[0;33m' 12 | BLUE='\033[0;34m' 13 | NC='\033[0m' # No Color 14 | 15 | # 检查参数 16 | if [ $# -lt 1 ]; then 17 | echo -e "${RED}错误: 缺少进度百分比参数${NC}" 18 | echo -e "用法: $0 <进度百分比> [\"更新内容\"]" 19 | exit 1 20 | fi 21 | 22 | PROGRESS="$1" 23 | UPDATE_CONTENT="${2:-项目进度更新}" 24 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 25 | PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" 26 | PROGRESS_FILE="$PROJECT_ROOT/PROJECT_PROGRESS.md" 27 | MAIN_CONTROL_FILE="$PROJECT_ROOT/project_management/control/MAIN_CONTROL.md" 28 | 29 | # 获取太平洋时间戳 30 | # 尝试使用Python时间戳脚本,如果失败则使用简单时间戳脚本 31 | CURRENT_DATE=$("$SCRIPT_DIR/timestamp.sh" date 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" date) 32 | FULL_TIMESTAMP=$("$SCRIPT_DIR/timestamp.sh" full 2>/dev/null || "$SCRIPT_DIR/simple_timestamp.sh" full) 33 | 34 | # 检查是否使用了简单时间戳脚本 35 | if ! "$SCRIPT_DIR/timestamp.sh" full &>/dev/null; then 36 | echo -e "${YELLOW}警告: 使用本地时间而非太平洋时间${NC}" 37 | echo -e "${YELLOW}如需使用太平洋时间,请确保已安装Python 3.6+和pytz库${NC}" 38 | fi 39 | 40 | # 验证进度百分比 41 | if ! [[ "$PROGRESS" =~ ^[0-9]+$ ]] || [ "$PROGRESS" -lt 0 ] || [ "$PROGRESS" -gt 100 ]; then 42 | echo -e "${RED}错误: 进度百分比必须是0-100之间的整数${NC}" 43 | exit 1 44 | fi 45 | 46 | echo -e "${BLUE}=== 更新项目进度: $PROGRESS% ===${NC}" 47 | echo -e "${BLUE}=== 时间戳: $FULL_TIMESTAMP ===${NC}" 48 | 49 | # 获取当前用户 50 | CURRENT_USER=$(whoami) 51 | 52 | # 更新 PROJECT_PROGRESS.md 53 | echo -e "${YELLOW}更新项目进度文件...${NC}" 54 | 55 | # 更新当前进度 56 | sed -i '' "s/- \*\*当前进度\*\*: \[[0-9]*-[0-9]*\]%/- **当前进度**: $PROGRESS%/g" "$PROGRESS_FILE" 57 | sed -i '' "s/- \*\*当前进度\*\*: [0-9]*%/- **当前进度**: $PROGRESS%/g" "$PROGRESS_FILE" 58 | 59 | # 更新最后更新时间 60 | sed -i '' "s/最后更新: .*$/最后更新: $FULL_TIMESTAMP/g" "$PROGRESS_FILE" 61 | 62 | # 添加进度更新历史 63 | # 查找进度更新历史表格的结束位置 64 | TABLE_END=$(grep -n "## 风险与问题" "$PROGRESS_FILE" | cut -d ":" -f 1) 65 | TABLE_START=$(grep -n "## 进度更新历史" "$PROGRESS_FILE" | cut -d ":" -f 1) 66 | TABLE_START=$((TABLE_START + 2)) # 跳过表头和分隔行 67 | 68 | # 在表格开头插入新行 69 | NEW_LINE="| $CURRENT_DATE | $PROGRESS% | $UPDATE_CONTENT | $CURRENT_USER |" 70 | sed -i '' "${TABLE_START}a\\ 71 | $NEW_LINE" "$PROGRESS_FILE" 72 | 73 | # 更新 MAIN_CONTROL.md 74 | echo -e "${YELLOW}更新中央控制文档...${NC}" 75 | sed -i '' "s/- \*\*进度\*\*: \[[0-9]*-[0-9]*\]%/- **进度**: $PROGRESS%/g" "$MAIN_CONTROL_FILE" 76 | sed -i '' "s/- \*\*进度\*\*: [0-9]*%/- **进度**: $PROGRESS%/g" "$MAIN_CONTROL_FILE" 77 | sed -i '' "s/- \*\*最后更新\*\*: .*$/- **最后更新**: $FULL_TIMESTAMP/g" "$MAIN_CONTROL_FILE" 78 | 79 | # 添加变更记录 80 | # 查找关键决策记录表格的开始位置 81 | DECISION_TABLE_START=$(grep -n "## 关键决策记录" "$MAIN_CONTROL_FILE" | cut -d ":" -f 1) 82 | DECISION_TABLE_START=$((DECISION_TABLE_START + 2)) # 跳过表头和分隔行 83 | 84 | # 生成新的决策ID 85 | LAST_DECISION_ID=$(grep -A 1 "## 关键决策记录" "$MAIN_CONTROL_FILE" | grep "D[0-9]\{3\}" | sort | tail -n 1 | awk '{print $1}' | sed 's/|//g') 86 | if [ -z "$LAST_DECISION_ID" ]; then 87 | NEW_DECISION_ID="D001" 88 | else 89 | LAST_NUM=${LAST_DECISION_ID:1} 90 | NEW_NUM=$((10#$LAST_NUM + 1)) 91 | NEW_DECISION_ID="D$(printf "%03d" $NEW_NUM)" 92 | fi 93 | 94 | # 在表格开头插入新行 95 | DECISION_LINE="| $NEW_DECISION_ID | $CURRENT_DATE | 进度更新至 $PROGRESS% | 项目进度变更 | $CURRENT_USER |" 96 | sed -i '' "${DECISION_TABLE_START}a\\ 97 | $DECISION_LINE" "$MAIN_CONTROL_FILE" 98 | 99 | echo -e "${GREEN}=== 项目进度已更新! ===${NC}" 100 | echo -e "当前进度: ${BLUE}$PROGRESS%${NC}" 101 | echo -e "更新内容: ${BLUE}$UPDATE_CONTENT${NC}" 102 | echo -e "更新时间: ${BLUE}$FULL_TIMESTAMP${NC}" 103 | echo -e "更新人: ${BLUE}$CURRENT_USER${NC}" -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name="cursormind", 5 | version="0.2.1", 6 | packages=find_packages(where="src"), 7 | package_dir={"": "src"}, 8 | install_requires=[ 9 | "click>=8.0.0", 10 | "rich>=10.0.0", 11 | "python-dateutil>=2.8.2", 12 | "pytz>=2021.3", 13 | ], 14 | entry_points={ 15 | "console_scripts": [ 16 | "cursormind=cursormind.cli:main", 17 | ], 18 | }, 19 | ) -------------------------------------------------------------------------------- /src/cursormind/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | CursorMind - 你的智能学习助手 📚 3 | """ 4 | 5 | __version__ = "0.2.1" 6 | __author__ = "Yagami" -------------------------------------------------------------------------------- /src/cursormind/__main__.py: -------------------------------------------------------------------------------- 1 | """ 2 | CursorMind 包的主入口 3 | """ 4 | from cursormind.cli import main 5 | 6 | if __name__ == '__main__': 7 | main() -------------------------------------------------------------------------------- /src/cursormind/cli.py: -------------------------------------------------------------------------------- 1 | """ 2 | 命令行接口模块 - 你的学习助手入口 🚀 3 | """ 4 | import click 5 | from typing import Dict, List, Optional 6 | from rich.console import Console 7 | from rich.table import Table 8 | from rich.markdown import Markdown 9 | from rich.progress import Progress, SpinnerColumn, TextColumn 10 | from cursormind.core.learning_path import learning_path_manager 11 | from cursormind.core.note_manager import note_manager 12 | from cursormind.core.achievement import achievement_manager 13 | from cursormind.core.cursor_framework import cursor_framework 14 | from cursormind.core.project_manager import project_manager 15 | from cursormind.core.code_review import CodeReview 16 | from cursormind.config.settings import settings 17 | from cursormind import __version__ 18 | 19 | console = Console() 20 | 21 | @click.group() 22 | @click.version_option(version=__version__) 23 | def main(): 24 | """CursorMind - 你的智能学习助手 📚""" 25 | pass 26 | 27 | @main.group(name='cursor') 28 | def cursor(): 29 | """Cursor 规范框架 🎯""" 30 | pass 31 | 32 | @cursor.command(name='init') 33 | @click.argument('project_path', type=click.Path(exists=True), default='.') 34 | @click.option('--template', '-t', default='default', help='项目模板名称') 35 | def cursor_init(project_path: str, template: str): 36 | """初始化项目结构""" 37 | with Progress( 38 | SpinnerColumn(), 39 | TextColumn("[progress.description]{task.description}"), 40 | console=console 41 | ) as progress: 42 | progress.add_task("正在生成项目结构...", total=None) 43 | if cursor_framework.generate_project_template(project_path, template): 44 | console.print("[green]✨ 项目结构初始化成功![/green]") 45 | else: 46 | console.print("[red]❌ 项目结构初始化失败[/red]") 47 | 48 | @cursor.command(name='check') 49 | @click.argument('project_path', type=click.Path(exists=True), default='.') 50 | def cursor_check(project_path: str): 51 | """检查项目结构是否符合规范""" 52 | issues = cursor_framework.check_project_structure(project_path) 53 | 54 | if not issues["missing_dirs"] and not issues["missing_files"]: 55 | console.print("[green]✨ 项目结构符合规范![/green]") 56 | return 57 | 58 | console.print("[yellow]⚠️ 发现以下问题:[/yellow]") 59 | 60 | if issues["missing_dirs"]: 61 | console.print("\n[red]缺少必要的目录:[/red]") 62 | for dir_name in issues["missing_dirs"]: 63 | console.print(f"- {dir_name}") 64 | 65 | if issues["missing_files"]: 66 | console.print("\n[red]缺少必要的文件:[/red]") 67 | for file_name in issues["missing_files"]: 68 | console.print(f"- {file_name}") 69 | 70 | @cursor.command(name='commit') 71 | @click.argument('message') 72 | def cursor_commit(message: str): 73 | """验证提交信息是否符合规范""" 74 | result = cursor_framework.validate_commit_message(message) 75 | 76 | if result["valid"]: 77 | console.print("[green]✨ 提交信息符合规范![/green]") 78 | else: 79 | console.print("[red]❌ 提交信息不符合规范[/red]") 80 | if not result["type_valid"]: 81 | console.print("\n提交类型必须是以下之一:") 82 | for type_ in cursor_framework.rules["git"]["commit_types"]: 83 | console.print(f"- {type_}") 84 | if not result["format_valid"]: 85 | console.print(f"\n提交格式必须符合:[yellow]{cursor_framework.rules['git']['commit_format']}[/yellow]") 86 | console.print("示例:feat(user): add login function") 87 | 88 | @cursor.command(name='branch') 89 | @click.argument('branch_name') 90 | def cursor_branch(branch_name: str): 91 | """验证分支名称是否符合规范""" 92 | result = cursor_framework.validate_branch_name(branch_name) 93 | 94 | if result["valid"]: 95 | console.print("[green]✨ 分支名称符合规范![/green]") 96 | else: 97 | console.print("[red]❌ 分支名称不符合规范[/red]") 98 | console.print("\n分支名称格式必须符合:") 99 | for type_, format_ in cursor_framework.rules["git"]["branch_format"].items(): 100 | console.print(f"- {type_}: {format_}") 101 | console.print(f" 示例:{format_.replace('', 'login')}") 102 | 103 | @main.group(name='path') 104 | def path(): 105 | """学习路径管理 🗺️""" 106 | pass 107 | 108 | @path.command(name='list') 109 | def path_list(): 110 | """列出所有可用的学习路径""" 111 | paths = learning_path_manager.get_all_paths() 112 | 113 | table = Table(title="可用的学习路径") 114 | table.add_column("ID", style="cyan") 115 | table.add_column("名称", style="green") 116 | table.add_column("描述", style="blue") 117 | table.add_column("难度", style="yellow") 118 | table.add_column("预计时间", style="magenta") 119 | 120 | for path in paths: 121 | table.add_row( 122 | path['id'], 123 | path['name'], 124 | path['description'], 125 | path['difficulty'], 126 | path['estimated_time'] 127 | ) 128 | 129 | console.print(table) 130 | 131 | @path.command(name='start') 132 | @click.argument('path_id') 133 | def path_start(path_id: str): 134 | """开始一个学习路径""" 135 | if learning_path_manager.set_current_path(path_id): 136 | progress = learning_path_manager.get_current_progress() 137 | console.print(f"[green]✨ 成功开始学习路径:{progress['path_name']}[/green]") 138 | console.print(f"\n当前阶段:[yellow]{progress['current_stage_name']}[/yellow]") 139 | console.print(f"当前任务:[blue]{progress['current_step_name']}[/blue]") 140 | 141 | # 显示学习资源 142 | resources = learning_path_manager.get_current_resources() 143 | if resources: 144 | console.print("\n📚 推荐学习资源:") 145 | for resource in resources: 146 | console.print(f"- {resource['name']}: {resource['url']}") 147 | 148 | # 显示练习项目 149 | projects = learning_path_manager.get_current_projects() 150 | if projects: 151 | console.print("\n🎯 练习项目:") 152 | for project in projects: 153 | console.print(f"- {project['name']}: {project['description']}") 154 | else: 155 | console.print(f"[red]❌ 未找到ID为 {path_id} 的学习路径[/red]") 156 | 157 | @path.command(name='status') 158 | def path_status(): 159 | """查看当前学习进度""" 160 | progress = learning_path_manager.get_current_progress() 161 | if progress: 162 | console.print(f"\n📊 当前学习进度:[green]{progress['path_name']}[/green]") 163 | console.print(f"阶段:[yellow]{progress['current_stage_name']}[/yellow]") 164 | console.print(f"任务:[blue]{progress['current_step_name']}[/blue]") 165 | console.print(f"完成度:[magenta]{progress['progress']} ({progress['percentage']}%)[/magenta]") 166 | 167 | # 显示当前阶段的资源和项目 168 | resources = learning_path_manager.get_current_resources() 169 | if resources: 170 | console.print("\n📚 当前阶段学习资源:") 171 | for resource in resources: 172 | console.print(f"- {resource['name']}: {resource['url']}") 173 | 174 | projects = learning_path_manager.get_current_projects() 175 | if projects: 176 | console.print("\n🎯 当前阶段练习项目:") 177 | for project in projects: 178 | console.print(f"- {project['name']}: {project['description']}") 179 | else: 180 | console.print("[yellow]⚠️ 你还没有开始任何学习路径[/yellow]") 181 | console.print("使用 [green]cursormind path list[/green] 查看可用的学习路径") 182 | console.print("使用 [green]cursormind path start <路径ID>[/green] 开始学习") 183 | 184 | @path.command(name='next') 185 | def path_next(): 186 | """完成当前任务,进入下一个任务""" 187 | progress_before = learning_path_manager.get_current_progress() 188 | if not progress_before: 189 | console.print("[yellow]⚠️ 你还没有开始任何学习路径[/yellow]") 190 | return 191 | 192 | if learning_path_manager.advance_progress(): 193 | progress = learning_path_manager.get_current_progress() 194 | console.print(f"[green]✨ 恭喜完成任务:{progress_before['current_step_name']}[/green]") 195 | if progress: 196 | console.print(f"\n下一个任务:[blue]{progress['current_step_name']}[/blue]") 197 | 198 | # 显示新任务的资源和项目 199 | resources = learning_path_manager.get_current_resources() 200 | if resources: 201 | console.print("\n📚 推荐学习资源:") 202 | for resource in resources: 203 | console.print(f"- {resource['name']}: {resource['url']}") 204 | 205 | projects = learning_path_manager.get_current_projects() 206 | if projects: 207 | console.print("\n🎯 练习项目:") 208 | for project in projects: 209 | console.print(f"- {project['name']}: {project['description']}") 210 | else: 211 | console.print("[yellow]🎉 恭喜!你已经完成了当前学习路径的所有任务![/yellow]") 212 | 213 | @main.group(name='note') 214 | def note(): 215 | """笔记管理 📝""" 216 | pass 217 | 218 | @note.command(name='add') 219 | @click.argument('content') 220 | @click.option('--topic', '-t', default='general', help='笔记主题') 221 | def note_add(content: str, topic: str): 222 | """添加新笔记""" 223 | note = note_manager.add_note(content, topic) 224 | console.print(f"[green]✨ 笔记已保存![/green]") 225 | console.print(f"ID: [blue]{note['id']}[/blue]") 226 | console.print(f"主题: [yellow]{note['topic']}[/yellow]") 227 | if note['tags']: 228 | console.print(f"标签: [magenta]{', '.join(note['tags'])}[/magenta]") 229 | 230 | @note.command(name='today') 231 | def note_today(): 232 | """查看今天的笔记""" 233 | notes = note_manager.get_daily_notes() 234 | if notes: 235 | console.print("\n📝 今日笔记:") 236 | for note in notes: 237 | console.print(f"\n[blue]{note['created_at']}[/blue]") 238 | console.print(f"[yellow]主题:{note['topic']}[/yellow]") 239 | if note['tags']: 240 | console.print(f"[magenta]标签:{', '.join(note['tags'])}[/magenta]") 241 | console.print(Markdown(note['content'])) 242 | else: 243 | console.print("[yellow]今天还没有记录笔记哦~[/yellow]") 244 | 245 | @note.command(name='topic') 246 | @click.argument('topic') 247 | def note_topic(topic: str): 248 | """查看指定主题的笔记""" 249 | notes = note_manager.get_topic_notes(topic) 250 | if notes: 251 | console.print(f"\n📚 主题 [green]{topic}[/green] 的笔记:") 252 | for note in notes: 253 | console.print(f"\n[blue]{note['created_at']}[/blue]") 254 | if note['tags']: 255 | console.print(f"[magenta]标签:{', '.join(note['tags'])}[/magenta]") 256 | console.print(Markdown(note['content'])) 257 | else: 258 | console.print(f"[yellow]还没有 {topic} 主题的笔记~[/yellow]") 259 | 260 | @note.command(name='search') 261 | @click.argument('query') 262 | def note_search(query: str): 263 | """搜索笔记""" 264 | notes = note_manager.search_notes(query) 265 | if notes: 266 | console.print(f"\n🔍 搜索结果:") 267 | for note in notes: 268 | console.print(f"\n[blue]{note['created_at']}[/blue]") 269 | console.print(f"[yellow]主题:{note['topic']}[/yellow]") 270 | if note['tags']: 271 | console.print(f"[magenta]标签:{', '.join(note['tags'])}[/magenta]") 272 | console.print(Markdown(note['content'])) 273 | else: 274 | console.print(f"[yellow]没有找到匹配的笔记~[/yellow]") 275 | 276 | @note.command(name='stats') 277 | def note_stats(): 278 | """查看笔记统计信息""" 279 | stats = note_manager.get_stats() 280 | 281 | console.print("\n📊 笔记统计:") 282 | console.print(f"总笔记数:[blue]{stats['total_notes']}[/blue] 条") 283 | console.print(f"总字数:[blue]{stats['total_words']}[/blue] 字") 284 | console.print(f"连续记录:[green]{stats['daily_streak']}[/green] 天") 285 | 286 | if stats['topics']: 287 | console.print("\n📚 主题分布:") 288 | topics_table = Table(show_header=False) 289 | topics_table.add_column("主题", style="yellow") 290 | topics_table.add_column("数量", style="cyan", justify="right") 291 | for topic, count in sorted(stats['topics'].items(), key=lambda x: x[1], reverse=True): 292 | topics_table.add_row(topic, str(count)) 293 | console.print(topics_table) 294 | 295 | if stats['tags']: 296 | console.print("\n🏷️ 常用标签:") 297 | tags_table = Table(show_header=False) 298 | tags_table.add_column("标签", style="magenta") 299 | tags_table.add_column("使用次数", style="cyan", justify="right") 300 | for tag, count in sorted(stats['tags'].items(), key=lambda x: x[1], reverse=True)[:10]: 301 | tags_table.add_row(tag, str(count)) 302 | console.print(tags_table) 303 | 304 | @note.command(name='review') 305 | @click.option('--days', '-d', default=7, help='要回顾的天数') 306 | def note_review(days: int): 307 | """生成学习回顾报告""" 308 | review = note_manager.generate_review(days) 309 | 310 | console.print(f"\n📅 学习回顾:{review['period']}") 311 | console.print(f"记录笔记:[blue]{review['total_notes']}[/blue] 条") 312 | console.print(f"总字数:[blue]{review['total_words']}[/blue] 字") 313 | 314 | if review['topics']: 315 | console.print("\n📚 主题分布:") 316 | topics_table = Table(show_header=False) 317 | topics_table.add_column("主题", style="yellow") 318 | topics_table.add_column("数量", style="cyan", justify="right") 319 | for topic, count in sorted(review['topics'].items(), key=lambda x: x[1], reverse=True): 320 | topics_table.add_row(topic, str(count)) 321 | console.print(topics_table) 322 | 323 | if review['tags']: 324 | console.print("\n🏷️ 常用标签:") 325 | tags_table = Table(show_header=False) 326 | tags_table.add_column("标签", style="magenta") 327 | tags_table.add_column("使用次数", style="cyan", justify="right") 328 | for tag, count in sorted(review['tags'].items(), key=lambda x: x[1], reverse=True)[:10]: 329 | tags_table.add_row(tag, str(count)) 330 | console.print(tags_table) 331 | 332 | if review['highlights']: 333 | console.print("\n✨ 学习亮点:") 334 | for note in review['highlights']: 335 | console.print(f"\n[blue]{note['created_at']}[/blue]") 336 | console.print(f"[yellow]主题:{note['topic']}[/yellow]") 337 | if note['tags']: 338 | console.print(f"[magenta]标签:{', '.join(note['tags'])}[/magenta]") 339 | console.print(Markdown(note['content'])) 340 | 341 | @main.group(name='achievement') 342 | def achievement(): 343 | """成就系统 🏆""" 344 | pass 345 | 346 | @achievement.command(name='list') 347 | @click.option('--all', '-a', is_flag=True, help='显示所有成就,包括未解锁的') 348 | def achievement_list(all: bool): 349 | """查看成就列表""" 350 | achievements = achievement_manager.get_achievements(include_locked=all) 351 | 352 | console.print("\n🏆 成就系统") 353 | stats = achievement_manager.get_stats() 354 | console.print(f"总积分:[green]{stats['points']}[/green] 分") 355 | console.print(f"已解锁:[blue]{len(stats['unlocked_achievements'])}[/blue] 个成就\n") 356 | 357 | for category, category_achievements in achievements.items(): 358 | if category_achievements: 359 | console.print(f"\n[yellow]== {category.upper()} ==[/yellow]") 360 | for achievement_id, achievement in category_achievements.items(): 361 | status = "[green]✓[/green]" if achievement['unlocked'] else "[grey]✗[/grey]" 362 | console.print( 363 | f"{status} {achievement['icon']} [{'green' if achievement['unlocked'] else 'grey'}" 364 | f"]{achievement['name']}[/{'green' if achievement['unlocked'] else 'grey'}]" 365 | ) 366 | console.print(f" {achievement['description']}") 367 | console.print(f" 奖励:[yellow]{achievement['reward']}[/yellow] 分") 368 | 369 | @achievement.command(name='stats') 370 | def achievement_stats(): 371 | """查看成就统计""" 372 | stats = achievement_manager.get_stats() 373 | 374 | console.print("\n📊 学习统计") 375 | console.print(f"总积分:[green]{stats['points']}[/green] 分") 376 | console.print(f"解锁成就:[blue]{len(stats['unlocked_achievements'])}[/blue] 个") 377 | 378 | stats_data = stats['stats'] 379 | console.print("\n[yellow]== 学习路径 ==[/yellow]") 380 | console.print(f"开始的路径:[blue]{stats_data['paths_started']}[/blue] 个") 381 | console.print(f"完成的路径:[green]{stats_data['paths_completed']}[/green] 个") 382 | 383 | console.print("\n[yellow]== 笔记记录 ==[/yellow]") 384 | console.print(f"笔记总数:[blue]{stats_data['notes_created']}[/blue] 条") 385 | console.print(f"连续记录:[green]{stats_data['daily_streak']}[/green] 天") 386 | console.print(f"使用的标签:[magenta]{len(stats_data['unique_tags'])}[/magenta] 个") 387 | console.print(f"涉及的主题:[cyan]{len(stats_data['unique_topics'])}[/cyan] 个") 388 | 389 | console.print("\n[yellow]== 学习回顾 ==[/yellow]") 390 | console.print(f"生成的回顾报告:[blue]{stats_data['reviews_generated']}[/blue] 次") 391 | 392 | console.print(f"\n最后更新:[grey]{stats['last_updated']}[/grey]") 393 | 394 | @main.group(name='project') 395 | def project(): 396 | """项目管理 📋""" 397 | pass 398 | 399 | @project.command(name='create') 400 | @click.argument('title') 401 | @click.option('--type', '-t', 'type_', help='任务类型') 402 | @click.option('--priority', '-p', help='优先级') 403 | @click.option('--assignee', '-a', help='负责人') 404 | @click.option('--description', '-d', help='任务描述') 405 | @click.option('--deadline', help='截止日期 (YYYY-MM-DD)') 406 | @click.option('--tags', help='标签(逗号分隔)') 407 | def project_create(title: str, type_: str, priority: str, assignee: str, 408 | description: str, deadline: str, tags: str): 409 | """创建新任务""" 410 | kwargs = {} 411 | if type_: 412 | kwargs['type'] = type_ 413 | if priority: 414 | kwargs['priority'] = priority 415 | if assignee: 416 | kwargs['assignee'] = assignee 417 | if description: 418 | kwargs['description'] = description 419 | if deadline: 420 | kwargs['deadline'] = deadline 421 | if tags: 422 | kwargs['tags'] = [tag.strip() for tag in tags.split(',')] 423 | 424 | task = project_manager.create_task(title, **kwargs) 425 | console.print(f"[green]✨ 任务创建成功![/green]") 426 | _print_task_details(task) 427 | 428 | @project.command(name='list') 429 | @click.option('--status', '-s', help='任务状态') 430 | @click.option('--priority', '-p', help='优先级') 431 | @click.option('--type', '-t', 'type_', help='任务类型') 432 | @click.option('--assignee', '-a', help='负责人') 433 | @click.option('--tags', help='标签(逗号分隔)') 434 | def project_list(status: str, priority: str, type_: str, assignee: str, tags: str): 435 | """列出任务""" 436 | tags_list = [tag.strip() for tag in tags.split(',')] if tags else None 437 | tasks = project_manager.list_tasks( 438 | status=status, 439 | priority=priority, 440 | type_=type_, 441 | assignee=assignee, 442 | tags=tags_list 443 | ) 444 | 445 | if not tasks: 446 | console.print("[yellow]没有找到匹配的任务[/yellow]") 447 | return 448 | 449 | table = Table(title="任务列表") 450 | table.add_column("ID", style="cyan") 451 | table.add_column("标题", style="green") 452 | table.add_column("状态", style="yellow") 453 | table.add_column("优先级", style="red") 454 | table.add_column("类型", style="blue") 455 | table.add_column("负责人", style="magenta") 456 | table.add_column("截止日期", style="cyan") 457 | 458 | for task in tasks: 459 | table.add_row( 460 | task['id'], 461 | task['title'], 462 | task['status'], 463 | task['priority'], 464 | task['type'], 465 | task['assignee'] or '-', 466 | task['deadline'] or '-' 467 | ) 468 | 469 | console.print(table) 470 | 471 | @project.command(name='show') 472 | @click.argument('task_id') 473 | def project_show(task_id: str): 474 | """查看任务详情""" 475 | task = project_manager.get_task(task_id) 476 | if not task: 477 | console.print(f"[red]未找到任务:{task_id}[/red]") 478 | return 479 | 480 | _print_task_details(task) 481 | 482 | @project.command(name='update') 483 | @click.argument('task_id') 484 | @click.option('--title', '-t', help='任务标题') 485 | @click.option('--status', '-s', help='任务状态') 486 | @click.option('--priority', '-p', help='优先级') 487 | @click.option('--type', 'type_', help='任务类型') 488 | @click.option('--assignee', '-a', help='负责人') 489 | @click.option('--description', '-d', help='任务描述') 490 | @click.option('--deadline', help='截止日期 (YYYY-MM-DD)') 491 | @click.option('--tags', help='标签(逗号分隔)') 492 | def project_update(task_id: str, **kwargs): 493 | """更新任务""" 494 | if kwargs.get('tags'): 495 | kwargs['tags'] = [tag.strip() for tag in kwargs['tags'].split(',')] 496 | 497 | task = project_manager.update_task(task_id, **{k: v for k, v in kwargs.items() if v is not None}) 498 | if not task: 499 | console.print(f"[red]未找到任务:{task_id}[/red]") 500 | return 501 | 502 | console.print(f"[green]✨ 任务更新成功![/green]") 503 | _print_task_details(task) 504 | 505 | @project.command(name='subtask') 506 | @click.argument('task_id') 507 | @click.argument('title') 508 | @click.option('--status', '-s', help='任务状态') 509 | def project_subtask(task_id: str, title: str, status: str): 510 | """添加子任务""" 511 | kwargs = {} 512 | if status: 513 | kwargs['status'] = status 514 | 515 | subtask = project_manager.add_subtask(task_id, title, **kwargs) 516 | if not subtask: 517 | console.print(f"[red]未找到任务:{task_id}[/red]") 518 | return 519 | 520 | console.print(f"[green]✨ 子任务添加成功![/green]") 521 | console.print(f"ID: [blue]{subtask['id']}[/blue]") 522 | console.print(f"标题: [green]{subtask['title']}[/green]") 523 | console.print(f"状态: [yellow]{subtask['status']}[/yellow]") 524 | 525 | @project.command(name='note') 526 | @click.argument('task_id') 527 | @click.argument('content') 528 | def project_note(task_id: str, content: str): 529 | """添加任务笔记""" 530 | note = project_manager.add_note(task_id, content) 531 | if not note: 532 | console.print(f"[red]未找到任务:{task_id}[/red]") 533 | return 534 | 535 | console.print(f"[green]✨ 笔记添加成功![/green]") 536 | console.print(f"ID: [blue]{note['id']}[/blue]") 537 | console.print(f"内容: [green]{note['content']}[/green]") 538 | console.print(f"时间: [yellow]{note['created_at']}[/yellow]") 539 | 540 | @project.command(name='link') 541 | @click.argument('task_id') 542 | @click.argument('related_task_id') 543 | def project_link(task_id: str, related_task_id: str): 544 | """关联任务""" 545 | if project_manager.link_tasks(task_id, related_task_id): 546 | console.print(f"[green]✨ 任务关联成功![/green]") 547 | else: 548 | console.print(f"[red]任务关联失败,请检查任务ID是否正确[/red]") 549 | 550 | @project.command(name='stats') 551 | def project_stats(): 552 | """查看任务统计""" 553 | stats = project_manager.get_task_stats() 554 | 555 | console.print("\n📊 任务统计") 556 | console.print(f"总任务数:[blue]{stats['total_tasks']}[/blue]") 557 | console.print(f"完成率:[green]{stats['completion_rate']:.1f}%[/green]") 558 | console.print(f"平均完成时间:[yellow]{stats['average_completion_time']:.1f} 天[/yellow]") 559 | 560 | if stats['status_counts']: 561 | console.print("\n[cyan]== 状态分布 ==[/cyan]") 562 | for status, count in stats['status_counts'].items(): 563 | console.print(f"{status}: [blue]{count}[/blue]") 564 | 565 | if stats['priority_counts']: 566 | console.print("\n[cyan]== 优先级分布 ==[/cyan]") 567 | for priority, count in stats['priority_counts'].items(): 568 | console.print(f"{priority}: [blue]{count}[/blue]") 569 | 570 | if stats['type_counts']: 571 | console.print("\n[cyan]== 类型分布 ==[/cyan]") 572 | for type_, count in stats['type_counts'].items(): 573 | console.print(f"{type_}: [blue]{count}[/blue]") 574 | 575 | if stats['assignee_counts']: 576 | console.print("\n[cyan]== 负责人分布 ==[/cyan]") 577 | for assignee, count in stats['assignee_counts'].items(): 578 | console.print(f"{assignee}: [blue]{count}[/blue]") 579 | 580 | if stats['tag_counts']: 581 | console.print("\n[cyan]== 标签统计 ==[/cyan]") 582 | for tag, count in sorted(stats['tag_counts'].items(), key=lambda x: x[1], reverse=True)[:10]: 583 | console.print(f"{tag}: [blue]{count}[/blue]") 584 | 585 | def _print_task_details(task: Dict): 586 | """打印任务详情""" 587 | console.print(f"\n[cyan]== 任务详情 ==[/cyan]") 588 | console.print(f"ID: [blue]{task['id']}[/blue]") 589 | console.print(f"标题: [green]{task['title']}[/green]") 590 | console.print(f"状态: [yellow]{task['status']}[/yellow]") 591 | console.print(f"优先级: [red]{task['priority']}[/red]") 592 | console.print(f"类型: [magenta]{task['type']}[/magenta]") 593 | 594 | if task['description']: 595 | console.print("\n[cyan]描述:[/cyan]") 596 | console.print(Markdown(task['description'])) 597 | 598 | if task['assignee']: 599 | console.print(f"负责人: [blue]{task['assignee']}[/blue]") 600 | 601 | if task['deadline']: 602 | console.print(f"截止日期: [yellow]{task['deadline']}[/yellow]") 603 | 604 | if task['tags']: 605 | console.print(f"标签: [magenta]{', '.join(task['tags'])}[/magenta]") 606 | 607 | if task['subtasks']: 608 | console.print("\n[cyan]子任务:[/cyan]") 609 | for subtask in task['subtasks']: 610 | status_color = "green" if subtask['status'] == "已完成" else "yellow" 611 | console.print( 612 | f"- [{status_color}]{subtask['status']}[/{status_color}] " 613 | f"{subtask['title']} [blue]({subtask['id']})[/blue]" 614 | ) 615 | 616 | if task['notes']: 617 | console.print("\n[cyan]笔记:[/cyan]") 618 | for note in task['notes']: 619 | console.print(f"\n[blue]{note['created_at']}[/blue]") 620 | console.print(Markdown(note['content'])) 621 | 622 | if task['related_tasks']: 623 | console.print("\n[cyan]关联任务:[/cyan]") 624 | for related_id in task['related_tasks']: 625 | related_task = project_manager.get_task(related_id) 626 | if related_task: 627 | console.print( 628 | f"- [blue]{related_id}[/blue]: " 629 | f"[green]{related_task['title']}[/green] " 630 | f"([yellow]{related_task['status']}[/yellow])" 631 | ) 632 | 633 | @main.group(name='review') 634 | def review(): 635 | """代码审查 🔍""" 636 | pass 637 | 638 | @review.command(name='file') 639 | @click.argument('file_path', type=click.Path(exists=True)) 640 | def review_file(file_path): 641 | """审查单个文件。 642 | 643 | Args: 644 | file_path: 要审查的文件路径 645 | """ 646 | try: 647 | reviewer = CodeReview() 648 | with console.status("正在审查文件..."): 649 | report = reviewer.review_file(file_path) 650 | 651 | console.print("\n== 文件审查报告 ==") 652 | console.print(f"文件:{report['file']}") 653 | console.print(f"时间:{report['time']}") 654 | 655 | issues = report["issues"] 656 | 657 | # 统计问题 658 | total_issues = len(issues) 659 | issue_types = {} 660 | issue_severities = {} 661 | 662 | for issue in issues: 663 | issue_type = issue["type"] 664 | issue_severity = issue["severity"] 665 | 666 | issue_types[issue_type] = issue_types.get(issue_type, 0) + 1 667 | issue_severities[issue_severity] = issue_severities.get(issue_severity, 0) + 1 668 | 669 | # 打印统计信息 670 | console.print("\n统计信息:") 671 | console.print(f"总问题数:{total_issues}") 672 | 673 | if issue_types: 674 | console.print("\n问题类型分布:") 675 | for type_name, count in issue_types.items(): 676 | console.print(f"- {type_name}: {count}") 677 | 678 | if issue_severities: 679 | console.print("\n严重程度分布:") 680 | for severity, count in issue_severities.items(): 681 | console.print(f"- {severity}: {count}") 682 | 683 | # 打印具体问题 684 | if issues: 685 | console.print("\n具体问题:\n") 686 | for issue in issues: 687 | severity = issue["severity"].upper() 688 | line = issue["line"] 689 | type_name = issue["type"] 690 | rule = issue["rule"] 691 | message = issue["message"] 692 | 693 | console.print(f"{severity} 第 {line} 行") 694 | console.print(f"类型:{type_name}") 695 | console.print(f"规则:{rule}") 696 | console.print(f"说明:{message}\n") 697 | 698 | except Exception as e: 699 | console.print(f"[red]错误:{str(e)}[/red]") 700 | raise click.Abort() 701 | 702 | @review.command(name='dir') 703 | @click.argument('directory', type=click.Path(exists=True, file_okay=False, dir_okay=True)) 704 | def review_directory(directory): 705 | """审查目录中的所有Python文件。 706 | 707 | Args: 708 | directory: 要审查的目录路径 709 | """ 710 | try: 711 | reviewer = CodeReview() 712 | with console.status("正在审查目录..."): 713 | report = reviewer.review_directory(directory) 714 | 715 | console.print("\n== 目录审查报告 ==") 716 | console.print(f"目录:{report['directory']}") 717 | console.print(f"时间:{report['time']}") 718 | console.print(f"审查文件数:{report['files_reviewed']}") 719 | 720 | total_issues = report["total_issues"] 721 | issue_types = report["issue_types"] 722 | issue_severities = report["issue_severities"] 723 | issues = report["issues"] 724 | 725 | # 打印统计信息 726 | console.print(f"\n总问题数:{total_issues}") 727 | 728 | if issue_types: 729 | console.print("\n问题类型分布:") 730 | for type_name, count in issue_types.items(): 731 | console.print(f"- {type_name}: {count}") 732 | 733 | if issue_severities: 734 | console.print("\n严重程度分布:") 735 | for severity, count in issue_severities.items(): 736 | console.print(f"- {severity}: {count}") 737 | 738 | # 打印具体问题 739 | if issues: 740 | console.print("\n具体问题:\n") 741 | for issue in issues: 742 | severity = issue["severity"].upper() 743 | line = issue["line"] 744 | type_name = issue["type"] 745 | rule = issue["rule"] 746 | message = issue["message"] 747 | 748 | console.print(f"{severity} 第 {line} 行") 749 | console.print(f"类型:{type_name}") 750 | console.print(f"规则:{rule}") 751 | console.print(f"说明:{message}\n") 752 | 753 | except Exception as e: 754 | console.print(f"[red]错误:{str(e)}[/red]") 755 | raise click.Abort() 756 | 757 | @review.command(name='list') 758 | def review_list(): 759 | """列出审查报告""" 760 | reports = CodeReview.list_reports() 761 | 762 | if not reports: 763 | console.print("[yellow]还没有审查报告[/yellow]") 764 | return 765 | 766 | table = Table(title="审查报告列表") 767 | table.add_column("ID", style="cyan") 768 | table.add_column("时间", style="blue") 769 | table.add_column("目标", style="green") 770 | table.add_column("问题数", style="red", justify="right") 771 | 772 | for report in reports: 773 | table.add_row( 774 | report["id"], 775 | report["timestamp"], 776 | report["target"], 777 | str(report["total_issues"]) 778 | ) 779 | 780 | console.print(table) 781 | 782 | @review.command(name='show') 783 | @click.argument('report_id') 784 | def review_show(report_id: str): 785 | """查看审查报告""" 786 | report = CodeReview.get_report(report_id) 787 | 788 | if not report: 789 | console.print(f"[red]未找到报告:{report_id}[/red]") 790 | return 791 | 792 | _print_review_report(report) 793 | 794 | def _print_review_report(report: Dict): 795 | """打印审查报告""" 796 | if "file" in report: 797 | console.print(f"\n[cyan]== 文件审查报告 ==[/cyan]") 798 | console.print(f"文件:[blue]{report['file']}[/blue]") 799 | else: 800 | console.print(f"\n[cyan]== 目录审查报告 ==[/cyan]") 801 | console.print(f"目录:[blue]{report['directory']}[/blue]") 802 | console.print(f"文件数:[green]{report['summary']['total_files']}[/green]") 803 | 804 | console.print(f"时间:[yellow]{report['timestamp']}[/yellow]") 805 | 806 | # 打印统计信息 807 | console.print("\n[cyan]统计信息:[/cyan]") 808 | console.print(f"总问题数:[red]{report['summary']['total']}[/red]") 809 | 810 | if report["summary"]["by_type"]: 811 | console.print("\n[yellow]问题类型分布:[/yellow]") 812 | for type_, count in report["summary"]["by_type"].items(): 813 | console.print(f"- {type_}: [blue]{count}[/blue]") 814 | 815 | if report["summary"]["by_severity"]: 816 | console.print("\n[yellow]严重程度分布:[/yellow]") 817 | for severity, count in report["summary"]["by_severity"].items(): 818 | color = { 819 | "error": "red", 820 | "warning": "yellow", 821 | "info": "blue" 822 | }.get(severity, "white") 823 | console.print(f"- {severity}: [{color}]{count}[/{color}]") 824 | 825 | # 打印具体问题 826 | if report["issues"]: 827 | console.print("\n[cyan]具体问题:[/cyan]") 828 | for issue in sorted(report["issues"], key=lambda x: (x["severity"], x["line"])): 829 | severity_color = { 830 | "error": "red", 831 | "warning": "yellow", 832 | "info": "blue" 833 | }.get(issue["severity"], "white") 834 | 835 | console.print( 836 | f"\n[{severity_color}]{issue['severity'].upper()}[/{severity_color}] " 837 | f"第 {issue['line']} 行" 838 | ) 839 | console.print(f"类型:[blue]{issue['type']}[/blue]") 840 | console.print(f"规则:[yellow]{issue['rule']}[/yellow]") 841 | console.print(f"说明:{issue['message']}") 842 | 843 | # 如果是目录报告,打印每个文件的问题数 844 | if "files" in report: 845 | console.print("\n[cyan]文件问题分布:[/cyan]") 846 | files_table = Table() 847 | files_table.add_column("文件", style="blue") 848 | files_table.add_column("问题数", style="red", justify="right") 849 | 850 | for file_report in sorted(report["files"], key=lambda x: len(x["issues"]), reverse=True): 851 | if file_report["issues"]: 852 | files_table.add_row( 853 | file_report["file"], 854 | str(len(file_report["issues"])) 855 | ) 856 | 857 | console.print(files_table) 858 | 859 | if __name__ == '__main__': 860 | main() -------------------------------------------------------------------------------- /src/cursormind/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagami1997/CursorMind/c85ceaa15e0371c4ec4ca426fdd9f2609287efe7/src/cursormind/config/__init__.py -------------------------------------------------------------------------------- /src/cursormind/config/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | 配置管理模块 - 保存你的个人设置 ⚙️ 3 | """ 4 | import os 5 | import json 6 | from datetime import datetime 7 | import pytz 8 | from pathlib import Path 9 | from typing import Dict, Any, Optional 10 | 11 | class Settings: 12 | """配置管理类""" 13 | 14 | def __init__(self): 15 | self._config: Dict[str, Any] = {} 16 | self._config_dir = Path.home() / '.cursormind' 17 | self._config_file = self._config_dir / 'config.json' 18 | self._first_time = not self._config_file.exists() 19 | self.load() 20 | 21 | def load(self) -> None: 22 | """ 23 | 加载配置文件 24 | 如果是第一次使用,会创建默认配置并显示欢迎信息 25 | """ 26 | if self._first_time: 27 | self._create_default_config() 28 | self._show_welcome() 29 | else: 30 | with open(self._config_file, 'r', encoding='utf-8') as f: 31 | self._config = json.load(f) 32 | 33 | def save(self) -> None: 34 | """保存配置到文件""" 35 | self._config_file.parent.mkdir(parents=True, exist_ok=True) 36 | with open(self._config_file, 'w', encoding='utf-8') as f: 37 | json.dump(self._config, f, ensure_ascii=False, indent=2) 38 | 39 | def get(self, key: str, default: Any = None) -> Any: 40 | """获取配置项""" 41 | return self._config.get(key, default) 42 | 43 | def set(self, key: str, value: Any) -> None: 44 | """设置配置项""" 45 | self._config[key] = value 46 | self.save() 47 | 48 | def _get_timestamp(self) -> str: 49 | """获取当前时间戳""" 50 | tz = pytz.timezone(self.get('timezone', 'America/Los_Angeles')) 51 | now = datetime.now(tz) 52 | return now.strftime("%Y-%m-%d %H:%M:%S %Z") 53 | 54 | def _create_default_config(self) -> None: 55 | """创建默认配置""" 56 | # 获取当前工作目录作为项目根目录 57 | project_root = str(Path.cwd()) 58 | 59 | default_config = { 60 | # 基本信息 61 | 'user_name': '', # 用户名 62 | 'current_project': '', # 当前项目 63 | 'learning_goal': '', # 学习目标 64 | 65 | # 个性化设置 66 | 'timezone': 'America/Los_Angeles', # 时区 67 | 'language': 'zh', # 语言 68 | 'theme': 'light', # 主题 69 | 'emoji_enabled': True, # 是否启用表情 70 | 71 | # 项目设置 72 | 'project_root': project_root, # 项目根目录 73 | 'learning_paths_dir': 'learning_paths', # 学习路径目录 74 | 'notes_dir': 'learning_notes', # 笔记目录 75 | 'backups_dir': 'backups', # 备份目录 76 | 77 | # 学习记录 78 | 'start_date': self._get_timestamp(), # 开始使用日期 79 | 'study_days': 0, # 学习天数 80 | 'total_notes': 0, # 笔记总数 81 | 'achievements': [], # 已获得的成就 82 | 83 | # 提醒设置 84 | 'daily_reminder': True, # 每日提醒 85 | 'reminder_time': '20:00', # 提醒时间 86 | 87 | # 版本信息 88 | 'version': 'Beta 0.1.1' # 当前版本 89 | } 90 | self._config = default_config 91 | self.save() 92 | 93 | def _show_welcome(self) -> None: 94 | """显示首次使用的欢迎信息""" 95 | welcome_message = """ 96 | 🎉 欢迎使用 CursorMind! 97 | 98 | 这是你第一次使用这个学习助手,我已经为你创建了默认配置文件: 99 | ~/.cursormind/config.json 100 | 101 | 你可以随时修改这些设置,让它更适合你的使用习惯。 102 | 现在,让我们开始你的学习之旅吧! 103 | 104 | 💡 快速开始: 105 | 1. cursormind path # 查看学习路径 106 | 2. cursormind start # 开始今天的学习 107 | 3. cursormind note "内容" # 记录学习笔记 108 | 4. cursormind help # 查看更多帮助 109 | 110 | 记住:每一个小进步都很重要,坚持记录,你会看到自己的成长! 💪 111 | """ 112 | print(welcome_message) 113 | 114 | # 创建全局配置实例 115 | settings = Settings() -------------------------------------------------------------------------------- /src/cursormind/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagami1997/CursorMind/c85ceaa15e0371c4ec4ca426fdd9f2609287efe7/src/cursormind/core/__init__.py -------------------------------------------------------------------------------- /src/cursormind/core/achievement.py: -------------------------------------------------------------------------------- 1 | """ 2 | 成就系统模块 - 跟踪和奖励学习进度 3 | """ 4 | import json 5 | import os 6 | from datetime import datetime, timedelta 7 | from typing import Dict, List, Optional 8 | from ..utils.helpers import get_timestamp, ensure_dir 9 | 10 | class AchievementManager: 11 | """成就系统管理器""" 12 | 13 | def __init__(self): 14 | """初始化成就系统""" 15 | self.base_dir = os.path.expanduser('~/.cursormind') 16 | self.achievements_dir = os.path.join(self.base_dir, 'achievements') 17 | self.achievements_file = os.path.join(self.achievements_dir, 'achievements.json') 18 | self.stats_file = os.path.join(self.achievements_dir, 'stats.json') 19 | 20 | # 确保目录存在 21 | ensure_dir(self.achievements_dir) 22 | 23 | # 初始化成就数据 24 | self._ensure_achievements_file() 25 | self._ensure_stats_file() 26 | 27 | # 加载成就定义和用户统计 28 | self.achievements = self._load_achievements() 29 | self.stats = self._load_stats() 30 | 31 | def _ensure_achievements_file(self): 32 | """确保成就定义文件存在,不存在则创建默认成就""" 33 | if not os.path.exists(self.achievements_file): 34 | default_achievements = { 35 | "learning_path": { 36 | "first_path": { 37 | "name": "学习启航", 38 | "description": "开始第一个学习路径", 39 | "icon": "🚀", 40 | "condition": {"type": "path_started", "count": 1}, 41 | "reward": 100 42 | }, 43 | "path_master": { 44 | "name": "学习大师", 45 | "description": "完成一个完整的学习路径", 46 | "icon": "🎓", 47 | "condition": {"type": "path_completed", "count": 1}, 48 | "reward": 500 49 | } 50 | }, 51 | "notes": { 52 | "first_note": { 53 | "name": "记录者", 54 | "description": "写下第一篇学习笔记", 55 | "icon": "📝", 56 | "condition": {"type": "note_created", "count": 1}, 57 | "reward": 50 58 | }, 59 | "note_streak": { 60 | "name": "坚持不懈", 61 | "description": "连续7天记录学习笔记", 62 | "icon": "🔥", 63 | "condition": {"type": "daily_streak", "count": 7}, 64 | "reward": 300 65 | }, 66 | "note_master": { 67 | "name": "笔记达人", 68 | "description": "累计记录100篇笔记", 69 | "icon": "✍️", 70 | "condition": {"type": "note_created", "count": 100}, 71 | "reward": 1000 72 | } 73 | }, 74 | "tags": { 75 | "tag_organizer": { 76 | "name": "标签达人", 77 | "description": "使用20个不同的标签", 78 | "icon": "🏷️", 79 | "condition": {"type": "unique_tags", "count": 20}, 80 | "reward": 200 81 | } 82 | }, 83 | "topics": { 84 | "topic_explorer": { 85 | "name": "主题探索者", 86 | "description": "在5个不同主题下记录笔记", 87 | "icon": "🗺️", 88 | "condition": {"type": "unique_topics", "count": 5}, 89 | "reward": 300 90 | } 91 | }, 92 | "review": { 93 | "weekly_reviewer": { 94 | "name": "复习达人", 95 | "description": "生成4次周回顾报告", 96 | "icon": "📊", 97 | "condition": {"type": "review_generated", "count": 4}, 98 | "reward": 200 99 | } 100 | } 101 | } 102 | 103 | with open(self.achievements_file, 'w', encoding='utf-8') as f: 104 | json.dump(default_achievements, f, ensure_ascii=False, indent=2) 105 | 106 | def _ensure_stats_file(self): 107 | """确保用户统计文件存在""" 108 | if not os.path.exists(self.stats_file): 109 | default_stats = { 110 | "points": 0, 111 | "unlocked_achievements": [], 112 | "stats": { 113 | "paths_started": 0, 114 | "paths_completed": 0, 115 | "notes_created": 0, 116 | "daily_streak": 0, 117 | "unique_tags": set(), 118 | "unique_topics": set(), 119 | "reviews_generated": 0 120 | }, 121 | "last_updated": get_timestamp() 122 | } 123 | 124 | with open(self.stats_file, 'w', encoding='utf-8') as f: 125 | json.dump(default_stats, f, ensure_ascii=False, indent=2, 126 | default=lambda x: list(x) if isinstance(x, set) else x) 127 | 128 | def _load_achievements(self) -> Dict: 129 | """加载成就定义""" 130 | with open(self.achievements_file, 'r', encoding='utf-8') as f: 131 | return json.load(f) 132 | 133 | def _load_stats(self) -> Dict: 134 | """加载用户统计数据""" 135 | with open(self.stats_file, 'r', encoding='utf-8') as f: 136 | stats = json.load(f) 137 | # 将列表转换回集合 138 | stats['stats']['unique_tags'] = set(stats['stats']['unique_tags']) 139 | stats['stats']['unique_topics'] = set(stats['stats']['unique_topics']) 140 | return stats 141 | 142 | def _save_stats(self): 143 | """保存用户统计数据""" 144 | with open(self.stats_file, 'w', encoding='utf-8') as f: 145 | json.dump(self.stats, f, ensure_ascii=False, indent=2, 146 | default=lambda x: list(x) if isinstance(x, set) else x) 147 | 148 | def _check_achievements(self) -> List[Dict]: 149 | """检查是否有新的成就达成""" 150 | new_achievements = [] 151 | stats = self.stats['stats'] 152 | 153 | for category, achievements in self.achievements.items(): 154 | for achievement_id, achievement in achievements.items(): 155 | # 跳过已解锁的成就 156 | if achievement_id in self.stats['unlocked_achievements']: 157 | continue 158 | 159 | condition = achievement['condition'] 160 | achieved = False 161 | 162 | # 检查不同类型的成就条件 163 | if condition['type'] == 'path_started': 164 | achieved = stats['paths_started'] >= condition['count'] 165 | elif condition['type'] == 'path_completed': 166 | achieved = stats['paths_completed'] >= condition['count'] 167 | elif condition['type'] == 'note_created': 168 | achieved = stats['notes_created'] >= condition['count'] 169 | elif condition['type'] == 'daily_streak': 170 | achieved = stats['daily_streak'] >= condition['count'] 171 | elif condition['type'] == 'unique_tags': 172 | achieved = len(stats['unique_tags']) >= condition['count'] 173 | elif condition['type'] == 'unique_topics': 174 | achieved = len(stats['unique_topics']) >= condition['count'] 175 | elif condition['type'] == 'review_generated': 176 | achieved = stats['reviews_generated'] >= condition['count'] 177 | 178 | if achieved: 179 | self.stats['unlocked_achievements'].append(achievement_id) 180 | self.stats['points'] += achievement['reward'] 181 | new_achievements.append({ 182 | 'id': achievement_id, 183 | 'name': achievement['name'], 184 | 'description': achievement['description'], 185 | 'icon': achievement['icon'], 186 | 'reward': achievement['reward'] 187 | }) 188 | 189 | if new_achievements: 190 | self._save_stats() 191 | 192 | return new_achievements 193 | 194 | def update_stats(self, event_type: str, data: Optional[Dict] = None) -> List[Dict]: 195 | """ 196 | 更新用户统计并检查成就 197 | 198 | Args: 199 | event_type: 事件类型,如 'path_started', 'note_created' 等 200 | data: 事件相关的数据 201 | 202 | Returns: 203 | 新解锁的成就列表 204 | """ 205 | stats = self.stats['stats'] 206 | 207 | if event_type == 'path_started': 208 | stats['paths_started'] += 1 209 | elif event_type == 'path_completed': 210 | stats['paths_completed'] += 1 211 | elif event_type == 'note_created': 212 | stats['notes_created'] += 1 213 | if data: 214 | if 'tags' in data: 215 | stats['unique_tags'].update(data['tags']) 216 | if 'topic' in data: 217 | stats['unique_topics'].add(data['topic']) 218 | elif event_type == 'review_generated': 219 | stats['reviews_generated'] += 1 220 | 221 | self.stats['last_updated'] = get_timestamp() 222 | self._save_stats() 223 | 224 | return self._check_achievements() 225 | 226 | def get_stats(self) -> Dict: 227 | """获取用户统计信息""" 228 | stats = self.stats.copy() 229 | # 转换集合为列表以便序列化 230 | stats['stats']['unique_tags'] = list(stats['stats']['unique_tags']) 231 | stats['stats']['unique_topics'] = list(stats['stats']['unique_topics']) 232 | return stats 233 | 234 | def get_achievements(self, include_locked: bool = False) -> Dict: 235 | """ 236 | 获取成就列表 237 | 238 | Args: 239 | include_locked: 是否包含未解锁的成就 240 | 241 | Returns: 242 | 成就列表,包含解锁状态 243 | """ 244 | result = {} 245 | for category, achievements in self.achievements.items(): 246 | result[category] = {} 247 | for achievement_id, achievement in achievements.items(): 248 | if achievement_id in self.stats['unlocked_achievements'] or include_locked: 249 | achievement_data = achievement.copy() 250 | achievement_data['unlocked'] = achievement_id in self.stats['unlocked_achievements'] 251 | result[category][achievement_id] = achievement_data 252 | return result 253 | 254 | # 创建全局实例 255 | achievement_manager = AchievementManager() -------------------------------------------------------------------------------- /src/cursormind/core/code_review.py: -------------------------------------------------------------------------------- 1 | """ 2 | 代码审查模块,提供代码风格、性能和安全性检查功能。 3 | """ 4 | import os 5 | import ast 6 | import json 7 | from typing import Dict, List, Optional, Tuple, Any 8 | from pathlib import Path 9 | import subprocess 10 | from datetime import datetime 11 | 12 | class CodeReview: 13 | """代码审查类,用于检查代码质量和安全性。 14 | 15 | 提供以下功能: 16 | 1. 代码风格检查:行长度、缩进、文档字符串等 17 | 2. 性能检查:函数复杂度、变量数量等 18 | 3. 安全性检查:SQL注入、命令注入等 19 | """ 20 | 21 | def __init__(self): 22 | """初始化代码审查类,设置配置目录和加载配置。""" 23 | self.config_dir = ( 24 | Path.home() / 25 | ".cursormind" / 26 | "code_review" 27 | ) 28 | self.config_dir.mkdir(parents=True, exist_ok=True) 29 | self.reports_dir = self.config_dir / "reports" 30 | self.reports_dir.mkdir(exist_ok=True) 31 | self.config_file = self.config_dir / "config.json" 32 | self.config = self._load_config() 33 | 34 | def _load_config(self) -> Dict[str, Any]: 35 | """加载配置文件,如果不存在则创建默认配置。 36 | 37 | Returns: 38 | Dict[str, Any]: 配置字典 39 | """ 40 | default_config = { 41 | "style": { 42 | "max_line_length": 88, 43 | "indent_size": 4, 44 | "quote_type": "double", 45 | "docstring_style": "google", 46 | "import_order": ["stdlib", "third_party", "local"] 47 | }, 48 | "performance": { 49 | "max_complexity": 10, 50 | "max_locals": 15, 51 | "max_returns": 5, 52 | "max_statements": 50 53 | }, 54 | "security": { 55 | "sql_risk_functions": [ 56 | "execute", "executemany", "raw_query" 57 | ], 58 | "shell_risk_functions": [ 59 | "system", "popen", "exec", "eval" 60 | ], 61 | "file_risk_functions": [ 62 | "open", "read", "write" 63 | ] 64 | } 65 | } 66 | 67 | if not self.config_file.exists(): 68 | self._save_config(default_config) 69 | return default_config 70 | 71 | try: 72 | with open(self.config_file, "r", encoding="utf-8") as f: 73 | config = json.load(f) 74 | # 验证配置文件结构 75 | if not all( 76 | key in config 77 | for key in ["style", "performance", "security"] 78 | ): 79 | raise ValueError("配置文件缺少必要的键") 80 | return config 81 | except Exception as e: 82 | print(f"加载配置文件时出错:{str(e)},使用默认配置") 83 | self._save_config(default_config) 84 | return default_config 85 | 86 | def _save_config(self, config: Dict[str, Any]) -> None: 87 | """保存配置到文件。 88 | 89 | Args: 90 | config: 要保存的配置字典 91 | """ 92 | try: 93 | with open(self.config_file, "w", encoding="utf-8") as f: 94 | json.dump(config, f, ensure_ascii=False, indent=2) 95 | except Exception as e: 96 | print(f"保存配置文件时出错:{str(e)}") 97 | 98 | def _safe_open(self, file_path: str, mode: str = "r") -> Optional[Path]: 99 | """安全地打开文件。 100 | 101 | Args: 102 | file_path: 要打开的文件路径 103 | mode: 打开模式 104 | 105 | Returns: 106 | Optional[Path]: 文件路径对象,如果不安全则返回 None 107 | """ 108 | try: 109 | path = Path(file_path).resolve() 110 | is_safe = True 111 | 112 | # 基本检查 113 | is_safe = is_safe and path.exists() and path.is_file() 114 | 115 | # 权限检查 116 | if mode == "w": 117 | is_safe = ( 118 | is_safe and 119 | os.access(path.parent, os.W_OK) and 120 | str(path).startswith(str(self.config_dir)) 121 | ) 122 | elif mode == "r": 123 | is_safe = is_safe and os.access(path, os.R_OK) 124 | 125 | # 符号链接检查 126 | is_safe = is_safe and not path.is_symlink() 127 | 128 | # 文件大小检查 129 | is_safe = is_safe and path.stat().st_size <= 10 * 1024 * 1024 # 10MB 130 | 131 | return path if is_safe else None 132 | 133 | except (TypeError, ValueError, OSError): 134 | return None 135 | 136 | def _check_line_length(self, lines: List[str]) -> List[Dict[str, Any]]: 137 | """检查行长度。 138 | 139 | Args: 140 | lines: 代码行列表 141 | 142 | Returns: 143 | 包含行长度问题的列表 144 | """ 145 | issues = [] 146 | max_length = self.config["style"]["max_line_length"] 147 | 148 | for i, line in enumerate(lines, 1): 149 | if len(line.rstrip()) > max_length: 150 | issues.append({ 151 | "type": "style", 152 | "rule": "line_length", 153 | "message": ( 154 | f"行长度超过 {max_length} " 155 | "个字符" 156 | ), 157 | "line": i, 158 | "severity": "warning" 159 | }) 160 | 161 | return issues 162 | 163 | def _check_indentation(self, tree: ast.AST) -> List[Dict[str, Any]]: 164 | """检查缩进。 165 | 166 | Args: 167 | tree: AST树 168 | 169 | Returns: 170 | 包含缩进问题的列表 171 | """ 172 | issues = [] 173 | indent_size = self.config["style"]["indent_size"] 174 | 175 | for node in ast.walk(tree): 176 | if isinstance( 177 | node, 178 | (ast.FunctionDef, ast.ClassDef, ast.If, ast.For, ast.While) 179 | ): 180 | if (hasattr(node, "col_offset") and 181 | node.col_offset % indent_size != 0): 182 | issues.append({ 183 | "type": "style", 184 | "rule": "indentation", 185 | "message": ( 186 | f"缩进应该是 {indent_size} " 187 | "的倍数" 188 | ), 189 | "line": node.lineno, 190 | "severity": "warning" 191 | }) 192 | 193 | return issues 194 | 195 | def _check_docstring(self, tree: ast.AST) -> List[Dict[str, Any]]: 196 | """检查文档字符串。 197 | 198 | Args: 199 | tree: AST树 200 | 201 | Returns: 202 | 包含文档字符串问题的列表 203 | """ 204 | issues = [] 205 | 206 | for node in ast.walk(tree): 207 | if isinstance(node, (ast.FunctionDef, ast.ClassDef, ast.Module)): 208 | if not ast.get_docstring(node): 209 | issues.append({ 210 | "type": "style", 211 | "rule": "docstring", 212 | "message": "缺少文档字符串", 213 | "line": node.lineno, 214 | "severity": "info" 215 | }) 216 | 217 | return issues 218 | 219 | def _check_quotes(self, lines: List[str]) -> List[Dict[str, Any]]: 220 | """检查引号使用。 221 | 222 | Args: 223 | lines: 代码行列表 224 | 225 | Returns: 226 | 包含引号使用问题的列表 227 | """ 228 | issues = [] 229 | quote_type = self.config["style"]["quote_type"] 230 | 231 | for i, line in enumerate(lines, 1): 232 | if quote_type == "double" and "'" in line and '"' not in line: 233 | issues.append({ 234 | "type": "style", 235 | "rule": "quotes", 236 | "message": "建议使用双引号", 237 | "line": i, 238 | "severity": "info" 239 | }) 240 | elif quote_type == "single" and '"' in line and "'" not in line: 241 | issues.append({ 242 | "type": "style", 243 | "rule": "quotes", 244 | "message": "建议使用单引号", 245 | "line": i, 246 | "severity": "info" 247 | }) 248 | 249 | return issues 250 | 251 | def check_style(self, content: str) -> List[Dict[str, Any]]: 252 | """检查代码风格。 253 | 254 | Args: 255 | content: 要检查的代码内容 256 | 257 | Returns: 258 | 包含风格问题的列表 259 | """ 260 | issues = [] 261 | 262 | try: 263 | tree = ast.parse(content) 264 | lines = content.split("\n") 265 | 266 | # 检查行长度 267 | issues.extend(self._check_line_length(lines)) 268 | 269 | # 检查缩进 270 | issues.extend(self._check_indentation(tree)) 271 | 272 | # 检查文档字符串 273 | issues.extend(self._check_docstring(tree)) 274 | 275 | # 检查引号使用 276 | issues.extend(self._check_quotes(lines)) 277 | 278 | except SyntaxError as e: 279 | issues.append({ 280 | "type": "error", 281 | "rule": "parsing", 282 | "message": f"解析代码时出错:{str(e)}", 283 | "line": e.lineno or 1, 284 | "severity": "error" 285 | }) 286 | except Exception as e: 287 | issues.append({ 288 | "type": "error", 289 | "rule": "parsing", 290 | "message": f"解析代码时出错:{str(e)}", 291 | "line": 1, 292 | "severity": "error" 293 | }) 294 | 295 | return issues 296 | 297 | def _check_complexity(self, node: ast.FunctionDef) -> Optional[Dict[str, Any]]: 298 | """检查函数复杂度。 299 | 300 | Args: 301 | node: 函数节点 302 | 303 | Returns: 304 | 如果存在问题则返回问题字典,否则返回 None 305 | """ 306 | complexity = 1 307 | for child in ast.walk(node): 308 | if isinstance(child, (ast.If, ast.For, ast.While, ast.Try)): 309 | complexity += 1 310 | 311 | if complexity > self.config["performance"]["max_complexity"]: 312 | return { 313 | "type": "performance", 314 | "rule": "complexity", 315 | "message": ( 316 | f"函数复杂度为 {complexity},超过最大值 " 317 | f"{self.config['performance']['max_complexity']}" 318 | ), 319 | "line": node.lineno, 320 | "severity": "warning" 321 | } 322 | 323 | return None 324 | 325 | def _check_locals(self, node: ast.FunctionDef) -> Optional[Dict[str, Any]]: 326 | """检查局部变量数量。 327 | 328 | Args: 329 | node: 函数节点 330 | 331 | Returns: 332 | 如果存在问题则返回问题字典,否则返回 None 333 | """ 334 | locals_count = len([ 335 | n for n in ast.walk(node) 336 | if isinstance(n, ast.Name) and isinstance(n.ctx, ast.Store) 337 | ]) 338 | 339 | if locals_count > self.config["performance"]["max_locals"]: 340 | return { 341 | "type": "performance", 342 | "rule": "locals", 343 | "message": ( 344 | f"局部变量数量为 {locals_count},超过最大值 " 345 | f"{self.config['performance']['max_locals']}" 346 | ), 347 | "line": node.lineno, 348 | "severity": "warning" 349 | } 350 | 351 | return None 352 | 353 | def _check_returns(self, node: ast.FunctionDef) -> Optional[Dict[str, Any]]: 354 | """检查return语句数量。 355 | 356 | Args: 357 | node: 函数节点 358 | 359 | Returns: 360 | 如果存在问题则返回问题字典,否则返回 None 361 | """ 362 | returns = len([ 363 | n for n in ast.walk(node) 364 | if isinstance(n, ast.Return) 365 | ]) 366 | 367 | if returns > self.config["performance"]["max_returns"]: 368 | return { 369 | "type": "performance", 370 | "rule": "returns", 371 | "message": ( 372 | f"return语句数量为 {returns},超过最大值 " 373 | f"{self.config['performance']['max_returns']}" 374 | ), 375 | "line": node.lineno, 376 | "severity": "warning" 377 | } 378 | 379 | return None 380 | 381 | def _check_statements(self, node: ast.FunctionDef) -> Optional[Dict[str, Any]]: 382 | """检查语句数量。 383 | 384 | Args: 385 | node: 函数节点 386 | 387 | Returns: 388 | 如果存在问题则返回问题字典,否则返回 None 389 | """ 390 | statements = len([ 391 | n for n in ast.walk(node) 392 | if isinstance(n, ast.stmt) 393 | ]) 394 | 395 | if statements > self.config["performance"]["max_statements"]: 396 | return { 397 | "type": "performance", 398 | "rule": "statements", 399 | "message": ( 400 | f"语句数量为 {statements},超过最大值 " 401 | f"{self.config['performance']['max_statements']}" 402 | ), 403 | "line": node.lineno, 404 | "severity": "warning" 405 | } 406 | 407 | return None 408 | 409 | def check_performance(self, content: str) -> List[Dict[str, Any]]: 410 | """检查代码性能相关问题。 411 | 412 | Args: 413 | content: 要检查的代码内容 414 | 415 | Returns: 416 | 包含性能问题的列表 417 | """ 418 | issues = [] 419 | 420 | try: 421 | tree = ast.parse(content) 422 | 423 | for node in ast.walk(tree): 424 | if isinstance(node, ast.FunctionDef): 425 | # 检查函数复杂度 426 | if issue := self._check_complexity(node): 427 | issues.append(issue) 428 | 429 | # 检查局部变量数量 430 | if issue := self._check_locals(node): 431 | issues.append(issue) 432 | 433 | # 检查return语句数量 434 | if issue := self._check_returns(node): 435 | issues.append(issue) 436 | 437 | # 检查语句数量 438 | if issue := self._check_statements(node): 439 | issues.append(issue) 440 | 441 | except SyntaxError as e: 442 | issues.append({ 443 | "type": "error", 444 | "rule": "parsing", 445 | "message": f"解析代码时出错:{str(e)}", 446 | "line": e.lineno or 1, 447 | "severity": "error" 448 | }) 449 | except Exception as e: 450 | issues.append({ 451 | "type": "error", 452 | "rule": "parsing", 453 | "message": f"解析代码时出错:{str(e)}", 454 | "line": 1, 455 | "severity": "error" 456 | }) 457 | 458 | return issues 459 | 460 | def _check_sql_injection(self, node: ast.Call) -> Optional[Dict[str, Any]]: 461 | """检查SQL注入风险。 462 | 463 | Args: 464 | node: 函数调用节点 465 | 466 | Returns: 467 | 如果存在问题则返回问题字典,否则返回 None 468 | """ 469 | if (isinstance(node.func, ast.Name) and 470 | node.func.id in self.config["security"]["sql_risk_functions"]): 471 | return { 472 | "type": "security", 473 | "rule": "sql_injection", 474 | "message": "可能存在SQL注入风险", 475 | "line": node.lineno, 476 | "severity": "error" 477 | } 478 | 479 | return None 480 | 481 | def _check_command_injection(self, node: ast.Call) -> Optional[Dict[str, Any]]: 482 | """检查命令注入风险。 483 | 484 | Args: 485 | node: 函数调用节点 486 | 487 | Returns: 488 | 如果存在问题则返回问题字典,否则返回 None 489 | """ 490 | if (isinstance(node.func, ast.Name) and 491 | node.func.id in self.config["security"]["shell_risk_functions"]): 492 | return { 493 | "type": "security", 494 | "rule": "command_injection", 495 | "message": "可能存在命令注入风险", 496 | "line": node.lineno, 497 | "severity": "error" 498 | } 499 | 500 | return None 501 | 502 | def _check_file_access(self, node: ast.Call) -> Optional[Dict[str, Any]]: 503 | """检查文件访问风险。 504 | 505 | Args: 506 | node: 函数调用节点 507 | 508 | Returns: 509 | 如果存在问题则返回问题字典,否则返回 None 510 | """ 511 | if (isinstance(node.func, ast.Name) and 512 | node.func.id in self.config["security"]["file_risk_functions"]): 513 | return { 514 | "type": "security", 515 | "rule": "file_access", 516 | "message": "可能存在不安全的文件访问", 517 | "line": node.lineno, 518 | "severity": "warning" 519 | } 520 | 521 | return None 522 | 523 | def check_security(self, content: str) -> List[Dict[str, Any]]: 524 | """检查代码安全性问题。 525 | 526 | Args: 527 | content: 要检查的代码内容 528 | 529 | Returns: 530 | 包含安全问题的列表 531 | """ 532 | issues = [] 533 | 534 | try: 535 | tree = ast.parse(content) 536 | 537 | for node in ast.walk(tree): 538 | if isinstance(node, ast.Call): 539 | # 检查SQL注入风险 540 | if issue := self._check_sql_injection(node): 541 | issues.append(issue) 542 | 543 | # 检查命令注入风险 544 | if issue := self._check_command_injection(node): 545 | issues.append(issue) 546 | 547 | # 检查文件访问风险 548 | if issue := self._check_file_access(node): 549 | issues.append(issue) 550 | 551 | except SyntaxError as e: 552 | issues.append({ 553 | "type": "error", 554 | "rule": "parsing", 555 | "message": f"解析代码时出错:{str(e)}", 556 | "line": e.lineno or 1, 557 | "severity": "error" 558 | }) 559 | except Exception as e: 560 | issues.append({ 561 | "type": "error", 562 | "rule": "parsing", 563 | "message": f"解析代码时出错:{str(e)}", 564 | "line": 1, 565 | "severity": "error" 566 | }) 567 | 568 | return issues 569 | 570 | def review_file(self, file_path: str) -> Dict[str, Any]: 571 | """审查单个文件。 572 | 573 | Args: 574 | file_path: 要审查的文件路径 575 | 576 | Returns: 577 | 包含审查结果的字典 578 | """ 579 | result = { 580 | "file": file_path, 581 | "time": datetime.now().isoformat(), 582 | "issues": [] 583 | } 584 | 585 | # 检查文件访问权限 586 | path = self._safe_open(file_path) 587 | if not path: 588 | result["issues"].append({ 589 | "type": "error", 590 | "rule": "file_access", 591 | "message": "无法访问文件", 592 | "line": 1, 593 | "severity": "error" 594 | }) 595 | return result 596 | 597 | try: 598 | with open(path, "r", encoding="utf-8") as f: 599 | content = f.read() 600 | 601 | # 检查文件是否为空 602 | if not content.strip(): 603 | result["issues"].append({ 604 | "type": "error", 605 | "rule": "empty_file", 606 | "message": "文件为空", 607 | "line": 1, 608 | "severity": "error" 609 | }) 610 | return result 611 | 612 | # 检查文件编码 613 | try: 614 | content.encode("utf-8").decode("utf-8") 615 | except UnicodeError: 616 | result["issues"].append({ 617 | "type": "error", 618 | "rule": "encoding", 619 | "message": "文件编码不是UTF-8", 620 | "line": 1, 621 | "severity": "error" 622 | }) 623 | return result 624 | 625 | # 检查语法错误 626 | try: 627 | ast.parse(content) 628 | except SyntaxError as e: 629 | result["issues"].append({ 630 | "type": "error", 631 | "rule": "syntax", 632 | "message": f"语法错误:{str(e)}", 633 | "line": e.lineno or 1, 634 | "severity": "error" 635 | }) 636 | return result 637 | 638 | # 进行代码审查 639 | result["issues"].extend(self.check_style(content)) 640 | result["issues"].extend(self.check_performance(content)) 641 | result["issues"].extend(self.check_security(content)) 642 | 643 | except Exception as e: 644 | result["issues"].append({ 645 | "type": "error", 646 | "rule": "file_read", 647 | "message": f"读取文件时出错:{str(e)}", 648 | "line": 1, 649 | "severity": "error" 650 | }) 651 | 652 | return result 653 | 654 | def review_directory(self, directory: str) -> Dict[str, Any]: 655 | """审查目录中的所有Python文件。 656 | 657 | Args: 658 | directory: 要审查的目录路径 659 | 660 | Returns: 661 | 包含审查结果的字典 662 | """ 663 | try: 664 | path = Path(directory).resolve() 665 | if not path.exists() or not path.is_dir(): 666 | return { 667 | "directory": directory, 668 | "time": datetime.now().isoformat(), 669 | "issues": [{ 670 | "type": "error", 671 | "rule": "directory_access", 672 | "message": "无法访问目录", 673 | "line": 1, 674 | "severity": "error" 675 | }] 676 | } 677 | 678 | issues = [] 679 | files_reviewed = 0 680 | 681 | for file_path in path.rglob("*.py"): 682 | result = self.review_file(str(file_path)) 683 | issues.extend(result["issues"]) 684 | files_reviewed += 1 685 | 686 | # 统计问题分布 687 | issue_types = {} 688 | issue_severities = {} 689 | 690 | for issue in issues: 691 | issue_type = issue["type"] 692 | issue_severity = issue["severity"] 693 | 694 | issue_types[issue_type] = issue_types.get( 695 | issue_type, 0 696 | ) + 1 697 | issue_severities[issue_severity] = issue_severities.get( 698 | issue_severity, 0 699 | ) + 1 700 | 701 | return { 702 | "directory": directory, 703 | "time": datetime.now().isoformat(), 704 | "files_reviewed": files_reviewed, 705 | "total_issues": len(issues), 706 | "issue_types": issue_types, 707 | "issue_severities": issue_severities, 708 | "issues": issues 709 | } 710 | 711 | except Exception as e: 712 | return { 713 | "directory": directory, 714 | "time": datetime.now().isoformat(), 715 | "issues": [{ 716 | "type": "error", 717 | "rule": "directory_review", 718 | "message": f"审查目录时出错:{str(e)}", 719 | "line": 1, 720 | "severity": "error" 721 | }] 722 | } 723 | 724 | def save_report(self, report: Dict) -> str: 725 | """保存审查报告。 726 | 727 | Args: 728 | report: 要保存的报告 729 | 730 | Returns: 731 | str: 报告ID 732 | """ 733 | report_id = datetime.now().strftime("%Y%m%d%H%M%S") 734 | report_file = self.reports_dir / f"report_{report_id}.json" 735 | 736 | path = self._safe_open(str(report_file), "w") 737 | if not path: 738 | return None 739 | 740 | with path.open("w", encoding="utf-8") as f: 741 | json.dump(report, f, ensure_ascii=False, indent=2) 742 | 743 | return report_id 744 | 745 | def get_report(self, report_id: str) -> Optional[Dict]: 746 | """获取审查报告。 747 | 748 | Args: 749 | report_id: 报告ID 750 | 751 | Returns: 752 | Optional[Dict]: 报告内容,如果不存在则返回 None 753 | """ 754 | report_file = self.reports_dir / f"report_{report_id}.json" 755 | path = self._safe_open(str(report_file)) 756 | if not path: 757 | return None 758 | 759 | with path.open("r", encoding="utf-8") as f: 760 | return json.load(f) 761 | 762 | def list_reports(self) -> List[Dict]: 763 | """列出所有审查报告。 764 | 765 | Returns: 766 | List[Dict]: 报告列表 767 | """ 768 | reports = [] 769 | for report_file in self.reports_dir.glob("report_*.json"): 770 | path = self._safe_open(str(report_file)) 771 | if not path: 772 | continue 773 | 774 | with path.open("r", encoding="utf-8") as f: 775 | report = json.load(f) 776 | reports.append({ 777 | "id": report_file.stem.replace("report_", ""), 778 | "timestamp": report["timestamp"], 779 | "target": report.get("file") or report.get("directory"), 780 | "total_issues": ( 781 | report["summary"]["total_issues"] 782 | if "total_issues" in report["summary"] 783 | else len(report["issues"]) 784 | ) 785 | }) 786 | 787 | return sorted(reports, key=lambda x: x["timestamp"], reverse=True) 788 | 789 | def _calculate_stats(self, issues: List[Dict[str, Any]]) -> Dict[str, Any]: 790 | """计算问题统计信息。 791 | 792 | Args: 793 | issues: 问题列表 794 | 795 | Returns: 796 | 包含统计信息的字典 797 | """ 798 | stats = { 799 | "total": len(issues), 800 | "by_type": {}, 801 | "by_severity": {}, 802 | "by_rule": {} 803 | } 804 | 805 | for issue in issues: 806 | # 按类型统计 807 | issue_type = issue.get("type", "unknown") 808 | stats["by_type"][issue_type] = stats["by_type"].get(issue_type, 0) + 1 809 | 810 | # 按严重程度统计 811 | severity = issue.get("severity", "unknown") 812 | stats["by_severity"][severity] = stats["by_severity"].get(severity, 0) + 1 813 | 814 | # 按规则统计 815 | rule = issue.get("rule", "unknown") 816 | stats["by_rule"][rule] = stats["by_rule"].get(rule, 0) + 1 817 | 818 | return stats 819 | 820 | code_review = CodeReview() -------------------------------------------------------------------------------- /src/cursormind/core/command_handler.py: -------------------------------------------------------------------------------- 1 | """ 2 | 命令处理核心模块 3 | """ 4 | from typing import Dict, Callable, Any, Optional 5 | import logging 6 | 7 | class CommandHandler: 8 | """命令处理器类""" 9 | 10 | def __init__(self): 11 | self._commands: Dict[str, Callable] = {} 12 | self._logger = logging.getLogger(__name__) 13 | 14 | def register(self, name: str) -> Callable: 15 | """ 16 | 命令注册装饰器 17 | 18 | Args: 19 | name: 命令名称 20 | 21 | Returns: 22 | 装饰器函数 23 | """ 24 | def decorator(func: Callable) -> Callable: 25 | self._commands[name] = func 26 | self._logger.debug(f"注册命令: {name}") 27 | return func 28 | return decorator 29 | 30 | def execute(self, name: str, *args: Any, **kwargs: Any) -> Optional[Any]: 31 | """ 32 | 执行命令 33 | 34 | Args: 35 | name: 命令名称 36 | args: 位置参数 37 | kwargs: 关键字参数 38 | 39 | Returns: 40 | 命令执行结果 41 | 42 | Raises: 43 | KeyError: 命令不存在时抛出 44 | """ 45 | if name not in self._commands: 46 | raise KeyError(f"未知命令: {name}") 47 | 48 | try: 49 | self._logger.info(f"执行命令: {name}") 50 | return self._commands[name](*args, **kwargs) 51 | except Exception as e: 52 | self._logger.error(f"命令执行失败: {name}, 错误: {str(e)}") 53 | raise 54 | 55 | # 创建全局命令处理器实例 56 | handler = CommandHandler() -------------------------------------------------------------------------------- /src/cursormind/core/cursor_framework.py: -------------------------------------------------------------------------------- 1 | """ 2 | Cursor 规范框架核心模块 3 | """ 4 | import os 5 | import json 6 | from typing import Dict, List, Optional 7 | from datetime import datetime 8 | from pathlib import Path 9 | 10 | class CursorFramework: 11 | def __init__(self): 12 | self.config_dir = Path.home() / '.cursormind' / 'cursor_framework' 13 | self.config_dir.mkdir(parents=True, exist_ok=True) 14 | self.templates_dir = self.config_dir / 'templates' 15 | self.templates_dir.mkdir(exist_ok=True) 16 | self.rules_file = self.config_dir / 'rules.json' 17 | self._load_rules() 18 | 19 | def _load_rules(self): 20 | """加载规范规则""" 21 | if not self.rules_file.exists(): 22 | self.rules = { 23 | "project_structure": { 24 | "required_dirs": ["src", "tests", "docs", "scripts"], 25 | "required_files": ["README.md", "LICENSE", "setup.py", "requirements.txt"] 26 | }, 27 | "code_style": { 28 | "python": { 29 | "line_length": 88, 30 | "indent": 4, 31 | "quotes": "double", 32 | "docstring": "google" 33 | } 34 | }, 35 | "git": { 36 | "commit_types": [ 37 | "feat", "fix", "docs", "style", "refactor", 38 | "perf", "test", "build", "ci", "chore" 39 | ], 40 | "commit_format": "(): ", 41 | "branch_format": { 42 | "feature": "feature/", 43 | "bugfix": "bugfix/", 44 | "hotfix": "hotfix/", 45 | "release": "release/" 46 | } 47 | }, 48 | "documentation": { 49 | "required_sections": [ 50 | "项目简介", 51 | "快速开始", 52 | "安装指南", 53 | "使用说明", 54 | "API文档", 55 | "贡献指南" 56 | ] 57 | } 58 | } 59 | self._save_rules() 60 | else: 61 | with open(self.rules_file, 'r', encoding='utf-8') as f: 62 | self.rules = json.load(f) 63 | 64 | def _save_rules(self): 65 | """保存规范规则""" 66 | with open(self.rules_file, 'w', encoding='utf-8') as f: 67 | json.dump(self.rules, f, ensure_ascii=False, indent=2) 68 | 69 | def check_project_structure(self, project_path: str) -> Dict[str, List[str]]: 70 | """检查项目结构是否符合规范""" 71 | issues = { 72 | "missing_dirs": [], 73 | "missing_files": [] 74 | } 75 | 76 | for required_dir in self.rules["project_structure"]["required_dirs"]: 77 | if not os.path.exists(os.path.join(project_path, required_dir)): 78 | issues["missing_dirs"].append(required_dir) 79 | 80 | for required_file in self.rules["project_structure"]["required_files"]: 81 | if not os.path.exists(os.path.join(project_path, required_file)): 82 | issues["missing_files"].append(required_file) 83 | 84 | return issues 85 | 86 | def validate_commit_message(self, message: str) -> Dict[str, bool]: 87 | """验证提交信息是否符合规范""" 88 | result = { 89 | "valid": False, 90 | "type_valid": False, 91 | "format_valid": False 92 | } 93 | 94 | # 检查是否为空 95 | if not message: 96 | return result 97 | 98 | # 检查格式 99 | parts = message.split(":") 100 | if len(parts) != 2: 101 | return result 102 | 103 | commit_type = parts[0].strip().lower() 104 | if "(" in commit_type: 105 | commit_type = commit_type.split("(")[0] 106 | 107 | # 检查类型 108 | result["type_valid"] = commit_type in self.rules["git"]["commit_types"] 109 | 110 | # 检查格式是否符合规范 111 | result["format_valid"] = ( 112 | len(parts[1].strip()) > 0 and # 描述不能为空 113 | len(parts[1].strip()) <= 72 # 描述不能太长 114 | ) 115 | 116 | result["valid"] = result["type_valid"] and result["format_valid"] 117 | return result 118 | 119 | def validate_branch_name(self, branch_name: str) -> Dict[str, bool]: 120 | """验证分支名称是否符合规范""" 121 | result = { 122 | "valid": False, 123 | "type_valid": False, 124 | "format_valid": False 125 | } 126 | 127 | if not branch_name or "/" not in branch_name: 128 | return result 129 | 130 | branch_type = branch_name.split("/")[0] 131 | 132 | # 检查分支类型 133 | result["type_valid"] = branch_type in self.rules["git"]["branch_format"] 134 | 135 | # 检查分支格式 136 | if result["type_valid"]: 137 | expected_format = self.rules["git"]["branch_format"][branch_type] 138 | format_parts = expected_format.split("/") 139 | branch_parts = branch_name.split("/") 140 | 141 | result["format_valid"] = ( 142 | len(branch_parts) == len(format_parts) and 143 | branch_parts[0] == format_parts[0] and 144 | len(branch_parts[1]) > 0 145 | ) 146 | 147 | result["valid"] = result["type_valid"] and result["format_valid"] 148 | return result 149 | 150 | def generate_project_template(self, project_path: str, template_name: str = "default") -> bool: 151 | """生成项目模板""" 152 | try: 153 | # 创建必要的目录 154 | for dir_name in self.rules["project_structure"]["required_dirs"]: 155 | os.makedirs(os.path.join(project_path, dir_name), exist_ok=True) 156 | 157 | # 创建必要的文件 158 | for file_name in self.rules["project_structure"]["required_files"]: 159 | file_path = os.path.join(project_path, file_name) 160 | if not os.path.exists(file_path): 161 | with open(file_path, 'w', encoding='utf-8') as f: 162 | if file_name == "README.md": 163 | f.write(self._generate_readme_template()) 164 | elif file_name == "setup.py": 165 | f.write(self._generate_setup_template()) 166 | elif file_name == "requirements.txt": 167 | f.write("# Project dependencies\n") 168 | 169 | return True 170 | except Exception as e: 171 | print(f"Error generating project template: {e}") 172 | return False 173 | 174 | def _generate_readme_template(self) -> str: 175 | """生成 README 模板""" 176 | sections = self.rules["documentation"]["required_sections"] 177 | template = "# 项目名称\n\n" 178 | 179 | for section in sections: 180 | template += f"## {section}\n\n" 181 | 182 | return template 183 | 184 | def _generate_setup_template(self) -> str: 185 | """生成 setup.py 模板""" 186 | return '''from setuptools import setup, find_packages 187 | 188 | setup( 189 | name="your-project-name", 190 | version="0.1.0", 191 | packages=find_packages(), 192 | install_requires=[ 193 | # 在这里列出你的项目依赖 194 | ], 195 | author="Your Name", 196 | author_email="your.email@example.com", 197 | description="A short description of your project", 198 | long_description=open("README.md").read(), 199 | long_description_content_type="text/markdown", 200 | url="https://github.com/username/project", 201 | classifiers=[ 202 | "Programming Language :: Python :: 3", 203 | "License :: OSI Approved :: MIT License", 204 | "Operating System :: OS Independent", 205 | ], 206 | python_requires=">=3.6", 207 | ) 208 | ''' 209 | 210 | cursor_framework = CursorFramework() -------------------------------------------------------------------------------- /src/cursormind/core/learning_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | 学习路径管理模块 - 指导你的学习之旅 🗺️ 3 | """ 4 | import os 5 | import json 6 | from pathlib import Path 7 | from typing import Dict, List, Any, Optional 8 | from ..config.settings import settings 9 | from ..utils.helpers import get_timestamp, ensure_dir 10 | from .achievement import achievement_manager 11 | 12 | class LearningPath: 13 | """学习路径管理类""" 14 | 15 | def __init__(self): 16 | # 获取项目根目录和学习路径目录 17 | self._project_root = Path(settings.get('project_root')) 18 | self._paths_dir = self._project_root / settings.get('learning_paths_dir') 19 | self._paths_file = self._paths_dir / 'paths.json' 20 | self._current_path_file = self._paths_dir / 'current_path.json' 21 | self._current_path: Optional[Dict[str, Any]] = None 22 | self._ensure_paths_file() 23 | self._ensure_current_path_file() 24 | 25 | def _ensure_paths_file(self) -> None: 26 | """确保学习路径文件存在""" 27 | # 确保目录存在 28 | ensure_dir(self._paths_dir) 29 | 30 | if not self._paths_file.exists(): 31 | default_paths = { 32 | "python-beginner": { 33 | "id": "python-beginner", 34 | "name": "Python入门之路", 35 | "description": "从零开始学习Python编程", 36 | "difficulty": "初级", 37 | "estimated_time": "4周", 38 | "stages": [ 39 | { 40 | "name": "基础语法", 41 | "steps": [ 42 | "变量和数据类型", 43 | "控制流程", 44 | "函数和模块" 45 | ], 46 | "resources": [ 47 | { 48 | "name": "Python官方文档", 49 | "url": "https://docs.python.org/zh-cn/3/" 50 | }, 51 | { 52 | "name": "Python入门教程", 53 | "url": "https://www.runoob.com/python3/python3-tutorial.html" 54 | } 55 | ], 56 | "projects": [ 57 | { 58 | "name": "数字游戏", 59 | "description": "创建一个简单的猜数字游戏" 60 | }, 61 | { 62 | "name": "计算器", 63 | "description": "实现一个基础的命令行计算器" 64 | } 65 | ] 66 | } 67 | ] 68 | }, 69 | "web-beginner": { 70 | "id": "web-beginner", 71 | "name": "网页设计入门", 72 | "description": "学习HTML、CSS和JavaScript基础", 73 | "difficulty": "初级", 74 | "estimated_time": "6周", 75 | "stages": [ 76 | { 77 | "name": "HTML基础", 78 | "steps": [ 79 | "HTML文档结构", 80 | "常用标签", 81 | "表单和表格" 82 | ], 83 | "resources": [ 84 | { 85 | "name": "MDN Web文档", 86 | "url": "https://developer.mozilla.org/zh-CN/" 87 | } 88 | ], 89 | "projects": [ 90 | { 91 | "name": "个人主页", 92 | "description": "创建一个简单的个人介绍页面" 93 | } 94 | ] 95 | } 96 | ] 97 | }, 98 | "project-beginner": { 99 | "id": "project-beginner", 100 | "name": "项目管理入门", 101 | "description": "学习基本的项目管理知识和工具", 102 | "difficulty": "初级", 103 | "estimated_time": "3周", 104 | "stages": [ 105 | { 106 | "name": "版本控制", 107 | "steps": [ 108 | "Git基础概念", 109 | "常用Git命令", 110 | "分支管理" 111 | ], 112 | "resources": [ 113 | { 114 | "name": "Git教程", 115 | "url": "https://www.liaoxuefeng.com/wiki/896043488029600" 116 | } 117 | ], 118 | "projects": [ 119 | { 120 | "name": "项目实践", 121 | "description": "创建一个Git仓库并进行基本操作" 122 | } 123 | ] 124 | } 125 | ] 126 | } 127 | } 128 | 129 | with open(self._paths_file, 'w', encoding='utf-8') as f: 130 | json.dump(default_paths, f, ensure_ascii=False, indent=2) 131 | 132 | def _ensure_current_path_file(self): 133 | """确保当前路径文件存在""" 134 | if not self._current_path_file.exists(): 135 | current_path = { 136 | "path_id": None, 137 | "current_stage": 0, 138 | "current_step": 0, 139 | "started_at": None, 140 | "last_updated": None 141 | } 142 | 143 | with open(self._current_path_file, 'w', encoding='utf-8') as f: 144 | json.dump(current_path, f, ensure_ascii=False, indent=2) 145 | 146 | def get_all_paths(self) -> List[Dict[str, Any]]: 147 | """获取所有学习路径""" 148 | if not self._paths_file.exists(): 149 | self._ensure_paths_file() 150 | with open(self._paths_file, 'r', encoding='utf-8') as f: 151 | data = json.load(f) 152 | return [ 153 | { 154 | 'id': path['id'], 155 | 'name': path['name'], 156 | 'description': path['description'], 157 | 'difficulty': path['difficulty'], 158 | 'estimated_time': path['estimated_time'] 159 | } 160 | for path in data['paths'] 161 | ] 162 | 163 | def get_path_info(self, path_id: str) -> Optional[Dict[str, Any]]: 164 | """获取指定学习路径的信息""" 165 | with open(self._paths_file, 'r', encoding='utf-8') as f: 166 | data = json.load(f) 167 | for path in data['paths']: 168 | if path['id'] == path_id: 169 | return path 170 | return None 171 | 172 | def set_current_path(self, path_id: str) -> bool: 173 | """设置当前学习路径""" 174 | path = self.get_path_info(path_id) 175 | if not path: 176 | return False 177 | 178 | current_path = { 179 | "path_id": path_id, 180 | "current_stage": 0, 181 | "current_step": 0, 182 | "started_at": get_timestamp(), 183 | "last_updated": get_timestamp() 184 | } 185 | 186 | with open(self._current_path_file, 'w', encoding='utf-8') as f: 187 | json.dump(current_path, f, ensure_ascii=False, indent=2) 188 | 189 | # 触发成就检查 190 | achievement_manager.update_stats('path_started') 191 | 192 | return True 193 | 194 | def get_current_progress(self) -> Optional[Dict[str, Any]]: 195 | """获取当前学习进度""" 196 | if not self._current_path_file.exists(): 197 | return None 198 | 199 | with open(self._current_path_file, 'r', encoding='utf-8') as f: 200 | current = json.load(f) 201 | 202 | if not current['path_id']: 203 | return None 204 | 205 | path = self.get_path_info(current['path_id']) 206 | if not path: 207 | return None 208 | 209 | total_steps = sum(len(stage['steps']) for stage in path['stages']) 210 | completed_steps = 0 211 | for i in range(current['current_stage']): 212 | completed_steps += len(path['stages'][i]['steps']) 213 | completed_steps += current['current_step'] 214 | 215 | return { 216 | 'path_id': current['path_id'], 217 | 'path_name': path['name'], 218 | 'current_stage': current['current_stage'], 219 | 'current_stage_name': path['stages'][current['current_stage']]['name'], 220 | 'current_step': current['current_step'], 221 | 'current_step_name': path['stages'][current['current_stage']]['steps'][current['current_step']], 222 | 'progress': f"{completed_steps}/{total_steps}", 223 | 'percentage': round(completed_steps / total_steps * 100, 1) 224 | } 225 | 226 | def advance_progress(self) -> bool: 227 | """推进当前进度""" 228 | if not self._current_path_file.exists(): 229 | return False 230 | 231 | with open(self._current_path_file, 'r', encoding='utf-8') as f: 232 | current = json.load(f) 233 | 234 | if not current['path_id']: 235 | return False 236 | 237 | path = self.get_path_info(current['path_id']) 238 | if not path: 239 | return False 240 | 241 | # 获取当前阶段 242 | stage = path['stages'][current['current_stage']] 243 | 244 | # 检查是否需要进入下一步或下一阶段 245 | if current['current_step'] + 1 < len(stage['steps']): 246 | # 进入下一步 247 | current['current_step'] += 1 248 | elif current['current_stage'] + 1 < len(path['stages']): 249 | # 进入下一阶段 250 | current['current_stage'] += 1 251 | current['current_step'] = 0 252 | else: 253 | # 学习路径已完成 254 | current['path_id'] = None 255 | # 触发成就检查 256 | achievement_manager.update_stats('path_completed') 257 | 258 | current['last_updated'] = get_timestamp() 259 | 260 | with open(self._current_path_file, 'w', encoding='utf-8') as f: 261 | json.dump(current, f, ensure_ascii=False, indent=2) 262 | 263 | return True 264 | 265 | def get_current_resources(self) -> List[Dict[str, str]]: 266 | """获取当前阶段的学习资源""" 267 | progress = self.get_current_progress() 268 | if not progress: 269 | return [] 270 | 271 | path = self.get_path_info(progress['path_id']) 272 | if not path or not path['stages']: 273 | return [] 274 | 275 | current_stage = int(progress['current_stage']) 276 | if current_stage >= len(path['stages']): 277 | return [] 278 | 279 | stage = path['stages'][current_stage] 280 | return stage.get('resources', []) 281 | 282 | def get_current_projects(self) -> List[Dict[str, str]]: 283 | """获取当前阶段的练习项目""" 284 | progress = self.get_current_progress() 285 | if not progress: 286 | return [] 287 | 288 | path = self.get_path_info(progress['path_id']) 289 | if not path or not path['stages']: 290 | return [] 291 | 292 | current_stage = int(progress['current_stage']) 293 | if current_stage >= len(path['stages']): 294 | return [] 295 | 296 | stage = path['stages'][current_stage] 297 | return stage.get('projects', []) 298 | 299 | # 创建全局实例 300 | learning_path_manager = LearningPath() -------------------------------------------------------------------------------- /src/cursormind/core/note_manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | 笔记管理模块 - 记录你的学习心得 📝 3 | """ 4 | import os 5 | import json 6 | from datetime import datetime, timedelta 7 | from pathlib import Path 8 | from typing import Dict, List, Optional, Set 9 | import re 10 | from ..config.settings import settings 11 | from ..utils.helpers import ensure_dir, get_timestamp 12 | from .achievement import achievement_manager 13 | 14 | class NoteManager: 15 | """笔记管理类""" 16 | 17 | def __init__(self): 18 | self._project_root = Path(settings.get('project_root')) 19 | self._notes_dir = self._project_root / settings.get('notes_dir') 20 | self._daily_dir = self._notes_dir / 'daily' 21 | self._topic_dir = self._notes_dir / 'topics' 22 | self._review_dir = self._notes_dir / 'reviews' 23 | self._stats_file = self._notes_dir / 'stats.json' 24 | self._ensure_structure() 25 | self._load_stats() 26 | self._update_daily_streak() 27 | 28 | def _ensure_structure(self) -> None: 29 | """确保笔记目录结构存在""" 30 | for dir_path in [self._daily_dir, self._topic_dir, self._review_dir]: 31 | ensure_dir(dir_path) 32 | 33 | if not self._stats_file.exists(): 34 | self._stats = { 35 | 'total_notes': 0, 36 | 'total_words': 0, 37 | 'topics': {}, 38 | 'tags': {}, 39 | 'daily_streak': 0, 40 | 'last_note_date': '', 41 | 'last_updated': get_timestamp() 42 | } 43 | self._save_stats() 44 | 45 | def _load_stats(self) -> None: 46 | """加载笔记统计数据""" 47 | if self._stats_file.exists(): 48 | with open(self._stats_file, 'r', encoding='utf-8') as f: 49 | self._stats = json.load(f) 50 | 51 | def _save_stats(self) -> None: 52 | """保存笔记统计数据""" 53 | with open(self._stats_file, 'w', encoding='utf-8') as f: 54 | json.dump(self._stats, f, ensure_ascii=False, indent=2) 55 | 56 | def _update_daily_streak(self): 57 | """更新连续记录天数""" 58 | with open(self._stats_file, 'r', encoding='utf-8') as f: 59 | stats = json.load(f) 60 | 61 | if not stats['last_note_date']: 62 | return 63 | 64 | last_note = datetime.fromisoformat(stats['last_note_date']) 65 | today = datetime.now() 66 | 67 | # 如果最后一条笔记是昨天的 68 | if (today - last_note).days > 1: 69 | stats['daily_streak'] = 0 70 | 71 | with open(self._stats_file, 'w', encoding='utf-8') as f: 72 | json.dump(stats, f, ensure_ascii=False, indent=2) 73 | 74 | def _extract_tags(self, content: str) -> Set[str]: 75 | """从内容中提取标签""" 76 | return set(tag.strip() for tag in re.findall(r'#(\w+)', content)) 77 | 78 | def _update_stats(self, content: str, topic: str, tags: Set[str]): 79 | """更新统计数据""" 80 | with open(self._stats_file, 'r', encoding='utf-8') as f: 81 | stats = json.load(f) 82 | 83 | # 更新基本统计 84 | stats['total_notes'] += 1 85 | stats['total_words'] += len(content.split()) 86 | 87 | # 更新主题统计 88 | if topic not in stats['topics']: 89 | stats['topics'][topic] = 0 90 | stats['topics'][topic] += 1 91 | 92 | # 更新标签统计 93 | for tag in tags: 94 | if tag not in stats['tags']: 95 | stats['tags'][tag] = 0 96 | stats['tags'][tag] += 1 97 | 98 | # 更新连续记录 99 | today = datetime.now().date() 100 | if stats['last_note_date']: 101 | last_note = datetime.fromisoformat(stats['last_note_date']).date() 102 | if today == last_note: 103 | pass # 同一天内不更新连续记录 104 | elif (today - last_note).days == 1: 105 | stats['daily_streak'] += 1 106 | else: 107 | stats['daily_streak'] = 1 108 | else: 109 | stats['daily_streak'] = 1 110 | 111 | stats['last_note_date'] = datetime.now().isoformat() 112 | stats['last_updated'] = get_timestamp() 113 | 114 | with open(self._stats_file, 'w', encoding='utf-8') as f: 115 | json.dump(stats, f, ensure_ascii=False, indent=2) 116 | 117 | # 触发成就检查 118 | achievement_manager.update_stats('note_created', { 119 | 'topic': topic, 120 | 'tags': list(tags) 121 | }) 122 | 123 | def add_note(self, content: str, topic: str = 'general') -> Dict: 124 | """ 125 | 添加新笔记 126 | :param content: 笔记内容 127 | :param topic: 主题 128 | :return: 笔记信息 129 | """ 130 | timestamp = get_timestamp() 131 | date = datetime.now().strftime('%Y-%m-%d') 132 | tags = self._extract_tags(content) 133 | 134 | # 创建笔记数据 135 | note = { 136 | 'id': f"{date}-{self._stats['total_notes'] + 1:04d}", 137 | 'content': content, 138 | 'topic': topic, 139 | 'tags': list(tags), 140 | 'created_at': timestamp, 141 | 'updated_at': timestamp 142 | } 143 | 144 | # 保存到日常笔记 145 | daily_file = self._daily_dir / f"{date}.json" 146 | daily_notes = [] 147 | if daily_file.exists(): 148 | with open(daily_file, 'r', encoding='utf-8') as f: 149 | daily_notes = json.load(f) 150 | daily_notes.append(note) 151 | with open(daily_file, 'w', encoding='utf-8') as f: 152 | json.dump(daily_notes, f, ensure_ascii=False, indent=2) 153 | 154 | # 保存到主题目录 155 | topic_dir = ensure_dir(self._topic_dir / topic) 156 | topic_file = topic_dir / f"{note['id']}.json" 157 | with open(topic_file, 'w', encoding='utf-8') as f: 158 | json.dump(note, f, ensure_ascii=False, indent=2) 159 | 160 | # 更新统计数据 161 | self._update_stats(content, topic, tags) 162 | 163 | return note 164 | 165 | def get_daily_notes(self, date: Optional[str] = None) -> List[Dict]: 166 | """ 167 | 获取指定日期的笔记 168 | :param date: 日期字符串(YYYY-MM-DD),默认为今天 169 | :return: 笔记列表 170 | """ 171 | if date is None: 172 | date = datetime.now().strftime('%Y-%m-%d') 173 | 174 | daily_file = self._daily_dir / f"{date}.json" 175 | if not daily_file.exists(): 176 | return [] 177 | 178 | with open(daily_file, 'r', encoding='utf-8') as f: 179 | return json.load(f) 180 | 181 | def get_topic_notes(self, topic: str) -> List[Dict]: 182 | """ 183 | 获取指定主题的所有笔记 184 | :param topic: 主题名称 185 | :return: 笔记列表 186 | """ 187 | topic_dir = self._topic_dir / topic 188 | if not topic_dir.exists(): 189 | return [] 190 | 191 | notes = [] 192 | for note_file in topic_dir.glob('*.json'): 193 | with open(note_file, 'r', encoding='utf-8') as f: 194 | notes.append(json.load(f)) 195 | 196 | return sorted(notes, key=lambda x: x['created_at'], reverse=True) 197 | 198 | def search_notes(self, query: str) -> List[Dict]: 199 | """ 200 | 搜索笔记 201 | :param query: 搜索关键词 202 | :return: 匹配的笔记列表 203 | """ 204 | results = [] 205 | for topic_dir in self._topic_dir.iterdir(): 206 | if topic_dir.is_dir(): 207 | for note_file in topic_dir.glob('*.json'): 208 | with open(note_file, 'r', encoding='utf-8') as f: 209 | note = json.load(f) 210 | if (query.lower() in note['content'].lower() or 211 | query.lower() in note['topic'].lower() or 212 | any(query.lower() in tag.lower() for tag in note['tags'])): 213 | results.append(note) 214 | 215 | return sorted(results, key=lambda x: x['created_at'], reverse=True) 216 | 217 | def get_stats(self) -> Dict: 218 | """获取笔记统计数据""" 219 | return self._stats 220 | 221 | def generate_review(self, days: int = 7) -> Dict: 222 | """ 223 | 生成复习报告 224 | :param days: 要回顾的天数 225 | :return: 复习报告 226 | """ 227 | end_date = datetime.now() 228 | start_date = end_date.replace(day=end_date.day - days + 1) 229 | 230 | review = { 231 | 'period': f"{start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}", 232 | 'total_notes': 0, 233 | 'total_words': 0, 234 | 'topics': {}, 235 | 'tags': {}, 236 | 'daily_notes': [], 237 | 'highlights': [] 238 | } 239 | 240 | current = start_date 241 | while current <= end_date: 242 | date = current.strftime('%Y-%m-%d') 243 | daily_notes = self.get_daily_notes(date) 244 | 245 | if daily_notes: 246 | review['total_notes'] += len(daily_notes) 247 | for note in daily_notes: 248 | review['total_words'] += len(note['content'].split()) 249 | 250 | # 更新主题统计 251 | if note['topic'] not in review['topics']: 252 | review['topics'][note['topic']] = 0 253 | review['topics'][note['topic']] += 1 254 | 255 | # 更新标签统计 256 | for tag in note['tags']: 257 | if tag not in review['tags']: 258 | review['tags'][tag] = 0 259 | review['tags'][tag] += 1 260 | 261 | # 添加到每日笔记列表 262 | review['daily_notes'].append({ 263 | 'date': date, 264 | 'notes': daily_notes 265 | }) 266 | 267 | # 如果笔记内容超过100字,添加到亮点列表 268 | if len(note['content'].split()) > 100: 269 | review['highlights'].append(note) 270 | 271 | current = current.replace(day=current.day + 1) 272 | 273 | # 保存复习报告 274 | review_file = self._review_dir / f"review_{end_date.strftime('%Y%m%d')}.json" 275 | with open(review_file, 'w', encoding='utf-8') as f: 276 | json.dump(review, f, ensure_ascii=False, indent=2) 277 | 278 | # 触发成就检查 279 | achievement_manager.update_stats('review_generated') 280 | 281 | return review 282 | 283 | # 创建全局实例 284 | note_manager = NoteManager() -------------------------------------------------------------------------------- /src/cursormind/core/project_manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | 项目管理工具模块 3 | """ 4 | import os 5 | import json 6 | from typing import Dict, List, Optional 7 | from datetime import datetime 8 | from pathlib import Path 9 | 10 | class ProjectManager: 11 | def __init__(self): 12 | self.config_dir = Path.home() / '.cursormind' / 'project_manager' 13 | self.config_dir.mkdir(parents=True, exist_ok=True) 14 | self.tasks_dir = self.config_dir / 'tasks' 15 | self.tasks_dir.mkdir(exist_ok=True) 16 | self.config_file = self.config_dir / 'config.json' 17 | self._load_config() 18 | 19 | def _load_config(self): 20 | """加载配置""" 21 | if not self.config_file.exists(): 22 | self.config = { 23 | "task_status_options": [ 24 | "待处理", "进行中", "已完成", "已取消", "已延期" 25 | ], 26 | "task_priority_options": [ 27 | "低", "中", "高", "紧急" 28 | ], 29 | "task_type_options": [ 30 | "功能开发", "bug修复", "文档编写", "代码重构", 31 | "性能优化", "测试编写", "其他" 32 | ], 33 | "default_task_fields": { 34 | "status": "待处理", 35 | "priority": "中", 36 | "type": "功能开发", 37 | "deadline": None, 38 | "assignee": None, 39 | "description": "", 40 | "notes": [], 41 | "subtasks": [], 42 | "related_tasks": [], 43 | "tags": [] 44 | } 45 | } 46 | self._save_config() 47 | else: 48 | with open(self.config_file, 'r', encoding='utf-8') as f: 49 | self.config = json.load(f) 50 | 51 | def _save_config(self): 52 | """保存配置""" 53 | with open(self.config_file, 'w', encoding='utf-8') as f: 54 | json.dump(self.config, f, ensure_ascii=False, indent=2) 55 | 56 | def create_task(self, title: str, **kwargs) -> Dict: 57 | """创建新任务""" 58 | task_id = datetime.now().strftime("%Y%m%d%H%M%S") 59 | task = { 60 | "id": task_id, 61 | "title": title, 62 | "created_at": datetime.now().isoformat(), 63 | "updated_at": datetime.now().isoformat(), 64 | **self.config["default_task_fields"], 65 | **kwargs 66 | } 67 | 68 | task_file = self.tasks_dir / f"{task_id}.json" 69 | with open(task_file, 'w', encoding='utf-8') as f: 70 | json.dump(task, f, ensure_ascii=False, indent=2) 71 | 72 | return task 73 | 74 | def update_task(self, task_id: str, **kwargs) -> Optional[Dict]: 75 | """更新任务""" 76 | task_file = self.tasks_dir / f"{task_id}.json" 77 | if not task_file.exists(): 78 | return None 79 | 80 | with open(task_file, 'r', encoding='utf-8') as f: 81 | task = json.load(f) 82 | 83 | task.update(kwargs) 84 | task["updated_at"] = datetime.now().isoformat() 85 | 86 | with open(task_file, 'w', encoding='utf-8') as f: 87 | json.dump(task, f, ensure_ascii=False, indent=2) 88 | 89 | return task 90 | 91 | def get_task(self, task_id: str) -> Optional[Dict]: 92 | """获取任务详情""" 93 | task_file = self.tasks_dir / f"{task_id}.json" 94 | if not task_file.exists(): 95 | return None 96 | 97 | with open(task_file, 'r', encoding='utf-8') as f: 98 | return json.load(f) 99 | 100 | def list_tasks(self, status: Optional[str] = None, priority: Optional[str] = None, 101 | type_: Optional[str] = None, assignee: Optional[str] = None, 102 | tags: Optional[List[str]] = None) -> List[Dict]: 103 | """列出任务""" 104 | tasks = [] 105 | for task_file in self.tasks_dir.glob("*.json"): 106 | with open(task_file, 'r', encoding='utf-8') as f: 107 | task = json.load(f) 108 | 109 | # 应用过滤条件 110 | if status and task["status"] != status: 111 | continue 112 | if priority and task["priority"] != priority: 113 | continue 114 | if type_ and task["type"] != type_: 115 | continue 116 | if assignee and task["assignee"] != assignee: 117 | continue 118 | if tags and not all(tag in task["tags"] for tag in tags): 119 | continue 120 | 121 | tasks.append(task) 122 | 123 | # 按优先级和创建时间排序 124 | priority_order = {p: i for i, p in enumerate(self.config["task_priority_options"])} 125 | tasks.sort(key=lambda x: (priority_order[x["priority"]], x["created_at"]), reverse=True) 126 | 127 | return tasks 128 | 129 | def add_subtask(self, parent_id: str, title: str, **kwargs) -> Optional[Dict]: 130 | """添加子任务""" 131 | parent_task = self.get_task(parent_id) 132 | if not parent_task: 133 | return None 134 | 135 | subtask = { 136 | "id": f"{parent_id}-{len(parent_task['subtasks'])+1}", 137 | "title": title, 138 | "created_at": datetime.now().isoformat(), 139 | "status": "待处理", 140 | **kwargs 141 | } 142 | 143 | parent_task["subtasks"].append(subtask) 144 | self.update_task(parent_id, subtasks=parent_task["subtasks"]) 145 | 146 | return subtask 147 | 148 | def add_note(self, task_id: str, content: str) -> Optional[Dict]: 149 | """添加任务笔记""" 150 | task = self.get_task(task_id) 151 | if not task: 152 | return None 153 | 154 | note = { 155 | "id": len(task["notes"]) + 1, 156 | "content": content, 157 | "created_at": datetime.now().isoformat() 158 | } 159 | 160 | task["notes"].append(note) 161 | self.update_task(task_id, notes=task["notes"]) 162 | 163 | return note 164 | 165 | def link_tasks(self, task_id: str, related_task_id: str) -> bool: 166 | """关联任务""" 167 | task = self.get_task(task_id) 168 | related_task = self.get_task(related_task_id) 169 | 170 | if not task or not related_task: 171 | return False 172 | 173 | if related_task_id not in task["related_tasks"]: 174 | task["related_tasks"].append(related_task_id) 175 | self.update_task(task_id, related_tasks=task["related_tasks"]) 176 | 177 | if task_id not in related_task["related_tasks"]: 178 | related_task["related_tasks"].append(task_id) 179 | self.update_task(related_task_id, related_tasks=related_task["related_tasks"]) 180 | 181 | return True 182 | 183 | def get_task_stats(self) -> Dict: 184 | """获取任务统计信息""" 185 | stats = { 186 | "total_tasks": 0, 187 | "status_counts": {}, 188 | "priority_counts": {}, 189 | "type_counts": {}, 190 | "assignee_counts": {}, 191 | "tag_counts": {}, 192 | "completion_rate": 0, 193 | "average_completion_time": 0 194 | } 195 | 196 | completed_tasks = [] 197 | for task_file in self.tasks_dir.glob("*.json"): 198 | with open(task_file, 'r', encoding='utf-8') as f: 199 | task = json.load(f) 200 | 201 | stats["total_tasks"] += 1 202 | 203 | # 统计状态 204 | stats["status_counts"][task["status"]] = \ 205 | stats["status_counts"].get(task["status"], 0) + 1 206 | 207 | # 统计优先级 208 | stats["priority_counts"][task["priority"]] = \ 209 | stats["priority_counts"].get(task["priority"], 0) + 1 210 | 211 | # 统计类型 212 | stats["type_counts"][task["type"]] = \ 213 | stats["type_counts"].get(task["type"], 0) + 1 214 | 215 | # 统计负责人 216 | if task["assignee"]: 217 | stats["assignee_counts"][task["assignee"]] = \ 218 | stats["assignee_counts"].get(task["assignee"], 0) + 1 219 | 220 | # 统计标签 221 | for tag in task["tags"]: 222 | stats["tag_counts"][tag] = stats["tag_counts"].get(tag, 0) + 1 223 | 224 | # 收集已完成的任务 225 | if task["status"] == "已完成": 226 | completed_tasks.append(task) 227 | 228 | # 计算完成率 229 | if stats["total_tasks"] > 0: 230 | stats["completion_rate"] = \ 231 | len(completed_tasks) / stats["total_tasks"] * 100 232 | 233 | # 计算平均完成时间(天) 234 | if completed_tasks: 235 | total_days = 0 236 | for task in completed_tasks: 237 | created = datetime.fromisoformat(task["created_at"]) 238 | updated = datetime.fromisoformat(task["updated_at"]) 239 | total_days += (updated - created).days 240 | stats["average_completion_time"] = total_days / len(completed_tasks) 241 | 242 | return stats 243 | 244 | project_manager = ProjectManager() -------------------------------------------------------------------------------- /src/cursormind/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yagami1997/CursorMind/c85ceaa15e0371c4ec4ca426fdd9f2609287efe7/src/cursormind/utils/__init__.py -------------------------------------------------------------------------------- /src/cursormind/utils/helpers.py: -------------------------------------------------------------------------------- 1 | """ 2 | 辅助函数模块 - 提供常用的工具函数 🛠️ 3 | """ 4 | import os 5 | from datetime import datetime 6 | from pathlib import Path 7 | from typing import Optional, Union 8 | import pytz 9 | from ..config.settings import settings 10 | 11 | def get_timestamp(timezone: str = 'America/Los_Angeles') -> str: 12 | """ 13 | 获取当前时间戳 14 | :param timezone: 时区名称 15 | :return: 格式化的时间戳字符串 16 | """ 17 | tz = pytz.timezone(timezone) 18 | now = datetime.now(tz) 19 | return now.strftime("%Y-%m-%d %H:%M:%S %Z") 20 | 21 | def ensure_dir(path: Union[str, Path]) -> Path: 22 | """ 23 | 确保目录存在,如果不存在则创建 24 | :param path: 目录路径(字符串或Path对象) 25 | :return: 目录路径 26 | """ 27 | path_obj = Path(path) if isinstance(path, str) else path 28 | path_obj.mkdir(parents=True, exist_ok=True) 29 | return path_obj 30 | 31 | def format_path(path: str) -> Path: 32 | """ 33 | 格式化路径字符串为Path对象 34 | :param path: 路径字符串 35 | :return: Path对象 36 | """ 37 | return Path(os.path.expanduser(path)) 38 | 39 | def get_relative_path(path: Path, base: Path) -> str: 40 | """ 41 | 获取相对路径 42 | :param path: 目标路径 43 | :param base: 基准路径 44 | :return: 相对路径字符串 45 | """ 46 | try: 47 | return str(path.relative_to(base)) 48 | except ValueError: 49 | return str(path) 50 | 51 | def get_project_root() -> Path: 52 | """ 53 | 获取项目根目录 54 | 55 | Returns: 56 | 项目根目录的Path对象 57 | """ 58 | return Path(settings.get('project_root')) 59 | 60 | def load_template(template_name: str) -> str: 61 | """ 62 | 加载模板文件内容 63 | 64 | Args: 65 | template_name: 模板文件名 66 | 67 | Returns: 68 | 模板文件内容 69 | 70 | Raises: 71 | FileNotFoundError: 模板文件不存在时抛出 72 | """ 73 | template_path = get_project_root() / settings.get('templates_dir') / template_name 74 | if not template_path.exists(): 75 | raise FileNotFoundError(f"模板文件不存在: {template_path}") 76 | 77 | with open(template_path, 'r', encoding='utf-8') as f: 78 | return f.read() 79 | 80 | def save_file(content: str, file_path: str) -> None: 81 | """ 82 | 保存内容到文件 83 | 84 | Args: 85 | content: 文件内容 86 | file_path: 文件路径 87 | """ 88 | path_obj = Path(file_path) 89 | path_obj.parent.mkdir(parents=True, exist_ok=True) 90 | 91 | with open(path_obj, 'w', encoding='utf-8') as f: 92 | f.write(content) -------------------------------------------------------------------------------- /src/cursormind/utils/note_manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | 笔记管理工具 - 记录你的学习历程 📝 3 | """ 4 | import os 5 | from datetime import datetime 6 | from pathlib import Path 7 | from typing import List, Dict 8 | import json 9 | from ..config.settings import settings 10 | from .helpers import get_timestamp, ensure_dir 11 | 12 | class NoteManager: 13 | """笔记管理类""" 14 | 15 | def __init__(self): 16 | self.notes_dir = Path(settings.get('notes_dir', 'learning_notes')) 17 | self.ensure_notes_structure() 18 | 19 | def ensure_notes_structure(self) -> None: 20 | """确保笔记目录结构完整""" 21 | ensure_dir(self.notes_dir) 22 | ensure_dir(self.notes_dir / 'daily') 23 | ensure_dir(self.notes_dir / 'projects') 24 | ensure_dir(self.notes_dir / 'ideas') 25 | 26 | def add_note(self, content: str, note_type: str = 'daily') -> Dict: 27 | """ 28 | 添加新笔记 29 | 30 | Args: 31 | content: 笔记内容 32 | note_type: 笔记类型(daily/project/idea) 33 | 34 | Returns: 35 | 笔记信息字典 36 | """ 37 | timestamp = get_timestamp() 38 | date_str = datetime.now().strftime('%Y-%m-%d') 39 | 40 | # 创建笔记数据 41 | note_data = { 42 | 'content': content, 43 | 'timestamp': timestamp, 44 | 'type': note_type, 45 | 'tags': self._extract_tags(content), 46 | 'project': settings.get('current_project', '') 47 | } 48 | 49 | # 保存笔记 50 | if note_type == 'daily': 51 | file_path = self.notes_dir / 'daily' / f'{date_str}.md' 52 | else: 53 | file_path = self.notes_dir / note_type / f'{date_str}_{self._generate_id()}.md' 54 | 55 | self._save_note(note_data, file_path) 56 | self._update_stats(note_data) 57 | 58 | return note_data 59 | 60 | def get_today_notes(self) -> List[Dict]: 61 | """获取今天的笔记列表""" 62 | date_str = datetime.now().strftime('%Y-%m-%d') 63 | daily_file = self.notes_dir / 'daily' / f'{date_str}.md' 64 | 65 | if not daily_file.exists(): 66 | return [] 67 | 68 | return self._read_notes(daily_file) 69 | 70 | def _save_note(self, note_data: Dict, file_path: Path) -> None: 71 | """保存笔记到文件""" 72 | # 确保目录存在 73 | file_path.parent.mkdir(parents=True, exist_ok=True) 74 | 75 | # 格式化笔记内容 76 | note_content = f""" 77 | ## {note_data['timestamp']} 78 | 79 | {note_data['content']} 80 | 81 | {'#' + ' #'.join(note_data['tags']) if note_data['tags'] else ''} 82 | 83 | --- 84 | """ 85 | # 追加或创建文件 86 | mode = 'a' if file_path.exists() else 'w' 87 | with open(file_path, mode, encoding='utf-8') as f: 88 | f.write(note_content) 89 | 90 | def _extract_tags(self, content: str) -> List[str]: 91 | """从内容中提取标签""" 92 | tags = [] 93 | words = content.split() 94 | for word in words: 95 | if word.startswith('#') and len(word) > 1: 96 | tags.append(word[1:]) 97 | return tags 98 | 99 | def _generate_id(self) -> str: 100 | """生成笔记ID""" 101 | return datetime.now().strftime('%H%M%S') 102 | 103 | def _update_stats(self, note_data: Dict) -> None: 104 | """更新笔记统计信息""" 105 | settings.set('total_notes', settings.get('total_notes', 0) + 1) 106 | 107 | # TODO: 实现更多统计功能 108 | # - 按类型统计 109 | # - 按标签统计 110 | # - 生成学习热力图 111 | 112 | def _read_notes(self, file_path: Path) -> List[Dict]: 113 | """读取笔记文件内容""" 114 | if not file_path.exists(): 115 | return [] 116 | 117 | notes = [] 118 | current_note = None 119 | 120 | with open(file_path, 'r', encoding='utf-8') as f: 121 | for line in f: 122 | line = line.strip() 123 | if line.startswith('## '): 124 | if current_note: 125 | notes.append(current_note) 126 | current_note = { 127 | 'timestamp': line[3:], 128 | 'content': '', 129 | 'tags': [] 130 | } 131 | elif current_note and line and not line.startswith('---'): 132 | if line.startswith('#'): 133 | current_note['tags'] = [tag[1:] for tag in line.split()] 134 | else: 135 | current_note['content'] += line + '\n' 136 | 137 | if current_note: 138 | notes.append(current_note) 139 | 140 | return notes 141 | 142 | # 创建全局笔记管理器实例 143 | note_manager = NoteManager() --------------------------------------------------------------------------------