This commit is contained in:
nose
2025-11-27 10:59:01 -08:00
parent e9b505e609
commit 9eff65d1af
30 changed files with 2099 additions and 1095 deletions

99
CLI.py
View File

@@ -240,6 +240,7 @@ def _close_cli_worker_manager() -> None:
global _CLI_WORKER_MANAGER
if _CLI_WORKER_MANAGER:
try:
# print("[CLI] Closing worker manager...", file=sys.stderr)
_CLI_WORKER_MANAGER.close()
except Exception:
pass
@@ -273,7 +274,7 @@ def _ensure_worker_manager(config: Dict[str, Any]) -> Optional[WorkerManagerType
_CLI_WORKER_MANAGER.close()
except Exception:
pass
_CLI_WORKER_MANAGER = WorkerManager(resolved_root, auto_refresh_interval=0)
_CLI_WORKER_MANAGER = WorkerManager(resolved_root, auto_refresh_interval=0.5)
manager = _CLI_WORKER_MANAGER
config['_worker_manager'] = manager
if manager and not _CLI_ORPHAN_CLEANUP_DONE:
@@ -586,17 +587,72 @@ def _create_cmdlet_cli():
app = typer.Typer(help="Medeia-Macina CLI")
@app.command("pipeline")
def pipeline(
command: str = typer.Option(..., "--pipeline", "-p", help="Pipeline command string to execute"),
seeds_json: Optional[str] = typer.Option(None, "--seeds-json", "-s", help="JSON string of seed items")
):
"""Execute a pipeline command non-interactively."""
import shlex
import json
import pipeline as ctx
# Load config
config = _load_cli_config()
# Initialize debug logging if enabled
if config:
from helper.logger import set_debug
set_debug(config.get("debug", False))
# Handle seeds if provided
if seeds_json:
try:
seeds = json.loads(seeds_json)
# If seeds is a list, use it directly. If single item, wrap in list.
if not isinstance(seeds, list):
seeds = [seeds]
# Set seeds as the result of a "virtual" previous stage
# This allows the first command in the pipeline to receive them as input
ctx.set_last_result_items_only(seeds)
except Exception as e:
print(f"Error parsing seeds JSON: {e}")
return
try:
tokens = shlex.split(command)
except ValueError:
tokens = command.split()
if not tokens:
return
# Execute
_execute_pipeline(tokens)
@app.command("repl")
def repl():
"""Start interactive REPL for cmdlets with autocomplete."""
banner = """
Medeia-Macina
=======================================
Commands: help | exit | <cmdlet> --help
Example: search-file --help
Medeia-Macina
=====================
|123456789|ABCDEFGHI|
|246813579|JKLMNOPQR|
|369369369|STUVWXYZ0|
|483726159|ABCDEFGHI|
|516273849|JKLMNOPQR|
|639639639|STUVWXYZ0|
|753186429|ABCDEFGHI|
|876543219|JKLMNOPQR|
|999999999|STUVWXYZ0|
=====================
"""
print(banner)
# Configurable prompt
prompt_text = ">>>|"
# Pre-acquire Hydrus session key at startup (like hub-ui does)
try:
config = _load_cli_config()
@@ -621,10 +677,12 @@ Example: search-file --help
# Check MPV availability at startup
try:
from hydrus_health_check import check_mpv_availability
from hydrus_health_check import check_mpv_availability, initialize_matrix_health_check, initialize_hydrus_health_check
check_mpv_availability()
initialize_hydrus_health_check(config)
initialize_matrix_health_check(config)
except Exception as e:
debug(f"⚠ Could not check MPV availability: {e}")
debug(f"⚠ Could not check service availability: {e}")
except Exception:
pass # Silently ignore if config loading fails
@@ -635,8 +693,8 @@ Example: search-file --help
style = Style.from_dict({
'cmdlet': '#ffffff', # white
'argument': '#3b8eea', # blue-ish
'value': '#ce9178', # red-ish
'string': '#ce55ff', # purple
'value': "#9a3209", # red-ish
'string': "#6d0d93", # purple
'pipe': '#4caf50', # green
})
@@ -646,16 +704,17 @@ Example: search-file --help
style=style
)
def get_input(prompt: str = ">>>|") -> str:
def get_input(prompt: str = prompt_text) -> str:
return session.prompt(prompt)
else:
def get_input(prompt: str = ">>>|") -> str:
def get_input(prompt: str = prompt_text) -> str:
return input(prompt)
while True:
print("#-------------------------------------------------------------------------#")
try:
user_input = get_input(">>>|").strip()
user_input = get_input(prompt_text).strip()
except (EOFError, KeyboardInterrupt):
print("\nGoodbye!")
break
@@ -741,6 +800,17 @@ Example: search-file --help
finally:
if pipeline_ctx_ref:
pipeline_ctx_ref.clear_current_command_text()
@app.callback(invoke_without_command=True)
def main_callback(ctx: typer.Context):
"""
Medeia-Macina CLI entry point.
If no command is provided, starts the interactive REPL.
"""
# Check if a subcommand is invoked
# Note: ctx.invoked_subcommand is None if no command was passed
if ctx.invoked_subcommand is None:
repl()
return app
@@ -933,7 +1003,7 @@ def _execute_pipeline(tokens: list):
stages.append(['.pipe'])
# Force should_expand_to_command to False so we fall through to filtering
should_expand_to_command = False
elif isinstance(piped_result, (list, tuple)):
first_item = piped_result[0] if piped_result else None
if isinstance(first_item, dict) and first_item.get('format_id') is not None:
@@ -1349,7 +1419,8 @@ def _execute_cmdlet(cmd_name: str, args: list):
# Special case: if this was a youtube search, print a hint about auto-piping
if cmd_name == 'search-file' and filtered_args and 'youtube' in filtered_args:
print("\n[Hint] Type @N to play a video in MPV (e.g. @1)")
# print("\n[Hint] Type @N to play a video in MPV (e.g. @1)")
pass
else:
# Fallback to raw output if ResultTable not available
for emitted in pipeline_ctx.emits: