""" 用户配置存取(per-userId,基于 wiki 物理目录) 所有连接器凭据通过 user_config_read / user_config_write 进行读写, 存储路径:{MINDOS_WIKI_DIR}/{userId}/.config/{connector}.json 设计原则: - 与 wiki/{userId}/ 物理目录隔离模式一致 - .config/ 前缀防止 Agent 的 search_files 扫到凭据 - 一个用户一个目录,导出/删除用户数据只需操作 wiki/{userId}/ """ import json import logging import os from pathlib import Path from typing import Any, Dict logger = logging.getLogger(__name__) def _wiki_root() -> Path: """返回知识花园根目录""" return Path(os.getenv("MINDOS_WIKI_DIR", os.path.expanduser("~/.hermes/wiki"))) def user_config_path(user_id: str, connector: str) -> Path: """返回 wiki/{userId}/.config/{connector}.json 的路径""" return _wiki_root() / user_id / ".config" / f"{connector}.json" def user_config_read(user_id: str, connector: str) -> Dict[str, Any]: """读取指定用户的连接器配置,不存在返回空 dict""" p = user_config_path(user_id, connector) try: if p.exists(): return json.loads(p.read_text(encoding="utf-8")) except Exception as e: logger.warning("[UserConfig] read failed %s/%s: %s", user_id[:8], connector, e) return {} def user_config_write(user_id: str, connector: str, data: Dict[str, Any]) -> None: """写入指定用户的连接器配置,自动创建目录""" p = user_config_path(user_id, connector) try: p.parent.mkdir(parents=True, exist_ok=True) p.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8") except Exception as e: logger.warning("[UserConfig] write failed %s/%s: %s", user_id[:8], connector, e) def user_config_delete(user_id: str, connector: str) -> None: """删除指定用户的连接器配置""" p = user_config_path(user_id, connector) try: p.unlink(missing_ok=True) except Exception as e: logger.warning("[UserConfig] delete failed %s/%s: %s", user_id[:8], connector, e)