112 lines
3.2 KiB
Python
112 lines
3.2 KiB
Python
|
|
"""Simple Hooks System - Event-driven automation."""
|
||
|
|
|
||
|
|
from datetime import datetime
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Any, Callable, Dict, List
|
||
|
|
|
||
|
|
|
||
|
|
class HookEvent:
|
||
|
|
"""Event passed to hook handlers."""
|
||
|
|
|
||
|
|
def __init__(
|
||
|
|
self,
|
||
|
|
event_type: str,
|
||
|
|
action: str,
|
||
|
|
context: Dict[str, Any] = None,
|
||
|
|
) -> None:
|
||
|
|
self.type = event_type
|
||
|
|
self.action = action
|
||
|
|
self.timestamp = datetime.now()
|
||
|
|
self.context = context or {}
|
||
|
|
self.messages: List[str] = []
|
||
|
|
|
||
|
|
|
||
|
|
class HooksSystem:
|
||
|
|
"""Simple hooks system for event-driven automation."""
|
||
|
|
|
||
|
|
def __init__(self) -> None:
|
||
|
|
self.handlers: Dict[str, List[Callable]] = {}
|
||
|
|
|
||
|
|
def register(
|
||
|
|
self, event_key: str, handler: Callable[[HookEvent], None]
|
||
|
|
) -> None:
|
||
|
|
"""Register a handler for an event."""
|
||
|
|
if event_key not in self.handlers:
|
||
|
|
self.handlers[event_key] = []
|
||
|
|
self.handlers[event_key].append(handler)
|
||
|
|
print(f"Registered hook: {handler.__name__} -> {event_key}")
|
||
|
|
|
||
|
|
def trigger(
|
||
|
|
self,
|
||
|
|
event_type: str,
|
||
|
|
action: str,
|
||
|
|
context: Dict = None,
|
||
|
|
) -> List[str]:
|
||
|
|
"""Trigger event and run all registered handlers."""
|
||
|
|
event = HookEvent(event_type, action, context)
|
||
|
|
|
||
|
|
event_key = f"{event_type}:{action}"
|
||
|
|
handlers = self.handlers.get(event_key, [])
|
||
|
|
handlers += self.handlers.get(event_type, [])
|
||
|
|
|
||
|
|
if handlers:
|
||
|
|
print(
|
||
|
|
f"Triggering {len(handlers)} hook(s) for {event_key}"
|
||
|
|
)
|
||
|
|
|
||
|
|
for handler in handlers:
|
||
|
|
try:
|
||
|
|
handler(event)
|
||
|
|
except Exception as e:
|
||
|
|
print(f"Hook error ({handler.__name__}): {e}")
|
||
|
|
|
||
|
|
return event.messages
|
||
|
|
|
||
|
|
|
||
|
|
def on_task_created(event: HookEvent) -> None:
|
||
|
|
"""Hook: When task is created."""
|
||
|
|
if event.type != "task" or event.action != "created":
|
||
|
|
return
|
||
|
|
|
||
|
|
task_title = event.context.get("title", "Unknown")
|
||
|
|
print(f"Task created: {task_title}")
|
||
|
|
event.messages.append(f"Task '{task_title}' logged")
|
||
|
|
|
||
|
|
|
||
|
|
def on_memory_sync(event: HookEvent) -> None:
|
||
|
|
"""Hook: When memory syncs."""
|
||
|
|
if event.type != "memory" or event.action != "synced":
|
||
|
|
return
|
||
|
|
|
||
|
|
files_count = event.context.get("files", 0)
|
||
|
|
print(f"Memory synced: {files_count} files")
|
||
|
|
|
||
|
|
|
||
|
|
def on_agent_startup(event: HookEvent) -> None:
|
||
|
|
"""Hook: When agent starts."""
|
||
|
|
if event.type != "agent" or event.action != "startup":
|
||
|
|
return
|
||
|
|
|
||
|
|
print("Agent started - loading BOOT.md if exists")
|
||
|
|
|
||
|
|
workspace_dir = event.context.get("workspace_dir")
|
||
|
|
if workspace_dir:
|
||
|
|
boot_path = Path(workspace_dir) / "BOOT.md"
|
||
|
|
if boot_path.exists():
|
||
|
|
print("Found BOOT.md - would execute startup tasks")
|
||
|
|
event.messages.append("Executed BOOT.md startup tasks")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
hooks = HooksSystem()
|
||
|
|
|
||
|
|
hooks.register("task:created", on_task_created)
|
||
|
|
hooks.register("memory:synced", on_memory_sync)
|
||
|
|
hooks.register("agent:startup", on_agent_startup)
|
||
|
|
|
||
|
|
hooks.trigger("task", "created", {"title": "Implement feature X"})
|
||
|
|
hooks.trigger("memory", "synced", {"files": 15})
|
||
|
|
hooks.trigger(
|
||
|
|
"agent", "startup", {"workspace_dir": "./memory_workspace"}
|
||
|
|
)
|