Files
agent-aide/aide-program/docs/05-配置文件规范.md
2025-12-13 04:37:41 +08:00

16 KiB
Raw Blame History

配置文件规范

一、概述

1.1 配置文件定位

  • 文件路径.aide/config.toml
  • 格式TOMLTom's Obvious, Minimal Language
  • 特点:自文档化,包含详细注释
  • 创建时机aide init 命令执行时

1.2 设计原则

  1. 自文档化:每个配置项都有注释说明
  2. 合理默认值:开箱即用,无需修改
  3. 类型安全:明确的数据类型
  4. 向后兼容:新版本保持旧配置可用

二、配置文件结构

2.1 完整示例

# 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]
# 可选工具配置

# 是否需要 uvPython 包管理器)
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 实现示例

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 实现示例

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 验证配置

验证规则

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 命令应该生成包含注释的默认配置:

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]
# 可选工具配置

# 是否需要 uvPython 包管理器)
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 配置文件创建流程

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 类设计

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 使用示例

# 初始化配置
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 版本兼容性

当配置文件格式升级时,需要提供迁移机制:

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 配置备份

修改配置前应该备份:

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 错误信息示例

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 测试用例

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