diff --git a/aide-program/README.md b/aide-program/README.md deleted file mode 100644 index 78ee37d..0000000 --- a/aide-program/README.md +++ /dev/null @@ -1,346 +0,0 @@ -# Aide 程序系统开发文档 - -## 一、项目概述 - -### 1.1 项目定位 - -Aide 是一套命令行工具集,用于支持 AI 辅助开发工作流。本项目实现 aide 程序的核心基础功能,包括: - -- 项目初始化(aide init) -- 环境管理(aide env) -- 配置管理(aide config) - -**注意**:本阶段不包含 `aide flow`(进度追踪)和 `aide decide`(待定项确认)的实现,这两个功能将在后续阶段开发。 - -### 1.2 技术栈要求 - -- **Python 3.10+**:主要编程语言 -- **Shell 脚本**:跨平台入口封装(aide.sh / aide.bat) -- **TOML**:配置文件格式 -- **标准库优先**:尽量使用 Python 标准库,减少外部依赖 - -### 1.3 设计原则 - -1. **确定性**:相同输入产生相同输出,避免不确定性 -2. **精简输出**:成功时输出极简,失败时输出详细 -3. **幂等性**:重复执行不产生副作用 -4. **自文档化**:配置文件包含详细注释 -5. **跨平台**:支持 Linux、macOS、Windows - ---- - -## 二、目录结构 - -``` -aide-program/ -├── README.md # 本文件:项目总览 -├── docs/ # 详细设计文档 -│ ├── 01-入口脚本设计.md # aide.sh / aide.bat 设计 -│ ├── 02-aide-init设计.md # aide init 命令设计 -│ ├── 03-aide-env设计.md # aide env 命令设计 -│ ├── 04-aide-config设计.md # aide config 命令设计 -│ ├── 05-配置文件规范.md # config.toml 格式规范 -│ ├── 06-输出格式规范.md # 统一输出格式规范 -│ └── 07-测试规范.md # 测试要求和用例 -├── src/ # 源代码目录(开发时创建) -│ ├── aide.sh # Linux/macOS 入口 -│ ├── aide.bat # Windows 入口 -│ ├── main.py # Python 主入口 -│ ├── core/ # 核心模块 -│ │ ├── __init__.py -│ │ ├── config.py # 配置读写 -│ │ └── output.py # 输出格式化 -│ ├── commands/ # 命令实现 -│ │ ├── __init__.py -│ │ ├── init.py # aide init -│ │ ├── env.py # aide env -│ │ └── config_cmd.py # aide config -│ └── utils/ # 工具函数 -│ ├── __init__.py -│ └── validators.py # 验证函数 -└── tests/ # 测试目录(开发时创建) - ├── test_init.py - ├── test_env.py - └── test_config.py -``` - ---- - -## 三、命令清单 - -### 3.1 本阶段实现的命令 - -| 命令 | 功能 | 优先级 | -|------|------|--------| -| `aide init` | 初始化 .aide 目录和配置文件 | P0 | -| `aide env ensure` | 检测并修复项目开发环境 | P0 | -| `aide env ensure --runtime` | 检测 aide 运行时环境 | P0 | -| `aide config get ` | 获取配置值 | P1 | -| `aide config set ` | 设置配置值 | P1 | - -### 3.2 后续阶段实现的命令 - -| 命令 | 功能 | 说明 | -|------|------|------| -| `aide flow ...` | 进度追踪和 git 集成 | 后续实现 | -| `aide decide ...` | 待定项确认 Web 服务 | 后续实现 | - ---- - -## 四、开发流程 - -### 4.1 阅读顺序 - -建议按以下顺序阅读文档: - -1. **README.md**(本文件)- 了解项目全貌 -2. **docs/06-输出格式规范.md** - 理解统一输出格式 -3. **docs/05-配置文件规范.md** - 理解配置文件结构 -4. **docs/01-入口脚本设计.md** - 理解命令调用流程 -5. **docs/02-aide-init设计.md** - 实现 aide init -6. **docs/03-aide-env设计.md** - 实现 aide env -7. **docs/04-aide-config设计.md** - 实现 aide config -8. **docs/07-测试规范.md** - 编写测试用例 - -### 4.2 开发步骤 - -1. **搭建基础框架** - - 创建目录结构 - - 实现入口脚本(aide.sh / aide.bat) - - 实现 main.py 命令分发 - - 实现 core/output.py 输出格式化 - -2. **实现核心模块** - - 实现 core/config.py 配置读写 - - 实现 utils/validators.py 验证函数 - -3. **实现命令** - - 实现 aide init - - 实现 aide env ensure --runtime - - 实现 aide env ensure - - 实现 aide config get/set - -4. **编写测试** - - 单元测试 - - 集成测试 - - 跨平台测试 - -5. **文档和打包** - - 编写用户文档 - - 准备分发包 - -### 4.3 质量要求 - -1. **代码质量** - - 遵循 PEP 8 代码规范 - - 函数和类必须有文档字符串 - - 关键逻辑必须有注释 - -2. **测试覆盖** - - 核心功能测试覆盖率 ≥ 80% - - 所有错误路径必须有测试用例 - - 跨平台兼容性测试 - -3. **用户体验** - - 输出信息清晰易懂 - - 错误提示包含解决建议 - - 命令执行速度快(< 1秒) - ---- - -## 五、核心概念 - -### 5.1 输出格式 - -所有 aide 命令遵循统一的输出格式: - -| 前缀 | 含义 | 使用场景 | -|------|------|---------| -| `✓` | 成功 | 操作成功完成 | -| `⚠` | 警告 | 有问题但可继续 | -| `✗` | 错误 | 操作失败 | -| `→` | 信息 | 进行中或提示信息 | - -**静默原则**:无输出 = 正常完成(适用于幂等操作) - -### 5.2 配置文件 - -- **位置**:`.aide/config.toml` -- **格式**:TOML -- **特点**:自文档化,包含详细注释 -- **访问**:通过 `aide config` 命令或 core/config.py 模块 - -### 5.3 数据存储 - -所有 aide 数据统一存放在项目根目录的 `.aide/` 下: - -``` -.aide/ -├── config.toml # 项目配置 -├── flow-status.json # 任务进度(后续实现) -├── decisions/ # 待定项记录(后续实现) -└── logs/ # 操作日志(可选) -``` - -### 5.4 错误处理 - -1. **预期错误**:返回明确的错误信息和建议 -2. **非预期错误**:记录详细日志,返回简化错误信息 -3. **退出码**: - - 0:成功 - - 1:一般错误 - - 2:参数错误 - - 3:环境错误 - ---- - -## 六、依赖管理 - -### 6.1 Python 依赖 - -**核心依赖**(必需): -- Python 3.10+ -- 标准库:os, sys, pathlib, subprocess, json, configparser - -**可选依赖**: -- tomli / tomllib(Python 3.11+ 内置):TOML 解析 -- tomli-w:TOML 写入 - -### 6.2 系统依赖 - -**必需**: -- Python 3.10+ - -**可选**(用于项目环境检测): -- git -- uv / pip - ---- - -## 七、交付物 - -### 7.1 必需交付物 - -1. **源代码** - - 完整的 Python 代码 - - 入口脚本(aide.sh / aide.bat) - - 所有必需的模块和工具函数 - -2. **测试代码** - - 单元测试 - - 集成测试 - - 测试数据和 fixtures - -3. **文档** - - 用户使用文档 - - 开发者文档(如有特殊设计) - - CHANGELOG - -### 7.2 可选交付物 - -1. **打包脚本** - - 用于生成分发包的脚本 - - 安装说明 - -2. **CI/CD 配置** - - GitHub Actions 或其他 CI 配置 - - 自动化测试流程 - ---- - -## 八、注意事项 - -### 8.1 设计约束 - -1. **不要实现 aide flow**:进度追踪功能后续实现 -2. **不要实现 aide decide**:待定项确认功能后续实现 -3. **不要硬编码路径**:所有路径通过配置或参数传入 -4. **不要假设环境**:所有环境依赖必须检测和验证 - -### 8.2 兼容性要求 - -1. **Python 版本**:支持 3.10+ -2. **操作系统**:Linux、macOS、Windows -3. **路径分隔符**:使用 pathlib 处理跨平台路径 -4. **编码**:统一使用 UTF-8 - -### 8.3 安全考虑 - -1. **配置文件权限**:不存储敏感信息 -2. **命令注入**:所有外部命令调用必须参数化 -3. **路径遍历**:验证所有文件路径 -4. **输入验证**:验证所有用户输入 - ---- - -## 九、参考资料 - -### 9.1 项目文档 - -- `../aide-requirements.md`:Aide 系统需求规格 -- `../aide-marketplace/aide-plugin/`:Commands 和 Skills 定义 -- `../discuss/`:设计讨论和决策记录 - -### 9.2 外部资源 - -- [TOML 规范](https://toml.io/) -- [PEP 8 代码规范](https://pep8.org/) -- [Python pathlib 文档](https://docs.python.org/3/library/pathlib.html) - ---- - -## 十、联系方式 - -如有疑问或需要澄清,请: - -1. 查阅 `docs/` 目录下的详细设计文档 -2. 参考 `../aide-requirements.md` 了解整体设计 -3. 查看 `../discuss/` 目录了解设计决策 - ---- - -## 附录:快速开始 - -### A.1 验证环境 - -```bash -# 检查 Python 版本 -python3 --version # 应该 >= 3.10 - -# 检查必要的库 -python3 -c "import tomllib" # Python 3.11+ -# 或 -python3 -c "import tomli" # Python 3.10 -``` - -### A.2 创建开发环境 - -```bash -# 创建虚拟环境 -cd aide-program -python3 -m venv .venv - -# 激活虚拟环境 -source .venv/bin/activate # Linux/macOS -# 或 -.venv\Scripts\activate # Windows - -# 安装依赖(如需要) -pip install tomli tomli-w -``` - -### A.3 运行测试 - -```bash -# 运行所有测试 -python3 -m pytest tests/ - -# 运行特定测试 -python3 -m pytest tests/test_init.py -``` - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 -**状态**:待开发 diff --git a/aide-program/docs/01-入口脚本设计.md b/aide-program/docs/01-入口脚本设计.md deleted file mode 100644 index 31c93ae..0000000 --- a/aide-program/docs/01-入口脚本设计.md +++ /dev/null @@ -1,554 +0,0 @@ -# 入口脚本设计 - -## 一、概述 - -### 1.1 设计目标 - -提供跨平台的统一命令行入口,使用户可以通过 `aide ` 的方式调用所有功能。 - -### 1.2 入口脚本清单 - -| 脚本 | 平台 | 说明 | -|------|------|------| -| `aide.sh` | Linux/macOS | Shell 脚本入口 | -| `aide.bat` | Windows | 批处理脚本入口 | -| `main.py` | 所有平台 | Python 主程序 | - ---- - -## 二、aide.sh 设计(Linux/macOS) - -### 2.1 功能要求 - -1. **定位 Python**:查找可用的 Python 3.10+ 解释器 -2. **定位脚本目录**:确定 main.py 的位置 -3. **传递参数**:将所有命令行参数传递给 Python 程序 -4. **处理错误**:Python 未找到时给出明确提示 - -### 2.2 实现示例 - -```bash -#!/usr/bin/env bash -# Aide 命令行工具入口脚本(Linux/macOS) -# 版本: 1.0 - -set -e # 遇到错误立即退出 - -# 获取脚本所在目录 -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Python 主程序路径 -MAIN_PY="${SCRIPT_DIR}/main.py" - -# 查找 Python 解释器 -find_python() { - # 尝试查找 Python 3.10+ - for cmd in python3.12 python3.11 python3.10 python3 python; do - if command -v "$cmd" &> /dev/null; then - # 检查版本 - version=$("$cmd" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') - major=$(echo "$version" | cut -d. -f1) - minor=$(echo "$version" | cut -d. -f2) - - if [ "$major" -eq 3 ] && [ "$minor" -ge 10 ]; then - echo "$cmd" - return 0 - fi - fi - done - - return 1 -} - -# 查找 Python -PYTHON=$(find_python) - -if [ -z "$PYTHON" ]; then - echo "✗ Python 3.10+ 未找到" >&2 - echo " 建议: 安装 Python 3.10 或更高版本" >&2 - echo " 文档: https://www.python.org/downloads/" >&2 - exit 3 -fi - -# 检查 main.py 是否存在 -if [ ! -f "$MAIN_PY" ]; then - echo "✗ 找不到 main.py" >&2 - echo " 位置: $MAIN_PY" >&2 - exit 1 -fi - -# 执行 Python 程序 -exec "$PYTHON" "$MAIN_PY" "$@" -``` - -### 2.3 安装方式 - -```bash -# 方式1:添加到 PATH -export PATH="/path/to/aide:$PATH" - -# 方式2:创建符号链接 -ln -s /path/to/aide/aide.sh /usr/local/bin/aide - -# 方式3:添加别名 -alias aide='/path/to/aide/aide.sh' -``` - ---- - -## 三、aide.bat 设计(Windows) - -### 3.1 功能要求 - -1. **定位 Python**:查找可用的 Python 3.10+ 解释器 -2. **定位脚本目录**:确定 main.py 的位置 -3. **传递参数**:将所有命令行参数传递给 Python 程序 -4. **处理错误**:Python 未找到时给出明确提示 - -### 3.2 实现示例 - -```batch -@echo off -REM Aide 命令行工具入口脚本(Windows) -REM 版本: 1.0 - -setlocal enabledelayedexpansion - -REM 获取脚本所在目录 -set "SCRIPT_DIR=%~dp0" - -REM Python 主程序路径 -set "MAIN_PY=%SCRIPT_DIR%main.py" - -REM 查找 Python 解释器 -set "PYTHON=" -for %%p in (python3.12 python3.11 python3.10 python3 python py) do ( - where %%p >nul 2>&1 - if !errorlevel! equ 0 ( - REM 检查版本 - for /f "delims=" %%v in ('%%p -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"') do ( - set "version=%%v" - ) - - REM 解析版本号 - for /f "tokens=1,2 delims=." %%a in ("!version!") do ( - set "major=%%a" - set "minor=%%b" - ) - - REM 检查是否满足要求(3.10+) - if !major! equ 3 if !minor! geq 10 ( - set "PYTHON=%%p" - goto :found - ) - ) -) - -:found -if "%PYTHON%"=="" ( - echo ✗ Python 3.10+ 未找到 >&2 - echo 建议: 安装 Python 3.10 或更高版本 >&2 - echo 文档: https://www.python.org/downloads/ >&2 - exit /b 3 -) - -REM 检查 main.py 是否存在 -if not exist "%MAIN_PY%" ( - echo ✗ 找不到 main.py >&2 - echo 位置: %MAIN_PY% >&2 - exit /b 1 -) - -REM 执行 Python 程序 -"%PYTHON%" "%MAIN_PY%" %* -exit /b %errorlevel% -``` - -### 3.3 安装方式 - -```batch -REM 方式1:添加到 PATH -set PATH=C:\path\to\aide;%PATH% - -REM 方式2:创建批处理文件到系统目录 -copy aide.bat C:\Windows\System32\aide.bat -``` - ---- - -## 四、main.py 设计 - -### 4.1 功能要求 - -1. **命令分发**:根据第一个参数分发到对应的命令处理函数 -2. **参数解析**:解析命令行参数 -3. **错误处理**:统一的错误处理和退出码 -4. **帮助信息**:提供 `--help` 和 `--version` 支持 - -### 4.2 实现框架 - -```python -#!/usr/bin/env python3 -""" -Aide 命令行工具主程序 -版本: 1.0 -""" - -import sys -from pathlib import Path - -# 添加 src 目录到 Python 路径 -SCRIPT_DIR = Path(__file__).parent -sys.path.insert(0, str(SCRIPT_DIR)) - -from core.output import ok, warn, err, info -from commands.init import cmd_init -from commands.env import cmd_env -from commands.config_cmd import cmd_config - - -VERSION = "1.0.0" - - -def show_help(): - """显示帮助信息""" - help_text = """Aide - AI 辅助开发工作流工具 - -用法: - aide [options] - -命令: - init 初始化 .aide 目录和配置文件 - env ensure 检测并修复项目开发环境 - env ensure --runtime 检测 aide 运行时环境 - config get 获取配置值 - config set 设置配置值 - -选项: - -h, --help 显示帮助信息 - -v, --version 显示版本信息 - -示例: - aide init - aide env ensure - aide config get task.source - aide config set task.source "new-task.md" - -文档: https://github.com/your-org/aide -""" - print(help_text) - - -def show_version(): - """显示版本信息""" - print(f"Aide v{VERSION}") - - -def main(): - """主函数""" - # 解析参数 - args = sys.argv[1:] - - # 无参数或帮助 - if not args or args[0] in ["-h", "--help", "help"]: - show_help() - return 0 - - # 版本信息 - if args[0] in ["-v", "--version", "version"]: - show_version() - return 0 - - # 获取命令 - command = args[0] - - try: - # 命令分发 - if command == "init": - return cmd_init(args[1:]) - elif command == "env": - return cmd_env(args[1:]) - elif command == "config": - return cmd_config(args[1:]) - else: - err( - f"未知命令: {command}", - [ - "可用命令: init, env, config", - "使用 'aide --help' 查看帮助" - ] - ) - return 2 - - except KeyboardInterrupt: - print("\n") - info("操作已取消") - return 130 # 128 + SIGINT(2) - - except Exception as e: - err( - "命令执行失败", - [ - f"原因: {str(e)}", - "使用 'aide --help' 查看帮助" - ] - ) - return 1 - - -if __name__ == "__main__": - sys.exit(main()) -``` - -### 4.3 命令处理函数接口 - -每个命令处理函数应该遵循以下接口: - -```python -def cmd_(args: list[str]) -> int: - """命令处理函数 - - Args: - args: 命令参数列表(不包含命令本身) - - Returns: - 退出码(0 表示成功) - """ - pass -``` - ---- - -## 五、参数解析 - -### 5.1 简单参数解析 - -对于简单的命令,可以手动解析参数: - -```python -def cmd_env(args: list[str]) -> int: - """env 命令处理""" - if not args: - err("缺少子命令", ["使用 'aide env ensure' 检测环境"]) - return 2 - - subcommand = args[0] - - if subcommand == "ensure": - # 检查 --runtime 参数 - runtime_only = "--runtime" in args - return env_ensure(runtime_only=runtime_only) - else: - err(f"未知子命令: {subcommand}", ["可用子命令: ensure"]) - return 2 -``` - -### 5.2 使用 argparse(可选) - -对于复杂的命令,可以使用 argparse: - -```python -import argparse - -def cmd_config(args: list[str]) -> int: - """config 命令处理""" - parser = argparse.ArgumentParser( - prog="aide config", - description="配置管理" - ) - - subparsers = parser.add_subparsers(dest="subcommand") - - # get 子命令 - parser_get = subparsers.add_parser("get", help="获取配置值") - parser_get.add_argument("key", help="配置键") - - # set 子命令 - parser_set = subparsers.add_parser("set", help="设置配置值") - parser_set.add_argument("key", help="配置键") - parser_set.add_argument("value", help="配置值") - - try: - parsed = parser.parse_args(args) - except SystemExit: - return 2 - - if parsed.subcommand == "get": - return config_get(parsed.key) - elif parsed.subcommand == "set": - return config_set(parsed.key, parsed.value) - else: - parser.print_help() - return 2 -``` - ---- - -## 六、错误处理 - -### 6.1 异常捕获 - -```python -def main(): - """主函数""" - try: - # 命令执行 - return execute_command() - - except KeyboardInterrupt: - # Ctrl+C 中断 - print("\n") - info("操作已取消") - return 130 - - except FileNotFoundError as e: - # 文件不存在 - err("文件不存在", [f"路径: {e.filename}"]) - return 5 - - except PermissionError as e: - # 权限错误 - err("权限不足", [f"路径: {e.filename}"]) - return 1 - - except Exception as e: - # 其他错误 - err("命令执行失败", [f"原因: {str(e)}"]) - return 1 -``` - -### 6.2 退出码规范 - -| 退出码 | 含义 | -|-------|------| -| 0 | 成功 | -| 1 | 一般错误 | -| 2 | 参数错误 | -| 3 | 环境错误 | -| 4 | 配置错误 | -| 5 | 文件错误 | -| 130 | 用户中断(Ctrl+C) | - ---- - -## 七、测试 - -### 7.1 入口脚本测试 - -```bash -# 测试 aide.sh -./aide.sh --version -./aide.sh --help -./aide.sh init -./aide.sh env ensure - -# 测试 aide.bat(Windows) -aide.bat --version -aide.bat --help -aide.bat init -aide.bat env ensure -``` - -### 7.2 main.py 测试 - -```python -def test_main_help(capsys): - """测试帮助信息""" - sys.argv = ["aide", "--help"] - result = main() - - assert result == 0 - captured = capsys.readouterr() - assert "用法:" in captured.out - -def test_main_version(capsys): - """测试版本信息""" - sys.argv = ["aide", "--version"] - result = main() - - assert result == 0 - captured = capsys.readouterr() - assert "Aide v" in captured.out - -def test_main_unknown_command(capsys): - """测试未知命令""" - sys.argv = ["aide", "unknown"] - result = main() - - assert result == 2 - captured = capsys.readouterr() - assert "未知命令" in captured.out -``` - ---- - -## 八、安装和分发 - -### 8.1 目录结构 - -``` -aide/ -├── aide.sh # Linux/macOS 入口 -├── aide.bat # Windows 入口 -├── main.py # Python 主程序 -├── core/ # 核心模块 -├── commands/ # 命令实现 -└── utils/ # 工具函数 -``` - -### 8.2 安装脚本(可选) - -```bash -#!/usr/bin/env bash -# install.sh - Aide 安装脚本 - -set -e - -INSTALL_DIR="${HOME}/.local/bin" - -# 创建安装目录 -mkdir -p "$INSTALL_DIR" - -# 复制文件 -cp -r aide "$INSTALL_DIR/" - -# 创建符号链接 -ln -sf "$INSTALL_DIR/aide/aide.sh" "$INSTALL_DIR/aide" - -# 添加到 PATH -if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then - echo "export PATH=\"$INSTALL_DIR:\$PATH\"" >> ~/.bashrc - echo "✓ 已添加到 PATH" - echo " 请运行: source ~/.bashrc" -fi - -echo "✓ Aide 安装完成" -echo " 使用 'aide --help' 查看帮助" -``` - ---- - -## 九、总结 - -### 9.1 核心要点 - -1. 提供跨平台的统一入口 -2. 自动查找合适的 Python 解释器 -3. 统一的命令分发和错误处理 -4. 清晰的帮助和版本信息 - -### 9.2 实现检查清单 - -- [ ] 实现 aide.sh(Linux/macOS) -- [ ] 实现 aide.bat(Windows) -- [ ] 实现 main.py 命令分发 -- [ ] 实现帮助和版本信息 -- [ ] 实现错误处理和退出码 -- [ ] 编写入口脚本测试 -- [ ] 验证跨平台兼容性 -- [ ] 编写安装脚本(可选) - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 diff --git a/aide-program/docs/02-aide-init设计.md b/aide-program/docs/02-aide-init设计.md deleted file mode 100644 index a6886f6..0000000 --- a/aide-program/docs/02-aide-init设计.md +++ /dev/null @@ -1,545 +0,0 @@ -# aide init 设计 - -## 一、命令概述 - -### 1.1 功能定位 - -`aide init` 命令用于初始化项目的 aide 工作环境,创建必要的目录和配置文件。 - -### 1.2 执行时机 - -- 首次在项目中使用 aide 时 -- 配置文件丢失需要重新创建时 -- 作为 `/aide:init` 命令的一部分 - -### 1.3 命令格式 - -```bash -aide init [options] -``` - -**选项**: -- 无(当前版本不需要选项) - ---- - -## 二、功能需求 - -### 2.1 核心功能 - -1. **创建 .aide 目录** - - 检查目录是否存在 - - 不存在则创建 - - 已存在则跳过(幂等性) - -2. **生成配置文件** - - 创建 `config.toml` - - 包含详细注释 - - 使用合理的默认值 - -3. **更新 .gitignore** - - 检查 `.gitignore` 是否存在 - - 添加 `.aide/` 到忽略列表 - - 避免重复添加 - -### 2.2 输出要求 - -**首次初始化**: -``` -✓ 已创建 .aide/ 目录 -✓ 已生成默认配置 -✓ 已添加 .aide/ 到 .gitignore -``` - -**重复初始化**: -``` -⚠ .aide/ 目录已存在 -⚠ 配置文件已存在,跳过生成 -``` - -**部分已存在**: -``` -⚠ .aide/ 目录已存在 -✓ 已生成默认配置 -✓ 已添加 .aide/ 到 .gitignore -``` - ---- - -## 三、实现设计 - -### 3.1 函数接口 - -```python -def cmd_init(args: list[str]) -> int: - """aide init 命令处理 - - Args: - args: 命令参数(当前版本为空) - - Returns: - 退出码(0 表示成功) - """ - pass -``` - -### 3.2 实现流程 - -```python -from pathlib import Path -from core.output import ok, warn, err -from core.config import generate_default_config - -def cmd_init(args: list[str]) -> int: - """aide init 命令实现""" - - # 1. 获取项目根目录(当前工作目录) - project_root = Path.cwd() - aide_dir = project_root / ".aide" - config_path = aide_dir / "config.toml" - gitignore_path = project_root / ".gitignore" - - # 2. 创建 .aide 目录 - if aide_dir.exists(): - warn(".aide/ 目录已存在") - else: - aide_dir.mkdir(parents=True, exist_ok=True) - ok("已创建 .aide/ 目录") - - # 3. 生成配置文件 - if config_path.exists(): - warn("配置文件已存在,跳过生成") - else: - config_content = generate_default_config() - config_path.write_text(config_content, encoding="utf-8") - ok("已生成默认配置") - - # 4. 更新 .gitignore - gitignore_updated = update_gitignore(gitignore_path) - if gitignore_updated: - ok("已添加 .aide/ 到 .gitignore") - - return 0 -``` - -### 3.3 辅助函数 - -#### 3.3.1 更新 .gitignore - -```python -def update_gitignore(gitignore_path: Path) -> bool: - """更新 .gitignore 文件 - - Args: - gitignore_path: .gitignore 文件路径 - - Returns: - 是否进行了更新 - """ - aide_ignore = ".aide/" - - # 读取现有内容 - if gitignore_path.exists(): - content = gitignore_path.read_text(encoding="utf-8") - lines = content.splitlines() - else: - lines = [] - - # 检查是否已存在 - if aide_ignore in lines or ".aide" in lines: - return False - - # 添加到末尾 - if lines and not lines[-1].strip(): - # 最后一行是空行,直接添加 - lines.append(aide_ignore) - else: - # 添加空行和 .aide/ - lines.extend(["", aide_ignore]) - - # 写回文件 - gitignore_path.write_text("\n".join(lines) + "\n", encoding="utf-8") - return True -``` - -#### 3.3.2 生成默认配置 - -```python -def generate_default_config() -> str: - """生成默认配置文件内容 - - Returns: - TOML 格式的配置内容 - """ - return '''# Aide 项目配置文件 -# 由 aide init 自动生成 -# 文档: https://github.com/your-org/aide - -[task] -# 任务原文档路径(prep 阶段使用) -# 可通过 /aide:prep [路径] 覆盖 -source = "task-now.md" - -# 任务细则文档路径(exec 阶段使用) -# 可通过 /aide:exec [路径] 覆盖 -spec = "task-spec.md" - -[env] -# 环境配置 - -[env.python] -# Python 版本要求(语义化版本) -# 格式: ">=3.10" 或 ">=3.10,<4.0" -version = ">=3.10" - -# 虚拟环境路径(相对于项目根目录) -venv = ".venv" - -[env.tools] -# 可选工具配置 - -# 是否需要 uv(Python 包管理器) -uv = false - -# 是否需要 git -git = true - -[flow] -# 流程追踪配置(aide flow 命令使用) - -# 环节列表(不建议修改) -phases = ["flow-design", "impl", "verify", "docs", "finish"] - -# PlantUML 流程图目录 -flowchart_dir = "program_flowchart" - -[decide] -# 待定项确认配置(aide decide 命令使用) - -# Web 服务端口 -port = 3721 - -# 决策记录保存目录 -decisions_dir = ".aide/decisions" - -[output] -# 输出配置 - -# 是否启用颜色输出 -# 可通过环境变量 NO_COLOR 禁用 -color = true - -# 输出语言(当前仅支持 zh-CN) -language = "zh-CN" -''' -``` - ---- - -## 四、错误处理 - -### 4.1 可能的错误 - -| 错误类型 | 处理方式 | 退出码 | -|---------|---------|--------| -| 无写入权限 | 显示错误信息和建议 | 1 | -| 磁盘空间不足 | 显示错误信息 | 1 | -| 配置文件格式错误 | 不应该发生(生成的内容固定) | - | - -### 4.2 错误处理示例 - -```python -def cmd_init(args: list[str]) -> int: - """aide init 命令实现(带错误处理)""" - - try: - project_root = Path.cwd() - aide_dir = project_root / ".aide" - - # 创建目录 - try: - aide_dir.mkdir(parents=True, exist_ok=True) - except PermissionError: - err( - "无法创建 .aide/ 目录", - [ - "原因: 权限不足", - f"位置: {aide_dir}", - "建议: 检查当前目录的写入权限" - ] - ) - return 1 - except OSError as e: - err( - "无法创建 .aide/ 目录", - [ - f"原因: {str(e)}", - f"位置: {aide_dir}" - ] - ) - return 1 - - # 生成配置文件 - config_path = aide_dir / "config.toml" - if not config_path.exists(): - try: - config_content = generate_default_config() - config_path.write_text(config_content, encoding="utf-8") - ok("已生成默认配置") - except OSError as e: - err( - "无法创建配置文件", - [ - f"原因: {str(e)}", - f"位置: {config_path}" - ] - ) - return 1 - else: - warn("配置文件已存在,跳过生成") - - # 更新 .gitignore - gitignore_path = project_root / ".gitignore" - try: - if update_gitignore(gitignore_path): - ok("已添加 .aide/ 到 .gitignore") - except OSError as e: - # .gitignore 更新失败不是致命错误 - warn(f"无法更新 .gitignore: {str(e)}") - - return 0 - - except Exception as e: - err( - "初始化失败", - [ - f"原因: {str(e)}", - "建议: 检查目录权限和磁盘空间" - ] - ) - return 1 -``` - ---- - -## 五、幂等性设计 - -### 5.1 幂等性要求 - -多次执行 `aide init` 应该: -1. 不破坏已有的配置 -2. 不重复添加 .gitignore 条目 -3. 给出清晰的提示信息 - -### 5.2 幂等性测试 - -```python -def test_init_idempotent(): - """测试 aide init 的幂等性""" - - # 第一次执行 - result1 = cmd_init([]) - assert result1 == 0 - - # 验证文件已创建 - assert Path(".aide").exists() - assert Path(".aide/config.toml").exists() - - # 第二次执行 - result2 = cmd_init([]) - assert result2 == 0 - - # 验证配置文件内容未改变 - config1 = Path(".aide/config.toml").read_text() - - # 第三次执行 - result3 = cmd_init([]) - assert result3 == 0 - - config2 = Path(".aide/config.toml").read_text() - assert config1 == config2 -``` - ---- - -## 六、测试用例 - -### 6.1 正常场景 - -```python -def test_init_success(tmp_path, monkeypatch): - """测试正常初始化""" - # 切换到临时目录 - monkeypatch.chdir(tmp_path) - - # 执行初始化 - result = cmd_init([]) - - # 验证退出码 - assert result == 0 - - # 验证目录创建 - assert (tmp_path / ".aide").exists() - assert (tmp_path / ".aide").is_dir() - - # 验证配置文件创建 - config_path = tmp_path / ".aide" / "config.toml" - assert config_path.exists() - assert config_path.is_file() - - # 验证配置文件内容 - content = config_path.read_text() - assert "[task]" in content - assert "[env]" in content - assert "source = " in content - - # 验证 .gitignore 更新 - gitignore_path = tmp_path / ".gitignore" - assert gitignore_path.exists() - gitignore_content = gitignore_path.read_text() - assert ".aide/" in gitignore_content -``` - -### 6.2 重复初始化 - -```python -def test_init_already_exists(tmp_path, monkeypatch, capsys): - """测试重复初始化""" - monkeypatch.chdir(tmp_path) - - # 第一次初始化 - cmd_init([]) - - # 第二次初始化 - result = cmd_init([]) - - # 验证退出码 - assert result == 0 - - # 验证输出包含警告 - captured = capsys.readouterr() - assert "已存在" in captured.out -``` - -### 6.3 权限错误 - -```python -def test_init_permission_error(tmp_path, monkeypatch, capsys): - """测试权限错误""" - monkeypatch.chdir(tmp_path) - - # 创建只读目录 - tmp_path.chmod(0o444) - - # 执行初始化 - result = cmd_init([]) - - # 恢复权限 - tmp_path.chmod(0o755) - - # 验证退出码 - assert result == 1 - - # 验证错误信息 - captured = capsys.readouterr() - assert "权限" in captured.out -``` - -### 6.4 .gitignore 已存在 - -```python -def test_init_gitignore_exists(tmp_path, monkeypatch): - """测试 .gitignore 已存在的情况""" - monkeypatch.chdir(tmp_path) - - # 创建已有的 .gitignore - gitignore_path = tmp_path / ".gitignore" - gitignore_path.write_text("*.pyc\n__pycache__/\n") - - # 执行初始化 - result = cmd_init([]) - - # 验证退出码 - assert result == 0 - - # 验证 .gitignore 内容 - content = gitignore_path.read_text() - assert "*.pyc" in content - assert ".aide/" in content - - # 验证不重复添加 - lines = content.splitlines() - aide_count = sum(1 for line in lines if ".aide" in line) - assert aide_count == 1 -``` - ---- - -## 七、集成测试 - -### 7.1 完整工作流测试 - -```python -def test_init_workflow(tmp_path, monkeypatch): - """测试完整的初始化工作流""" - monkeypatch.chdir(tmp_path) - - # 1. 执行初始化 - result = cmd_init([]) - assert result == 0 - - # 2. 验证可以读取配置 - from core.config import Config - config = Config(tmp_path) - config.load() - - # 3. 验证配置值 - assert config.get("task.source") == "task-now.md" - assert config.get("task.spec") == "task-spec.md" - assert config.get("env.python.version") == ">=3.10" - - # 4. 验证可以修改配置 - config.set("task.source", "new-task.md") - assert config.get("task.source") == "new-task.md" -``` - ---- - -## 八、性能要求 - -### 8.1 执行时间 - -- 正常情况:< 100ms -- 包含 .gitignore 更新:< 200ms - -### 8.2 资源占用 - -- 内存:< 10MB -- 磁盘空间:< 10KB(配置文件) - ---- - -## 九、总结 - -### 9.1 核心要点 - -1. 创建 .aide 目录和配置文件 -2. 自动更新 .gitignore -3. 幂等性设计,可重复执行 -4. 完善的错误处理 - -### 9.2 实现检查清单 - -- [ ] 实现 cmd_init 函数 -- [ ] 实现 generate_default_config 函数 -- [ ] 实现 update_gitignore 函数 -- [ ] 实现错误处理 -- [ ] 编写单元测试 -- [ ] 编写集成测试 -- [ ] 验证幂等性 -- [ ] 性能测试 - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 diff --git a/aide-program/docs/03-aide-env设计.md b/aide-program/docs/03-aide-env设计.md deleted file mode 100644 index 1fefd97..0000000 --- a/aide-program/docs/03-aide-env设计.md +++ /dev/null @@ -1,599 +0,0 @@ -# aide env 设计 - -## 一、命令概述 - -### 1.1 功能定位 - -`aide env` 命令用于检测和修复项目开发环境,确保所有必需的工具和依赖都已正确安装。 - -### 1.2 执行时机 - -- `/aide:init` 命令中调用(两次) -- 用户手动检查环境时 -- 环境配置变更后 - -### 1.3 命令格式 - -```bash -aide env ensure [--runtime] -``` - -**选项**: -- `--runtime`:仅检查 aide 运行时环境(不依赖配置文件) - ---- - -## 二、功能需求 - -### 2.1 aide env ensure --runtime - -**用途**:检查 aide 程序自身运行所需的环境 - -**检查项**: -1. Python 版本(>= 3.10) -2. 必需的 Python 库(tomli/tomllib, tomli-w) - -**特点**: -- 不读取项目配置文件 -- 在 `aide init` 之前执行 -- 失败时给出明确的安装建议 - -**输出示例**: - -成功: -``` -✓ 环境就绪 (python:3.12) -``` - -失败: -``` -✗ Python 版本不满足要求 (需要 >=3.10, 当前 3.8) - 建议: 安装 Python 3.10+ 或使用 pyenv 管理版本 - 文档: https://www.python.org/downloads/ -``` - -### 2.2 aide env ensure - -**用途**:检查项目开发环境 - -**检查项**: -1. Python 版本(根据配置文件) -2. 虚拟环境(根据配置文件) -3. 可选工具(git, uv 等,根据配置文件) - -**特点**: -- 读取 `.aide/config.toml` -- 在 `aide init` 之后执行 -- 可以自动修复部分问题 - -**输出示例**: - -成功(无问题): -``` -✓ 环境就绪 (python:3.12, git:2.40.0) -``` - -成功(自动修复): -``` -⚠ 已修复: 创建虚拟环境 .venv -✓ 环境就绪 (python:3.12) -``` - -失败(无法修复): -``` -✗ Python 版本不满足要求 (需要 >=3.11, 当前 3.10) - 建议: 升级 Python 到 3.11+ 或修改配置文件 - 配置: .aide/config.toml (env.python.version) -``` - ---- - -## 三、实现设计 - -### 3.1 函数接口 - -```python -def cmd_env(args: list[str]) -> int: - """aide env 命令处理 - - Args: - args: 命令参数 - - Returns: - 退出码(0 表示成功) - """ - pass - -def env_ensure(runtime_only: bool = False) -> int: - """环境检测和修复 - - Args: - runtime_only: 是否仅检查运行时环境 - - Returns: - 退出码(0 表示成功) - """ - pass -``` - -### 3.2 实现流程 - -#### 3.2.1 aide env ensure --runtime - -```python -import sys -import subprocess -from pathlib import Path -from core.output import ok, err - -def env_ensure_runtime() -> int: - """检查 aide 运行时环境""" - - # 1. 检查 Python 版本 - python_version = sys.version_info - if python_version.major < 3 or (python_version.major == 3 and python_version.minor < 10): - err( - f"Python 版本不满足要求 (需要 >=3.10, 当前 {python_version.major}.{python_version.minor})", - [ - "建议: 安装 Python 3.10+ 或使用 pyenv 管理版本", - "文档: https://www.python.org/downloads/" - ] - ) - return 3 - - # 2. 检查必需的库 - try: - # Python 3.11+ 内置 tomllib - if python_version.minor >= 11: - import tomllib - else: - import tomli as tomllib - - import tomli_w - except ImportError as e: - err( - f"缺少必需的 Python 库: {e.name}", - [ - "建议: 运行 'pip install tomli tomli-w'", - "或使用 uv: 'uv pip install tomli tomli-w'" - ] - ) - return 3 - - # 3. 输出成功信息 - version_str = f"{python_version.major}.{python_version.minor}.{python_version.micro}" - ok(f"环境就绪 (python:{version_str})") - - return 0 -``` - -#### 3.2.2 aide env ensure - -```python -from core.config import Config -from core.output import ok, warn, err - -def env_ensure_project() -> int: - """检查项目开发环境""" - - # 1. 加载配置 - try: - config = Config(Path.cwd()) - config.load() - except FileNotFoundError: - err( - "配置文件不存在", - [ - "位置: .aide/config.toml", - "建议: 运行 'aide init' 创建配置文件" - ] - ) - return 4 - except Exception as e: - err( - "配置文件读取失败", - [ - f"原因: {str(e)}", - "建议: 检查配置文件格式" - ] - ) - return 4 - - # 2. 检查 Python 版本 - required_version = config.get("env.python.version", ">=3.10") - if not check_python_version(required_version): - err( - f"Python 版本不满足要求 (需要 {required_version}, 当前 {get_python_version()})", - [ - "建议: 升级 Python 或修改配置文件", - "配置: .aide/config.toml (env.python.version)" - ] - ) - return 3 - - # 3. 检查虚拟环境 - venv_path = config.get("env.python.venv", ".venv") - venv_result = check_venv(venv_path) - - if venv_result == "missing": - # 尝试创建虚拟环境 - if create_venv(venv_path): - warn(f"已修复: 创建虚拟环境 {venv_path}") - else: - err( - f"虚拟环境不存在且无法创建 ({venv_path})", - [ - "建议: 手动创建虚拟环境", - f"命令: python3 -m venv {venv_path}" - ] - ) - return 3 - - # 4. 检查可选工具 - tools_info = [] - - # 检查 git - if config.get("env.tools.git", True): - git_version = get_tool_version("git") - if git_version: - tools_info.append(f"git:{git_version}") - else: - warn("git 未安装(可选)") - - # 检查 uv - if config.get("env.tools.uv", False): - uv_version = get_tool_version("uv") - if uv_version: - tools_info.append(f"uv:{uv_version}") - else: - warn("uv 未安装(可选)") - - # 5. 输出成功信息 - python_version = get_python_version() - info_parts = [f"python:{python_version}"] + tools_info - ok(f"环境就绪 ({', '.join(info_parts)})") - - return 0 -``` - -### 3.3 辅助函数 - -#### 3.3.1 版本检查 - -```python -import re -from packaging import version - -def check_python_version(requirement: str) -> bool: - """检查 Python 版本是否满足要求 - - Args: - requirement: 版本要求(如 ">=3.10") - - Returns: - 是否满足要求 - """ - current = get_python_version() - - # 解析要求 - match = re.match(r'(>=|<=|>|<|==)?(\d+\.\d+(?:\.\d+)?)', requirement) - if not match: - return True # 无法解析,假设满足 - - operator, required = match.groups() - operator = operator or "==" - - # 比较版本 - try: - current_ver = version.parse(current) - required_ver = version.parse(required) - - if operator == ">=": - return current_ver >= required_ver - elif operator == "<=": - return current_ver <= required_ver - elif operator == ">": - return current_ver > required_ver - elif operator == "<": - return current_ver < required_ver - elif operator == "==": - return current_ver == required_ver - except Exception: - return True - - return True - -def get_python_version() -> str: - """获取当前 Python 版本 - - Returns: - 版本字符串(如 "3.12.0") - """ - v = sys.version_info - return f"{v.major}.{v.minor}.{v.micro}" -``` - -#### 3.3.2 虚拟环境检查 - -```python -import subprocess - -def check_venv(venv_path: str) -> str: - """检查虚拟环境状态 - - Args: - venv_path: 虚拟环境路径 - - Returns: - 状态:'ok', 'missing', 'invalid' - """ - venv_dir = Path(venv_path) - - if not venv_dir.exists(): - return "missing" - - # 检查是否是有效的虚拟环境 - if sys.platform == "win32": - python_exe = venv_dir / "Scripts" / "python.exe" - else: - python_exe = venv_dir / "bin" / "python" - - if python_exe.exists(): - return "ok" - else: - return "invalid" - -def create_venv(venv_path: str) -> bool: - """创建虚拟环境 - - Args: - venv_path: 虚拟环境路径 - - Returns: - 是否创建成功 - """ - try: - subprocess.run( - [sys.executable, "-m", "venv", venv_path], - check=True, - capture_output=True, - text=True - ) - return True - except subprocess.CalledProcessError: - return False - except Exception: - return False -``` - -#### 3.3.3 工具版本检查 - -```python -def get_tool_version(tool: str) -> str | None: - """获取工具版本 - - Args: - tool: 工具名称(如 "git", "uv") - - Returns: - 版本字符串,未安装则返回 None - """ - try: - result = subprocess.run( - [tool, "--version"], - capture_output=True, - text=True, - timeout=5 - ) - - if result.returncode == 0: - # 解析版本号 - output = result.stdout.strip() - match = re.search(r'(\d+\.\d+\.\d+)', output) - if match: - return match.group(1) - return "unknown" - except (subprocess.TimeoutExpired, FileNotFoundError): - pass - - return None -``` - ---- - -## 四、错误处理 - -### 4.1 错误分类 - -| 错误类型 | 退出码 | 处理方式 | -|---------|--------|---------| -| Python 版本不满足 | 3 | 显示当前版本和要求,给出升级建议 | -| 配置文件不存在 | 4 | 提示运行 aide init | -| 配置文件格式错误 | 4 | 显示错误位置和原因 | -| 虚拟环境无法创建 | 3 | 显示创建命令 | -| 必需工具未安装 | 3 | 显示安装建议 | - -### 4.2 错误恢复 - -```python -def env_ensure_with_retry(runtime_only: bool = False, max_retries: int = 3) -> int: - """带重试的环境检测 - - Args: - runtime_only: 是否仅检查运行时 - max_retries: 最大重试次数 - - Returns: - 退出码 - """ - for attempt in range(max_retries): - result = env_ensure(runtime_only) - - if result == 0: - return 0 - - if attempt < max_retries - 1: - info(f"重试 ({attempt + 1}/{max_retries})...") - - return result -``` - ---- - -## 五、测试用例 - -### 5.1 runtime 模式测试 - -```python -def test_env_ensure_runtime_success(): - """测试运行时环境检测成功""" - result = env_ensure_runtime() - assert result == 0 - -def test_env_ensure_runtime_old_python(monkeypatch): - """测试 Python 版本过低""" - # 模拟 Python 3.8 - monkeypatch.setattr(sys, "version_info", (3, 8, 0, "final", 0)) - - result = env_ensure_runtime() - assert result == 3 - -def test_env_ensure_runtime_missing_lib(monkeypatch): - """测试缺少必需库""" - # 模拟 import 失败 - def mock_import(name, *args, **kwargs): - if name in ["tomli", "tomllib"]: - raise ImportError(f"No module named '{name}'") - return __import__(name, *args, **kwargs) - - monkeypatch.setattr("builtins.__import__", mock_import) - - result = env_ensure_runtime() - assert result == 3 -``` - -### 5.2 项目环境测试 - -```python -def test_env_ensure_project_success(tmp_path, monkeypatch): - """测试项目环境检测成功""" - monkeypatch.chdir(tmp_path) - - # 创建配置文件 - cmd_init([]) - - # 检测环境 - result = env_ensure_project() - assert result == 0 - -def test_env_ensure_project_no_config(tmp_path, monkeypatch): - """测试配置文件不存在""" - monkeypatch.chdir(tmp_path) - - result = env_ensure_project() - assert result == 4 - -def test_env_ensure_project_create_venv(tmp_path, monkeypatch): - """测试自动创建虚拟环境""" - monkeypatch.chdir(tmp_path) - - # 创建配置文件 - cmd_init([]) - - # 确保虚拟环境不存在 - venv_path = tmp_path / ".venv" - if venv_path.exists(): - shutil.rmtree(venv_path) - - # 检测环境(应该自动创建虚拟环境) - result = env_ensure_project() - assert result == 0 - assert venv_path.exists() -``` - -### 5.3 版本检查测试 - -```python -def test_check_python_version(): - """测试 Python 版本检查""" - # 测试各种版本要求 - assert check_python_version(">=3.10") == True # 假设当前是 3.12 - assert check_python_version(">=3.15") == False - assert check_python_version("==3.12") == True - assert check_python_version("<4.0") == True - -def test_get_python_version(): - """测试获取 Python 版本""" - version = get_python_version() - assert re.match(r'\d+\.\d+\.\d+', version) -``` - ---- - -## 六、性能要求 - -### 6.1 执行时间 - -- `--runtime` 模式:< 100ms -- 项目环境检测(无修复):< 500ms -- 项目环境检测(创建虚拟环境):< 10s - -### 6.2 资源占用 - -- 内存:< 50MB -- CPU:低(主要是 I/O 操作) - ---- - -## 七、集成测试 - -### 7.1 完整工作流 - -```python -def test_env_workflow(tmp_path, monkeypatch): - """测试完整的环境检测工作流""" - monkeypatch.chdir(tmp_path) - - # 1. 检查运行时环境 - result = env_ensure_runtime() - assert result == 0 - - # 2. 初始化项目 - result = cmd_init([]) - assert result == 0 - - # 3. 检查项目环境 - result = env_ensure_project() - assert result == 0 - - # 4. 验证虚拟环境已创建 - assert (tmp_path / ".venv").exists() -``` - ---- - -## 八、总结 - -### 8.1 核心要点 - -1. 两种模式:runtime 和 project -2. 自动修复部分问题(如创建虚拟环境) -3. 清晰的错误信息和建议 -4. 完善的版本检查逻辑 - -### 8.2 实现检查清单 - -- [ ] 实现 cmd_env 函数 -- [ ] 实现 env_ensure_runtime 函数 -- [ ] 实现 env_ensure_project 函数 -- [ ] 实现版本检查函数 -- [ ] 实现虚拟环境检查和创建 -- [ ] 实现工具版本检查 -- [ ] 编写单元测试 -- [ ] 编写集成测试 -- [ ] 性能测试 - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 diff --git a/aide-program/docs/04-aide-config设计.md b/aide-program/docs/04-aide-config设计.md deleted file mode 100644 index 3620ac4..0000000 --- a/aide-program/docs/04-aide-config设计.md +++ /dev/null @@ -1,745 +0,0 @@ -# aide config 设计 - -## 一、命令概述 - -### 1.1 功能定位 - -`aide config` 命令用于读取和修改项目配置文件,提供命令行方式访问配置。 - -### 1.2 执行时机 - -- 用户需要查看配置值时 -- 用户需要修改配置值时 -- Commands 中需要获取配置时(如 prep/exec 的默认文档路径) - -### 1.3 命令格式 - -```bash -aide config get -aide config set -``` - -**参数**: -- ``:配置键,支持点号分隔(如 `task.source`) -- ``:配置值(仅 set 命令需要) - ---- - -## 二、功能需求 - -### 2.1 aide config get - -**功能**:获取配置值 - -**输出格式**: - -单个值: -``` -task.source = "task-now.md" -``` - -数组值: -``` -flow.phases = ["flow-design", "impl", "verify", "docs", "finish"] -``` - -布尔值: -``` -env.tools.git = true -``` - -**错误处理**: - -配置键不存在: -``` -✗ 配置键不存在: invalid.key - 可用的配置键: task.source, task.spec, env.python.version -``` - -配置文件不存在: -``` -✗ 配置文件不存在 - 位置: .aide/config.toml - 建议: 运行 'aide init' 创建配置文件 -``` - -### 2.2 aide config set - -**功能**:设置配置值 - -**输出**: - -成功时无输出(静默原则) - -**错误处理**: - -配置键不存在: -``` -✗ 配置键不存在: invalid.key - 可用的配置键: task.source, task.spec, env.python.version -``` - -配置值类型错误: -``` -✗ 配置值类型错误 - 键: env.tools.git - 期望类型: boolean - 实际值: "yes" - 建议: 使用 true 或 false -``` - ---- - -## 三、实现设计 - -### 3.1 函数接口 - -```python -def cmd_config(args: list[str]) -> int: - """aide config 命令处理 - - Args: - args: 命令参数 - - Returns: - 退出码(0 表示成功) - """ - pass - -def config_get(key: str) -> int: - """获取配置值 - - Args: - key: 配置键 - - Returns: - 退出码 - """ - pass - -def config_set(key: str, value: str) -> int: - """设置配置值 - - Args: - key: 配置键 - value: 配置值(字符串形式) - - Returns: - 退出码 - """ - pass -``` - -### 3.2 实现流程 - -#### 3.2.1 cmd_config - -```python -from core.output import err - -def cmd_config(args: list[str]) -> int: - """aide config 命令处理""" - - if not args: - err( - "缺少子命令", - [ - "用法: aide config get ", - " aide config set " - ] - ) - return 2 - - subcommand = args[0] - - if subcommand == "get": - if len(args) < 2: - err("缺少参数: key") - return 2 - return config_get(args[1]) - - elif subcommand == "set": - if len(args) < 3: - err("缺少参数: key 或 value") - return 2 - return config_set(args[1], args[2]) - - else: - err( - f"未知子命令: {subcommand}", - ["可用子命令: get, set"] - ) - return 2 -``` - -#### 3.2.2 config_get - -```python -from pathlib import Path -from core.config import Config -from core.output import err - -def config_get(key: str) -> int: - """获取配置值""" - - try: - # 加载配置 - config = Config(Path.cwd()) - config.load() - - # 获取值 - value = config.get(key) - - if value is None: - # 配置键不存在 - available_keys = get_available_keys(config._config) - err( - f"配置键不存在: {key}", - [f"可用的配置键: {', '.join(available_keys)}"] - ) - return 4 - - # 格式化输出 - formatted_value = format_config_value(value) - print(f"{key} = {formatted_value}") - - return 0 - - except FileNotFoundError: - err( - "配置文件不存在", - [ - "位置: .aide/config.toml", - "建议: 运行 'aide init' 创建配置文件" - ] - ) - return 4 - - except Exception as e: - err( - "配置读取失败", - [f"原因: {str(e)}"] - ) - return 4 -``` - -#### 3.2.3 config_set - -```python -def config_set(key: str, value_str: str) -> int: - """设置配置值""" - - try: - # 加载配置 - config = Config(Path.cwd()) - config.load() - - # 验证配置键是否存在 - if not is_valid_config_key(key): - available_keys = get_available_keys(config._config) - err( - f"配置键不存在: {key}", - [f"可用的配置键: {', '.join(available_keys)}"] - ) - return 4 - - # 解析值 - try: - value = parse_config_value(key, value_str, config._config) - except ValueError as e: - err( - "配置值类型错误", - [ - f"键: {key}", - f"原因: {str(e)}" - ] - ) - return 4 - - # 设置值 - config.set(key, value) - - # 成功时无输出(静默原则) - return 0 - - except FileNotFoundError: - err( - "配置文件不存在", - [ - "位置: .aide/config.toml", - "建议: 运行 'aide init' 创建配置文件" - ] - ) - return 4 - - except Exception as e: - err( - "配置写入失败", - [f"原因: {str(e)}"] - ) - return 4 -``` - -### 3.3 辅助函数 - -#### 3.3.1 格式化配置值 - -```python -import json - -def format_config_value(value) -> str: - """格式化配置值用于输出 - - Args: - value: 配置值 - - Returns: - 格式化后的字符串 - """ - if isinstance(value, str): - return f'"{value}"' - elif isinstance(value, bool): - return "true" if value else "false" - elif isinstance(value, (list, dict)): - return json.dumps(value, ensure_ascii=False) - else: - return str(value) -``` - -#### 3.3.2 解析配置值 - -```python -def parse_config_value(key: str, value_str: str, config: dict): - """解析配置值 - - Args: - key: 配置键 - value_str: 值字符串 - config: 当前配置(用于推断类型) - - Returns: - 解析后的值 - - Raises: - ValueError: 值类型错误 - """ - # 获取当前值以推断类型 - current_value = get_config_value(config, key) - - if current_value is None: - # 新键,尝试自动推断类型 - return auto_parse_value(value_str) - - # 根据当前值的类型解析 - if isinstance(current_value, bool): - return parse_bool(value_str) - elif isinstance(current_value, int): - return parse_int(value_str) - elif isinstance(current_value, float): - return parse_float(value_str) - elif isinstance(current_value, list): - return parse_list(value_str) - elif isinstance(current_value, dict): - return parse_dict(value_str) - else: - # 字符串 - return value_str - -def parse_bool(value_str: str) -> bool: - """解析布尔值""" - lower = value_str.lower() - if lower in ["true", "yes", "1"]: - return True - elif lower in ["false", "no", "0"]: - return False - else: - raise ValueError(f"无效的布尔值: {value_str},使用 true 或 false") - -def parse_int(value_str: str) -> int: - """解析整数""" - try: - return int(value_str) - except ValueError: - raise ValueError(f"无效的整数: {value_str}") - -def parse_float(value_str: str) -> float: - """解析浮点数""" - try: - return float(value_str) - except ValueError: - raise ValueError(f"无效的浮点数: {value_str}") - -def parse_list(value_str: str) -> list: - """解析列表(JSON 格式)""" - try: - value = json.loads(value_str) - if not isinstance(value, list): - raise ValueError("不是列表") - return value - except json.JSONDecodeError: - raise ValueError(f"无效的列表格式: {value_str},使用 JSON 格式") - -def parse_dict(value_str: str) -> dict: - """解析字典(JSON 格式)""" - try: - value = json.loads(value_str) - if not isinstance(value, dict): - raise ValueError("不是字典") - return value - except json.JSONDecodeError: - raise ValueError(f"无效的字典格式: {value_str},使用 JSON 格式") - -def auto_parse_value(value_str: str): - """自动推断并解析值""" - # 尝试 JSON - try: - return json.loads(value_str) - except json.JSONDecodeError: - pass - - # 尝试布尔值 - if value_str.lower() in ["true", "false", "yes", "no"]: - return parse_bool(value_str) - - # 尝试数字 - try: - if "." in value_str: - return float(value_str) - else: - return int(value_str) - except ValueError: - pass - - # 默认为字符串 - return value_str -``` - -#### 3.3.3 获取可用配置键 - -```python -def get_available_keys(config: dict, prefix: str = "") -> list[str]: - """获取所有可用的配置键 - - Args: - config: 配置字典 - prefix: 键前缀 - - Returns: - 配置键列表 - """ - keys = [] - - for key, value in config.items(): - full_key = f"{prefix}{key}" if prefix else key - - if isinstance(value, dict): - # 递归获取嵌套键 - keys.extend(get_available_keys(value, f"{full_key}.")) - else: - keys.append(full_key) - - return sorted(keys) - -def is_valid_config_key(key: str) -> bool: - """验证配置键是否有效 - - Args: - key: 配置键 - - Returns: - 是否有效 - """ - # 定义允许的配置键 - valid_keys = [ - "task.source", - "task.spec", - "env.python.version", - "env.python.venv", - "env.tools.uv", - "env.tools.git", - "flow.phases", - "flow.flowchart_dir", - "decide.port", - "decide.decisions_dir", - "output.color", - "output.language" - ] - - return key in valid_keys -``` - ---- - -## 四、错误处理 - -### 4.1 错误分类 - -| 错误类型 | 退出码 | 处理方式 | -|---------|--------|---------| -| 缺少参数 | 2 | 显示用法 | -| 配置文件不存在 | 4 | 提示运行 aide init | -| 配置键不存在 | 4 | 显示可用的键 | -| 配置值类型错误 | 4 | 显示期望类型和建议 | -| 配置文件格式错误 | 4 | 显示错误位置 | - -### 4.2 类型验证 - -```python -def validate_config_value(key: str, value) -> list[str]: - """验证配置值 - - Args: - key: 配置键 - value: 配置值 - - Returns: - 错误列表(空列表表示无错误) - """ - errors = [] - - # 验证特定键的值 - if key == "env.python.version": - if not isinstance(value, str): - errors.append("env.python.version 必须是字符串") - elif not is_valid_version_spec(value): - errors.append(f"无效的版本格式: {value}") - - elif key == "env.python.venv": - if not isinstance(value, str): - errors.append("env.python.venv 必须是字符串") - - elif key in ["env.tools.uv", "env.tools.git", "output.color"]: - if not isinstance(value, bool): - errors.append(f"{key} 必须是布尔值") - - elif key == "flow.phases": - if not isinstance(value, list): - errors.append("flow.phases 必须是数组") - elif not all(isinstance(p, str) for p in value): - errors.append("flow.phases 的元素必须是字符串") - - elif key == "decide.port": - if not isinstance(value, int): - errors.append("decide.port 必须是整数") - elif not (1024 <= value <= 65535): - errors.append("decide.port 必须在 1024-65535 之间") - - return errors -``` - ---- - -## 五、测试用例 - -### 5.1 config get 测试 - -```python -def test_config_get_success(tmp_path, monkeypatch, capsys): - """测试获取配置成功""" - monkeypatch.chdir(tmp_path) - - # 初始化配置 - cmd_init([]) - - # 获取配置 - result = config_get("task.source") - - # 验证退出码 - assert result == 0 - - # 验证输出 - captured = capsys.readouterr() - assert 'task.source = "task-now.md"' in captured.out - -def test_config_get_not_found(tmp_path, monkeypatch, capsys): - """测试配置键不存在""" - monkeypatch.chdir(tmp_path) - - # 初始化配置 - cmd_init([]) - - # 获取不存在的配置 - result = config_get("invalid.key") - - # 验证退出码 - assert result == 4 - - # 验证输出 - captured = capsys.readouterr() - assert "配置键不存在" in captured.out - -def test_config_get_no_config(tmp_path, monkeypatch, capsys): - """测试配置文件不存在""" - monkeypatch.chdir(tmp_path) - - # 获取配置(未初始化) - result = config_get("task.source") - - # 验证退出码 - assert result == 4 - - # 验证输出 - captured = capsys.readouterr() - assert "配置文件不存在" in captured.out -``` - -### 5.2 config set 测试 - -```python -def test_config_set_success(tmp_path, monkeypatch): - """测试设置配置成功""" - monkeypatch.chdir(tmp_path) - - # 初始化配置 - cmd_init([]) - - # 设置配置 - result = config_set("task.source", "new-task.md") - - # 验证退出码 - assert result == 0 - - # 验证配置已更新 - config = Config(tmp_path) - config.load() - assert config.get("task.source") == "new-task.md" - -def test_config_set_bool(tmp_path, monkeypatch): - """测试设置布尔值""" - monkeypatch.chdir(tmp_path) - - # 初始化配置 - cmd_init([]) - - # 设置布尔值 - result = config_set("env.tools.uv", "true") - assert result == 0 - - # 验证 - config = Config(tmp_path) - config.load() - assert config.get("env.tools.uv") == True - -def test_config_set_invalid_type(tmp_path, monkeypatch, capsys): - """测试设置错误类型""" - monkeypatch.chdir(tmp_path) - - # 初始化配置 - cmd_init([]) - - # 设置错误类型 - result = config_set("env.tools.git", "yes") - - # 验证退出码 - assert result == 4 - - # 验证输出 - captured = capsys.readouterr() - assert "类型错误" in captured.out -``` - -### 5.3 值解析测试 - -```python -def test_parse_bool(): - """测试布尔值解析""" - assert parse_bool("true") == True - assert parse_bool("false") == False - assert parse_bool("yes") == True - assert parse_bool("no") == False - - with pytest.raises(ValueError): - parse_bool("invalid") - -def test_parse_list(): - """测试列表解析""" - result = parse_list('["a", "b", "c"]') - assert result == ["a", "b", "c"] - - with pytest.raises(ValueError): - parse_list("not a list") - -def test_auto_parse_value(): - """测试自动解析""" - assert auto_parse_value("true") == True - assert auto_parse_value("123") == 123 - assert auto_parse_value("3.14") == 3.14 - assert auto_parse_value('["a"]') == ["a"] - assert auto_parse_value("text") == "text" -``` - ---- - -## 六、使用示例 - -### 6.1 查看配置 - -```bash -# 查看任务文档路径 -aide config get task.source - -# 查看 Python 版本要求 -aide config get env.python.version - -# 查看流程环节列表 -aide config get flow.phases -``` - -### 6.2 修改配置 - -```bash -# 修改任务文档路径 -aide config set task.source "my-task.md" - -# 修改 Python 版本要求 -aide config set env.python.version ">=3.11" - -# 启用 uv -aide config set env.tools.uv true - -# 修改端口 -aide config set decide.port 8080 -``` - ---- - -## 七、性能要求 - -### 7.1 执行时间 - -- config get:< 100ms -- config set:< 200ms - -### 7.2 资源占用 - -- 内存:< 20MB -- 磁盘 I/O:最小化 - ---- - -## 八、总结 - -### 8.1 核心要点 - -1. 支持 get 和 set 两个子命令 -2. 点号分隔的键访问 -3. 自动类型推断和验证 -4. 静默原则(set 成功时无输出) -5. 清晰的错误信息 - -### 8.2 实现检查清单 - -- [ ] 实现 cmd_config 函数 -- [ ] 实现 config_get 函数 -- [ ] 实现 config_set 函数 -- [ ] 实现值格式化函数 -- [ ] 实现值解析函数 -- [ ] 实现类型验证 -- [ ] 编写单元测试 -- [ ] 编写集成测试 -- [ ] 性能测试 - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 diff --git a/aide-program/docs/05-配置文件规范.md b/aide-program/docs/05-配置文件规范.md deleted file mode 100644 index 01ad8c5..0000000 --- a/aide-program/docs/05-配置文件规范.md +++ /dev/null @@ -1,698 +0,0 @@ -# 配置文件规范 - -## 一、概述 - -### 1.1 配置文件定位 - -- **文件路径**:`.aide/config.toml` -- **格式**:TOML(Tom's Obvious, Minimal Language) -- **特点**:自文档化,包含详细注释 -- **创建时机**:`aide init` 命令执行时 - -### 1.2 设计原则 - -1. **自文档化**:每个配置项都有注释说明 -2. **合理默认值**:开箱即用,无需修改 -3. **类型安全**:明确的数据类型 -4. **向后兼容**:新版本保持旧配置可用 - ---- - -## 二、配置文件结构 - -### 2.1 完整示例 - -```toml -# Aide 项目配置文件 -# 由 aide init 自动生成 -# 版本: 1.0 - -[task] -# 任务原文档路径(prep 阶段使用) -source = "task-now.md" - -# 任务细则文档路径(exec 阶段使用) -spec = "task-spec.md" - -[env] -# 环境配置 - -[env.python] -# Python 版本要求(语义化版本) -version = ">=3.10" - -# 虚拟环境路径(相对于项目根目录) -venv = ".venv" - -[env.tools] -# 可选工具配置 - -# 是否需要 uv(Python 包管理器) -uv = false - -# 是否需要 git -git = true - -[flow] -# 流程追踪配置(后续实现) - -# 环节列表 -phases = ["flow-design", "impl", "verify", "docs", "finish"] - -# PlantUML 流程图目录 -flowchart_dir = "program_flowchart" - -[decide] -# 待定项确认配置(后续实现) - -# Web 服务端口 -port = 3721 - -# 决策记录保存目录 -decisions_dir = ".aide/decisions" - -[output] -# 输出配置 - -# 是否启用颜色输出 -color = true - -# 输出语言(当前仅支持 zh-CN) -language = "zh-CN" -``` - -### 2.2 配置项说明 - -#### 2.2.1 [task] 任务配置 - -| 键 | 类型 | 默认值 | 说明 | -|---|------|--------|------| -| `source` | string | `"task-now.md"` | 任务原文档路径 | -| `spec` | string | `"task-spec.md"` | 任务细则文档路径 | - -**使用场景**: -- `prep` 命令未传入参数时,使用 `task.source` -- `exec` 命令未传入参数时,使用 `task.spec` - -#### 2.2.2 [env.python] Python 环境配置 - -| 键 | 类型 | 默认值 | 说明 | -|---|------|--------|------| -| `version` | string | `">=3.10"` | Python 版本要求 | -| `venv` | string | `".venv"` | 虚拟环境路径 | - -**版本格式**: -- `">=3.10"` - 大于等于 3.10 -- `">=3.10,<4.0"` - 3.10 到 4.0 之间 -- `"3.12"` - 精确匹配 3.12 - -#### 2.2.3 [env.tools] 工具配置 - -| 键 | 类型 | 默认值 | 说明 | -|---|------|--------|------| -| `uv` | boolean | `false` | 是否需要 uv | -| `git` | boolean | `true` | 是否需要 git | - -#### 2.2.4 [flow] 流程配置(后续实现) - -| 键 | 类型 | 默认值 | 说明 | -|---|------|--------|------| -| `phases` | array | `["flow-design", "impl", "verify", "docs", "finish"]` | 环节列表 | -| `flowchart_dir` | string | `"program_flowchart"` | 流程图目录 | - -#### 2.2.5 [decide] 待定项配置(后续实现) - -| 键 | 类型 | 默认值 | 说明 | -|---|------|--------|------| -| `port` | integer | `3721` | Web 服务端口 | -| `decisions_dir` | string | `".aide/decisions"` | 决策记录目录 | - -#### 2.2.6 [output] 输出配置 - -| 键 | 类型 | 默认值 | 说明 | -|---|------|--------|------| -| `color` | boolean | `true` | 是否启用颜色 | -| `language` | string | `"zh-CN"` | 输出语言 | - ---- - -## 三、配置文件操作 - -### 3.1 读取配置 - -**Python 实现示例**: - -```python -import tomllib # Python 3.11+ -# 或 -import tomli # Python 3.10 - -from pathlib import Path - -def load_config(project_root: Path) -> dict: - """加载配置文件 - - Args: - project_root: 项目根目录 - - Returns: - 配置字典 - - Raises: - FileNotFoundError: 配置文件不存在 - tomllib.TOMLDecodeError: 配置文件格式错误 - """ - config_path = project_root / ".aide" / "config.toml" - - if not config_path.exists(): - raise FileNotFoundError(f"配置文件不存在: {config_path}") - - with open(config_path, "rb") as f: - return tomllib.load(f) - -def get_config_value(config: dict, key: str, default=None): - """获取配置值(支持点号分隔的键) - - Args: - config: 配置字典 - key: 配置键(如 "task.source") - default: 默认值 - - Returns: - 配置值 - - Example: - >>> config = {"task": {"source": "task-now.md"}} - >>> get_config_value(config, "task.source") - 'task-now.md' - """ - keys = key.split(".") - value = config - - for k in keys: - if isinstance(value, dict) and k in value: - value = value[k] - else: - return default - - return value -``` - -### 3.2 写入配置 - -**Python 实现示例**: - -```python -import tomli_w -from pathlib import Path - -def save_config(project_root: Path, config: dict) -> None: - """保存配置文件 - - Args: - project_root: 项目根目录 - config: 配置字典 - """ - config_path = project_root / ".aide" / "config.toml" - - with open(config_path, "wb") as f: - tomli_w.dump(config, f) - -def set_config_value(config: dict, key: str, value) -> dict: - """设置配置值(支持点号分隔的键) - - Args: - config: 配置字典 - key: 配置键(如 "task.source") - value: 配置值 - - Returns: - 更新后的配置字典 - - Example: - >>> config = {"task": {"source": "task-now.md"}} - >>> set_config_value(config, "task.source", "new-task.md") - {'task': {'source': 'new-task.md'}} - """ - keys = key.split(".") - current = config - - # 导航到倒数第二层 - for k in keys[:-1]: - if k not in current: - current[k] = {} - current = current[k] - - # 设置最后一层的值 - current[keys[-1]] = value - - return config -``` - -### 3.3 验证配置 - -**验证规则**: - -```python -from typing import Any - -def validate_config(config: dict) -> list[str]: - """验证配置文件 - - Args: - config: 配置字典 - - Returns: - 错误列表(空列表表示无错误) - """ - errors = [] - - # 验证必需的顶层键 - required_sections = ["task", "env", "output"] - for section in required_sections: - if section not in config: - errors.append(f"缺少必需的配置节: [{section}]") - - # 验证 task 配置 - if "task" in config: - if "source" not in config["task"]: - errors.append("缺少配置项: task.source") - if "spec" not in config["task"]: - errors.append("缺少配置项: task.spec") - - # 验证 env.python 配置 - if "env" in config and "python" in config["env"]: - python_config = config["env"]["python"] - if "version" not in python_config: - errors.append("缺少配置项: env.python.version") - else: - # 验证版本格式 - version = python_config["version"] - if not is_valid_version_spec(version): - errors.append(f"无效的版本格式: {version}") - - # 验证 output 配置 - if "output" in config: - output_config = config["output"] - if "language" in output_config: - lang = output_config["language"] - if lang not in ["zh-CN", "en-US"]: - errors.append(f"不支持的语言: {lang}") - - return errors - -def is_valid_version_spec(spec: str) -> bool: - """验证版本规格字符串 - - Args: - spec: 版本规格(如 ">=3.10") - - Returns: - 是否有效 - """ - import re - # 简化的版本规格验证 - pattern = r'^(>=|<=|>|<|==)?\d+\.\d+(\.\d+)?$' - return bool(re.match(pattern, spec)) -``` - ---- - -## 四、默认配置生成 - -### 4.1 生成逻辑 - -`aide init` 命令应该生成包含注释的默认配置: - -```python -def generate_default_config() -> str: - """生成默认配置文件内容(带注释) - - Returns: - TOML 格式的配置文件内容 - """ - return '''# Aide 项目配置文件 -# 由 aide init 自动生成 -# 文档: https://github.com/your-org/aide - -[task] -# 任务原文档路径(prep 阶段使用) -# 可通过 /aide:prep [路径] 覆盖 -source = "task-now.md" - -# 任务细则文档路径(exec 阶段使用) -# 可通过 /aide:exec [路径] 覆盖 -spec = "task-spec.md" - -[env] -# 环境配置 - -[env.python] -# Python 版本要求(语义化版本) -# 格式: ">=3.10" 或 ">=3.10,<4.0" -version = ">=3.10" - -# 虚拟环境路径(相对于项目根目录) -venv = ".venv" - -[env.tools] -# 可选工具配置 - -# 是否需要 uv(Python 包管理器) -uv = false - -# 是否需要 git -git = true - -[flow] -# 流程追踪配置(aide flow 命令使用) - -# 环节列表(不建议修改) -phases = ["flow-design", "impl", "verify", "docs", "finish"] - -# PlantUML 流程图目录 -flowchart_dir = "program_flowchart" - -[decide] -# 待定项确认配置(aide decide 命令使用) - -# Web 服务端口 -port = 3721 - -# 决策记录保存目录 -decisions_dir = ".aide/decisions" - -[output] -# 输出配置 - -# 是否启用颜色输出 -# 可通过环境变量 NO_COLOR 禁用 -color = true - -# 输出语言(当前仅支持 zh-CN) -language = "zh-CN" -''' -``` - -### 4.2 配置文件创建流程 - -```python -from pathlib import Path - -def create_config_file(project_root: Path) -> bool: - """创建配置文件 - - Args: - project_root: 项目根目录 - - Returns: - 是否创建成功(False 表示文件已存在) - """ - aide_dir = project_root / ".aide" - config_path = aide_dir / "config.toml" - - # 检查是否已存在 - if config_path.exists(): - return False - - # 确保 .aide 目录存在 - aide_dir.mkdir(exist_ok=True) - - # 写入默认配置 - config_content = generate_default_config() - config_path.write_text(config_content, encoding="utf-8") - - return True -``` - ---- - -## 五、配置访问接口 - -### 5.1 Config 类设计 - -```python -from pathlib import Path -from typing import Any, Optional - -class Config: - """配置管理类""" - - def __init__(self, project_root: Path): - """初始化配置 - - Args: - project_root: 项目根目录 - """ - self.project_root = project_root - self.config_path = project_root / ".aide" / "config.toml" - self._config: Optional[dict] = None - - def load(self) -> None: - """加载配置文件""" - if not self.config_path.exists(): - raise FileNotFoundError(f"配置文件不存在: {self.config_path}") - - with open(self.config_path, "rb") as f: - self._config = tomllib.load(f) - - def get(self, key: str, default: Any = None) -> Any: - """获取配置值 - - Args: - key: 配置键(支持点号分隔) - default: 默认值 - - Returns: - 配置值 - """ - if self._config is None: - self.load() - - return get_config_value(self._config, key, default) - - def set(self, key: str, value: Any) -> None: - """设置配置值 - - Args: - key: 配置键(支持点号分隔) - value: 配置值 - """ - if self._config is None: - self.load() - - set_config_value(self._config, key, value) - self.save() - - def save(self) -> None: - """保存配置文件""" - if self._config is None: - return - - with open(self.config_path, "wb") as f: - tomli_w.dump(self._config, f) - - def validate(self) -> list[str]: - """验证配置 - - Returns: - 错误列表 - """ - if self._config is None: - self.load() - - return validate_config(self._config) -``` - -### 5.2 使用示例 - -```python -# 初始化配置 -config = Config(Path.cwd()) - -# 获取配置值 -task_source = config.get("task.source", "task-now.md") -python_version = config.get("env.python.version", ">=3.10") - -# 设置配置值 -config.set("task.source", "new-task.md") -config.set("env.python.version", ">=3.11") - -# 验证配置 -errors = config.validate() -if errors: - for error in errors: - print(f"✗ 配置错误: {error}") -``` - ---- - -## 六、配置迁移 - -### 6.1 版本兼容性 - -当配置文件格式升级时,需要提供迁移机制: - -```python -def migrate_config(config: dict, from_version: str, to_version: str) -> dict: - """迁移配置文件 - - Args: - config: 旧配置 - from_version: 源版本 - to_version: 目标版本 - - Returns: - 新配置 - """ - if from_version == "1.0" and to_version == "1.1": - # 示例:添加新的配置项 - if "output" not in config: - config["output"] = { - "color": True, - "language": "zh-CN" - } - - return config -``` - -### 6.2 配置备份 - -修改配置前应该备份: - -```python -import shutil -from datetime import datetime - -def backup_config(config_path: Path) -> Path: - """备份配置文件 - - Args: - config_path: 配置文件路径 - - Returns: - 备份文件路径 - """ - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - backup_path = config_path.with_suffix(f".toml.backup.{timestamp}") - shutil.copy2(config_path, backup_path) - return backup_path -``` - ---- - -## 七、错误处理 - -### 7.1 常见错误 - -| 错误类型 | 处理方式 | -|---------|---------| -| 配置文件不存在 | 提示使用 `aide init` 创建 | -| 配置文件格式错误 | 显示具体错误位置和原因 | -| 配置项缺失 | 使用默认值并警告 | -| 配置值类型错误 | 显示期望类型和实际类型 | - -### 7.2 错误信息示例 - -```python -def handle_config_error(error: Exception, config_path: Path) -> None: - """处理配置错误 - - Args: - error: 异常对象 - config_path: 配置文件路径 - """ - if isinstance(error, FileNotFoundError): - err( - "配置文件不存在", - [ - f"位置: {config_path}", - "建议: 运行 'aide init' 创建配置文件" - ] - ) - elif isinstance(error, tomllib.TOMLDecodeError): - err( - f"配置文件格式错误 (第{error.lineno}行)", - [ - f"位置: {config_path}:{error.lineno}", - f"原因: {error.msg}", - "建议: 检查 TOML 语法,确保格式正确" - ] - ) - else: - err( - "配置文件读取失败", - [ - f"位置: {config_path}", - f"原因: {str(error)}" - ] - ) -``` - ---- - -## 八、测试要求 - -### 8.1 测试用例 - -```python -def test_load_config(): - """测试加载配置""" - # 创建测试配置 - # 加载配置 - # 验证配置内容 - -def test_get_config_value(): - """测试获取配置值""" - # 测试简单键 - # 测试嵌套键 - # 测试不存在的键 - # 测试默认值 - -def test_set_config_value(): - """测试设置配置值""" - # 测试设置简单键 - # 测试设置嵌套键 - # 测试创建新键 - -def test_validate_config(): - """测试配置验证""" - # 测试有效配置 - # 测试缺少必需项 - # 测试无效值类型 - # 测试无效版本格式 - -def test_config_migration(): - """测试配置迁移""" - # 测试版本升级 - # 测试向后兼容 -``` - ---- - -## 九、总结 - -### 9.1 核心要点 - -1. 使用 TOML 格式,自文档化 -2. 提供合理的默认值 -3. 支持点号分隔的键访问 -4. 完善的错误处理和验证 -5. 配置迁移和备份机制 - -### 9.2 实现检查清单 - -- [ ] 实现配置文件读取(load_config) -- [ ] 实现配置文件写入(save_config) -- [ ] 实现配置值获取(get_config_value) -- [ ] 实现配置值设置(set_config_value) -- [ ] 实现配置验证(validate_config) -- [ ] 实现默认配置生成(generate_default_config) -- [ ] 实现 Config 类 -- [ ] 编写配置测试用例 -- [ ] 验证 TOML 格式正确性 - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 diff --git a/aide-program/docs/06-输出格式规范.md b/aide-program/docs/06-输出格式规范.md deleted file mode 100644 index d9299c3..0000000 --- a/aide-program/docs/06-输出格式规范.md +++ /dev/null @@ -1,428 +0,0 @@ -# 输出格式规范 - -## 一、设计原则 - -### 1.1 核心原则 - -1. **精简优先**:成功时输出极简,失败时输出详细 -2. **一致性**:所有命令使用统一的输出格式 -3. **可解析性**:输出格式便于程序解析(如需要) -4. **用户友好**:错误信息包含解决建议 - -### 1.2 静默原则 - -**无输出 = 正常完成** - -适用于幂等操作,例如: -- 配置项已经是目标值时,`aide config set` 不输出 -- 目录已存在时,创建目录操作不输出 - ---- - -## 二、输出前缀 - -### 2.1 前缀定义 - -所有输出行必须以以下前缀之一开头: - -| 前缀 | Unicode | 含义 | 颜色(可选) | 退出码 | -|------|---------|------|-------------|--------| -| `✓` | U+2713 | 成功 | 绿色 | 0 | -| `⚠` | U+26A0 | 警告(可继续) | 黄色 | 0 | -| `✗` | U+2717 | 错误(失败) | 红色 | 非0 | -| `→` | U+2192 | 信息/进行中 | 蓝色 | - | - -### 2.2 使用场景 - -**✓ 成功** -``` -✓ 环境就绪 (python:3.12) -✓ 已创建 .aide/ 目录 -✓ 已生成默认配置 -``` - -**⚠ 警告** -``` -⚠ 已修复: 创建虚拟环境 .venv -⚠ 配置文件不存在,使用默认配置 -⚠ Python 版本较旧 (3.10),建议升级到 3.11+ -``` - -**✗ 错误** -``` -✗ Python 版本不满足要求 (需要 >=3.10, 当前 3.8) - 建议: 安装 Python 3.10+ 或使用 pyenv 管理版本 -✗ 配置文件格式错误: 第5行缺少引号 - 位置: .aide/config.toml:5 -``` - -**→ 信息** -``` -→ 正在检测环境... -→ 正在创建配置文件... -→ 配置值: task.source = "task-now.md" -``` - ---- - -## 三、输出格式 - -### 3.1 单行输出 - -**格式**:`<前缀> <消息>` - -**示例**: -``` -✓ 环境就绪 (python:3.12) -⚠ 已修复: 创建虚拟环境 .venv -✗ Python 未安装 -``` - -### 3.2 多行输出 - -**格式**: -``` -<前缀> <主消息> - <详细信息行1> - <详细信息行2> -``` - -**缩进规则**: -- 主消息行:前缀 + 空格 + 消息 -- 详细信息行:2个空格缩进 - -**示例**: -``` -✗ Python 版本不满足要求 (需要 >=3.10, 当前 3.8) - 建议: 安装 Python 3.10+ 或使用 pyenv 管理版本 - 文档: https://docs.python.org/3/using/index.html -``` - -### 3.3 列表输出 - -**格式**: -``` -<前缀> <标题> - - <项目1> - - <项目2> -``` - -**示例**: -``` -✓ 环境就绪 - - python: 3.12.0 - - uv: 0.4.0 - - git: 2.40.0 -``` - ---- - -## 四、特殊场景 - -### 4.1 配置输出 - -**aide config get** - -单个值: -``` -task.source = "task-now.md" -``` - -多个值(如果支持): -``` -task.source = "task-now.md" -task.spec = "task-spec.md" -``` - -数组值: -``` -flow.phases = ["flow-design", "impl", "verify", "docs", "finish"] -``` - -**aide config set** - -成功时无输出(静默原则) - -失败时: -``` -✗ 配置键不存在: invalid.key - 可用的配置键: task.source, task.spec, env.python.version -``` - -### 4.2 环境检测输出 - -**成功(无问题)**: -``` -✓ 环境就绪 (python:3.12) -``` - -**成功(自动修复)**: -``` -⚠ 已修复: 创建虚拟环境 .venv -✓ 环境就绪 (python:3.12) -``` - -**失败(无法修复)**: -``` -✗ Python 版本不满足要求 (需要 >=3.10, 当前 3.8) - 建议: 安装 Python 3.10+ 或使用 pyenv 管理版本 -``` - -### 4.3 初始化输出 - -**首次初始化**: -``` -✓ 已创建 .aide/ 目录 -✓ 已生成默认配置 -✓ 已添加 .aide/ 到 .gitignore -``` - -**重复初始化**: -``` -⚠ .aide/ 目录已存在 -⚠ 配置文件已存在,跳过生成 -``` - ---- - -## 五、实现规范 - -### 5.1 输出函数接口 - -建议在 `core/output.py` 中实现以下函数: - -```python -def ok(message: str, details: list[str] | None = None) -> None: - """输出成功信息 - - Args: - message: 主消息 - details: 详细信息列表(可选) - """ - pass - -def warn(message: str, details: list[str] | None = None) -> None: - """输出警告信息 - - Args: - message: 主消息 - details: 详细信息列表(可选) - """ - pass - -def err(message: str, details: list[str] | None = None) -> None: - """输出错误信息 - - Args: - message: 主消息 - details: 详细信息列表(可选) - """ - pass - -def info(message: str, details: list[str] | None = None) -> None: - """输出信息 - - Args: - message: 主消息 - details: 详细信息列表(可选) - """ - pass -``` - -### 5.2 使用示例 - -```python -from core.output import ok, warn, err, info - -# 简单成功 -ok("环境就绪 (python:3.12)") - -# 带详细信息的警告 -warn("已修复: 创建虚拟环境 .venv") - -# 带建议的错误 -err( - "Python 版本不满足要求 (需要 >=3.10, 当前 3.8)", - [ - "建议: 安装 Python 3.10+ 或使用 pyenv 管理版本", - "文档: https://docs.python.org/3/using/index.html" - ] -) - -# 进行中信息 -info("正在检测环境...") -``` - -### 5.3 颜色支持(可选) - -如果实现颜色输出,必须: - -1. **检测终端支持**:使用 `sys.stdout.isatty()` 检测 -2. **提供禁用选项**:通过环境变量 `NO_COLOR` 或 `--no-color` 参数 -3. **跨平台兼容**:Windows 需要特殊处理(colorama 或 ANSI 转义) - -**颜色映射**: -- ✓ 成功:绿色(`\033[32m`) -- ⚠ 警告:黄色(`\033[33m`) -- ✗ 错误:红色(`\033[31m`) -- → 信息:蓝色(`\033[34m`) - ---- - -## 六、错误信息规范 - -### 6.1 错误信息结构 - -``` -✗ <问题描述> (<具体原因>) - <解决建议> - <相关信息> -``` - -### 6.2 错误信息要素 - -1. **问题描述**:清晰说明出了什么问题 -2. **具体原因**:括号内说明具体原因(如版本号、路径等) -3. **解决建议**:以"建议:"开头,提供可行的解决方案 -4. **相关信息**:文档链接、配置位置等 - -### 6.3 错误信息示例 - -**环境错误**: -``` -✗ Python 版本不满足要求 (需要 >=3.10, 当前 3.8) - 建议: 安装 Python 3.10+ 或使用 pyenv 管理版本 -``` - -**配置错误**: -``` -✗ 配置文件格式错误 (第5行: 缺少引号) - 位置: .aide/config.toml:5 - 建议: 检查 TOML 语法,确保字符串值使用引号 -``` - -**文件错误**: -``` -✗ 任务文档不存在 (task-now.md) - 建议: 创建任务文档或使用 --file 参数指定路径 -``` - -**权限错误**: -``` -✗ 无法创建目录 (.aide/) - 原因: 权限不足 - 建议: 检查当前目录的写入权限 -``` - ---- - -## 七、退出码规范 - -### 7.1 退出码定义 - -| 退出码 | 含义 | 使用场景 | -|-------|------|---------| -| 0 | 成功 | 操作成功完成 | -| 1 | 一般错误 | 操作失败,原因不明确 | -| 2 | 参数错误 | 命令参数错误或缺失 | -| 3 | 环境错误 | 环境不满足要求 | -| 4 | 配置错误 | 配置文件错误 | -| 5 | 文件错误 | 文件不存在或无法访问 | - -### 7.2 退出码使用 - -```python -import sys - -# 成功 -sys.exit(0) - -# 参数错误 -sys.exit(2) - -# 环境错误 -sys.exit(3) -``` - ---- - -## 八、测试要求 - -### 8.1 输出测试 - -每个命令必须测试: - -1. **成功场景**:验证输出格式正确 -2. **警告场景**:验证警告信息正确 -3. **错误场景**:验证错误信息和退出码 -4. **静默场景**:验证幂等操作无输出 - -### 8.2 测试示例 - -```python -def test_env_ensure_success(capsys): - """测试环境检测成功输出""" - # 执行命令 - result = env_ensure() - - # 验证退出码 - assert result == 0 - - # 验证输出 - captured = capsys.readouterr() - assert "✓ 环境就绪" in captured.out - assert "python:" in captured.out - -def test_env_ensure_failure(capsys): - """测试环境检测失败输出""" - # 模拟 Python 版本过低 - with mock_python_version("3.8"): - result = env_ensure() - - # 验证退出码 - assert result == 3 - - # 验证输出 - captured = capsys.readouterr() - assert "✗ Python 版本不满足要求" in captured.out - assert "建议:" in captured.out -``` - ---- - -## 九、国际化考虑(可选) - -如果需要支持多语言: - -1. **消息模板**:将所有消息定义为模板 -2. **语言检测**:通过环境变量 `LANG` 或 `--lang` 参数 -3. **回退机制**:不支持的语言回退到英文 - -**当前阶段**:仅支持简体中文,国际化可在后续版本实现。 - ---- - -## 十、总结 - -### 10.1 核心要点 - -1. 使用统一的前缀(✓ ⚠ ✗ →) -2. 成功时输出极简,失败时输出详细 -3. 错误信息包含解决建议 -4. 遵循静默原则(幂等操作) -5. 使用明确的退出码 - -### 10.2 实现检查清单 - -- [ ] 实现 `core/output.py` 模块 -- [ ] 定义 ok/warn/err/info 函数 -- [ ] 支持单行和多行输出 -- [ ] 实现颜色支持(可选) -- [ ] 定义退出码常量 -- [ ] 编写输出测试用例 -- [ ] 验证跨平台兼容性 - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 diff --git a/aide-program/docs/07-测试规范.md b/aide-program/docs/07-测试规范.md deleted file mode 100644 index 85a0df3..0000000 --- a/aide-program/docs/07-测试规范.md +++ /dev/null @@ -1,708 +0,0 @@ -# 测试规范 - -## 一、测试概述 - -### 1.1 测试目标 - -确保 aide 程序的所有功能正确、稳定、可靠,满足设计要求。 - -### 1.2 测试范围 - -- 单元测试:核心模块和函数 -- 集成测试:命令完整流程 -- 跨平台测试:Linux、macOS、Windows -- 性能测试:执行时间和资源占用 - -### 1.3 测试工具 - -- **pytest**:测试框架 -- **pytest-cov**:代码覆盖率 -- **pytest-mock**:模拟和打桩 -- **pytest-timeout**:超时控制 - ---- - -## 二、测试结构 - -### 2.1 目录结构 - -``` -tests/ -├── __init__.py -├── conftest.py # pytest 配置和 fixtures -├── unit/ # 单元测试 -│ ├── __init__.py -│ ├── test_output.py # 输出模块测试 -│ ├── test_config.py # 配置模块测试 -│ └── test_validators.py # 验证函数测试 -├── integration/ # 集成测试 -│ ├── __init__.py -│ ├── test_init.py # aide init 测试 -│ ├── test_env.py # aide env 测试 -│ └── test_config_cmd.py # aide config 测试 -└── fixtures/ # 测试数据 - ├── sample_config.toml - └── sample_gitignore -``` - -### 2.2 命名规范 - -- 测试文件:`test_.py` -- 测试类:`Test` -- 测试函数:`test_` - -**示例**: -```python -# test_config.py -class TestConfig: - def test_load_success(self): - """测试成功加载配置""" - pass - - def test_load_file_not_found(self): - """测试配置文件不存在""" - pass -``` - ---- - -## 三、单元测试 - -### 3.1 core/output.py 测试 - -```python -# tests/unit/test_output.py -import pytest -from core.output import ok, warn, err, info - -def test_ok_simple(capsys): - """测试简单成功输出""" - ok("操作成功") - - captured = capsys.readouterr() - assert "✓ 操作成功" in captured.out - -def test_ok_with_details(capsys): - """测试带详细信息的成功输出""" - ok("操作成功", ["详细信息1", "详细信息2"]) - - captured = capsys.readouterr() - assert "✓ 操作成功" in captured.out - assert " 详细信息1" in captured.out - assert " 详细信息2" in captured.out - -def test_warn(capsys): - """测试警告输出""" - warn("这是警告") - - captured = capsys.readouterr() - assert "⚠ 这是警告" in captured.out - -def test_err(capsys): - """测试错误输出""" - err("这是错误", ["建议: 检查配置"]) - - captured = capsys.readouterr() - assert "✗ 这是错误" in captured.out - assert " 建议: 检查配置" in captured.out - -def test_info(capsys): - """测试信息输出""" - info("正在处理...") - - captured = capsys.readouterr() - assert "→ 正在处理..." in captured.out -``` - -### 3.2 core/config.py 测试 - -```python -# tests/unit/test_config.py -import pytest -from pathlib import Path -from core.config import Config, get_config_value, set_config_value - -def test_get_config_value(): - """测试获取配置值""" - config = { - "task": { - "source": "task-now.md" - } - } - - assert get_config_value(config, "task.source") == "task-now.md" - assert get_config_value(config, "task.spec", "default") == "default" - -def test_set_config_value(): - """测试设置配置值""" - config = {"task": {}} - - set_config_value(config, "task.source", "new-task.md") - assert config["task"]["source"] == "new-task.md" - -def test_config_load(tmp_path): - """测试加载配置""" - # 创建测试配置文件 - config_dir = tmp_path / ".aide" - config_dir.mkdir() - config_path = config_dir / "config.toml" - config_path.write_text('[task]\nsource = "test.md"\n') - - # 加载配置 - config = Config(tmp_path) - config.load() - - assert config.get("task.source") == "test.md" - -def test_config_load_not_found(tmp_path): - """测试配置文件不存在""" - config = Config(tmp_path) - - with pytest.raises(FileNotFoundError): - config.load() - -def test_config_save(tmp_path): - """测试保存配置""" - # 创建配置 - config_dir = tmp_path / ".aide" - config_dir.mkdir() - - config = Config(tmp_path) - config._config = {"task": {"source": "test.md"}} - config.save() - - # 验证文件已创建 - config_path = tmp_path / ".aide" / "config.toml" - assert config_path.exists() - - # 验证内容 - content = config_path.read_text() - assert "task" in content - assert "test.md" in content -``` - -### 3.3 utils/validators.py 测试 - -```python -# tests/unit/test_validators.py -import pytest -from utils.validators import is_valid_version_spec, validate_config - -def test_is_valid_version_spec(): - """测试版本规格验证""" - assert is_valid_version_spec(">=3.10") == True - assert is_valid_version_spec("3.12") == True - assert is_valid_version_spec(">=3.10,<4.0") == True - assert is_valid_version_spec("invalid") == False - -def test_validate_config(): - """测试配置验证""" - # 有效配置 - valid_config = { - "task": {"source": "task.md", "spec": "spec.md"}, - "env": {"python": {"version": ">=3.10"}}, - "output": {"language": "zh-CN"} - } - errors = validate_config(valid_config) - assert len(errors) == 0 - - # 缺少必需项 - invalid_config = {"task": {}} - errors = validate_config(invalid_config) - assert len(errors) > 0 - assert any("task.source" in e for e in errors) -``` - ---- - -## 四、集成测试 - -### 4.1 aide init 测试 - -```python -# tests/integration/test_init.py -import pytest -from pathlib import Path -from commands.init import cmd_init - -def test_init_success(tmp_path, monkeypatch): - """测试初始化成功""" - monkeypatch.chdir(tmp_path) - - result = cmd_init([]) - - assert result == 0 - assert (tmp_path / ".aide").exists() - assert (tmp_path / ".aide" / "config.toml").exists() - assert (tmp_path / ".gitignore").exists() - -def test_init_idempotent(tmp_path, monkeypatch): - """测试幂等性""" - monkeypatch.chdir(tmp_path) - - # 第一次初始化 - result1 = cmd_init([]) - assert result1 == 0 - - # 读取配置内容 - config_path = tmp_path / ".aide" / "config.toml" - content1 = config_path.read_text() - - # 第二次初始化 - result2 = cmd_init([]) - assert result2 == 0 - - # 验证配置未改变 - content2 = config_path.read_text() - assert content1 == content2 - -def test_init_permission_error(tmp_path, monkeypatch): - """测试权限错误""" - monkeypatch.chdir(tmp_path) - - # 设置只读权限 - tmp_path.chmod(0o444) - - result = cmd_init([]) - - # 恢复权限 - tmp_path.chmod(0o755) - - assert result != 0 -``` - -### 4.2 aide env 测试 - -```python -# tests/integration/test_env.py -import pytest -from commands.env import cmd_env, env_ensure_runtime, env_ensure_project - -def test_env_ensure_runtime_success(): - """测试运行时环境检测成功""" - result = env_ensure_runtime() - assert result == 0 - -def test_env_ensure_project_success(tmp_path, monkeypatch): - """测试项目环境检测成功""" - monkeypatch.chdir(tmp_path) - - # 初始化项目 - from commands.init import cmd_init - cmd_init([]) - - # 检测环境 - result = env_ensure_project() - assert result == 0 - -def test_env_ensure_project_no_config(tmp_path, monkeypatch): - """测试配置文件不存在""" - monkeypatch.chdir(tmp_path) - - result = env_ensure_project() - assert result == 4 - -def test_env_ensure_create_venv(tmp_path, monkeypatch): - """测试自动创建虚拟环境""" - monkeypatch.chdir(tmp_path) - - # 初始化项目 - from commands.init import cmd_init - cmd_init([]) - - # 检测环境(应该自动创建虚拟环境) - result = env_ensure_project() - assert result == 0 - - # 验证虚拟环境已创建 - assert (tmp_path / ".venv").exists() -``` - -### 4.3 aide config 测试 - -```python -# tests/integration/test_config_cmd.py -import pytest -from commands.config_cmd import cmd_config, config_get, config_set - -def test_config_get_success(tmp_path, monkeypatch, capsys): - """测试获取配置成功""" - monkeypatch.chdir(tmp_path) - - # 初始化 - from commands.init import cmd_init - cmd_init([]) - - # 获取配置 - result = config_get("task.source") - assert result == 0 - - captured = capsys.readouterr() - assert "task.source" in captured.out - assert "task-now.md" in captured.out - -def test_config_set_success(tmp_path, monkeypatch): - """测试设置配置成功""" - monkeypatch.chdir(tmp_path) - - # 初始化 - from commands.init import cmd_init - cmd_init([]) - - # 设置配置 - result = config_set("task.source", "new-task.md") - assert result == 0 - - # 验证配置已更新 - result = config_get("task.source") - assert result == 0 - -def test_config_cmd_no_args(capsys): - """测试无参数""" - result = cmd_config([]) - assert result == 2 - - captured = capsys.readouterr() - assert "缺少子命令" in captured.out -``` - ---- - -## 五、跨平台测试 - -### 5.1 路径处理测试 - -```python -def test_path_handling_cross_platform(tmp_path): - """测试跨平台路径处理""" - from pathlib import Path - - # 使用 pathlib 确保跨平台兼容 - aide_dir = tmp_path / ".aide" - config_path = aide_dir / "config.toml" - - aide_dir.mkdir() - config_path.write_text("test") - - assert config_path.exists() - assert config_path.is_file() -``` - -### 5.2 命令执行测试 - -```python -@pytest.mark.skipif(sys.platform == "win32", reason="Unix only") -def test_unix_specific(): - """Unix 特定测试""" - pass - -@pytest.mark.skipif(sys.platform != "win32", reason="Windows only") -def test_windows_specific(): - """Windows 特定测试""" - pass -``` - ---- - -## 六、性能测试 - -### 6.1 执行时间测试 - -```python -import time - -def test_init_performance(tmp_path, monkeypatch): - """测试初始化性能""" - monkeypatch.chdir(tmp_path) - - start = time.time() - result = cmd_init([]) - elapsed = time.time() - start - - assert result == 0 - assert elapsed < 0.2 # 应该在 200ms 内完成 - -def test_config_get_performance(tmp_path, monkeypatch): - """测试配置读取性能""" - monkeypatch.chdir(tmp_path) - - # 初始化 - cmd_init([]) - - # 测试性能 - start = time.time() - result = config_get("task.source") - elapsed = time.time() - start - - assert result == 0 - assert elapsed < 0.1 # 应该在 100ms 内完成 -``` - -### 6.2 内存占用测试 - -```python -import psutil -import os - -def test_memory_usage(): - """测试内存占用""" - process = psutil.Process(os.getpid()) - mem_before = process.memory_info().rss / 1024 / 1024 # MB - - # 执行操作 - cmd_init([]) - - mem_after = process.memory_info().rss / 1024 / 1024 # MB - mem_used = mem_after - mem_before - - assert mem_used < 50 # 应该小于 50MB -``` - ---- - -## 七、测试覆盖率 - -### 7.1 覆盖率要求 - -- **核心模块**:≥ 80% -- **命令模块**:≥ 80% -- **工具模块**:≥ 70% -- **整体**:≥ 75% - -### 7.2 运行覆盖率测试 - -```bash -# 运行测试并生成覆盖率报告 -pytest --cov=src --cov-report=html --cov-report=term - -# 查看覆盖率报告 -open htmlcov/index.html -``` - -### 7.3 覆盖率配置 - -```ini -# .coveragerc -[run] -source = src -omit = - */tests/* - */venv/* - */__pycache__/* - -[report] -exclude_lines = - pragma: no cover - def __repr__ - raise AssertionError - raise NotImplementedError - if __name__ == .__main__.: -``` - ---- - -## 八、测试 Fixtures - -### 8.1 conftest.py - -```python -# tests/conftest.py -import pytest -from pathlib import Path -import shutil - -@pytest.fixture -def temp_project(tmp_path): - """创建临时项目目录""" - project_dir = tmp_path / "test_project" - project_dir.mkdir() - return project_dir - -@pytest.fixture -def initialized_project(temp_project, monkeypatch): - """创建已初始化的项目""" - monkeypatch.chdir(temp_project) - from commands.init import cmd_init - cmd_init([]) - return temp_project - -@pytest.fixture -def sample_config(): - """示例配置""" - return { - "task": { - "source": "task-now.md", - "spec": "task-spec.md" - }, - "env": { - "python": { - "version": ">=3.10", - "venv": ".venv" - } - } - } -``` - ---- - -## 九、持续集成 - -### 9.1 GitHub Actions 配置 - -```yaml -# .github/workflows/test.yml -name: Tests - -on: [push, pull_request] - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.10', '3.11', '3.12'] - - steps: - - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pytest pytest-cov pytest-mock - pip install tomli tomli-w - - - name: Run tests - run: | - pytest --cov=src --cov-report=xml - - - name: Upload coverage - uses: codecov/codecov-action@v3 - with: - file: ./coverage.xml -``` - ---- - -## 十、测试最佳实践 - -### 10.1 测试原则 - -1. **独立性**:每个测试独立运行,不依赖其他测试 -2. **可重复性**:多次运行结果一致 -3. **清晰性**:测试意图明确,易于理解 -4. **快速性**:测试执行快速,及时反馈 - -### 10.2 测试模式 - -**AAA 模式**(Arrange-Act-Assert): - -```python -def test_example(): - # Arrange:准备测试数据 - config = {"task": {"source": "test.md"}} - - # Act:执行操作 - result = get_config_value(config, "task.source") - - # Assert:验证结果 - assert result == "test.md" -``` - -### 10.3 Mock 使用 - -```python -from unittest.mock import Mock, patch - -def test_with_mock(monkeypatch): - """使用 mock 测试""" - # Mock 函数 - mock_func = Mock(return_value=True) - monkeypatch.setattr("module.function", mock_func) - - # 执行测试 - result = some_function() - - # 验证 mock 被调用 - mock_func.assert_called_once() -``` - ---- - -## 十一、测试检查清单 - -### 11.1 单元测试 - -- [ ] core/output.py 所有函数 -- [ ] core/config.py 所有函数 -- [ ] utils/validators.py 所有函数 -- [ ] 边界条件测试 -- [ ] 错误路径测试 - -### 11.2 集成测试 - -- [ ] aide init 完整流程 -- [ ] aide env ensure --runtime -- [ ] aide env ensure -- [ ] aide config get -- [ ] aide config set -- [ ] 命令组合测试 - -### 11.3 跨平台测试 - -- [ ] Linux 测试通过 -- [ ] macOS 测试通过 -- [ ] Windows 测试通过 -- [ ] 路径处理正确 - -### 11.4 性能测试 - -- [ ] 执行时间符合要求 -- [ ] 内存占用符合要求 -- [ ] 无内存泄漏 - -### 11.5 覆盖率 - -- [ ] 核心模块 ≥ 80% -- [ ] 命令模块 ≥ 80% -- [ ] 整体 ≥ 75% - ---- - -## 十二、总结 - -### 12.1 核心要点 - -1. 完整的测试覆盖(单元、集成、跨平台) -2. 明确的覆盖率要求 -3. 持续集成自动化 -4. 遵循测试最佳实践 - -### 12.2 运行测试 - -```bash -# 运行所有测试 -pytest - -# 运行特定测试 -pytest tests/unit/test_config.py - -# 运行带覆盖率的测试 -pytest --cov=src - -# 运行性能测试 -pytest -m performance - -# 运行跨平台测试 -pytest -m cross_platform -``` - ---- - -**版本**:v1.0 -**更新日期**:2025-12-13 diff --git a/now-status.md b/now-status.md index cfaf29a..334791c 100644 --- a/now-status.md +++ b/now-status.md @@ -16,7 +16,7 @@ claude code正在辅助我完成一项任务 ## 细节补充 -前面已经根据 @aide-requirements.md 产出了 discuss/ 目录下的信息,当前完成了01报告中的Phase 1和Phase 2,产出了 aide-marketplace/ 和02报告,然后我提出了 @reply/re-03.md 中所述的意见,现在re-03已经完成了commands部分的内容,还有skills部分没有开始调整, +前面已经根据 @aide-requirements.md 产出了 discuss/ 目录下的信息,当前完成了01报告中的Phase 1和Phase 2,产出了 aide-marketplace/ 和02报告,然后我提出了 @reply/re-03.md 中所述的意见,现在re-03已经完成, # 要求 @@ -24,4 +24,4 @@ claude code正在辅助我完成一项任务 你必须亲自完整仔细的阅读所有提及的文件、目录及其子目录下所包含的所有文件内容(除了anthropic-agent-skills/仅要按需学习即可),必须一行不漏的完全审阅了所有文件,然后继续完成任务, -根据re-03的意见调整skills内容,然后根据re-03中意见的语义,更新 @aide-requirements.md +在aide-program/目录下,实现aide程序系统(入口脚本封装+python实现,但不要考虑、不要实现aide flow和aide decide,它们留到后面单独讨论细节), \ No newline at end of file diff --git a/reply/re-04.md b/reply/re-04.md deleted file mode 100644 index 639e3a9..0000000 --- a/reply/re-04.md +++ /dev/null @@ -1,5 +0,0 @@ -在aide-program/目录下,编写一套详细准确的,可用于开始开发aide体系程序的文档(但不包含aide flow和aide decide), - -注意:这些文档必须足够详细足够准确,但是不允许直接给出具体的代码片段(可以定义细节、逻辑、接口、数据结构,但不允许在设计这一步给定固定死的代码实现) - -然后我将会把aide-program/目录单独打包交给开发人员,完成好程序的开发(封装脚本+python程序)和测试后,再回来我们继续谈flow和decide的具体细节 \ No newline at end of file