mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-08 23:33:16 +08:00
Remove stock/image/video specialists, Gmail watcher, CocoLoop market, desktop packaging, and extra memory plugins; disable dynamic agents and hide Session Monitor / API grants / Admin Audit from nav. Co-authored-by: Cursor <cursoragent@cursor.com>
138 lines
4.9 KiB
Python
138 lines
4.9 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any, Callable
|
|
|
|
from svc.config.runtime_paths import runtime_extensions_root
|
|
from .python_extensions_loader import build_python_extensions_registry
|
|
|
|
GatewayHandler = Callable[..., Any]
|
|
LogFn = Callable[[str], None]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GatewayPluginLoadResult:
|
|
plugin_registry: dict[str, Any]
|
|
gateway_methods: list[str]
|
|
|
|
|
|
def _apply_plugin_auto_enable(cfg: dict[str, Any]) -> dict[str, Any]:
|
|
"""Python rewrite placeholder for plugin auto-enable policy.
|
|
|
|
Keep behavior deterministic: when no runtime policy engine is attached,
|
|
the incoming config is treated as already normalized.
|
|
"""
|
|
return dict(cfg or {})
|
|
|
|
|
|
def _resolve_gateway_startup_plugin_ids(
|
|
*,
|
|
config: dict[str, Any],
|
|
workspace_dir: str,
|
|
) -> list[str]:
|
|
ws_root = Path(workspace_dir).resolve()
|
|
plugins = ((config.get("plugins") or {}).get("enabled") or []) if isinstance(config, dict) else []
|
|
out = [str(x).strip() for x in plugins if str(x).strip()]
|
|
slot_cfg = ((config.get("plugins") or {}).get("slots") or {}) if isinstance(config, dict) else {}
|
|
memory_slot = str(slot_cfg.get("memory") or "").strip()
|
|
memory_plugin_ids = {"memory-wiki"}
|
|
skip_plugin_ids = {"telegram", "memory-core", "memory-lancedb"}
|
|
if out:
|
|
if memory_slot:
|
|
out = [x for x in out if x not in {"memory-core", "memory-wiki", "memory-lancedb"}]
|
|
if memory_slot.lower() != "none" and memory_slot not in skip_plugin_ids:
|
|
out.append(memory_slot)
|
|
return [x for x in out if x not in skip_plugin_ids]
|
|
# Auto-discover local plugins when explicit list is absent.
|
|
roots = [
|
|
runtime_extensions_root(),
|
|
ws_root / "oclaw" / "runtime" / "extensions",
|
|
ws_root / "runtime" / "extensions",
|
|
]
|
|
seen: set[str] = set()
|
|
for root in roots:
|
|
if not root.exists() or not root.is_dir():
|
|
continue
|
|
for child in root.iterdir():
|
|
if not child.is_dir():
|
|
continue
|
|
pid = str(child.name or "").strip()
|
|
if not pid or pid.startswith(".") or pid in seen:
|
|
continue
|
|
seen.add(pid)
|
|
out.append(pid)
|
|
if memory_slot:
|
|
out = [x for x in out if x not in {"memory-core", "memory-wiki", "memory-lancedb"}]
|
|
if memory_slot.lower() != "none" and memory_slot not in skip_plugin_ids:
|
|
out.append(memory_slot)
|
|
return [x for x in out if x not in skip_plugin_ids]
|
|
|
|
|
|
def _load_oclaw_plugins(
|
|
*,
|
|
config: dict[str, Any],
|
|
workspace_dir: str,
|
|
only_plugin_ids: list[str],
|
|
core_gateway_handlers: dict[str, GatewayHandler] | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Minimal Python replacement for loadOclawPlugins.
|
|
|
|
This function intentionally returns a stable registry shape that matches
|
|
the gateway startup contract used by this project.
|
|
"""
|
|
core_gateway_handlers = dict(core_gateway_handlers or {})
|
|
registry = build_python_extensions_registry(
|
|
app_config=dict(config or {}),
|
|
workspace_dir=workspace_dir,
|
|
only_plugin_ids=list(only_plugin_ids or []),
|
|
)
|
|
registry["gateway_handlers"] = {k: v for k, v in core_gateway_handlers.items()}
|
|
registry["workspace_dir"] = workspace_dir
|
|
return registry
|
|
|
|
|
|
def load_gateway_plugins(
|
|
*,
|
|
cfg: dict[str, Any],
|
|
workspace_dir: str,
|
|
log: dict[str, LogFn],
|
|
core_gateway_handlers: dict[str, GatewayHandler],
|
|
base_methods: list[str],
|
|
plugin_ids: list[str] | None = None,
|
|
) -> GatewayPluginLoadResult:
|
|
"""Python rewrite of `gateway/server-plugins.ts::loadGatewayPlugins`.
|
|
|
|
Behavior:
|
|
- Resolve startup plugin ids
|
|
- Load plugin registry
|
|
- Merge plugin gateway handlers into gateway methods
|
|
"""
|
|
resolved_cfg = _apply_plugin_auto_enable(cfg)
|
|
chosen_plugin_ids = list(
|
|
plugin_ids or _resolve_gateway_startup_plugin_ids(config=resolved_cfg, workspace_dir=workspace_dir)
|
|
)
|
|
if not chosen_plugin_ids:
|
|
plugin_registry = {"plugins": [], "gateway_handlers": {}, "http_routes": [], "diagnostics": []}
|
|
return GatewayPluginLoadResult(plugin_registry=plugin_registry, gateway_methods=list(base_methods))
|
|
|
|
plugin_registry = _load_oclaw_plugins(
|
|
config=resolved_cfg,
|
|
workspace_dir=workspace_dir,
|
|
only_plugin_ids=chosen_plugin_ids,
|
|
core_gateway_handlers=core_gateway_handlers,
|
|
)
|
|
plugin_methods = list((plugin_registry.get("gateway_handlers") or {}).keys())
|
|
merged_methods: list[str] = []
|
|
seen: set[str] = set()
|
|
for method in [*base_methods, *plugin_methods]:
|
|
if method not in seen:
|
|
seen.add(method)
|
|
merged_methods.append(method)
|
|
|
|
info = log.get("info")
|
|
if callable(info):
|
|
info(f"[gateway] loaded {len(chosen_plugin_ids)} plugins for workspace={workspace_dir}")
|
|
|
|
return GatewayPluginLoadResult(plugin_registry=plugin_registry, gateway_methods=merged_methods)
|
|
|