mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 04:40:45 +08:00
重构仓库目录为统一的 runtime 分层并清理历史 openclaw 残留。
本次迁移将网关/通道/工具/技能/脚本与协议资源集中到新结构,统一路径常量与脚本转发机制,减少顶层噪音并保证运行与测试行为一致。 Made-with: Cursor
This commit is contained in:
parent
ba3836f00f
commit
4a23b715a2
498 changed files with 2760 additions and 2200 deletions
104
runtime/hooks/loader.py
Normal file
104
runtime/hooks/loader.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from .internal_hooks import HookHandler, register_hook, unregister_hook
|
||||
from .policy import resolve_hook_enable_state, resolve_hook_config
|
||||
from .workspace import HookEntry, load_workspace_hook_entries
|
||||
|
||||
|
||||
def _load_module_from_path(module_path: str, unique_key: str) -> Optional[object]:
|
||||
"""
|
||||
Dynamically import a Python module from an absolute path.
|
||||
"""
|
||||
p = Path(module_path)
|
||||
if not p.exists() or not p.is_file():
|
||||
return None
|
||||
name = f"oclaw_hook_{unique_key}_{p.stem}".replace("-", "_")
|
||||
spec = importlib.util.spec_from_file_location(name, str(p))
|
||||
if not spec or not spec.loader:
|
||||
return None
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod) # type: ignore[assignment]
|
||||
return mod
|
||||
|
||||
|
||||
def _resolve_handler(mod: object, export_name: str) -> Optional[HookHandler]:
|
||||
handler = getattr(mod, export_name, None)
|
||||
if callable(handler):
|
||||
return handler # type: ignore[return-value]
|
||||
# fallback: common names
|
||||
for candidate in ("handle", "handler", "main"):
|
||||
h = getattr(mod, candidate, None)
|
||||
if callable(h):
|
||||
return h # type: ignore[return-value]
|
||||
return None
|
||||
|
||||
|
||||
def load_internal_hooks(
|
||||
config: Dict[str, Any],
|
||||
workspace_dir: str,
|
||||
*,
|
||||
managed_hooks_dir: Optional[str] = None,
|
||||
bundled_hooks_dir: Optional[str] = None,
|
||||
) -> int:
|
||||
"""
|
||||
Discover python hooks and register them into the in-process registry.
|
||||
|
||||
Hook file layout:
|
||||
<hookDir>/HOOK.md (YAML frontmatter with oclaw metadata)
|
||||
<hookDir>/handler.py (or index.py)
|
||||
|
||||
Metadata fields used:
|
||||
metadata.oclaw.events: ["type", "type:action", ...]
|
||||
metadata.oclaw.export: handler function name (default: "default" -> we map to "handle")
|
||||
"""
|
||||
# Hook system is on by default; only skip when explicitly disabled.
|
||||
if (((config.get("hooks") or {}).get("internal") or {}).get("enabled")) is False:
|
||||
return 0
|
||||
|
||||
entries = load_workspace_hook_entries(
|
||||
workspace_dir,
|
||||
managed_hooks_dir=managed_hooks_dir,
|
||||
bundled_hooks_dir=bundled_hooks_dir,
|
||||
extra_dirs=(((config.get("hooks") or {}).get("internal") or {}).get("load") or {}).get("extraDirs"),
|
||||
)
|
||||
|
||||
loaded = 0
|
||||
for idx, entry in enumerate(entries):
|
||||
state = resolve_hook_enable_state(entry, config)
|
||||
if not state.get("enabled"):
|
||||
continue
|
||||
|
||||
md = entry.get("metadata") or {}
|
||||
events = md.get("events") if isinstance(md, dict) else None
|
||||
if not isinstance(events, list) or not events:
|
||||
continue
|
||||
|
||||
hook = entry.get("hook") or {}
|
||||
handler_path = hook.get("handlerPath")
|
||||
if not isinstance(handler_path, str) or not handler_path:
|
||||
continue
|
||||
|
||||
export_name = md.get("export") if isinstance(md, dict) else None
|
||||
if not isinstance(export_name, str) or not export_name.strip():
|
||||
export_name = "handle"
|
||||
|
||||
mod = _load_module_from_path(handler_path, unique_key=str(idx))
|
||||
if mod is None:
|
||||
continue
|
||||
|
||||
handler = _resolve_handler(mod, export_name)
|
||||
if handler is None:
|
||||
continue
|
||||
|
||||
for event_key in events:
|
||||
if isinstance(event_key, str) and event_key.strip():
|
||||
register_hook(event_key.strip(), handler)
|
||||
loaded += 1
|
||||
|
||||
return loaded
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue