diff --git a/engine/app/main.py b/engine/app/main.py index 183a245..53f4750 100644 --- a/engine/app/main.py +++ b/engine/app/main.py @@ -34,6 +34,82 @@ except ImportError: from .pipeline_runner import run_pipeline_mode +def _handle_pipeline_mutation(pipeline: Pipeline, command: dict) -> bool: + """Handle pipeline mutation commands from REPL or other external control. + + Args: + pipeline: The pipeline to mutate + command: Command dictionary with 'action' and other parameters + + Returns: + True if command was successfully handled, False otherwise + """ + action = command.get("action") + + if action == "add_stage": + print(f" [Pipeline] add_stage command received: {command}") + return True + + elif action == "remove_stage": + stage_name = command.get("stage") + if stage_name: + result = pipeline.remove_stage(stage_name) + print(f" [Pipeline] Removed stage '{stage_name}': {result is not None}") + return result is not None + + elif action == "replace_stage": + stage_name = command.get("stage") + print(f" [Pipeline] replace_stage command received: {command}") + return True + + elif action == "swap_stages": + stage1 = command.get("stage1") + stage2 = command.get("stage2") + if stage1 and stage2: + result = pipeline.swap_stages(stage1, stage2) + print(f" [Pipeline] Swapped stages '{stage1}' and '{stage2}': {result}") + return result + + elif action == "move_stage": + stage_name = command.get("stage") + after = command.get("after") + before = command.get("before") + if stage_name: + result = pipeline.move_stage(stage_name, after, before) + print(f" [Pipeline] Moved stage '{stage_name}': {result}") + return result + + elif action == "enable_stage": + stage_name = command.get("stage") + if stage_name: + result = pipeline.enable_stage(stage_name) + print(f" [Pipeline] Enabled stage '{stage_name}': {result}") + return result + + elif action == "disable_stage": + stage_name = command.get("stage") + if stage_name: + result = pipeline.disable_stage(stage_name) + print(f" [Pipeline] Disabled stage '{stage_name}': {result}") + return result + + elif action == "cleanup_stage": + stage_name = command.get("stage") + if stage_name: + pipeline.cleanup_stage(stage_name) + print(f" [Pipeline] Cleaned up stage '{stage_name}'") + return True + + elif action == "can_hot_swap": + stage_name = command.get("stage") + if stage_name: + can_swap = pipeline.can_hot_swap(stage_name) + print(f" [Pipeline] Can hot-swap '{stage_name}': {can_swap}") + return True + + return False + + def main(): """Main entry point - all modes now use presets or CLI construction.""" if config.PIPELINE_DIAGRAM: @@ -391,6 +467,20 @@ def run_pipeline_mode_direct(): except Exception: pass + # Check for REPL effect in pipeline + repl_effect = None + for stage in pipeline.stages.values(): + if isinstance(stage, EffectPluginStage) and stage._effect.name == "repl": + repl_effect = stage._effect + print( + " \033[38;5;46mREPL effect detected - Interactive mode enabled\033[0m" + ) + break + + # Enable raw mode for REPL if present and not already enabled + if repl_effect and hasattr(display, "set_raw_mode"): + display.set_raw_mode(True) + # Run pipeline loop from engine.display import render_ui_panel @@ -453,6 +543,31 @@ def run_pipeline_mode_direct(): except Exception: pass + # --- REPL Input Handling --- + if repl_effect and hasattr(display, "get_input_keys"): + # Get keyboard input (non-blocking) + keys = display.get_input_keys(timeout=0.0) + + for key in keys: + if key == "return": + # Get command string before processing + cmd_str = repl_effect.state.current_command + if cmd_str: + repl_effect.process_command(cmd_str, ctx) + # Check for pending pipeline mutations + pending = repl_effect.get_pending_command() + if pending: + _handle_pipeline_mutation(pipeline, pending) + elif key == "up": + repl_effect.navigate_history(-1) + elif key == "down": + repl_effect.navigate_history(1) + elif key == "backspace": + repl_effect.backspace() + elif len(key) == 1: + repl_effect.append_to_command(key) + # --- End REPL Input Handling --- + # Check for quit request if hasattr(display, "is_quit_requested") and display.is_quit_requested(): if hasattr(display, "clear_quit_request"):