diff --git a/.aide/config.toml b/.aide/config.toml index 7943617..2f4e381 100644 --- a/.aide/config.toml +++ b/.aide/config.toml @@ -1,8 +1,9 @@ # Aide 默认配置(由 aide init 生成) # runtime: aide 自身运行要求 # task: 任务文档路径 -# env: 虚拟环境与依赖配置 +# env: 环境模块配置 # flow: 环节名称列表,供流程校验使用 + [runtime] python_min = "3.11" use_uv = true @@ -12,8 +13,20 @@ source = "task-now.md" spec = "task-spec.md" [env] -venv = ".venv" -requirements = "requirements.txt" +# 启用的模块列表 +modules = ["python", "uv", "venv", "requirements"] + +# Python 版本要求(可选,默认使用 runtime.python_min) +# [env.python] +# min_version = "3.11" + +# 虚拟环境配置(类型B模块,必须配置) +[env.venv] +path = ".venv" + +# 依赖文件配置(类型B模块,必须配置) +[env.requirements] +path = "requirements.txt" [flow] phases = ["task-optimize", "flow-design", "impl", "verify", "docs", "finish"] diff --git a/.gitignore b/.gitignore index 67cd2f5..405b695 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ anthropic-agent-skills/ __pycache__/ .venv/ -test-cache/ \ No newline at end of file +test-cache/ +.aide/ diff --git a/README.md b/README.md index 14fc3a5..f7b6c3b 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,10 @@ ccoptimize/ │ │ ├── prep.md │ │ └── exec.md │ ├── skills/ -│ │ └── aide/ -│ │ └── SKILL.md +│ │ ├── aide/ +│ │ │ └── SKILL.md # 基础命令指南 +│ │ └── env-config/ +│ │ └── SKILL.md # 环境配置详细指南(按需触发) │ └── docs/ # 设计文档(给人) │ ├── README.md │ ├── commands/ @@ -94,10 +96,11 @@ ccoptimize/ │ ├── registry.py # 模块注册表 │ └── modules/ # 环境检测模块 │ ├── base.py - │ ├── python.py - │ ├── uv.py - │ ├── venv.py - │ └── requirements.py + │ ├── python.py, uv.py + │ ├── rust.py, node.py, flutter.py + │ ├── android.py, node_deps.py + │ ├── venv.py, requirements.py + │ └── ... └── docs/ # 设计文档(给人) ├── README.md ├── commands/ @@ -121,9 +124,14 @@ ccoptimize/ | /aide:init | ✅ 设计完成 | 项目认知与环境初始化 | | /aide:prep | ✅ 设计完成 | 任务准备流程 | | /aide:exec | ✅ 设计完成 | 任务执行流程 | -| aide skill | ✅ 设计完成 | aide 命令使用指南 | +| aide skill | ✅ 设计完成 | aide 基础命令指南 | +| env-config skill | ✅ 设计完成 | 环境配置详细指南(按需触发) | -执行文件位于 `aide-marketplace/aide-plugin/commands/` 和 `skills/aide/SKILL.md` +执行文件位于 `aide-marketplace/aide-plugin/commands/` 和 `skills/` + +**Skill 设计理念**: +- `aide` skill:始终加载,提供基础命令用法 +- `env-config` skill:按需触发,仅在 `aide env ensure` 失败时使用 ### 3.2 aide-program @@ -132,6 +140,7 @@ ccoptimize/ | aide init | ✅ 已实现 | 初始化 .aide 目录和配置 | | aide env list | ✅ 已实现 | 列出所有可用模块 | | aide env ensure | ✅ 已实现 | 模块化环境检测与修复 | +| aide env set | ✅ 已实现 | 设置环境配置(带验证) | | aide env ensure --runtime | ✅ 已实现 | 运行时环境检测 | | aide env ensure --modules | ✅ 已实现 | 指定模块检测 | | aide env ensure --all | ✅ 已实现 | 全量检测(仅检查) | @@ -148,11 +157,17 @@ ccoptimize/ |------|------|------|------| | python | A | check | Python 解释器版本 | | uv | A | check | uv 包管理器 | +| rust | A | check | Rust 工具链(rustc + cargo) | +| node | A | check | Node.js 运行时 | +| flutter | A | check | Flutter SDK | +| android | A | check | Android SDK | | venv | B | check, ensure | Python 虚拟环境 | | requirements | B | check, ensure | Python 依赖管理 | +| node_deps | B | check, ensure | Node.js 项目依赖 | - 类型A:无需配置即可检测 - 类型B:需要配置路径才能检测 +- 支持模块实例化命名:`模块类型:实例名`(如 `node_deps:react`) ### 3.4 设计文档 @@ -216,11 +231,11 @@ ccoptimize/ ### 5.3 扩展环境模块(可选) 可按需添加更多环境检测模块: -- node - Node.js 版本检测 -- npm - npm 依赖管理 - java - Java JDK 检测 - go - Go 语言检测 -- rust - Rust 工具链检测 +- docker - Docker 环境检测 +- cargo_deps - Rust 项目依赖(类似 node_deps) +- pub_deps - Flutter/Dart 项目依赖 ### 5.4 整体验证 @@ -254,7 +269,11 @@ ccoptimize/ ## 七、版本信息 -- 文档版本:1.1.0 +- 文档版本:1.2.0 - 更新日期:2025-12-14 - 项目阶段:设计完成,部分实现 -- 最近更新:aide env 模块化重构 +- 最近更新: + - aide env set 命令实现 + - 新增环境模块:rust, node, flutter, android, node_deps + - 支持模块实例化命名(多项目场景) + - Skill 拆分:aide(基础)+ env-config(按需) diff --git a/aide-marketplace/aide-plugin/commands/init.md b/aide-marketplace/aide-plugin/commands/init.md index b31ef33..730c32a 100644 --- a/aide-marketplace/aide-plugin/commands/init.md +++ b/aide-marketplace/aide-plugin/commands/init.md @@ -57,9 +57,9 @@ aide env ensure - 输出环境状态和配置信息 根据输出处理: -- `✓`:环境就绪,继续 +- `✓`:环境就绪,继续到步骤 5 - `⚠`:有警告但可继续,记录并继续 -- `✗`:按提示修复,3次失败则告知用户 +- `✗`:**触发 `env-config` skill**,按指导完成配置后重试 **注意**: - 此时不带 `--runtime` 参数,会读取项目配置文件检查项目环境 diff --git a/aide-marketplace/aide-plugin/docs/README.md b/aide-marketplace/aide-plugin/docs/README.md index 6e3aaa4..3e0b648 100644 --- a/aide-marketplace/aide-plugin/docs/README.md +++ b/aide-marketplace/aide-plugin/docs/README.md @@ -82,12 +82,18 @@ Commands 只告诉 LLM: ## 三、Skill 索引 -| Skill | 设计文档 | 执行文件 | 职责 | -|-------|----------|----------|------| -| aide | [skill/aide.md](skill/aide.md) | [../../skills/aide/SKILL.md](../skills/aide/SKILL.md) | aide 命令行工具使用指南 | +| Skill | 执行文件 | 职责 | 触发时机 | +|-------|----------|------|----------| +| aide | [../skills/aide/SKILL.md](../skills/aide/SKILL.md) | aide 基础命令指南 | 始终加载 | +| env-config | [../skills/env-config/SKILL.md](../skills/env-config/SKILL.md) | 环境配置详细指南 | `aide env ensure` 失败时 | ### 3.1 Skill 设计原则 +**按需触发,避免信息过载** + +- `aide` skill:始终加载,提供基础命令用法 +- `env-config` skill:按需触发,仅在环境检测失败时使用 + **纯工具说明,便于快速查阅** Skill 只包含: @@ -97,6 +103,20 @@ Skill 只包含: 不包含流程指导和业务逻辑。 +### 3.2 Skill 触发逻辑 + +``` +aide env ensure + │ + ├─ 全部 ✓ → 继续流程(无需额外 skill) + │ + └─ 有 ✗ → 触发 env-config skill + │ + ├─ 分析项目类型 + ├─ aide env set 配置 + └─ 重试 aide env ensure +``` + --- ## 四、职责边界 @@ -134,11 +154,13 @@ Skill 只包含: ### 5.2 修改 Skill -1. 阅读 [skill/aide.md](skill/aide.md) -2. 理解各子命令的接口 -3. 修改执行文件 `../skills/aide/SKILL.md` -4. 更新设计文档 -5. 如涉及 aide-program 变更,同步更新 [aide-program 文档](../../../aide-program/docs/README.md) +1. 确定要修改的 skill(aide 或 env-config) +2. 修改对应执行文件 `../skills//SKILL.md` +3. 如涉及 aide-program 变更,同步更新 [aide-program 文档](../../../aide-program/docs/README.md) + +**注意**: +- `aide` skill 保持精简,仅包含基础命令用法 +- 详细配置指导放在 `env-config` skill ### 5.3 新增 Command diff --git a/aide-marketplace/aide-plugin/skills/aide/SKILL.md b/aide-marketplace/aide-plugin/skills/aide/SKILL.md index 841f6e5..ca9f6d7 100644 --- a/aide-marketplace/aide-plugin/skills/aide/SKILL.md +++ b/aide-marketplace/aide-plugin/skills/aide/SKILL.md @@ -22,46 +22,16 @@ Aide 是一套命令行工具,用于支持 Aide 工作流体系。所有 aide ## aide env - 环境管理 -### aide env list - -列出所有可用的环境检测模块。 - -```bash -aide env list -``` - -**输出示例**: -``` -可用模块: - 模块 描述 能力 需要配置 - ──────────────────────────────────────────────────────────── - python Python 解释器版本 check 否 - uv uv 包管理器 check 否 - venv Python 虚拟环境 check, ensure 是 [path] - requirements Python 依赖管理 check, ensure 是 [path] - -当前启用: python, uv, venv, requirements -``` - ### aide env ensure 检测并修复开发环境。 ```bash -# 检查项目开发环境(按配置启用的模块) -aide env ensure - -# 仅检查 aide 运行时环境(不依赖配置文件) +# 仅检查 aide 运行时环境(init 流程使用) aide env ensure --runtime -# 检测指定模块 -aide env ensure --modules python,uv - -# 检测所有已启用模块(仅检查不修复) -aide env ensure --all - -# 显示详细配置信息(供人工确认) -aide env ensure --verbose +# 检查项目开发环境(按配置启用的模块) +aide env ensure ``` **参数**: @@ -79,27 +49,33 @@ aide env ensure --verbose # 成功 ✓ python: 3.14.2 (>=3.11) ✓ uv: uv 0.9.16 -✓ venv: .venv -✓ requirements: requirements.txt -✓ 环境就绪 (python:3.14.2, uv:uv 0.9.16, venv:.venv, requirements:requirements.txt) +✓ 环境就绪 (python:3.14.2, uv:uv 0.9.16) ``` ``` -# 自动修复 -✓ python: 3.14.2 (>=3.11) -✓ uv: uv 0.9.16 -→ venv: 虚拟环境不存在: .venv,尝试修复... -✓ venv: 已创建 -✓ 环境就绪 (...) -``` - -``` -# 失败(启用模块缺少配置) -✓ python: 3.14.2 (>=3.11) -✓ uv: uv 0.9.16 +# 失败 ✗ venv: 已启用但缺少配置项: path ``` +**失败处理**:当 `aide env ensure` 输出 `✗` 时,触发 `env-config` skill 获取详细配置指导。 + +### aide env list + +列出所有可用的环境检测模块。 + +```bash +aide env list +``` + +### aide env set + +设置环境配置(详细用法见 `env-config` skill)。 + +```bash +aide env set modules <模块列表> +aide env set <模块名>.<配置项> <值> +``` + --- ## aide flow - 进度追踪 diff --git a/aide-marketplace/aide-plugin/skills/env-config/SKILL.md b/aide-marketplace/aide-plugin/skills/env-config/SKILL.md new file mode 100644 index 0000000..de206f3 --- /dev/null +++ b/aide-marketplace/aide-plugin/skills/env-config/SKILL.md @@ -0,0 +1,256 @@ +--- +name: env-config +description: 环境配置详细指南。当 aide env ensure 检测失败需要配置环境时使用。提供模块选择、配置设置、多项目场景处理等详细指导。 +--- + +# 环境配置指南 + +当 `aide env ensure` 检测失败(输出 `✗`)时,使用本指南分析项目所需环境并完成配置。 + +--- + +## 一、问题诊断 + +### 1.1 常见失败原因 + +| 错误信息 | 原因 | 解决方案 | +|----------|------|----------| +| `已启用但缺少配置项: path` | 类型B模块未配置路径 | 使用 `aide env set` 配置 | +| `未知模块: xxx` | 启用了不存在的模块 | 检查模块名拼写 | +| `xxx 未安装` | 工具未安装 | 安装对应工具或移除该模块 | +| `node_modules 不存在` | Node.js 依赖未安装 | 配置 node_deps 模块 | + +### 1.2 查看可用模块 + +```bash +aide env list +``` + +--- + +## 二、模块分类 + +### 2.1 类型A:全局工具检测(无需配置) + +| 模块 | 检测内容 | +|------|----------| +| `python` | Python 解释器版本 | +| `uv` | uv 包管理器 | +| `rust` | Rust 工具链(rustc + cargo) | +| `node` | Node.js 运行时 | +| `flutter` | Flutter SDK | +| `android` | Android SDK(ANDROID_HOME) | + +### 2.2 类型B:项目级检测(需要配置) + +| 模块 | 配置项 | 说明 | +|------|--------|------| +| `venv` | `path` | Python 虚拟环境目录 | +| `requirements` | `path` | Python 依赖文件路径 | +| `node_deps` | `path`, `manager`(可选) | Node.js 项目依赖 | + +--- + +## 三、配置命令 + +### 3.1 aide env set + +```bash +# 设置启用的模块列表 +aide env set modules <模块列表> + +# 设置模块配置 +aide env set <模块名>.<配置项> <值> +``` + +### 3.2 验证规则 + +- 设置 `modules` 时,验证每个模块类型是否存在 +- 无效模块名会报错并显示可用模块列表 + +```bash +# 验证失败示例 +$ aide env set modules python,fortran +✗ 未知模块: fortran +→ 可用模块: python, uv, venv, requirements, rust, node, flutter, node_deps, android +``` + +--- + +## 四、项目类型配置 + +### 4.1 项目特征与模块映射 + +| 项目特征 | 推荐模块 | +|----------|----------| +| 存在 `Cargo.toml` | `rust` | +| 存在 `package.json` | `node`, `node_deps` | +| 存在 `pubspec.yaml` | `flutter` | +| 存在 `build.gradle` 或 `android/` | `android` | +| 存在 `requirements.txt` 或 `.venv` | `python`, `uv`, `venv`, `requirements` | + +### 4.2 配置示例 + +**Rust 项目**: +```bash +aide env set modules rust +``` + +**Node.js 项目**: +```bash +aide env set modules node,node_deps +aide env set node_deps.path . +``` + +**Flutter 项目**: +```bash +aide env set modules flutter +# 如果需要构建 Android APK +aide env set modules flutter,android +``` + +**Python 项目**: +```bash +aide env set modules python,uv,venv,requirements +aide env set venv.path .venv +aide env set requirements.path requirements.txt +``` + +**混合项目**(多种技术栈): +```bash +aide env set modules rust,node,flutter,android +``` + +--- + +## 五、多项目场景 + +### 5.1 模块实例化命名 + +当工作目录下有多个同类型子项目时,使用 `模块类型:实例名` 格式: + +```bash +# 多个 Node.js 项目 +aide env set modules node,node_deps:frontend,node_deps:admin +aide env set node_deps:frontend.path frontend +aide env set node_deps:admin.path admin +``` + +### 5.2 配置文件格式 + +```toml +[env] +modules = ["node", "node_deps:frontend", "node_deps:admin"] + +[env."node_deps:frontend"] +path = "frontend" + +[env."node_deps:admin"] +path = "admin" +manager = "pnpm" +``` + +### 5.3 输出示例 + +``` +✓ node: 24.11.1 (npm 11.6.2) +✓ node_deps:frontend: frontend (npm) +✓ node_deps:admin: admin (pnpm) +✓ 环境就绪 (...) +``` + +--- + +## 六、node_deps 模块详解 + +### 6.1 配置项 + +| 配置项 | 必需 | 说明 | +|--------|------|------| +| `path` | 是 | package.json 所在目录 | +| `manager` | 否 | 包管理器,默认自动检测 | + +### 6.2 包管理器自动检测 + +根据锁文件自动判断: + +| 锁文件 | 包管理器 | +|--------|----------| +| `pnpm-lock.yaml` | pnpm | +| `yarn.lock` | yarn | +| `bun.lockb` | bun | +| `package-lock.json` 或无 | npm | + +### 6.3 ensure 行为 + +检测失败时自动运行对应的安装命令: +- npm: `npm install` +- pnpm: `pnpm install` +- yarn: `yarn install` +- bun: `bun install` + +--- + +## 七、配置流程 + +### 7.1 标准流程 + +```bash +# 1. 查看可用模块 +aide env list + +# 2. 分析项目类型,设置模块 +aide env set modules <根据项目选择> + +# 3. 配置类型B模块(如有) +aide env set <模块>.<配置项> <值> + +# 4. 验证配置 +aide env ensure +``` + +### 7.2 快速配置模板 + +**前端项目**: +```bash +aide env set modules node,node_deps +aide env set node_deps.path . +aide env ensure +``` + +**全栈项目**: +```bash +aide env set modules node,node_deps:frontend,node_deps:backend +aide env set node_deps:frontend.path frontend +aide env set node_deps:backend.path backend +aide env ensure +``` + +**移动端项目**: +```bash +aide env set modules flutter,android +aide env ensure +``` + +--- + +## 八、故障排除 + +### 8.1 模块检测失败 + +```bash +# 查看详细信息 +aide env ensure --verbose +``` + +### 8.2 重置配置 + +直接修改 `.aide/config.toml` 或重新运行: + +```bash +aide env set modules <新的模块列表> +``` + +### 8.3 跳过某个模块 + +从 modules 列表中移除该模块即可。 diff --git a/aide-program/aide/env/manager.py b/aide-program/aide/env/manager.py index 3ff1111..0339464 100644 --- a/aide-program/aide/env/manager.py +++ b/aide-program/aide/env/manager.py @@ -16,6 +16,40 @@ RUNTIME_MODULES = ["python", "uv"] DEFAULT_MODULES = ["python", "uv", "venv", "requirements"] +def parse_module_name(name: str) -> tuple[str, str | None]: + """解析模块名称,支持实例化命名。 + + Args: + name: 模块名称,如 "node_deps" 或 "node_deps:react" + + Returns: + (模块类型, 实例名) - 实例名可能为 None + """ + if ":" in name: + parts = name.split(":", 1) + return parts[0], parts[1] + return name, None + + +def validate_modules(module_names: list[str]) -> tuple[bool, list[str]]: + """验证模块名称是否有效。 + + Args: + module_names: 要验证的模块名称列表 + + Returns: + (是否全部有效, 无效的模块类型列表) + """ + register_builtin_modules() + available = set(ModuleRegistry.names()) + invalid = [] + for name in module_names: + module_type, _ = parse_module_name(name) + if module_type not in available: + invalid.append(module_type) + return len(invalid) == 0, invalid + + class EnvManager: """环境管理器。""" @@ -163,12 +197,20 @@ class EnvManager: return env_config.get("modules", DEFAULT_MODULES) def _get_module_config(self, name: str, config: dict[str, Any]) -> dict[str, Any]: - """获取模块配置。""" + """获取模块配置。 + + 支持实例化命名,如 node_deps:react 会查找 [env."node_deps:react"] + """ env_config = config.get("env", {}) - # 尝试新格式 [env.模块名] + # 支持实例化命名:先尝试完整名称(如 node_deps:react) module_config = env_config.get(name, {}) + # 如果没找到且是实例化命名,尝试不带引号的格式 + if not module_config and ":" in name: + # TOML 中可能存储为 env."node_deps:react" 或嵌套格式 + pass # 已经在上面尝试过了 + # 兼容旧格式:如果值是字符串而不是字典,转换为 {"path": value} if isinstance(module_config, str): module_config = {"path": module_config} @@ -204,10 +246,15 @@ class EnvManager: ) -> tuple[bool, str]: """处理单个模块的检测/修复。 + 支持实例化命名,如 node_deps:react + Returns: (是否成功, 版本/路径信息) """ - module = ModuleRegistry.get(name) + # 解析模块名称,支持实例化命名 + module_type, instance_name = parse_module_name(name) + + module = ModuleRegistry.get(module_type) if not module: if is_enabled: output.err(f"{name}: 未知模块") @@ -216,6 +263,7 @@ class EnvManager: output.warn(f"{name}: 未知模块") return True, "" + # 获取配置时使用完整名称(包含实例名) module_config = self._get_module_config(name, config) # verbose: 输出模块配置 @@ -272,3 +320,54 @@ class EnvManager: else: output.warn(f"{name}: {result.message}") return True, "" + + def set_modules(self, module_names: list[str]) -> bool: + """设置启用的模块列表(带验证)。 + + Args: + module_names: 要启用的模块名称列表 + + Returns: + 是否设置成功 + """ + # 验证模块名称 + valid, invalid = validate_modules(module_names) + if not valid: + available = ModuleRegistry.names() + output.err(f"未知模块: {', '.join(invalid)}") + output.info(f"可用模块: {', '.join(available)}") + return False + + # 设置配置 + self.cfg.set_value("env.modules", module_names) + return True + + def set_module_config(self, module_name: str, key: str, value: Any) -> bool: + """设置模块配置(带验证)。 + + 支持实例化命名,如 node_deps:react.path + + Args: + module_name: 模块名称(可包含实例名,如 node_deps:react) + key: 配置键 + value: 配置值 + + Returns: + 是否设置成功 + """ + # 解析模块名称,支持实例化命名 + module_type, _ = parse_module_name(module_name) + + # 验证模块类型是否存在 + module = ModuleRegistry.get(module_type) + if not module: + available = ModuleRegistry.names() + output.err(f"未知模块: {module_type}") + output.info(f"可用模块: {', '.join(available)}") + return False + + # 设置配置,使用完整模块名(包含实例名) + # 注意:TOML 中带冒号的键需要引号,但 set_value 会自动处理 + config_key = f"env.{module_name}.{key}" + self.cfg.set_value(config_key, value) + return True diff --git a/aide-program/aide/env/modules/android.py b/aide-program/aide/env/modules/android.py new file mode 100644 index 0000000..0f1ba04 --- /dev/null +++ b/aide-program/aide/env/modules/android.py @@ -0,0 +1,146 @@ +"""Android 开发环境检测模块。""" + +from __future__ import annotations + +import os +import subprocess +from pathlib import Path +from typing import Any + +from aide.env.modules.base import BaseModule, CheckResult, ModuleInfo + + +class AndroidModule(BaseModule): + """Android 开发环境检测模块(类型A:无需配置)。 + + 检测 Android SDK 和相关工具: + - ANDROID_HOME / ANDROID_SDK_ROOT 环境变量 + - Android SDK 目录结构 + - 关键工具:adb, aapt, sdkmanager + """ + + @property + def info(self) -> ModuleInfo: + return ModuleInfo( + name="android", + description="Android SDK", + capabilities=["check"], + requires_config=False, + ) + + def check(self, config: dict[str, Any], root: Path) -> CheckResult: + """检测 Android 开发环境。""" + # 检测 ANDROID_HOME 或 ANDROID_SDK_ROOT + sdk_root = self._get_sdk_root() + if not sdk_root: + return CheckResult( + success=False, + message="ANDROID_HOME 或 ANDROID_SDK_ROOT 未设置", + can_ensure=False, + ) + + sdk_path = Path(sdk_root) + if not sdk_path.exists(): + return CheckResult( + success=False, + message=f"Android SDK 目录不存在: {sdk_root}", + can_ensure=False, + ) + + # 检测关键目录 + platform_tools = sdk_path / "platform-tools" + build_tools = sdk_path / "build-tools" + platforms = sdk_path / "platforms" + + missing = [] + if not platform_tools.exists(): + missing.append("platform-tools") + if not build_tools.exists(): + missing.append("build-tools") + if not platforms.exists(): + missing.append("platforms") + + if missing: + return CheckResult( + success=False, + message=f"缺少 SDK 组件: {', '.join(missing)}", + can_ensure=False, + ) + + # 获取版本信息 + build_tools_versions = self._get_build_tools_versions(build_tools) + platform_versions = self._get_platform_versions(platforms) + + # 检测 adb + adb_version = self._get_adb_version(platform_tools) + + # 构建版本信息 + version_info = [] + if adb_version: + version_info.append(f"adb {adb_version}") + if build_tools_versions: + version_info.append(f"build-tools {build_tools_versions[0]}") + if platform_versions: + version_info.append(f"API {platform_versions[0]}") + + return CheckResult( + success=True, + version=sdk_root, + message=", ".join(version_info) if version_info else None, + ) + + def _get_sdk_root(self) -> str | None: + """获取 Android SDK 根目录。""" + return os.environ.get("ANDROID_HOME") or os.environ.get("ANDROID_SDK_ROOT") + + def _get_adb_version(self, platform_tools: Path) -> str | None: + """获取 adb 版本。""" + adb_path = platform_tools / "adb" + if not adb_path.exists(): + return None + + try: + result = subprocess.run( + [str(adb_path), "version"], + capture_output=True, + text=True, + timeout=10, + ) + if result.returncode == 0: + # Android Debug Bridge version 1.0.41 + lines = result.stdout.strip().split("\n") + if lines: + parts = lines[0].split() + if len(parts) >= 5: + return parts[4] + return None + except (subprocess.TimeoutExpired, Exception): + return None + + def _get_build_tools_versions(self, build_tools: Path) -> list[str]: + """获取已安装的 build-tools 版本列表(降序)。""" + if not build_tools.exists(): + return [] + + versions = [] + for item in build_tools.iterdir(): + if item.is_dir() and item.name[0].isdigit(): + versions.append(item.name) + + return sorted(versions, reverse=True) + + def _get_platform_versions(self, platforms: Path) -> list[str]: + """获取已安装的 platform 版本列表(降序)。""" + if not platforms.exists(): + return [] + + versions = [] + for item in platforms.iterdir(): + if item.is_dir() and item.name.startswith("android-"): + api_level = item.name.replace("android-", "") + versions.append(api_level) + + return sorted(versions, key=lambda x: int(x) if x.isdigit() else 0, reverse=True) + + +module = AndroidModule() diff --git a/aide-program/aide/env/modules/flutter.py b/aide-program/aide/env/modules/flutter.py new file mode 100644 index 0000000..f169f15 --- /dev/null +++ b/aide-program/aide/env/modules/flutter.py @@ -0,0 +1,132 @@ +"""Flutter SDK 检测模块。""" + +from __future__ import annotations + +import subprocess +from pathlib import Path +from typing import Any + +from aide.env.modules.base import BaseModule, CheckResult, ModuleInfo + + +class FlutterModule(BaseModule): + """Flutter SDK 检测模块(类型A:无需配置)。""" + + @property + def info(self) -> ModuleInfo: + return ModuleInfo( + name="flutter", + description="Flutter SDK", + capabilities=["check"], + requires_config=False, + ) + + def check(self, config: dict[str, Any], root: Path) -> CheckResult: + """检测 Flutter SDK。""" + flutter_version = self._get_flutter_version() + dart_version = self._get_dart_version() + + if not flutter_version: + return CheckResult( + success=False, + message="flutter 未安装", + can_ensure=False, + ) + + # 检查最低版本要求(如果配置了) + min_version = config.get("min_version") + if min_version: + if not self._version_satisfies(flutter_version, min_version): + return CheckResult( + success=False, + version=flutter_version, + message=f"版本不足,要求>={min_version},当前 {flutter_version}", + can_ensure=False, + ) + + # 构建版本信息 + extra = f"dart {dart_version}" if dart_version else "" + return CheckResult( + success=True, + version=flutter_version, + message=extra, + ) + + def _get_flutter_version(self) -> str | None: + """获取 Flutter 版本。""" + try: + result = subprocess.run( + ["flutter", "--version", "--machine"], + capture_output=True, + text=True, + timeout=30, + ) + if result.returncode == 0: + # 尝试解析 JSON 输出 + import json + try: + data = json.loads(result.stdout) + return data.get("frameworkVersion") + except json.JSONDecodeError: + pass + + # 回退到普通版本输出 + result = subprocess.run( + ["flutter", "--version"], + capture_output=True, + text=True, + timeout=30, + ) + if result.returncode == 0: + # Flutter 3.16.0 • channel stable • ... + output = result.stdout.strip() + lines = output.split("\n") + if lines: + parts = lines[0].split() + if len(parts) >= 2 and parts[0] == "Flutter": + return parts[1] + return None + except (FileNotFoundError, subprocess.TimeoutExpired): + return None + + def _get_dart_version(self) -> str | None: + """获取 Dart 版本。""" + try: + result = subprocess.run( + ["dart", "--version"], + capture_output=True, + text=True, + timeout=10, + ) + if result.returncode == 0: + # Dart SDK version: 3.2.0 (stable) ... + output = result.stdout.strip() + if not output: + output = result.stderr.strip() # dart 有时输出到 stderr + parts = output.split() + for i, part in enumerate(parts): + if part == "version:" and i + 1 < len(parts): + return parts[i + 1] + return None + except (FileNotFoundError, subprocess.TimeoutExpired): + return None + + def _version_satisfies(self, current: str, minimum: str) -> bool: + """检查版本是否满足最低要求。""" + current_parts = self._parse_version(current) + min_parts = self._parse_version(minimum) + return current_parts >= min_parts + + @staticmethod + def _parse_version(version: str) -> tuple[int, ...]: + """解析版本号字符串。""" + parts = [] + for part in version.split("."): + try: + parts.append(int(part)) + except ValueError: + break + return tuple(parts) + + +module = FlutterModule() diff --git a/aide-program/aide/env/modules/node.py b/aide-program/aide/env/modules/node.py new file mode 100644 index 0000000..b404f72 --- /dev/null +++ b/aide-program/aide/env/modules/node.py @@ -0,0 +1,93 @@ +"""Node.js 环境检测模块。""" + +from __future__ import annotations + +import subprocess +from pathlib import Path +from typing import Any + +from aide.env.modules.base import BaseModule, CheckResult, ModuleInfo + + +class NodeModule(BaseModule): + """Node.js 检测模块(类型A:无需配置)。""" + + @property + def info(self) -> ModuleInfo: + return ModuleInfo( + name="node", + description="Node.js 运行时", + capabilities=["check"], + requires_config=False, + ) + + def check(self, config: dict[str, Any], root: Path) -> CheckResult: + """检测 Node.js 版本。""" + node_version = self._get_version("node") + npm_version = self._get_version("npm") + + if not node_version: + return CheckResult( + success=False, + message="node 未安装", + can_ensure=False, + ) + + # 检查最低版本要求(如果配置了) + min_version = config.get("min_version") + if min_version: + if not self._version_satisfies(node_version, min_version): + return CheckResult( + success=False, + version=node_version, + message=f"版本不足,要求>={min_version},当前 {node_version}", + can_ensure=False, + ) + + # 构建版本信息 + extra = f"npm {npm_version}" if npm_version else "npm 未安装" + return CheckResult( + success=True, + version=node_version, + message=extra, + ) + + def _get_version(self, cmd: str) -> str | None: + """获取命令版本。""" + try: + result = subprocess.run( + [cmd, "--version"], + capture_output=True, + text=True, + timeout=10, + ) + if result.returncode == 0: + # node: v20.10.0 -> 20.10.0 + # npm: 10.2.3 -> 10.2.3 + output = result.stdout.strip() + if output.startswith("v"): + output = output[1:] + return output + return None + except (FileNotFoundError, subprocess.TimeoutExpired): + return None + + def _version_satisfies(self, current: str, minimum: str) -> bool: + """检查版本是否满足最低要求。""" + current_parts = self._parse_version(current) + min_parts = self._parse_version(minimum) + return current_parts >= min_parts + + @staticmethod + def _parse_version(version: str) -> tuple[int, ...]: + """解析版本号字符串。""" + parts = [] + for part in version.split("."): + try: + parts.append(int(part)) + except ValueError: + break + return tuple(parts) + + +module = NodeModule() diff --git a/aide-program/aide/env/modules/node_deps.py b/aide-program/aide/env/modules/node_deps.py new file mode 100644 index 0000000..0047ee7 --- /dev/null +++ b/aide-program/aide/env/modules/node_deps.py @@ -0,0 +1,141 @@ +"""Node.js 项目依赖检测模块。""" + +from __future__ import annotations + +import subprocess +from pathlib import Path +from typing import Any + +from aide.env.modules.base import BaseModule, CheckResult, ModuleInfo + + +class NodeDepsModule(BaseModule): + """Node.js 项目依赖检测模块(类型B:需要配置)。 + + 支持多种包管理器:npm, pnpm, yarn, bun + 自动根据锁文件检测包管理器类型 + """ + + # 锁文件到包管理器的映射 + LOCK_FILES = { + "pnpm-lock.yaml": "pnpm", + "yarn.lock": "yarn", + "bun.lockb": "bun", + "package-lock.json": "npm", + } + + # 包管理器安装命令 + INSTALL_COMMANDS = { + "npm": ["npm", "install"], + "pnpm": ["pnpm", "install"], + "yarn": ["yarn", "install"], + "bun": ["bun", "install"], + } + + @property + def info(self) -> ModuleInfo: + return ModuleInfo( + name="node_deps", + description="Node.js 项目依赖", + capabilities=["check", "ensure"], + requires_config=True, + config_keys=["path"], + ) + + def check(self, config: dict[str, Any], root: Path) -> CheckResult: + """检测 Node.js 项目依赖。""" + project_path = root / config["path"] + + # 检测 package.json 是否存在 + package_json = project_path / "package.json" + if not package_json.exists(): + return CheckResult( + success=False, + message=f"package.json 不存在: {config['path']}", + can_ensure=False, + ) + + # 检测 node_modules 是否存在 + node_modules = project_path / "node_modules" + if not node_modules.exists(): + manager = self._detect_manager(project_path, config) + return CheckResult( + success=False, + message=f"node_modules 不存在", + can_ensure=True, + ) + + # 检测包管理器 + manager = self._detect_manager(project_path, config) + + return CheckResult( + success=True, + version=config["path"], + message=manager, + ) + + def ensure(self, config: dict[str, Any], root: Path) -> CheckResult: + """安装 Node.js 项目依赖。""" + project_path = root / config["path"] + manager = self._detect_manager(project_path, config) + + # 检测包管理器是否已安装 + if not self._is_manager_installed(manager): + return CheckResult( + success=False, + message=f"{manager} 未安装", + ) + + # 运行安装命令 + install_cmd = self.INSTALL_COMMANDS.get(manager, ["npm", "install"]) + + try: + subprocess.run( + install_cmd, + cwd=project_path, + check=True, + capture_output=True, + ) + return CheckResult( + success=True, + version=config["path"], + message=f"已安装 ({manager})", + ) + except subprocess.CalledProcessError as exc: + error_msg = exc.stderr.decode() if exc.stderr else str(exc) + return CheckResult( + success=False, + message=f"安装失败: {error_msg[:100]}", + ) + + def _detect_manager(self, project_path: Path, config: dict[str, Any]) -> str: + """检测包管理器类型。 + + 优先使用配置指定的 manager,否则根据锁文件自动检测。 + """ + # 优先使用配置指定的 manager + if "manager" in config: + return config["manager"] + + # 根据锁文件检测 + for lock_file, manager in self.LOCK_FILES.items(): + if (project_path / lock_file).exists(): + return manager + + # 默认使用 npm + return "npm" + + def _is_manager_installed(self, manager: str) -> bool: + """检测包管理器是否已安装。""" + try: + subprocess.run( + [manager, "--version"], + capture_output=True, + timeout=10, + ) + return True + except (FileNotFoundError, subprocess.TimeoutExpired): + return False + + +module = NodeDepsModule() diff --git a/aide-program/aide/env/modules/rust.py b/aide-program/aide/env/modules/rust.py new file mode 100644 index 0000000..008ceb2 --- /dev/null +++ b/aide-program/aide/env/modules/rust.py @@ -0,0 +1,98 @@ +"""Rust 工具链检测模块。""" + +from __future__ import annotations + +import subprocess +from pathlib import Path +from typing import Any + +from aide.env.modules.base import BaseModule, CheckResult, ModuleInfo + + +class RustModule(BaseModule): + """Rust 工具链检测模块(类型A:无需配置)。""" + + @property + def info(self) -> ModuleInfo: + return ModuleInfo( + name="rust", + description="Rust 工具链", + capabilities=["check"], + requires_config=False, + ) + + def check(self, config: dict[str, Any], root: Path) -> CheckResult: + """检测 Rust 工具链(rustc 和 cargo)。""" + rustc_version = self._get_version("rustc") + cargo_version = self._get_version("cargo") + + if not rustc_version: + return CheckResult( + success=False, + message="rustc 未安装", + can_ensure=False, + ) + + if not cargo_version: + return CheckResult( + success=False, + message="cargo 未安装", + can_ensure=False, + ) + + # 检查最低版本要求(如果配置了) + min_version = config.get("min_version") + if min_version: + if not self._version_satisfies(rustc_version, min_version): + return CheckResult( + success=False, + version=rustc_version, + message=f"版本不足,要求>={min_version},当前 {rustc_version}", + can_ensure=False, + ) + + return CheckResult( + success=True, + version=rustc_version, + message=f"cargo {cargo_version}", + ) + + def _get_version(self, cmd: str) -> str | None: + """获取命令版本。""" + try: + result = subprocess.run( + [cmd, "--version"], + capture_output=True, + text=True, + timeout=10, + ) + if result.returncode == 0: + # rustc 1.75.0 (xxx) -> 1.75.0 + # cargo 1.75.0 (xxx) -> 1.75.0 + output = result.stdout.strip() + parts = output.split() + if len(parts) >= 2: + return parts[1] + return None + except (FileNotFoundError, subprocess.TimeoutExpired): + return None + + def _version_satisfies(self, current: str, minimum: str) -> bool: + """检查版本是否满足最低要求。""" + current_parts = self._parse_version(current) + min_parts = self._parse_version(minimum) + return current_parts >= min_parts + + @staticmethod + def _parse_version(version: str) -> tuple[int, ...]: + """解析版本号字符串。""" + parts = [] + for part in version.split("."): + try: + parts.append(int(part)) + except ValueError: + break + return tuple(parts) + + +module = RustModule() diff --git a/aide-program/aide/env/registry.py b/aide-program/aide/env/registry.py index bb71d09..d087e8b 100644 --- a/aide-program/aide/env/registry.py +++ b/aide-program/aide/env/registry.py @@ -43,8 +43,12 @@ class ModuleRegistry: def register_builtin_modules() -> None: """注册内置模块。""" - from aide.env.modules import python, uv, venv, requirements + from aide.env.modules import ( + python, uv, venv, requirements, + rust, node, flutter, + node_deps, android, + ) - for mod in [python, uv, venv, requirements]: + for mod in [python, uv, venv, requirements, rust, node, flutter, node_deps, android]: if hasattr(mod, "module"): ModuleRegistry.register(mod.module) diff --git a/aide-program/aide/main.py b/aide-program/aide/main.py index c73322d..b82a81e 100644 --- a/aide-program/aide/main.py +++ b/aide-program/aide/main.py @@ -69,6 +69,12 @@ def build_parser() -> argparse.ArgumentParser: list_parser = env_sub.add_parser("list", help="列出所有可用模块") list_parser.set_defaults(func=handle_env_list) + # aide env set + set_parser = env_sub.add_parser("set", help="设置环境配置(带验证)") + set_parser.add_argument("key", help="配置键:modules 或 模块名.配置项") + set_parser.add_argument("value", help="配置值") + set_parser.set_defaults(func=handle_env_set) + # aide env(无子命令时等同于 ensure) env_parser.set_defaults(func=handle_env_default) @@ -137,6 +143,34 @@ def handle_env_list(args: argparse.Namespace) -> bool: return True +def handle_env_set(args: argparse.Namespace) -> bool: + """aide env set 处理。""" + root = Path.cwd() + cfg = ConfigManager(root) + manager = EnvManager(root, cfg) + + key = args.key + value = args.value + + if key == "modules": + # 设置启用的模块列表 + module_names = [m.strip() for m in value.split(",") if m.strip()] + return manager.set_modules(module_names) + elif "." in key: + # 设置模块配置,如 venv.path + parts = key.split(".", 1) + module_name = parts[0] + config_key = parts[1] + parsed_value = _parse_value(value) + return manager.set_module_config(module_name, config_key, parsed_value) + else: + # 无效的键格式 + output.err(f"无效的配置键: {key}") + output.info("用法: aide env set modules <模块列表>") + output.info(" aide env set <模块名>.<配置项> <值>") + return False + + def handle_config_get(args: argparse.Namespace) -> bool: root = Path.cwd() cfg = ConfigManager(root) diff --git a/aide-program/docs/README.md b/aide-program/docs/README.md index 48afb64..de58496 100644 --- a/aide-program/docs/README.md +++ b/aide-program/docs/README.md @@ -43,11 +43,29 @@ aide-program 是 Aide 工作流体系的命令行工具,为 aide-plugin 提供 | 子命令 | 设计文档 | 实现状态 | 职责 | |--------|----------|----------|------| | `aide init` | [commands/init.md](commands/init.md) | ✅ 已实现 | 初始化 .aide 目录 | -| `aide env` | [commands/env.md](commands/env.md) | ✅ 已实现 | 环境检测与修复 | +| `aide env ensure` | [commands/env.md](commands/env.md) | ✅ 已实现 | 环境检测与修复 | +| `aide env list` | [commands/env.md](commands/env.md) | ✅ 已实现 | 列出可用模块 | +| `aide env set` | [commands/env.md](commands/env.md) | ✅ 已实现 | 设置环境配置(带验证) | | `aide config` | [formats/config.md](formats/config.md) | ✅ 已实现 | 配置读写 | | `aide flow` | [commands/flow.md](commands/flow.md) | ⏳ 待实现 | 进度追踪与 git 集成 | | `aide decide` | [commands/decide.md](commands/decide.md) | ⏳ 待实现 | 待定项 Web 确认 | +### 2.1 环境检测模块 + +| 模块 | 类型 | 说明 | +|------|------|------| +| python, uv | A | Python 运行时 | +| rust | A | Rust 工具链 | +| node | A | Node.js 运行时 | +| flutter | A | Flutter SDK | +| android | A | Android SDK | +| venv, requirements | B | Python 项目依赖 | +| node_deps | B | Node.js 项目依赖 | + +- 类型A:无需配置即可检测 +- 类型B:需要配置路径 +- 支持模块实例化命名:`模块类型:实例名` + --- ## 三、目录结构 @@ -71,21 +89,21 @@ aide-program/ ├── __main__.py # 支持 python -m aide ├── main.py # CLI 解析与命令分发 ├── core/ - │ ├── __init__.py │ ├── config.py # 配置读写 │ └── output.py # 输出格式(✓/⚠/✗/→) ├── env/ - │ ├── __init__.py - │ └── ensure.py # 环境检测与修复 + │ ├── manager.py # 环境管理器 + │ ├── registry.py # 模块注册表 + │ └── modules/ # 环境检测模块 + │ ├── base.py # 模块基类 + │ ├── python.py, uv.py, rust.py + │ ├── node.py, flutter.py, android.py + │ ├── venv.py, requirements.py + │ └── node_deps.py ├── flow/ # 待实现 - │ ├── __init__.py - │ ├── tracker.py # 进度追踪 - │ ├── git.py # git 自动提交 - │ └── validator.py # 流程校验 + │ └── ... └── decide/ # 待实现 - ├── __init__.py - ├── server.py # HTTP 服务 - └── web/ # 静态前端 + └── ... ``` --- diff --git a/aide-program/docs/commands/env.md b/aide-program/docs/commands/env.md index 0eef833..aa928aa 100644 --- a/aide-program/docs/commands/env.md +++ b/aide-program/docs/commands/env.md @@ -28,6 +28,7 @@ aide env # 等同于 aide env ensure aide env ensure [options] # 检测并修复 aide env list # 列出所有可用模块 +aide env set # 设置环境配置(带验证) ``` ### 2.1 aide env ensure @@ -47,6 +48,45 @@ aide env list # 列出所有可用模块 列出所有可用的环境检测模块及其状态。 +### 2.3 aide env set + +设置环境配置,带模块名称验证。 + +**用法:** + +```bash +aide env set modules <模块列表> # 设置启用的模块(逗号分隔) +aide env set <模块名>.<配置项> <值> # 设置模块配置 +``` + +**示例:** + +```bash +# 设置启用的模块 +aide env set modules python,uv,rust,node + +# 设置模块配置 +aide env set venv.path .venv +aide env set requirements.path requirements.txt + +# 设置实例化模块(多项目场景) +aide env set modules rust,node,flutter,android,node_deps:react +aide env set node_deps:react.path react-demo +``` + +**验证规则:** + +- 设置 `modules` 时,验证每个模块类型是否存在 +- 设置模块配置时,验证模块类型是否存在 +- 无效模块名会报错并显示可用模块列表 + +**错误示例:** + +``` +✗ 未知模块: fortran, cobol +→ 可用模块: python, uv, venv, requirements, rust, node, flutter, node_deps, android +``` + --- ## 三、模块系统 @@ -59,6 +99,10 @@ aide env list # 列出所有可用模块 |------|------|------| | `python` | Python 解释器版本 | check | | `uv` | uv 包管理器 | check | +| `rust` | Rust 工具链(rustc + cargo) | check | +| `node` | Node.js 运行时 | check | +| `flutter` | Flutter SDK | check | +| `android` | Android SDK | check | **类型B:路径依赖模块(必须有配置才能检测)** @@ -66,12 +110,36 @@ aide env list # 列出所有可用模块 |------|------|------|----------| | `venv` | Python 虚拟环境 | check, ensure | `path` | | `requirements` | Python 依赖管理 | check, ensure | `path` | +| `node_deps` | Node.js 项目依赖 | check, ensure | `path` | ### 3.2 模块能力 - `check`:检测环境是否可用 - `ensure`:检测失败时尝试自动修复 +### 3.3 模块实例化命名 + +支持 `模块类型:实例名` 格式,用于同类型多实例场景: + +```toml +# 多个 Node.js 项目 +modules = ["node", "node_deps:react", "node_deps:vue"] + +[env."node_deps:react"] +path = "react-demo" + +[env."node_deps:vue"] +path = "vue-demo" +manager = "pnpm" +``` + +**输出示例:** +``` +✓ node: 24.11.1 (npm 11.6.2) +✓ node_deps:react: react-demo (npm) +✓ node_deps:vue: vue-demo (pnpm) +``` + --- ## 四、配置 @@ -95,7 +163,32 @@ path = ".venv" path = "requirements.txt" ``` -### 4.2 配置兼容性 +### 4.2 多项目配置示例 + +```toml +[env] +modules = ["rust", "node", "flutter", "android", "node_deps:react"] + +# Node.js 项目依赖(实例化命名) +[env."node_deps:react"] +path = "react-demo" +# manager = "npm" # 可选,默认自动检测 +``` + +### 4.3 node_deps 模块配置 + +| 配置项 | 必需 | 说明 | +|--------|------|------| +| `path` | 是 | package.json 所在目录 | +| `manager` | 否 | 包管理器:npm/pnpm/yarn/bun,默认自动检测 | + +**自动检测逻辑**(按锁文件判断): +- `pnpm-lock.yaml` → pnpm +- `yarn.lock` → yarn +- `bun.lockb` → bun +- `package-lock.json` 或无锁文件 → npm + +### 4.4 配置兼容性 支持旧格式配置: @@ -129,88 +222,6 @@ requirements = "requirements.txt" - 未启用模块失败 = 警告(⚠) = 可忽略 - 启用的B类模块无配置 = 错误(✗) = 配置错误 -### 5.2 业务流程 - -``` -@startuml -skinparam defaultFontName "PingFang SC" - -start - -:读取配置; -:获取启用模块列表; - -if (--runtime?) then (是) - :target = [python, uv]; -else if (--modules?) then (是) - :target = 指定模块; -else if (--all?) then (是) - :target = 启用模块; - :check_only = true; -else (否) - :target = 启用模块; -endif - -if (verbose?) then (是) - :输出详细头部信息; -endif - -:遍历 target 模块; - -repeat - :获取模块实例; - :获取模块配置; - - if (verbose?) then (是) - :输出模块配置详情; - endif - - if (B类模块 && 无配置?) then (是) - if (在启用列表?) then (是) - :输出错误; - stop - else (否) - :输出警告,跳过; - endif - endif - - :执行 check(); - - if (成功?) then (是) - :输出成功; - else (否) - if (check_only?) then (是) - :输出警告; - else if (可修复?) then (是) - :执行 ensure(); - if (修复成功?) then (是) - :输出成功; - else (否) - if (在启用列表?) then (是) - :输出错误; - stop - else (否) - :输出警告; - endif - endif - else (否) - if (在启用列表?) then (是) - :输出错误; - stop - else (否) - :输出警告; - endif - endif - endif - -repeat while (还有模块?) - -:输出环境就绪; - -stop -@enduml -``` - --- ## 六、输出示例 @@ -219,93 +230,48 @@ stop ``` 可用模块: - 模块 描述 能力 需要配置 + 模块 描述 能力 需要配置 ──────────────────────────────────────────────────────────── - python Python 解释器版本 check 否 - uv uv 包管理器 check 否 - venv Python 虚拟环境 check, ensure 是 [path] - requirements Python 依赖管理 check, ensure 是 [path] + python Python 解释器版本 check 否 + uv uv 包管理器 check 否 + venv Python 虚拟环境 check, ensure 是 [path] + requirements Python 依赖管理 check, ensure 是 [path] + rust Rust 工具链 check 否 + node Node.js 运行时 check 否 + flutter Flutter SDK check 否 + node_deps Node.js 项目依赖 check, ensure 是 [path] + android Android SDK check 否 -当前启用: python, uv, venv, requirements +当前启用: rust, node, flutter, android, node_deps:react ``` -### 6.2 aide env ensure - -**成功:** -``` -✓ python: 3.14.2 (>=3.11) -✓ uv: uv 0.9.16 -✓ venv: .venv -✓ requirements: requirements.txt -✓ 环境就绪 (python:3.14.2, uv:uv 0.9.16, venv:.venv, requirements:requirements.txt) -``` - -**需修复:** -``` -✓ python: 3.14.2 (>=3.11) -✓ uv: uv 0.9.16 -→ venv: 虚拟环境不存在: .venv,尝试修复... -✓ venv: 已创建 -✓ requirements: requirements.txt -✓ 环境就绪 (...) -``` - -**启用模块失败:** -``` -✓ python: 3.14.2 (>=3.11) -✓ uv: uv 0.9.16 -✗ venv: 已启用但缺少配置项: path -``` - -### 6.3 aide env ensure --verbose +### 6.2 aide env ensure(多项目场景) ``` -============================================================ -环境检测详细信息 -============================================================ - - 工作目录: /home/user/myproject - 配置文件: /home/user/myproject/.aide/config.toml - 配置存在: 是 - - 启用模块: python, uv, venv, requirements - - 目标模块: python, uv, venv, requirements - - [python] 配置: - min_version: 3.11 -✓ python: 3.14.2 (>=3.11) - [uv] 配置: - (无配置) -✓ uv: uv 0.9.16 - [venv] 配置: - path: .venv - path (绝对): /home/user/myproject/.venv - path (存在): 是 -✓ venv: .venv - [requirements] 配置: - path: requirements.txt - path (绝对): /home/user/myproject/requirements.txt - path (存在): 是 -✓ requirements: requirements.txt -✓ 环境就绪 (...) +✓ rust: 1.94.0-nightly (cargo 1.94.0-nightly) +✓ node: 24.11.1 (npm 11.6.2) +✓ flutter: 3.38.4 (dart 3.10.3) +✓ android: /home/user/android-sdk (adb 1.0.41, build-tools 36.1.0, API 36) +→ node_deps:react: node_modules 不存在,尝试修复... +✓ node_deps:react: 已安装 (npm) +✓ 环境就绪 (rust:1.94.0-nightly, node:24.11.1, flutter:3.38.4, android:/home/user/android-sdk, node_deps:react:react-demo) ``` -### 6.4 aide env ensure --runtime +### 6.3 aide env set 示例 -``` -✓ python: 3.14.2 (>=3.11) -✓ uv: uv 0.9.16 -✓ 环境就绪 (python:3.14.2, uv:uv 0.9.16) -``` +```bash +# 设置多种环境模块 +$ aide env set modules rust,node,flutter,android,node_deps:react +✓ 已更新 env.modules = ['rust', 'node', 'flutter', 'android', 'node_deps:react'] -### 6.5 aide env ensure --all +# 设置实例化模块配置 +$ aide env set node_deps:react.path react-demo +✓ 已更新 env."node_deps:react".path = 'react-demo' -``` -✓ python: 3.14.2 (>=3.11) -✓ uv: uv 0.9.16 -✓ venv: .venv -✓ requirements: requirements.txt +# 验证失败示例 +$ aide env set modules python,fortran +✗ 未知模块: fortran +→ 可用模块: python, uv, venv, requirements, rust, node, flutter, node_deps, android ``` --- @@ -323,7 +289,12 @@ aide/env/ ├── python.py # Python 模块 ├── uv.py # uv 模块 ├── venv.py # venv 模块 - └── requirements.py # requirements 模块 + ├── requirements.py # requirements 模块 + ├── rust.py # Rust 模块 + ├── node.py # Node.js 模块 + ├── flutter.py # Flutter 模块 + ├── node_deps.py # Node.js 项目依赖模块 + └── android.py # Android SDK 模块 ``` ### 7.1 模块基类 diff --git a/aide-program/docs/formats/config.md b/aide-program/docs/formats/config.md index adbeec1..81d41e6 100644 --- a/aide-program/docs/formats/config.md +++ b/aide-program/docs/formats/config.md @@ -89,10 +89,20 @@ phases = ["task-optimize", "flow-design", "impl", "verify", "docs", "finish"] | `modules` | array | `["python", "uv", "venv", "requirements"]` | 启用的环境检测模块 | **可用模块**: -- `python` - Python 解释器版本检测 -- `uv` - uv 包管理器检测 -- `venv` - Python 虚拟环境管理 -- `requirements` - Python 依赖管理 + +| 模块 | 类型 | 说明 | +|------|------|------| +| `python` | A | Python 解释器版本检测 | +| `uv` | A | uv 包管理器检测 | +| `rust` | A | Rust 工具链检测(rustc + cargo) | +| `node` | A | Node.js 运行时检测 | +| `flutter` | A | Flutter SDK 检测 | +| `android` | A | Android SDK 检测 | +| `venv` | B | Python 虚拟环境管理 | +| `requirements` | B | Python 依赖管理 | +| `node_deps` | B | Node.js 项目依赖管理 | + +**模块实例化命名**:支持 `模块类型:实例名` 格式,用于同类型多实例场景。 #### 4.3.2 模块配置 @@ -111,6 +121,24 @@ path = ".venv" # 虚拟环境目录路径 [env.requirements] path = "requirements.txt" # 依赖文件路径 + +[env.node_deps] +path = "frontend" # package.json 所在目录 +manager = "npm" # 可选:npm/pnpm/yarn/bun,默认自动检测 +``` + +**实例化模块配置**(多项目场景): + +```toml +[env] +modules = ["node", "node_deps:react", "node_deps:vue"] + +[env."node_deps:react"] +path = "react-demo" + +[env."node_deps:vue"] +path = "vue-demo" +manager = "pnpm" ``` **使用场景**: diff --git a/cache/setup-test-projects.sh b/cache/setup-test-projects.sh new file mode 100644 index 0000000..67e6749 --- /dev/null +++ b/cache/setup-test-projects.sh @@ -0,0 +1,109 @@ +#!/bin/bash +# 创建 aide-env-test 测试目录和项目 + +set -e + +BASE_DIR="/home/user/temp/ccoptimize/test-cache/aide-env-test" + +# 创建基础目录 +mkdir -p "$BASE_DIR" + +# 创建 rust-demo 项目 +mkdir -p "$BASE_DIR/rust-demo/src" +cat > "$BASE_DIR/rust-demo/Cargo.toml" << 'EOF' +[package] +name = "rust-demo" +version = "0.1.0" +edition = "2021" + +[dependencies] +EOF + +cat > "$BASE_DIR/rust-demo/src/main.rs" << 'EOF' +fn main() { + println!("Hello from Rust demo!"); +} +EOF + +# 创建 flutter-demo 项目(简化结构) +mkdir -p "$BASE_DIR/flutter-demo/lib" +cat > "$BASE_DIR/flutter-demo/pubspec.yaml" << 'EOF' +name: flutter_demo +description: A Flutter demo project for aide env testing. +version: 1.0.0 + +environment: + sdk: '>=3.0.0 <4.0.0' + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter +EOF + +cat > "$BASE_DIR/flutter-demo/lib/main.dart" << 'EOF' +import 'package:flutter/material.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + home: const Scaffold( + body: Center( + child: Text('Hello from Flutter demo!'), + ), + ), + ); + } +} +EOF + +# 创建 react-demo 项目(简化结构) +mkdir -p "$BASE_DIR/react-demo/src" +cat > "$BASE_DIR/react-demo/package.json" << 'EOF' +{ + "name": "react-demo", + "version": "1.0.0", + "description": "A React demo project for aide env testing", + "main": "src/index.js", + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "react-scripts": "5.0.1" + } +} +EOF + +cat > "$BASE_DIR/react-demo/src/index.js" << 'EOF' +import React from 'react'; +import ReactDOM from 'react-dom/client'; + +function App() { + return

Hello from React demo!

; +} + +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); +EOF + +echo "✓ 测试项目目录结构创建完成" +echo " - $BASE_DIR/rust-demo" +echo " - $BASE_DIR/flutter-demo" +echo " - $BASE_DIR/react-demo"