forked from genewildish/Mainline
Major changes: - Pipeline architecture with capability-based dependency resolution - Effects plugin system with performance monitoring - Display abstraction with multiple backends (terminal, null, websocket) - Camera system for viewport scrolling - Sensor framework for real-time input - Command-and-control system via ntfy - WebSocket display backend for browser clients - Comprehensive test suite and documentation Issue #48: ADR for preset scripting language included This commit consolidates 110 individual commits into a single feature integration that can be reviewed and tested before further refinement.
144 lines
3.9 KiB
Python
144 lines
3.9 KiB
Python
"""
|
|
Stage adapters - Bridge existing components to the Stage interface.
|
|
|
|
This module provides adapters that wrap existing components
|
|
(DataSource) as Stage implementations.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
from engine.data_sources import SourceItem
|
|
from engine.pipeline.core import DataType, PipelineContext, Stage
|
|
|
|
|
|
class DataSourceStage(Stage):
|
|
"""Adapter wrapping DataSource as a Stage."""
|
|
|
|
def __init__(self, data_source, name: str = "headlines"):
|
|
self._source = data_source
|
|
self.name = name
|
|
self.category = "source"
|
|
self.optional = False
|
|
|
|
@property
|
|
def capabilities(self) -> set[str]:
|
|
return {f"source.{self.name}"}
|
|
|
|
@property
|
|
def dependencies(self) -> set[str]:
|
|
return set()
|
|
|
|
@property
|
|
def inlet_types(self) -> set:
|
|
return {DataType.NONE} # Sources don't take input
|
|
|
|
@property
|
|
def outlet_types(self) -> set:
|
|
return {DataType.SOURCE_ITEMS}
|
|
|
|
def process(self, data: Any, ctx: PipelineContext) -> Any:
|
|
"""Fetch data from source."""
|
|
if hasattr(self._source, "get_items"):
|
|
return self._source.get_items()
|
|
return data
|
|
|
|
|
|
class PassthroughStage(Stage):
|
|
"""Simple stage that passes data through unchanged.
|
|
|
|
Used for sources that already provide the data in the correct format
|
|
(e.g., pipeline introspection that outputs text directly).
|
|
"""
|
|
|
|
def __init__(self, name: str = "passthrough"):
|
|
self.name = name
|
|
self.category = "render"
|
|
self.optional = True
|
|
|
|
@property
|
|
def stage_type(self) -> str:
|
|
return "render"
|
|
|
|
@property
|
|
def capabilities(self) -> set[str]:
|
|
return {"render.output"}
|
|
|
|
@property
|
|
def dependencies(self) -> set[str]:
|
|
return {"source"}
|
|
|
|
@property
|
|
def inlet_types(self) -> set:
|
|
return {DataType.SOURCE_ITEMS}
|
|
|
|
@property
|
|
def outlet_types(self) -> set:
|
|
return {DataType.SOURCE_ITEMS}
|
|
|
|
def process(self, data: Any, ctx: PipelineContext) -> Any:
|
|
"""Pass data through unchanged."""
|
|
return data
|
|
|
|
|
|
class SourceItemsToBufferStage(Stage):
|
|
"""Convert SourceItem objects to text buffer.
|
|
|
|
Takes a list of SourceItem objects and extracts their content,
|
|
splitting on newlines to create a proper text buffer for display.
|
|
"""
|
|
|
|
def __init__(self, name: str = "items-to-buffer"):
|
|
self.name = name
|
|
self.category = "render"
|
|
self.optional = True
|
|
|
|
@property
|
|
def stage_type(self) -> str:
|
|
return "render"
|
|
|
|
@property
|
|
def capabilities(self) -> set[str]:
|
|
return {"render.output"}
|
|
|
|
@property
|
|
def dependencies(self) -> set[str]:
|
|
return {"source"}
|
|
|
|
@property
|
|
def inlet_types(self) -> set:
|
|
return {DataType.SOURCE_ITEMS}
|
|
|
|
@property
|
|
def outlet_types(self) -> set:
|
|
return {DataType.TEXT_BUFFER}
|
|
|
|
def process(self, data: Any, ctx: PipelineContext) -> Any:
|
|
"""Convert SourceItem list to text buffer."""
|
|
if data is None:
|
|
return []
|
|
|
|
# If already a list of strings, return as-is
|
|
if isinstance(data, list) and data and isinstance(data[0], str):
|
|
return data
|
|
|
|
# If it's a list of SourceItem, extract content
|
|
if isinstance(data, list):
|
|
result = []
|
|
for item in data:
|
|
if isinstance(item, SourceItem):
|
|
# Split content by newline to get individual lines
|
|
lines = item.content.split("\n")
|
|
result.extend(lines)
|
|
elif hasattr(item, "content"): # Has content attribute
|
|
lines = str(item.content).split("\n")
|
|
result.extend(lines)
|
|
else:
|
|
result.append(str(item))
|
|
return result
|
|
|
|
# Single item
|
|
if isinstance(data, SourceItem):
|
|
return data.content.split("\n")
|
|
|
|
return [str(data)]
|