Files
Mainline/engine/effects/chain.py
David Gwilliam 291e96d11e feat(effects): add plugin architecture for visual effects
- Extract effects as fully decoupled plugins in engine/effects/
- Add EffectConfig, EffectContext dataclasses and EffectPlugin protocol
- Add EffectRegistry for plugin discovery and management
- Add EffectChain for ordered pipeline execution
- Move built-in effects to effects_plugins/ directory
- Add interactive effects config picker during startup
- Add NTFY command handler for /effects commands
- Add tests for effects system (24 new tests)
- Update AGENTS.md with effects plugin documentation
- Add conventional commits section to AGENTS.md

chore: add coverage.xml to .gitignore
2026-03-15 17:16:49 -07:00

48 lines
1.5 KiB
Python

from engine.effects.registry import EffectRegistry
from engine.effects.types import EffectContext
class EffectChain:
def __init__(self, registry: EffectRegistry):
self._registry = registry
self._order: list[str] = []
def set_order(self, names: list[str]) -> None:
self._order = list(names)
def get_order(self) -> list[str]:
return self._order.copy()
def add_effect(self, name: str, position: int | None = None) -> bool:
if name not in self._registry.list_all():
return False
if position is None:
self._order.append(name)
else:
self._order.insert(position, name)
return True
def remove_effect(self, name: str) -> bool:
if name in self._order:
self._order.remove(name)
return True
return False
def reorder(self, new_order: list[str]) -> bool:
all_plugins = set(self._registry.list_all().keys())
if not all(name in all_plugins for name in new_order):
return False
self._order = list(new_order)
return True
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
result = list(buf)
for name in self._order:
plugin = self._registry.get(name)
if plugin and plugin.config.enabled:
try:
result = plugin.process(result, ctx)
except Exception:
plugin.config.enabled = False
return result