oclaw/runtime/hooks/user_config_hooks.py
oliver 9d2900db02 完成运行时与启动链路的全面相对路径整改,统一以仓库根为路径基准并移除 oclaw 双层硬编码。
同时补齐路径回归测试与开源自检文档,确保从非仓库 cwd 启动时 workspace 根、配置和 wiki 路径仍稳定可用。

Made-with: Cursor
2026-04-26 09:22:42 +08:00

81 lines
2.3 KiB
Python

from __future__ import annotations
import json
import os
from pathlib import Path
from typing import Any
from oclaw.platform.config.paths import PROJECT_ROOT
def resolve_hooks_config_storage_path() -> Path:
"""
Path used for persistent ``hooks.internal.entries`` edits.
Matches ``resolve_runtime_config`` file resolution: ``OCLAW_CONFIG_PATH`` (optional
relative to ``PROJECT_ROOT``), else ``<PROJECT_ROOT>/oclaw.json``.
"""
raw = str(os.getenv("OCLAW_CONFIG_PATH") or "").strip()
if raw:
p = Path(raw).expanduser()
if not p.is_absolute():
p = (Path(PROJECT_ROOT) / p).resolve()
return p
return (Path(PROJECT_ROOT) / "oclaw.json").resolve()
def load_storage_config_document() -> dict[str, Any]:
p = resolve_hooks_config_storage_path()
if not p.is_file():
return {}
try:
raw = p.read_text(encoding="utf-8")
obj = json.loads(raw)
return dict(obj) if isinstance(obj, dict) else {}
except Exception:
return {}
def save_storage_config_document(doc: dict[str, Any]) -> None:
p = resolve_hooks_config_storage_path()
p.parent.mkdir(parents=True, exist_ok=True)
tmp = p.with_suffix(p.suffix + ".tmp")
tmp.write_text(json.dumps(doc, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
tmp.replace(p)
def apply_hook_entry_enabled(
doc: dict[str, Any],
hook_key: str,
enabled: bool,
*,
ensure_internal_hooks_enabled: bool = False,
) -> None:
"""Mutate *doc* in place (shallow structure for ``hooks.internal`` only)."""
key = str(hook_key or "").strip()
if not key:
raise ValueError("hook_key is empty")
hooks = doc.setdefault("hooks", {})
if not isinstance(hooks, dict):
doc["hooks"] = {}
hooks = doc["hooks"]
internal = hooks.setdefault("internal", {})
if not isinstance(internal, dict):
hooks["internal"] = {}
internal = hooks["internal"]
if ensure_internal_hooks_enabled and enabled:
internal["enabled"] = True
entries = internal.setdefault("entries", {})
if not isinstance(entries, dict):
internal["entries"] = {}
entries = internal["entries"]
row = entries.get(key)
if not isinstance(row, dict):
entries[key] = {}
row = entries[key]
row["enabled"] = bool(enabled)