Files
agent-aide/aide-program/docs/03-aide-env设计.md
2025-12-13 04:37:41 +08:00

600 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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