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

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

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/utils_branch_condition",
"version": "1.0.0",
"description": "utils_branch_condition plugin",
"description": "Evaluate branch conditions using various comparison modes",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["utils", "workflow", "plugin"],
"main": "utils_branch_condition.py",
"files": ["utils_branch_condition.py", "factory.py"],
"metadata": {
"plugin_type": "utils.branch_condition",
"category": "utils"
"category": "utils",
"class": "BranchCondition",
"entrypoint": "execute"
}
}

View File

@@ -1,25 +1,35 @@
"""Workflow plugin: branch condition."""
import re
from ...base import NodeExecutor
def run(_runtime, inputs):
"""Evaluate a branch condition."""
value = inputs.get("value")
mode = inputs.get("mode", "is_truthy")
compare = inputs.get("compare", "")
decision = False
if mode == "is_empty":
decision = not value if isinstance(value, (list, dict, str)) else not bool(value)
elif mode == "is_truthy":
decision = bool(value)
elif mode == "equals":
decision = str(value) == compare
elif mode == "not_equals":
decision = str(value) != compare
elif mode == "contains":
decision = compare in str(value)
elif mode == "regex":
decision = bool(re.search(compare, str(value)))
class BranchCondition(NodeExecutor):
"""Evaluate a branch condition using various comparison modes."""
return {"result": decision}
node_type = "utils.branch_condition"
category = "utils"
description = "Evaluate a branch condition using various comparison modes"
def execute(self, inputs, runtime=None):
"""Evaluate a branch condition."""
value = inputs.get("value")
mode = inputs.get("mode", "is_truthy")
compare = inputs.get("compare", "")
decision = False
if mode == "is_empty":
decision = not value if isinstance(value, (list, dict, str)) else not bool(value)
elif mode == "is_truthy":
decision = bool(value)
elif mode == "equals":
decision = str(value) == compare
elif mode == "not_equals":
decision = str(value) != compare
elif mode == "contains":
decision = compare in str(value)
elif mode == "regex":
decision = bool(re.search(compare, str(value)))
return {"result": decision}

View File

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

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/utils_check_mvp",
"version": "1.0.0",
"description": "utils_check_mvp plugin",
"description": "Check if the MVP section in ROADMAP.md is completed",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["utils", "workflow", "plugin"],
"main": "utils_check_mvp.py",
"files": ["utils_check_mvp.py", "factory.py"],
"metadata": {
"plugin_type": "utils.check_mvp",
"category": "utils"
"category": "utils",
"class": "CheckMvp",
"entrypoint": "execute"
}
}

View File

@@ -1,37 +1,46 @@
"""Workflow plugin: check if MVP is reached."""
import os
import re
from ...base import NodeExecutor
def _is_mvp_reached() -> bool:
class CheckMvp(NodeExecutor):
"""Check if the MVP section in ROADMAP.md is completed."""
if not os.path.exists("ROADMAP.md"):
node_type = "utils.check_mvp"
category = "utils"
description = "Check if the MVP section in ROADMAP.md is completed"
def execute(self, inputs, runtime=None):
"""Check if the MVP section in ROADMAP.md is completed."""
mvp_reached = self._is_mvp_reached()
return {"mvp_reached": mvp_reached}
def _is_mvp_reached(self) -> bool:
"""Check if the MVP section in ROADMAP.md is completed."""
if not os.path.exists("ROADMAP.md"):
return False
with open("ROADMAP.md", "r", encoding="utf-8") as f:
content = f.read()
# Find the header line containing (MVP)
header_match = re.search(r"^## .*?\(MVP\).*?$", content, re.MULTILINE | re.IGNORECASE)
if not header_match:
return False
start_pos = header_match.end()
next_header_match = re.search(r"^## ", content[start_pos:], re.MULTILINE)
if next_header_match:
mvp_section = content[start_pos : start_pos + next_header_match.start()]
else:
mvp_section = content[start_pos:]
if "[ ]" in mvp_section:
return False
if "[x]" in mvp_section:
return True
return False
with open("ROADMAP.md", "r", encoding="utf-8") as f:
content = f.read()
# Find the header line containing (MVP)
header_match = re.search(r"^## .*?\(MVP\).*?$", content, re.MULTILINE | re.IGNORECASE)
if not header_match:
return False
start_pos = header_match.end()
next_header_match = re.search(r"^## ", content[start_pos:], re.MULTILINE)
if next_header_match:
mvp_section = content[start_pos : start_pos + next_header_match.start()]
else:
mvp_section = content[start_pos:]
if "[ ]" in mvp_section:
return False
if "[x]" in mvp_section:
return True
return False
def run(_runtime, _inputs):
"""Check if the MVP section in ROADMAP.md is completed."""
mvp_reached = _is_mvp_reached()
return {"mvp_reached": mvp_reached}

View File

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

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/utils_filter_list",
"version": "1.0.0",
"description": "utils_filter_list plugin",
"description": "Filter items using a match mode",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["utils", "workflow", "plugin"],
"main": "utils_filter_list.py",
"files": ["utils_filter_list.py", "factory.py"],
"metadata": {
"plugin_type": "utils.filter_list",
"category": "utils"
"category": "utils",
"class": "FilterList",
"entrypoint": "execute"
}
}

View File

@@ -1,33 +1,43 @@
"""Workflow plugin: filter list."""
import re
from ...base import NodeExecutor
def run(_runtime, inputs):
class FilterList(NodeExecutor):
"""Filter items using a match mode."""
items = inputs.get("items", [])
if not isinstance(items, list):
items = [items] if items else []
mode = inputs.get("mode", "contains")
pattern = inputs.get("pattern", "")
filtered = []
node_type = "utils.filter_list"
category = "utils"
description = "Filter items using a match mode"
for item in items:
candidate = str(item)
matched = False
if mode == "contains":
matched = pattern in candidate
elif mode == "regex":
matched = bool(re.search(pattern, candidate))
elif mode == "equals":
matched = candidate == pattern
elif mode == "not_equals":
matched = candidate != pattern
elif mode == "starts_with":
matched = candidate.startswith(pattern)
elif mode == "ends_with":
matched = candidate.endswith(pattern)
if matched:
filtered.append(item)
def execute(self, inputs, runtime=None):
"""Filter items using a match mode."""
items = inputs.get("items", [])
if not isinstance(items, list):
items = [items] if items else []
return {"items": filtered}
mode = inputs.get("mode", "contains")
pattern = inputs.get("pattern", "")
filtered = []
for item in items:
candidate = str(item)
matched = False
if mode == "contains":
matched = pattern in candidate
elif mode == "regex":
matched = bool(re.search(pattern, candidate))
elif mode == "equals":
matched = candidate == pattern
elif mode == "not_equals":
matched = candidate != pattern
elif mode == "starts_with":
matched = candidate.startswith(pattern)
elif mode == "ends_with":
matched = candidate.endswith(pattern)
if matched:
filtered.append(item)
return {"items": filtered}

View File

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

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/utils_map_list",
"version": "1.0.0",
"description": "utils_map_list plugin",
"description": "Map items to formatted strings",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["utils", "workflow", "plugin"],
"main": "utils_map_list.py",
"files": ["utils_map_list.py", "factory.py"],
"metadata": {
"plugin_type": "utils.map_list",
"category": "utils"
"category": "utils",
"class": "MapList",
"entrypoint": "execute"
}
}

View File

@@ -1,19 +1,28 @@
"""Workflow plugin: map list."""
from ...base import NodeExecutor
def run(_runtime, inputs):
class MapList(NodeExecutor):
"""Map items to formatted strings."""
items = inputs.get("items", [])
if not isinstance(items, list):
items = [items] if items else []
template = inputs.get("template", "{item}")
mapped = []
node_type = "utils.map_list"
category = "utils"
description = "Map items to formatted strings"
for item in items:
try:
mapped.append(template.format(item=item))
except Exception:
mapped.append(str(item))
def execute(self, inputs, runtime=None):
"""Map items to formatted strings."""
items = inputs.get("items", [])
if not isinstance(items, list):
items = [items] if items else []
return {"items": mapped}
template = inputs.get("template", "{item}")
mapped = []
for item in items:
try:
mapped.append(template.format(item=item))
except Exception:
mapped.append(str(item))
return {"items": mapped}

View File

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

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/utils_not",
"version": "1.0.0",
"description": "utils_not plugin",
"description": "Negate a boolean value",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["utils", "workflow", "plugin"],
"main": "utils_not.py",
"files": ["utils_not.py", "factory.py"],
"metadata": {
"plugin_type": "utils.not",
"category": "utils"
"category": "utils",
"class": "Not",
"entrypoint": "execute"
}
}

View File

@@ -1,7 +1,16 @@
"""Workflow plugin: boolean not."""
from ...base import NodeExecutor
def run(_runtime, inputs):
class Not(NodeExecutor):
"""Negate a boolean value."""
value = inputs.get("value")
return {"result": not bool(value)}
node_type = "utils.not"
category = "utils"
description = "Negate a boolean value"
def execute(self, inputs, runtime=None):
"""Negate a boolean value."""
value = inputs.get("value")
return {"result": not bool(value)}

View File

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

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/utils_reduce_list",
"version": "1.0.0",
"description": "utils_reduce_list plugin",
"description": "Reduce a list into a string",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["utils", "workflow", "plugin"],
"main": "utils_reduce_list.py",
"files": ["utils_reduce_list.py", "factory.py"],
"metadata": {
"plugin_type": "utils.reduce_list",
"category": "utils"
"category": "utils",
"class": "ReduceList",
"entrypoint": "execute"
}
}

View File

@@ -1,18 +1,27 @@
"""Workflow plugin: reduce list."""
from ...base import NodeExecutor
def run(_runtime, inputs):
class ReduceList(NodeExecutor):
"""Reduce a list into a string."""
items = inputs.get("items", [])
if not isinstance(items, list):
items = [items] if items else []
separator = inputs.get("separator", "")
# Handle escape sequences
if separator == "\\n":
separator = "\n"
elif separator == "\\t":
separator = "\t"
node_type = "utils.reduce_list"
category = "utils"
description = "Reduce a list into a string"
reduced = separator.join([str(item) for item in items])
return {"result": reduced}
def execute(self, inputs, runtime=None):
"""Reduce a list into a string."""
items = inputs.get("items", [])
if not isinstance(items, list):
items = [items] if items else []
separator = inputs.get("separator", "")
# Handle escape sequences
if separator == "\\n":
separator = "\n"
elif separator == "\\t":
separator = "\t"
reduced = separator.join([str(item) for item in items])
return {"result": reduced}

View File

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

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/utils_update_roadmap",
"version": "1.0.0",
"description": "utils_update_roadmap plugin",
"description": "Update ROADMAP.md with new content",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["utils", "workflow", "plugin"],
"main": "utils_update_roadmap.py",
"files": ["utils_update_roadmap.py", "factory.py"],
"metadata": {
"plugin_type": "utils.update_roadmap",
"category": "utils"
"category": "utils",
"class": "UpdateRoadmap",
"entrypoint": "execute"
}
}

View File

@@ -1,21 +1,30 @@
"""Workflow plugin: update roadmap file."""
import logging
from ...base import NodeExecutor
logger = logging.getLogger("metabuilder")
def _update_roadmap(content: str):
class UpdateRoadmap(NodeExecutor):
"""Update ROADMAP.md with new content."""
with open("ROADMAP.md", "w", encoding="utf-8") as f:
f.write(content)
logger.info("ROADMAP.md updated successfully.")
node_type = "utils.update_roadmap"
category = "utils"
description = "Update ROADMAP.md with new content"
def run(_runtime, inputs):
"""Update ROADMAP.md with new content."""
content = inputs.get("content")
if not content:
return {"error": "Content is required"}
def execute(self, inputs, runtime=None):
"""Update ROADMAP.md with new content."""
content = inputs.get("content")
if not content:
return {"error": "Content is required"}
_update_roadmap(content)
return {"result": "ROADMAP.md updated successfully"}
self._update_roadmap(content)
return {"result": "ROADMAP.md updated successfully"}
def _update_roadmap(self, content: str):
"""Update ROADMAP.md with new content."""
with open("ROADMAP.md", "w", encoding="utf-8") as f:
f.write(content)
logger.info("ROADMAP.md updated successfully.")