✨ feat: 实现部分aide
This commit is contained in:
109
aide-program/aide/core/config.py
Normal file
109
aide-program/aide/core/config.py
Normal file
@@ -0,0 +1,109 @@
|
||||
"""配置管理:生成默认配置、读取/写入配置、维护 .aide 目录与 .gitignore。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
import tomllib
|
||||
|
||||
from tomli_w import dumps as toml_dumps
|
||||
|
||||
from aide.core import output
|
||||
|
||||
DEFAULT_CONFIG = """# Aide 默认配置(由 aide init 生成)
|
||||
# runtime: aide 自身运行要求
|
||||
# task: 任务文档路径
|
||||
# env: 虚拟环境与依赖配置
|
||||
# flow: 环节名称列表,供流程校验使用
|
||||
[runtime]
|
||||
python_min = "3.11"
|
||||
use_uv = true
|
||||
|
||||
[task]
|
||||
source = "task-now.md"
|
||||
spec = "task-spec.md"
|
||||
|
||||
[env]
|
||||
venv = ".venv"
|
||||
requirements = "requirements.txt"
|
||||
|
||||
[flow]
|
||||
phases = ["task-optimize", "flow-design", "impl", "verify", "docs", "finish"]
|
||||
"""
|
||||
|
||||
|
||||
class ConfigManager:
|
||||
def __init__(self, root: Path):
|
||||
self.root = root
|
||||
self.aide_dir = self.root / ".aide"
|
||||
self.config_path = self.aide_dir / "config.toml"
|
||||
self.decisions_dir = self.aide_dir / "decisions"
|
||||
self.logs_dir = self.aide_dir / "logs"
|
||||
|
||||
def ensure_base_dirs(self) -> None:
|
||||
self.aide_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.decisions_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.logs_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def ensure_gitignore(self) -> None:
|
||||
gitignore_path = self.root / ".gitignore"
|
||||
marker = ".aide/"
|
||||
if gitignore_path.exists():
|
||||
content = gitignore_path.read_text(encoding="utf-8").splitlines()
|
||||
if any(line.strip() == marker for line in content):
|
||||
return
|
||||
content.append(marker)
|
||||
gitignore_path.write_text("\n".join(content) + "\n", encoding="utf-8")
|
||||
else:
|
||||
gitignore_path.write_text(f"{marker}\n", encoding="utf-8")
|
||||
|
||||
def ensure_config(self) -> dict[str, Any]:
|
||||
self.ensure_base_dirs()
|
||||
if not self.config_path.exists():
|
||||
self.config_path.write_text(DEFAULT_CONFIG, encoding="utf-8")
|
||||
output.ok("已创建默认配置 .aide/config.toml")
|
||||
return self.load_config()
|
||||
|
||||
def load_config(self) -> dict[str, Any]:
|
||||
if not self.config_path.exists():
|
||||
return {}
|
||||
try:
|
||||
with self.config_path.open("rb") as f:
|
||||
return tomllib.load(f)
|
||||
except Exception as exc: # pragma: no cover - 兼容性输出
|
||||
output.err(f"读取配置失败: {exc}")
|
||||
return {}
|
||||
|
||||
def get_value(self, key: str) -> Any:
|
||||
data = self.load_config()
|
||||
return self._walk_get(data, key)
|
||||
|
||||
def set_value(self, key: str, value: Any) -> None:
|
||||
data = self.ensure_config()
|
||||
self._walk_set(data, key, value)
|
||||
self._write_config(data)
|
||||
output.ok(f"已更新 {key} = {value!r}")
|
||||
|
||||
def _write_config(self, data: dict[str, Any]) -> None:
|
||||
self.config_path.write_text(toml_dumps(data), encoding="utf-8")
|
||||
|
||||
@staticmethod
|
||||
def _walk_get(data: dict[str, Any], dotted_key: str) -> Any:
|
||||
current: Any = data
|
||||
for part in dotted_key.split("."):
|
||||
if not isinstance(current, dict):
|
||||
return None
|
||||
if part not in current:
|
||||
return None
|
||||
current = current[part]
|
||||
return current
|
||||
|
||||
@staticmethod
|
||||
def _walk_set(data: dict[str, Any], dotted_key: str, value: Any) -> None:
|
||||
parts = dotted_key.split(".")
|
||||
current = data
|
||||
for part in parts[:-1]:
|
||||
if part not in current or not isinstance(current[part], dict):
|
||||
current[part] = {}
|
||||
current = current[part]
|
||||
current[parts[-1]] = value
|
||||
Reference in New Issue
Block a user