Structure, config loader, personality/tools/memory from clawd, venv, 22 tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
77 lines
2.2 KiB
Python
77 lines
2.2 KiB
Python
"""
|
|
Config loader for Echo-Core.
|
|
|
|
Loads config.json from project root, provides dot-notation access,
|
|
save/reload support, and raw dict access.
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
_DEFAULT_CONFIG_PATH = Path(__file__).resolve().parent.parent / "config.json"
|
|
|
|
|
|
class Config:
|
|
"""Configuration manager with dot-notation get/set."""
|
|
|
|
def __init__(self, path: Path | str | None = None):
|
|
self._path = Path(path) if path else _DEFAULT_CONFIG_PATH
|
|
self._data: dict = {}
|
|
self.reload()
|
|
|
|
def reload(self) -> None:
|
|
"""Reload config from disk."""
|
|
with open(self._path, "r", encoding="utf-8") as f:
|
|
self._data = json.load(f)
|
|
|
|
def save(self) -> None:
|
|
"""Write current config back to disk."""
|
|
with open(self._path, "w", encoding="utf-8") as f:
|
|
json.dump(self._data, f, indent=2, ensure_ascii=False)
|
|
f.write("\n")
|
|
|
|
def get(self, key: str, default: Any = None) -> Any:
|
|
"""
|
|
Get a value using dot-notation.
|
|
|
|
Examples:
|
|
config.get("bot.name") -> "Echo"
|
|
config.get("channels") -> {}
|
|
config.get("missing", "fallback") -> "fallback"
|
|
"""
|
|
parts = key.split(".")
|
|
current = self._data
|
|
for part in parts:
|
|
if isinstance(current, dict) and part in current:
|
|
current = current[part]
|
|
else:
|
|
return default
|
|
return current
|
|
|
|
def set(self, key: str, value: Any) -> None:
|
|
"""
|
|
Set a value using dot-notation. Creates intermediate dicts as needed.
|
|
|
|
Examples:
|
|
config.set("bot.name", "NewName")
|
|
config.set("new.nested.key", 42)
|
|
"""
|
|
parts = key.split(".")
|
|
current = self._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
|
|
|
|
def raw(self) -> dict:
|
|
"""Return the raw config dict (reference, not copy)."""
|
|
return self._data
|
|
|
|
|
|
def load_config(path: Path | str | None = None) -> Config:
|
|
"""Convenience function to create a Config instance."""
|
|
return Config(path)
|