refactor(workflow): convert all plugins to class/struct + factory pattern

- Python: class extending NodeExecutor + factory.py (80+ plugins)
- TypeScript: class implements NodeExecutor + factory.ts (7 groups, 116 classes)
- Go: struct with methods + factory.go (36 plugins)
- Rust: struct impl NodeExecutor trait + factory.rs (54 plugins)
- Mojo: struct + factory.mojo (11 plugins)

All package.json files now include:
- files array listing source files
- metadata.class/struct field
- metadata.entrypoint field

This enables a unified plugin loading system across all languages
with no import side effects (Spring-style DI pattern).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-22 14:53:04 +00:00
parent 2562c2f55b
commit 7ce8b4ae8a
653 changed files with 13243 additions and 3034 deletions

View File

@@ -1,50 +1,59 @@
"""Workflow plugin: load workflow plugins."""
import os
import json
import importlib.util
from ...base import NodeExecutor
def run(runtime, inputs):
"""Load workflow plugins from directory.
class LoadPlugins(NodeExecutor):
"""Load workflow plugins from directory."""
Inputs:
path: Path to plugins directory
"""
path = inputs.get("path", "workflow/plugins/python")
node_type = "backend.load_plugins"
category = "backend"
description = "Load workflow plugins from directory"
if not os.path.exists(path):
return {"success": False, "error": f"Path not found: {path}"}
def execute(self, inputs, runtime=None):
"""Load workflow plugins from directory.
plugins = {}
categories = []
Inputs:
path: Path to plugins directory
"""
path = inputs.get("path", "workflow/plugins/python")
for category in os.listdir(path):
category_path = os.path.join(path, category)
if not os.path.isdir(category_path) or category.startswith("_"):
continue
if not os.path.exists(path):
return {"success": False, "error": f"Path not found: {path}"}
categories.append(category)
plugins = {}
categories = []
for plugin_name in os.listdir(category_path):
plugin_path = os.path.join(category_path, plugin_name)
if not os.path.isdir(plugin_path):
for category in os.listdir(path):
category_path = os.path.join(path, category)
if not os.path.isdir(category_path) or category.startswith("_"):
continue
package_json = os.path.join(plugin_path, "package.json")
if os.path.exists(package_json):
with open(package_json) as f:
metadata = json.load(f)
plugin_type = metadata.get("metadata", {}).get("plugin_type")
if plugin_type:
plugins[plugin_type] = {
"path": plugin_path,
"metadata": metadata
}
categories.append(category)
runtime.context["plugins"] = plugins
for plugin_name in os.listdir(category_path):
plugin_path = os.path.join(category_path, plugin_name)
if not os.path.isdir(plugin_path):
continue
return {
"success": True,
"categories": categories,
"plugin_count": len(plugins)
}
package_json = os.path.join(plugin_path, "package.json")
if os.path.exists(package_json):
with open(package_json) as f:
metadata = json.load(f)
plugin_type = metadata.get("metadata", {}).get("plugin_type")
if plugin_type:
plugins[plugin_type] = {
"path": plugin_path,
"metadata": metadata
}
runtime.context["plugins"] = plugins
return {
"success": True,
"categories": categories,
"plugin_count": len(plugins)
}

View File

@@ -0,0 +1,7 @@
"""Factory for LoadPlugins plugin."""
from .backend_load_plugins import LoadPlugins
def create():
return LoadPlugins()

View File

@@ -6,8 +6,11 @@
"license": "MIT",
"keywords": ["backend", "workflow", "plugin", "loader"],
"main": "backend_load_plugins.py",
"files": ["backend_load_plugins.py", "factory.py"],
"metadata": {
"plugin_type": "backend.load_plugins",
"category": "backend"
"category": "backend",
"class": "LoadPlugins",
"entrypoint": "execute"
}
}