from __future__ import annotations
"""Medeia-Macina CLI.

This module intentionally uses a class-based architecture:
- no legacy procedural entrypoints
- no compatibility shims
- all REPL/pipeline/cmdlet execution state lives on objects
"""

# When running the CLI directly (not via the 'mm' launcher), honor the
# repository config `debug` flag by enabling `MM_DEBUG` so import-time
# diagnostics and bootstrap debug output are visible without setting the
# environment variable manually.
import os
from pathlib import Path
if not os.environ.get("MM_DEBUG"):
    try:
        # Check database first
        db_path = Path(__file__).resolve().parent / "medios.db"
        if db_path.exists():
            import sqlite3
            with sqlite3.connect(str(db_path), timeout=30.0) as conn:
                cur = conn.cursor()
                # Check for global debug key
                cur.execute("SELECT value FROM config WHERE key = 'debug' AND category = 'global'")
                row = cur.fetchone()
                if row:
                    val = str(row[0]).strip().lower()
                    if val in ("1", "true", "yes", "on"):
                        os.environ["MM_DEBUG"] = "1"
    except Exception:
        pass

import json
import shlex
import sys
import threading
import time
import uuid
from copy import deepcopy

from pathlib import Path
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, cast

import typer
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.document import Document
from prompt_toolkit.styles import Style
from rich.console import Console
from rich.layout import Layout
from rich.panel import Panel
from rich.markdown import Markdown
from rich.bar import Bar
from rich.table import Table as RichTable
from SYS.rich_display import (
    stderr_console,
    stdout_console,
)
from cmdnat._status_shared import (
    add_startup_check as _shared_add_startup_check,
    collect_plugin_startup_checks as _collect_plugin_startup_checks,
    has_provider as _has_provider,
)


def _install_rich_traceback(*, show_locals: bool = False) -> None:
    """Install Rich traceback handler as the default excepthook.

    This keeps uncaught exceptions readable in the terminal.
    """
    try:
        from rich.traceback import install as rich_traceback_install

        rich_traceback_install(show_locals=bool(show_locals))
    except Exception:
        # Fall back to the standard Python traceback if Rich isn't available.
        return


# Default to Rich tracebacks for the whole process.
_install_rich_traceback(show_locals=False)

from SYS.logger import debug, set_debug
from SYS.repl_queue import clear_repl_state, pop_repl_commands, touch_repl_state
from SYS.worker_manager import WorkerManager

from SYS.cmdlet_catalog import (
    get_cmdlet_arg_choices,
    get_cmdlet_arg_flags,
    get_cmdlet_metadata,
    import_cmd_module,
    list_cmdlet_metadata,
    list_cmdlet_names,
)
from SYS.config import load_config
from SYS.result_table import Table

from SYS.worker import WorkerManagerRegistry, WorkerStages, WorkerOutputMirror, WorkerStageSession
from SYS.pipeline import PipelineExecutor
from PluginCore.registry import plugin_inline_query_choices



# Selection parsing and REPL lexer moved to SYS.cli_parsing
from SYS.cli_parsing import SelectionSyntax, SelectionFilterSyntax, MedeiaLexer


# SelectionFilterSyntax moved to SYS.cli_parsing (imported above)












def _send_mpv_ipc_command(
    command: List[Any],
    *,
    ipc_path: Optional[str] = None,
    timeout: float = 0.75,
    wait_for_response: bool = True,
) -> bool:
    if not isinstance(command, list) or not command:
        return False

    try:
        from plugins.mpv.mpv_ipc import MPVIPCClient, get_ipc_pipe_path

        client = MPVIPCClient(
            socket_path=str(ipc_path or get_ipc_pipe_path()),
            timeout=max(0.1, float(timeout or 0.75)),
            silent=True,
        )
        try:
            response = client.send_command({
                "command": command,
            }, wait=bool(wait_for_response))
        finally:
            try:
                client.disconnect()
            except Exception:
                pass

        if not wait_for_response:
            return bool(response and (response.get("async") or response.get("request_id") is not None))

        return bool(response and response.get("error") == "success")
    except Exception as exc:
        debug(f"mpv ipc command failed: {exc}")
        return False


def _notify_mpv_osd(text: str, *, duration_ms: int = 3500, ipc_path: Optional[str] = None) -> bool:
    message = str(text or "").strip()
    if not message:
        return False

    return _send_mpv_ipc_command(
        [
            "show-text",
            message,
            max(0, int(duration_ms)),
        ],
        ipc_path=ipc_path,
        wait_for_response=False,
    )


def _send_mpv_callback_event(metadata: Dict[str, Any], payload: Dict[str, Any]) -> bool:
    callback = metadata.get("mpv_callback") if isinstance(metadata, dict) else None
    if not isinstance(callback, dict):
        return False

    script_name = str(callback.get("script") or "").strip()
    message_name = str(callback.get("message") or "").strip()
    ipc_path = str(callback.get("ipc_path") or "").strip() or None
    if not script_name or not message_name:
        return False

    event_payload = {
        "kind": str(metadata.get("kind") or "").strip(),
    }
    if isinstance(payload, dict):
        event_payload.update(payload)

    return _send_mpv_ipc_command(
        [
            "script-message-to",
            script_name,
            message_name,
            json.dumps(event_payload, ensure_ascii=False),
        ],
        ipc_path=ipc_path,
        wait_for_response=False,
    )


def _notify_mpv_callback(metadata: Dict[str, Any], execution_result: Dict[str, Any]) -> bool:
    return _send_mpv_callback_event(
        metadata,
        {
            "phase": "completed",
            "success": bool(execution_result.get("success")),
            "status": str(execution_result.get("status") or "completed"),
            "error": str(execution_result.get("error") or "").strip(),
            "command_text": str(execution_result.get("command_text") or "").strip(),
        },
    )


def _build_mpv_progress_callback(metadata: Dict[str, Any]) -> Optional[Any]:
    callback = metadata.get("mpv_callback") if isinstance(metadata, dict) else None
    if not isinstance(callback, dict):
        return None

    last_sent_at: Dict[str, float] = {}
    last_percent: Dict[str, int] = {}
    last_text: Dict[str, str] = {}

    def emit(payload: Dict[str, Any]) -> bool:
        if not isinstance(payload, dict):
            return False

        event_name = str(payload.get("event") or "").strip().lower()
        now = time.monotonic()
        throttle_key = event_name or "progress"

        if event_name == "pipe-percent":
            pipe_index = int(payload.get("pipe_index") or 0)
            percent = max(0, min(100, int(payload.get("percent") or 0)))
            throttle_key = f"pipe-percent:{pipe_index}"
            prev = last_percent.get(throttle_key)
            if prev == percent:
                return False
            if prev is not None and percent < 100 and (percent - prev) < 5 and (now - last_sent_at.get(throttle_key, 0.0)) < 0.35:
                return False
            last_percent[throttle_key] = percent
            payload = dict(payload)
            payload["percent"] = percent
        elif event_name == "transfer":
            label = str(payload.get("label") or "transfer").strip() or "transfer"
            throttle_key = f"transfer:{label}"
            completed = payload.get("completed")
            total = payload.get("total")
            percent = None
            try:
                if total is not None and int(total) > 0 and completed is not None:
                    percent = max(0, min(100, int(round((int(completed) / max(1, int(total))) * 100.0))))
            except Exception:
                percent = None
            if percent is not None:
                prev = last_percent.get(throttle_key)
                if prev == percent:
                    return False
                if prev is not None and percent < 100 and (percent - prev) < 3 and (now - last_sent_at.get(throttle_key, 0.0)) < 0.35:
                    return False
                last_percent[throttle_key] = percent
                payload = dict(payload)
                payload["percent"] = percent
        elif event_name == "status":
            pipe_index = int(payload.get("pipe_index") or 0)
            throttle_key = f"status:{pipe_index}"
            text = str(payload.get("text") or "").strip()
            if last_text.get(throttle_key) == text and (now - last_sent_at.get(throttle_key, 0.0)) < 0.5:
                return False
            last_text[throttle_key] = text

        last_sent_at[throttle_key] = now
        event_payload = dict(payload)
        event_payload.setdefault("phase", "progress")
        return _send_mpv_callback_event(metadata, event_payload)

    return emit


def _notify_mpv_completion(metadata: Dict[str, Any], execution_result: Dict[str, Any]) -> bool:
    callback_sent = _notify_mpv_callback(metadata, execution_result)

    notify = metadata.get("mpv_notify") if isinstance(metadata, dict) else None
    if not isinstance(notify, dict):
        return callback_sent

    success = bool(execution_result.get("success"))
    error_text = str(execution_result.get("error") or "").strip()
    if success:
        message = str(notify.get("success_text") or "").strip()
    else:
        failure_prefix = str(notify.get("failure_text") or "").strip()
        message = failure_prefix
        if error_text:
            if message:
                message = f"{message}: {error_text}"
            else:
                message = error_text

    if not message:
        return callback_sent

    try:
        duration_ms = int(notify.get("duration_ms") or 3500)
    except Exception:
        duration_ms = 3500

    ipc_path = str(notify.get("ipc_path") or "").strip() or None
    notified = _notify_mpv_osd(message, duration_ms=duration_ms, ipc_path=ipc_path)
    return bool(callback_sent or notified)


class _OldWorkerStages:
    """Factory methods for stage/pipeline worker sessions."""

    @staticmethod
    def _start_worker_session(
        worker_manager: Optional[WorkerManager],
        *,
        worker_type: str,
        title: str,
        description: str,
        pipe_text: str,
        config: Optional[Dict[str,
                              Any]],
        completion_label: str,
        error_label: str,
        skip_logging_for: Optional[Set[str]] = None,
        session_worker_ids: Optional[Set[str]] = None,
    ) -> Optional[WorkerStageSession]:
        if worker_manager is None:
            return None
        if skip_logging_for and worker_type in skip_logging_for:
            return None

        safe_type = worker_type or "cmd"
        worker_id = f"cli_{safe_type[:8]}_{uuid.uuid4().hex[:6]}"

        try:
            tracked = worker_manager.track_worker(
                worker_id,
                worker_type=worker_type,
                title=title,
                description=description or "(no args)",
                pipe=pipe_text,
            )
            if not tracked:
                return None
        except Exception as exc:
            print(f"[worker] Failed to track {worker_type}: {exc}", file=sys.stderr)
            return None

        if session_worker_ids is not None:
            session_worker_ids.add(worker_id)

        logging_enabled = False
        try:
            handler = worker_manager.enable_logging_for_worker(worker_id)
            logging_enabled = handler is not None
        except Exception:
            logging_enabled = False

        orig_stdout = sys.stdout
        orig_stderr = sys.stderr
        stdout_proxy = WorkerOutputMirror(
            orig_stdout,
            worker_manager,
            worker_id,
            "stdout"
        )
        stderr_proxy = WorkerOutputMirror(
            orig_stderr,
            worker_manager,
            worker_id,
            "stderr"
        )
        sys.stdout = stdout_proxy
        sys.stderr = stderr_proxy
        if isinstance(config, dict):
            config["_current_worker_id"] = worker_id

        try:
            worker_manager.log_step(worker_id, f"Started {worker_type}")
        except Exception:
            pass

        return WorkerStageSession(
            manager=worker_manager,
            worker_id=worker_id,
            orig_stdout=orig_stdout,
            orig_stderr=orig_stderr,
            stdout_proxy=stdout_proxy,
            stderr_proxy=stderr_proxy,
            config=config,
            logging_enabled=logging_enabled,
            completion_label=completion_label,
            error_label=error_label,
        )

    @classmethod
    def begin_stage(
        cls,
        worker_manager: Optional[WorkerManager],
        *,
        cmd_name: str,
        stage_tokens: Sequence[str],
        config: Optional[Dict[str,
                              Any]],
        command_text: str,
    ) -> Optional[WorkerStageSession]:
        description = " ".join(stage_tokens[1:]
                               ) if len(stage_tokens) > 1 else "(no args)"
        session_worker_ids = None
        if isinstance(config, dict):
            session_worker_ids = config.get("_session_worker_ids")

        return cls._start_worker_session(
            worker_manager,
            worker_type=cmd_name,
            title=f"{cmd_name} stage",
            description=description,
            pipe_text=command_text,
            config=config,
            completion_label="Stage completed",
            error_label="Stage error",
            skip_logging_for={".worker",
                              "worker",
                              "workers"},
            session_worker_ids=session_worker_ids,
        )

    @classmethod
    def begin_pipeline(
        cls,
        worker_manager: Optional[WorkerManager],
        *,
        pipeline_text: str,
        config: Optional[Dict[str,
                              Any]],
    ) -> Optional[WorkerStageSession]:
        session_worker_ids: Set[str] = set()
        if isinstance(config, dict):
            config["_session_worker_ids"] = session_worker_ids

        return cls._start_worker_session(
            worker_manager,
            worker_type="pipeline",
            title="Pipeline run",
            description=pipeline_text,
            pipe_text=pipeline_text,
            config=config,
            completion_label="Pipeline completed",
            error_label="Pipeline error",
            session_worker_ids=session_worker_ids,
        )


class CmdletIntrospection:

    @staticmethod
    def cmdlet_names(force: bool = False) -> List[str]:
        try:
            return list_cmdlet_names(force=force) or []
        except Exception:
            return []

    @staticmethod
    def cmdlet_args(cmd_name: str,
                    config: Optional[Dict[str,
                                          Any]] = None) -> List[str]:
        try:
            return get_cmdlet_arg_flags(cmd_name, config=config) or []
        except Exception:
            return []

    @staticmethod
    def store_choices(config: Dict[str, Any], force: bool = False) -> List[str]:
        try:
            # Use the cached startup check from SharedArgs
            from SYS.cmdlet_spec import SharedArgs
            return SharedArgs.get_store_choices(config, force=force)
        except Exception:
            return []

    @classmethod
    def arg_choices(cls,
                    *,
                    cmd_name: str,
                    arg_name: str,
                    config: Dict[str,
                                 Any],
                    force: bool = False) -> List[str]:
        try:
            normalized_arg = (arg_name or "").lstrip("-").strip().lower()

            if normalized_arg in ("storage", "store"):
                # Use cached/lightweight names for completions to avoid instantiating backends
                # (instantiating backends may perform heavy initialization).
                backends = cls.store_choices(config, force=False)
                if backends:
                    return backends

            if normalized_arg == "plugin":
                canonical_cmd = (cmd_name or "").replace("_", "-").lower()
                try:
                    from PluginCore.registry import list_plugin_names_for_cmdlet
                except Exception:
                    list_plugin_names_for_cmdlet = None  # type: ignore

                plugin_choices: List[str] = []

                def _merge_choice_groups(*groups: Sequence[str]) -> List[str]:
                    seen: Set[str] = set()
                    merged: List[str] = []
                    for group in groups:
                        for entry in group or []:
                            key = str(entry or "").strip().lower()
                            if not key or key in seen:
                                continue
                            seen.add(key)
                            merged.append(str(entry))
                    return merged

                if canonical_cmd == "file" and list_plugin_names_for_cmdlet is not None:
                    configured_add = list_plugin_names_for_cmdlet(
                        "add-file",
                        config,
                        configured_only=True,
                    ) or []
                    available_add = list_plugin_names_for_cmdlet(
                        "add-file",
                        config,
                        configured_only=False,
                    ) or []
                    configured_search = list_plugin_names_for_cmdlet(
                        "search-file",
                        config,
                        configured_only=True,
                    ) or []
                    available_search = list_plugin_names_for_cmdlet(
                        "search-file",
                        config,
                        configured_only=False,
                    ) or []
                    plugin_choices = _merge_choice_groups(
                        configured_add,
                        available_add,
                        configured_search,
                        available_search,
                    )
                elif list_plugin_names_for_cmdlet is not None:
                    configured = list_plugin_names_for_cmdlet(
                        canonical_cmd,
                        config,
                        configured_only=True,
                    ) or []
                    available = list_plugin_names_for_cmdlet(
                        canonical_cmd,
                        config,
                        configured_only=False,
                    ) or []
                    # Prefer configured plugins first, but still show valid plugin options.
                    plugin_choices = _merge_choice_groups(configured, available)

                if plugin_choices:
                    return plugin_choices

            if normalized_arg == "scrape":
                try:
                    from plugins.metadata_plugin import list_metadata_plugins

                    metadata_plugins = list_metadata_plugins(config) or {}
                    if metadata_plugins:
                        return sorted(metadata_plugins.keys())
                except Exception:
                    pass

            return get_cmdlet_arg_choices(cmd_name, arg_name) or []
        except Exception:
            return []

    @staticmethod
    def query_args(cmd_name: str,
                   config: Optional[Dict[str,
                                         Any]] = None) -> List[Dict[str,
                                                                    Any]]:
        try:
            meta = get_cmdlet_metadata(cmd_name, config=config) or {}
        except Exception:
            return []

        args = meta.get("args", []) if isinstance(meta, dict) else []
        if not isinstance(args, list):
            return []

        query_args: List[Dict[str, Any]] = []
        for arg in args:
            if not isinstance(arg, dict):
                continue
            key = str(arg.get("query_key") or "").strip().lower()
            aliases = [
                str(value).strip().lower()
                for value in (arg.get("query_aliases") or [])
                if str(value).strip()
            ]
            if not key and not aliases:
                continue
            query_args.append(arg)
        return query_args

    @staticmethod
    def plugin_names_for_cmdlet(
        cmd_name: str,
        config: Optional[Dict[str, Any]] = None,
        *,
        configured_only: bool = False,
    ) -> List[str]:
        try:
            from PluginCore.registry import list_plugin_names_for_cmdlet

            return list_plugin_names_for_cmdlet(
                cmd_name,
                config,
                configured_only=configured_only,
            ) or []
        except Exception:
            return []


class CmdletCompleter(Completer):
    """Prompt-toolkit completer for the Medeia cmdlet REPL."""

    _CMDLET_NAME_REFRESH_SECONDS = 2.0
    _FILE_STAGE_ACTION_CMDLETS: Tuple[Tuple[str, str], ...] = (
        ("search", "search-file"),
        ("add", "add-file"),
        ("delete", "delete-file"),
        ("merge", "merge-file"),
        ("download", "download-file"),
        ("convert", "convert-file"),
        ("trim", "trim-file"),
        ("archive", "archive-file"),
        ("screenshot", "screen-shot"),
    )

    def __init__(self, *, config_loader: "ConfigLoader") -> None:
        self._config_loader = config_loader
        self.cmdlet_names = CmdletIntrospection.cmdlet_names()
        self._cmdlet_names_refreshed_at = time.monotonic()
        self._cmdlet_args_cache: Dict[Tuple[str, int], List[str]] = {}
        self._query_args_cache: Dict[Tuple[str, int], List[Dict[str, Any]]] = {}
        self._arg_choices_cache: Dict[Tuple[str, str, int], List[str]] = {}
        self._inline_query_choices_cache: Dict[Tuple[str, str, int], List[str]] = {}
        self._plugins_for_cmdlet_cache: Dict[Tuple[str, int, bool], List[str]] = {}

    def _refresh_cmdlet_names(self) -> None:
        now = time.monotonic()
        if self.cmdlet_names and (now - self._cmdlet_names_refreshed_at) < self._CMDLET_NAME_REFRESH_SECONDS:
            return
        self.cmdlet_names = CmdletIntrospection.cmdlet_names(force=False)
        self._cmdlet_names_refreshed_at = now

    @staticmethod
    def _config_cache_key(config: Dict[str, Any]) -> int:
        return id(config) if isinstance(config, dict) else 0

    def _cmdlet_args(self, cmd_name: str, config: Dict[str, Any]) -> List[str]:
        key = (str(cmd_name or "").lower(), self._config_cache_key(config))
        cached = self._cmdlet_args_cache.get(key)
        if cached is not None:
            return cached
        value = CmdletIntrospection.cmdlet_args(cmd_name, config)
        self._cmdlet_args_cache[key] = value
        return value

    def _query_args(self, cmd_name: str, config: Dict[str, Any]) -> List[Dict[str, Any]]:
        key = (str(cmd_name or "").lower(), self._config_cache_key(config))
        cached = self._query_args_cache.get(key)
        if cached is not None:
            return cached
        value = CmdletIntrospection.query_args(cmd_name, config)
        self._query_args_cache[key] = value
        return value

    def _arg_choices(
        self,
        *,
        cmd_name: str,
        arg_name: str,
        config: Dict[str, Any],
        force: bool = False,
    ) -> List[str]:
        key = (
            str(cmd_name or "").lower(),
            str(arg_name or "").lower(),
            self._config_cache_key(config),
        )
        if not force:
            cached = self._arg_choices_cache.get(key)
            if cached is not None:
                return cached
        value = CmdletIntrospection.arg_choices(
            cmd_name=cmd_name,
            arg_name=arg_name,
            config=config,
            force=force,
        )
        self._arg_choices_cache[key] = value
        return value

    def _inline_query_choices(
        self,
        provider_name: str,
        field_name: str,
        config: Dict[str, Any],
    ) -> List[str]:
        key = (
            str(provider_name or "").lower(),
            str(field_name or "").lower(),
            self._config_cache_key(config),
        )
        cached = self._inline_query_choices_cache.get(key)
        if cached is not None:
            return cached
        value = plugin_inline_query_choices(provider_name, field_name, config)
        self._inline_query_choices_cache[key] = value
        return value

    def _plugins_for_cmdlet(
        self,
        cmd_name: str,
        config: Dict[str, Any],
        *,
        configured_only: bool = False,
    ) -> List[str]:
        key = (
            str(cmd_name or "").lower(),
            self._config_cache_key(config),
            bool(configured_only),
        )
        cached = self._plugins_for_cmdlet_cache.get(key)
        if cached is not None:
            return cached
        value = CmdletIntrospection.plugin_names_for_cmdlet(
            cmd_name,
            config,
            configured_only=configured_only,
        )
        self._plugins_for_cmdlet_cache[key] = value
        return value

    def _used_arg_logicals(
        self,
        cmd_name: str,
        stage_tokens: List[str],
        config: Dict[str,
                     Any]
    ) -> Set[str]:
        """Return logical argument names already used in this cmdlet stage.

        Example: if the user has typed `download-file -url ...`, then `url`
        is considered used and should not be suggested again (even as `--url`).
        """
        arg_flags = self._cmdlet_args(cmd_name, config)
        allowed = {a.lstrip("-").strip().lower()
                   for a in arg_flags if a}
        if not allowed:
            return set()

        used: Set[str] = set()
        for tok in stage_tokens[1:]:
            if not tok or not tok.startswith("-"):
                continue
            if tok in {"-",
                       "--"}:
                continue
            # Handle common `-arg=value` form.
            raw = tok.split("=", 1)[0]
            logical = raw.lstrip("-").strip().lower()
            if logical and logical in allowed:
                used.add(logical)

        return used

    @staticmethod
    def _flag_value(tokens: Sequence[str], *flags: str) -> Optional[str]:
        want = {str(f).strip().lower() for f in flags if str(f).strip()}
        if not want:
            return None
        for idx, tok in enumerate(tokens):
            low = str(tok or "").strip().lower()
            if "=" in low:
                head, _ = low.split("=", 1)
                if head in want:
                    return tok.split("=", 1)[1]
            if low in want and idx + 1 < len(tokens):
                return tokens[idx + 1]
        return None

    @staticmethod
    def _effective_cmd_name(cmd_name: str, stage_tokens: Sequence[str]) -> str:
        canonical_cmd = str(cmd_name or "").replace("_", "-").strip().lower()
        if canonical_cmd != "file":
            return canonical_cmd

        lowered = {str(tok or "").strip().lower() for tok in (stage_tokens or [])}
        if "-search" in lowered or "--search" in lowered:
            return "search-file"
        if "-download" in lowered or "--download" in lowered or "-dl" in lowered or "--dl" in lowered:
            return "download-file"
        if "-add" in lowered or "--add" in lowered:
            return "add-file"
        if "-delete" in lowered or "--delete" in lowered or "-del" in lowered or "--del" in lowered:
            return "delete-file"
        if "-merge" in lowered or "--merge" in lowered:
            return "merge-file"
        if "-query" in lowered or "--query" in lowered or any(tok.startswith("-query=") or tok.startswith("--query=") for tok in lowered):
            return "search-file"
        return canonical_cmd

    @staticmethod
    def _selected_plugin_name(cmd_name: str, stage_tokens: Sequence[str]) -> Optional[str]:
        canonical_cmd = CmdletCompleter._effective_cmd_name(cmd_name, stage_tokens)
        if canonical_cmd not in {"file", "search-file", "add-file", "download-file"}:
            return None
        raw_plugin = CmdletCompleter._flag_value(stage_tokens, "-plugin", "--plugin")
        if raw_plugin:
            # Strip quotes if present, then normalize to lowercase
            stripped = CmdletCompleter._strip_quotes(str(raw_plugin or ""))
            return stripped.strip().lower() if stripped else None
        return None

    @staticmethod
    def _plugin_instance_choices(plugin_name: Optional[str], config: Dict[str, Any]) -> List[str]:
        plugin_key = str(plugin_name or "").strip().lower()
        if not plugin_key:
            return []

        try:
            from PluginCore.registry import get_plugin_class
        except Exception:
            return []

        plugin_class = get_plugin_class(plugin_key)
        if plugin_class is None:
            return []

        try:
            plugin = plugin_class(config)
        except Exception:
            return []

        try:
            instances = plugin.configured_instances()
        except Exception:
            return []

        out: List[str] = []
        seen: Set[str] = set()
        for value in instances or []:
            text = str(value or "").strip()
            lowered = text.lower()
            if not text or lowered in seen:
                continue
            seen.add(lowered)
            out.append(text)
        return out

    @staticmethod
    def _plugin_instance_accepts_direct_path(plugin_name: Optional[str]) -> bool:
        return str(plugin_name or "").strip().lower() == "local"

    @staticmethod
    def _looks_like_path_fragment(value: str) -> bool:
        text = str(value or "").strip()
        if not text:
            return False
        if text[:1] in {"'", '"'}:
            text = text[1:]
        if not text:
            return False
        if text.startswith((".", "~", "\\", "/")):
            return True
        if "\\" in text or "/" in text:
            return True
        if len(text) >= 2 and text[1] == ":":
            return True
        return False

    @staticmethod
    def _path_instance_choices(current_token: str) -> List[str]:
        raw = str(current_token or "")
        if not CmdletCompleter._looks_like_path_fragment(raw):
            return []

        quote_prefix = raw[:1] if raw[:1] in {"'", '"'} else ""
        fragment = raw[1:] if quote_prefix else raw
        if not fragment:
            return []

        expanded = os.path.expanduser(fragment)
        candidate = Path(expanded)

        if fragment.endswith(("\\", "/")):
            parent = candidate
            prefix = ""
        else:
            parent = candidate.parent if str(candidate.parent) not in {"", "."} else Path.cwd()
            prefix = candidate.name

        try:
            if not parent.exists() or not parent.is_dir():
                return []
        except Exception:
            return []

        out: List[str] = []
        seen: Set[str] = set()
        prefix_lower = prefix.lower()
        try:
            entries = sorted(parent.iterdir(), key=lambda item: item.name.lower())
        except Exception:
            return []

        for entry in entries:
            try:
                if not entry.is_dir():
                    continue
                if prefix_lower and not entry.name.lower().startswith(prefix_lower):
                    continue
                suggestion = str(entry)
                if quote_prefix:
                    suggestion = quote_prefix + suggestion
                elif " " in suggestion:
                    suggestion = f'"{suggestion}"'
            except Exception:
                continue

            lowered = suggestion.lower()
            if lowered in seen:
                continue
            seen.add(lowered)
            out.append(suggestion)

        return out

    def _file_stage_order(
        self,
        *,
        stage_tokens: Sequence[str],
        config: Dict[str, Any],
    ) -> Optional[List[str]]:
        if self._effective_cmd_name("file", stage_tokens) != "file":
            return None

        plugin_name = self._selected_plugin_name("file", stage_tokens)
        if not plugin_name:
            return [
                "search",
                "add",
                "delete",
                "merge",
                "download",
                "convert",
                "trim",
                "archive",
                "screenshot",
            ]

        plugin_key = str(plugin_name or "").strip().lower()
        supports_search = plugin_key in {
            str(name or "").strip().lower()
            for name in self._plugins_for_cmdlet("search-file", config)
        }
        supports_any_action = False
        ordered: List[str] = []

        instance_choices = self._plugin_instance_choices(plugin_name, config)
        accepts_direct_path = self._plugin_instance_accepts_direct_path(plugin_name)
        if instance_choices or accepts_direct_path:
            ordered.append("instance")

        if supports_search:
            ordered.append("query")

        for logical, target_cmd in self._FILE_STAGE_ACTION_CMDLETS:
            supported = plugin_key in {
                str(name or "").strip().lower()
                for name in self._plugins_for_cmdlet(target_cmd, config)
            }
            if not supported:
                continue
            supports_any_action = True
            if logical not in ordered:
                ordered.append(logical)

        if supports_search or supports_any_action:
            return ordered
        return []

    def _file_search_stage_order(
        self,
        *,
        stage_tokens: Sequence[str],
        config: Dict[str, Any],
    ) -> List[str]:
        plugin_name = self._selected_plugin_name("search-file", stage_tokens)
        if not plugin_name:
            return ["plugin", "query", "limit"]

        ordered = ["query"]
        if self._plugin_instance_choices(plugin_name, config):
            ordered.append("instance")
        ordered.extend(["plugin", "limit"])
        return ordered

    def _filter_stage_arg_names(
        self,
        *,
        cmd_name: str,
        stage_tokens: Sequence[str],
        config: Dict[str, Any],
        arg_names: List[str],
    ) -> List[str]:
        if not arg_names:
            return []

        source_cmd = (
            str(stage_tokens[0] or "").replace("_", "-").strip().lower()
            if stage_tokens else str(cmd_name or "").replace("_", "-").strip().lower()
        )
        canonical_cmd = self._effective_cmd_name(source_cmd, stage_tokens)
        plugin_name = self._selected_plugin_name(canonical_cmd, stage_tokens)
        instance_choices = self._plugin_instance_choices(plugin_name, config)
        has_named_instances = bool(instance_choices)
        accepts_direct_path = self._plugin_instance_accepts_direct_path(plugin_name)
        allow_instance_without_plugin = canonical_cmd == "search-file" and source_cmd != "file"

        file_stage_order = None
        file_stage_rank: Dict[str, int] = {}
        if source_cmd == "file" and canonical_cmd == "file":
            file_stage_order = self._file_stage_order(
                stage_tokens=stage_tokens,
                config=config,
            )
            if file_stage_order is not None:
                file_stage_rank = {
                    logical: idx for idx, logical in enumerate(file_stage_order)
                }
        elif source_cmd == "file" and canonical_cmd == "search-file":
            file_stage_order = self._file_search_stage_order(
                stage_tokens=stage_tokens,
                config=config,
            )
            file_stage_rank = {
                logical: idx for idx, logical in enumerate(file_stage_order)
            }

        filtered: List[Tuple[int, int, str]] = []
        for index, arg in enumerate(arg_names):
            logical = str(arg or "").lstrip("-").strip().lower()
            if file_stage_order is not None and logical not in file_stage_rank:
                continue
            if logical == "open":
                continue
            if logical == "instance":
                if allow_instance_without_plugin:
                    pass
                elif not plugin_name:
                    continue
                if not allow_instance_without_plugin and not has_named_instances and not accepts_direct_path:
                    continue
            rank = file_stage_rank.get(logical, len(file_stage_rank))
            filtered.append((rank, index, arg))

        if file_stage_order is not None:
            filtered.sort(key=lambda item: (item[0], item[1]))

        return [arg for _, _, arg in filtered]

    @staticmethod
    def _tokenize_quoted(text: str) -> List[str]:
        """Tokenize text preserving quoted strings as single tokens.
        
        Handles pipes as pipeline separators and preserves quoted strings
        (single or double quotes) as atomic tokens.
        """
        tokens = []
        current = ""
        in_quote = None  # None, "'", or '"'
        i = 0
        
        while i < len(text):
            char = text[i]
            
            if in_quote:
                current += char
                if char == in_quote and (i == 0 or text[i - 1] != "\\"):
                    in_quote = None
            elif char in ("'", '"'):
                in_quote = char
                current += char
            elif char == "|":
                if current.strip():
                    tokens.append(current.strip())
                tokens.append("|")
                current = ""
            elif char.isspace():
                if current.strip():
                    tokens.append(current.strip())
                current = ""
            else:
                current += char
            
            i += 1
        
        if current.strip():
            tokens.append(current.strip())
        
        return tokens

    @staticmethod
    def _strip_quotes(token: str) -> str:
        """Remove surrounding quotes from a token if present.
        
        Preserves internal content exactly. Only removes matching outer quotes.
        """
        token = str(token or "").strip()
        if len(token) >= 2:
            if (token[0] == '"' and token[-1] == '"') or (token[0] == "'" and token[-1] == "'"):
                return token[1:-1]
        return token

    def get_completions(
        self,
        document: Document,
        complete_event
    ):  # type: ignore[override]
        self._refresh_cmdlet_names()

        text = document.text_before_cursor
        tokens = self._tokenize_quoted(text)
        ends_with_space = bool(text) and text[-1].isspace()

        last_pipe = -1
        for idx, tok in enumerate(tokens):
            if tok == "|":
                last_pipe = idx
        stage_tokens = tokens[last_pipe + 1:] if last_pipe >= 0 else tokens

        if not stage_tokens:
            for cmd in self.cmdlet_names:
                yield Completion(cmd, start_position=0)
            return

        if len(stage_tokens) == 1:
            current = stage_tokens[0].lower()

            if ends_with_space:
                cmd_name = current.replace("_", "-")

                config = self._config_loader.load_shared()

                if cmd_name == "help":
                    for cmd in self.cmdlet_names:
                        yield Completion(cmd, start_position=0)
                    return

                if cmd_name not in self.cmdlet_names:
                    return

                arg_names = self._filter_stage_arg_names(
                    cmd_name=cmd_name,
                    stage_tokens=stage_tokens,
                    config=config,
                    arg_names=self._cmdlet_args(cmd_name, config),
                )
                seen_logicals: Set[str] = set()
                for arg in arg_names:
                    arg_low = arg.lower()
                    if arg_low.startswith("--"):
                        continue
                    logical = arg.lstrip("-").lower()
                    if logical in seen_logicals:
                        continue
                    yield Completion(arg, start_position=0)
                    seen_logicals.add(logical)
                return

            for cmd in self.cmdlet_names:
                if cmd.startswith(current):
                    yield Completion(cmd, start_position=-len(current))
            for keyword in ("help", "exit", "quit"):
                if keyword.startswith(current):
                    yield Completion(keyword, start_position=-len(current))
            return

        cmd_name = stage_tokens[0].replace("_", "-").lower()
        effective_cmd = self._effective_cmd_name(cmd_name, stage_tokens)
        if ends_with_space:
            raw_current_token = ""
            current_token = ""
            prev_token = stage_tokens[-1].lower()
        else:
            raw_current_token = stage_tokens[-1]
            current_token = raw_current_token.lower()
            prev_token = stage_tokens[-2].lower() if len(stage_tokens) > 1 else ""

        config = self._config_loader.load_shared()

        provider_name = None
        if effective_cmd == "search-file":
            raw_provider = self._flag_value(stage_tokens, "-plugin", "--plugin")
            if raw_provider:
                stripped = self._strip_quotes(str(raw_provider or ""))
                provider_name = stripped.strip().lower() if stripped else None

        selected_plugin = self._selected_plugin_name(effective_cmd, stage_tokens)

        query_specs = self._query_args(effective_cmd, config)
        query_flag_index = -1
        for idx, tok in enumerate(stage_tokens):
            if str(tok or "").strip().lower() in {"-query", "--query"}:
                query_flag_index = idx

        if query_specs and query_flag_index >= 0:
            query_parts = stage_tokens[query_flag_index + 1:]
            query_started_quoted = bool(query_parts and str(query_parts[0] or "")[:1] in {"'", '"'})

            query_fragment: Optional[str] = None
            if prev_token in {"-query", "--query"} and current_token[:1] in {"'", '"'}:
                query_fragment = current_token
            elif query_started_quoted and not ends_with_space and not current_token.startswith("-"):
                # Only continue in query mode if the previous token is not a flag (new argument)
                if not prev_token.startswith("-"):
                    query_fragment = current_token
            elif query_started_quoted and ends_with_space and ":" in prev_token:
                query_fragment = ""

            if query_fragment is not None:
                field_choices: Dict[str, List[str]] = {}
                ordered_fields: List[str] = []
                for spec in query_specs:
                    key = str(spec.get("query_key") or spec.get("name") or "").strip().lower()
                    if not key:
                        continue
                    if key not in field_choices:
                        ordered_fields.append(key)
                    field_choices[key] = [str(choice) for choice in list(spec.get("choices", []) or [])]
                    for alias in spec.get("query_aliases", []) or []:
                        alias_text = str(alias or "").strip().lower()
                        if not alias_text:
                            continue
                        field_choices.setdefault(alias_text, field_choices[key])

                raw_fragment = str(query_fragment or "")
                segment = raw_fragment[1:] if raw_fragment[:1] in {"'", '"'} else raw_fragment
                if "," in segment:
                    segment = segment.rsplit(",", 1)[-1].lstrip()
                segment = segment.lstrip()

                if ":" in segment:
                    field, partial = segment.split(":", 1)
                    field = field.strip().lower()
                    partial_lower = partial.strip().lower()

                    inline_choices = []
                    if effective_cmd == "search-file" and provider_name:
                        inline_choices = self._inline_query_choices(provider_name, field, config)

                    choice_pool = inline_choices or field_choices.get(field, [])
                    if choice_pool:
                        filtered = (
                            [choice for choice in choice_pool if partial_lower in str(choice).lower()]
                            if partial_lower else list(choice_pool)
                        )
                        for choice in (filtered or choice_pool):
                            yield Completion(str(choice), start_position=-len(partial))
                        return
                else:
                    partial_lower = segment.strip().lower()
                    field_pool = ordered_fields
                    filtered_fields = (
                        [field for field in field_pool if field.startswith(partial_lower)]
                        if partial_lower else field_pool
                    )
                    for field in (filtered_fields or field_pool):
                        yield Completion(f"{field}:", start_position=-len(segment))
                    if filtered_fields or field_pool:
                        return

        if (
            effective_cmd == "search-file"
            and provider_name
            and not ends_with_space
            and ":" in current_token
            and not current_token.startswith("-")
        ):
            # Allow quoted tokens like "system:g
            quote_prefix = current_token[0] if current_token[:1] in {"'", '"'} else ""
            inline_token = current_token[1:] if quote_prefix else current_token
            if inline_token.endswith(quote_prefix) and len(inline_token) > 1:
                inline_token = inline_token[:-1]

            # Allow comma-separated inline specs; operate on the last segment only.
            if "," in inline_token:
                inline_token = inline_token.split(",")[-1].lstrip()

            if ":" not in inline_token:
                return

            field, partial = inline_token.split(":", 1)
            field = field.strip().lower()
            partial_lower = partial.strip().lower()
            inline_choices = self._inline_query_choices(provider_name, field, config)
            if inline_choices:
                filtered = (
                    [c for c in inline_choices if partial_lower in str(c).lower()]
                    if partial_lower
                    else list(inline_choices)
                )
                for choice in (filtered or inline_choices):
                    # Replace only the partial after the colon; keep the field prefix and quotes as typed.
                    start_pos = -len(partial)
                    suggestion = str(choice)
                    yield Completion(suggestion, start_position=start_pos)
                return

        normalized_prev = prev_token.lstrip("-").strip().lower()
        choices: List[str] = []
        if normalized_prev == "instance" and selected_plugin:
            choices = self._plugin_instance_choices(selected_plugin, config)
            if self._plugin_instance_accepts_direct_path(selected_plugin):
                path_choices = self._path_instance_choices(raw_current_token)
                if path_choices:
                    seen_choice_values = {str(choice).lower() for choice in choices}
                    for choice in path_choices:
                        lowered = str(choice).lower()
                        if lowered in seen_choice_values:
                            continue
                        choices.append(choice)
                        seen_choice_values.add(lowered)
        if not choices:
            choices = self._arg_choices(
                cmd_name=effective_cmd,
                arg_name=prev_token,
                config=config,
                force=False,
            )
        if choices:
            choice_list = choices
            if normalized_prev == "plugin" and current_token:
                current_lower = current_token.lower()
                filtered = [c for c in choices if c.lower().startswith(current_lower)]
                if filtered:
                    choice_list = filtered

            if normalized_prev == "instance" and current_token:
                current_lower = current_token.lower()
                filtered = [c for c in choice_list if current_lower in c.lower()]
                if filtered:
                    choice_list = filtered

            for choice in choice_list:
                yield Completion(choice, start_position=-len(raw_current_token))
            # Example: if the user has typed `download-file -url ...`, then `url`
            # is considered used and should not be suggested again (even as `--url`).
            return

        arg_names = self._filter_stage_arg_names(
            cmd_name=effective_cmd,
            stage_tokens=stage_tokens,
            config=config,
            arg_names=self._cmdlet_args(effective_cmd, config),
        )
        used_logicals = self._used_arg_logicals(effective_cmd, stage_tokens, config)
        logical_seen: Set[str] = set()
        for arg in arg_names:
            arg_low = arg.lower()
            prefer_single_dash = current_token in {"",
                                                   "-"}
            if prefer_single_dash and arg_low.startswith("--"):
                continue
            logical = arg.lstrip("-").lower()
            if logical in used_logicals:
                continue
            if prefer_single_dash and logical in logical_seen:
                continue
            if arg_low.startswith(current_token):
                yield Completion(arg, start_position=-len(current_token))
                if prefer_single_dash:
                    logical_seen.add(logical)

class ConfigLoader:

    def __init__(self, *, root: Path) -> None:
        self._root = root

    def load_shared(self) -> Dict[str, Any]:
        try:
            return load_config(emit_summary=False)
        except Exception:
            return {}

    def load(self) -> Dict[str, Any]:
        try:
            return deepcopy(self.load_shared())
        except Exception:
            return {}


class CmdletHelp:

    @staticmethod
    def show_cmdlet_list() -> None:
        try:
            metadata = list_cmdlet_metadata() or {}
            from rich.box import SIMPLE
            from rich.panel import Panel
            from rich.table import Table as RichTable

            table = RichTable(
                show_header=True,
                header_style="bold",
                box=SIMPLE,
                expand=True
            )
            table.add_column("Cmdlet", no_wrap=True)
            table.add_column("Aliases")
            table.add_column("Args")
            table.add_column("Summary")

            for cmd_name in sorted(metadata.keys()):
                info = metadata[cmd_name]
                aliases = info.get("aliases", [])
                args = info.get("args", [])
                summary = info.get("summary") or ""
                alias_str = ", ".join(
                    [str(a) for a in (aliases or []) if str(a).strip()]
                )
                arg_names = [
                    a.get("name") for a in (args or [])
                    if isinstance(a, dict) and a.get("name")
                ]
                args_str = ", ".join([str(a) for a in arg_names if str(a).strip()])
                table.add_row(str(cmd_name), alias_str, args_str, str(summary))

            stdout_console().print(Panel(table, title="Cmdlets", expand=False))
        except Exception as exc:
            from rich.panel import Panel
            from rich.text import Text

            stderr_console().print(
                Panel(Text(f"Error: {exc}"),
                      title="Error",
                      expand=False)
            )

    @staticmethod
    def show_cmdlet_help(cmd_name: str) -> None:
        try:
            meta = get_cmdlet_metadata(cmd_name)
            if meta:
                CmdletHelp._print_metadata(cmd_name, meta)
                return
            print(f"Unknown command: {cmd_name}\n")
        except Exception as exc:
            print(f"Error: {exc}\n")

    @staticmethod
    def _print_metadata(cmd_name: str, data: Any) -> None:
        d = data.to_dict() if hasattr(data, "to_dict") else data
        if not isinstance(d, dict):
            from rich.panel import Panel
            from rich.text import Text

            stderr_console().print(
                Panel(
                    Text(f"Invalid metadata for {cmd_name}"),
                    title="Error",
                    expand=False
                )
            )
            return

        name = d.get("name", cmd_name)
        summary = d.get("summary", "")
        usage = d.get("usage", "")
        description = d.get("description", "")
        args = d.get("args", [])
        details = d.get("details", [])

        from rich.box import SIMPLE
        from rich.console import Group
        from rich.panel import Panel
        from rich.table import Table as RichTable
        from rich.text import Text

        header = Text.assemble((str(name), "bold"))
        synopsis = Text(str(usage or name))
        stdout_console().print(
            Panel(Group(header,
                        synopsis),
                  title="Help",
                  expand=False)
        )

        if summary or description:
            desc_bits: List[Text] = []
            if summary:
                desc_bits.append(Text(str(summary)))
            if description:
                desc_bits.append(Text(str(description)))
            stdout_console().print(
                Panel(Group(*desc_bits),
                      title="Description",
                      expand=False)
            )

        if args and isinstance(args, list):
            param_table = RichTable(
                show_header=True,
                header_style="bold",
                box=SIMPLE,
                expand=True
            )
            param_table.add_column("Arg", no_wrap=True)
            param_table.add_column("Type", no_wrap=True)
            param_table.add_column("Required", no_wrap=True)
            param_table.add_column("Description")
            for arg in args:
                if isinstance(arg, dict):
                    name_str = arg.get("name", "?")
                    typ = arg.get("type", "string")
                    required = bool(arg.get("required", False))
                    desc = arg.get("description", "")
                else:
                    name_str = getattr(arg, "name", "?")
                    typ = getattr(arg, "type", "string")
                    required = bool(getattr(arg, "required", False))
                    desc = getattr(arg, "description", "")

                param_table.add_row(
                    f"-{name_str}",
                    str(typ),
                    "yes" if required else "no",
                    str(desc or "")
                )

            stdout_console().print(Panel(param_table, title="Parameters", expand=False))

        if details:
            stdout_console().print(
                Panel(
                    Group(*[Text(str(x)) for x in details]),
                    title="Remarks",
                    expand=False
                )
            )


class CmdletExecutor:

    def __init__(self, *, config_loader: ConfigLoader) -> None:
        self._config_loader = config_loader

    @staticmethod
    def _get_table_title_for_command(
        cmd_name: str,
        emitted_items: Optional[List[Any]] = None,
        cmd_args: Optional[List[str]] = None,
    ) -> str:
        def _file_action(args: Optional[List[str]]) -> str | None:
            tokens = [str(t or "").strip().lower() for t in (args or [])]
            token_set = set(tokens)
            if "-search" in token_set or "--search" in token_set:
                return "search-file"
            if "-download" in token_set or "--download" in token_set or "-dl" in token_set or "--dl" in token_set:
                return "download-file"
            if "-add" in token_set or "--add" in token_set:
                return "add-file"
            if "-delete" in token_set or "--delete" in token_set or "-del" in token_set or "--del" in token_set:
                return "delete-file"
            if "-merge" in token_set or "--merge" in token_set:
                return "merge-file"
            if "-query" in token_set or "--query" in token_set or any(tok.startswith("-query=") or tok.startswith("--query=") for tok in token_set):
                return "search-file"
            return None

        normalized_cmd = str(cmd_name or "").replace("_", "-").lower().strip()
        mapped_cmd = _file_action(cmd_args) if normalized_cmd == "file" else normalized_cmd

        title_map = {
            "search-file": "Results",
            "search_file": "Results",
            "download-data": "Downloads",
            "download_data": "Downloads",
            "download-file": "Downloads",
            "download_file": "Downloads",
            "metadata": "Tags",
            "add-url": "Results",
            "add_url": "Results",
            "get-url": "url",
            "get_url": "url",
            "delete-url": "Results",
            "delete_url": "Results",
            "get-note": "Notes",
            "get_note": "Notes",
            "add-note": "Results",
            "add_note": "Results",
            "delete-note": "Results",
            "delete_note": "Results",
            "get-relationship": "Relationships",
            "get_relationship": "Relationships",
            "add-relationship": "Results",
            "add_relationship": "Results",
            "add-file": "Results",
            "add_file": "Results",
            "delete-file": "Results",
            "delete_file": "Results",
            "get-metadata": None,
            "get_metadata": None,
        }
        mapped = title_map.get(mapped_cmd or normalized_cmd, "Results")
        if mapped is not None:
            return mapped

        if emitted_items:
            first = emitted_items[0]
            try:
                if isinstance(first, dict) and first.get("title"):
                    return str(first.get("title"))
                if hasattr(first, "title") and getattr(first, "title"):
                    return str(getattr(first, "title"))
            except Exception:
                pass
        return "Results"

    def execute(self, cmd_name: str, args: List[str]) -> None:
        from SYS import pipeline as ctx
        from cmdlet import REGISTRY

        # REPL guard: stage-local selection tables should not leak across independent
        # commands. @ selection can always re-seed from the last result table.
        try:
            if hasattr(ctx, "set_current_stage_table"):
                ctx.set_current_stage_table(None)
        except Exception:
            pass

        cmd_fn = REGISTRY.get(cmd_name)
        try:
            mod = import_cmd_module(cmd_name, reload_loaded=True)
            data = getattr(mod, "CMDLET", None) if mod else None
            if data and hasattr(data, "exec") and callable(getattr(data, "exec")):
                from SYS.cmdlet_spec import collect_registered_cmdlet_names

                run_fn = getattr(data, "exec")
                for registered_name in collect_registered_cmdlet_names(data, fallback_name=cmd_name):
                    REGISTRY[registered_name] = run_fn
                cmd_fn = run_fn
        except Exception:
            pass

        if not cmd_fn:
            # Lazy-import module and register its CMDLET.
            try:
                mod = import_cmd_module(cmd_name)
                data = getattr(mod, "CMDLET", None) if mod else None
                if data and hasattr(data, "exec") and callable(getattr(data, "exec")):
                    run_fn = getattr(data, "exec")
                    REGISTRY[cmd_name] = run_fn
                    cmd_fn = run_fn
            except Exception:
                cmd_fn = None

        if not cmd_fn:
            print(f"Unknown command: {cmd_name}\n")
            try:
                ctx.set_last_execution_result(
                    status="failed",
                    error=f"Unknown command: {cmd_name}",
                    command_text=" ".join([cmd_name, *args]).strip() or cmd_name,
                )
            except Exception:
                pass
            return

        config = self._config_loader.load()

        # ------------------------------------------------------------------
        # Single-command Live pipeline progress (match REPL behavior)
        # ------------------------------------------------------------------
        progress_ui = None
        pipe_idx: Optional[int] = None

        def _maybe_start_single_live_progress(
            *,
            cmd_name_norm: str,
            filtered_args: List[str],
            piped_input: Any,
            config: Any,
        ) -> None:
            nonlocal progress_ui, pipe_idx

            def _effective_file_cmd(name: str, args: List[str]) -> str:
                norm = str(name or "").replace("_", "-").strip().lower()
                if norm != "file":
                    return norm
                lowered = {str(a or "").strip().lower() for a in (args or [])}
                if "-add" in lowered or "--add" in lowered:
                    return "add-file"
                if "-delete" in lowered or "--delete" in lowered or "-del" in lowered or "--del" in lowered:
                    return "delete-file"
                if "-download" in lowered or "--download" in lowered or "-dl" in lowered or "--dl" in lowered:
                    return "download-file"
                return norm

            effective_cmd = _effective_file_cmd(cmd_name_norm, filtered_args)

            # Keep behavior consistent with pipeline runner exclusions.
            # Some commands render their own Rich UI (tables/panels) and don't
            # play nicely with Live cursor control.
            if effective_cmd in {
                    "get-relationship",
                    "get-rel",
                    ".pipe",
                    ".mpv",
                    ".matrix",
                    ".telegram",
                    "telegram",
                    "delete-file",
                    "del-file",
            }:
                return

            # add-file directory selector mode: show only the selection table, no Live progress.
            if effective_cmd in {"add-file", "add_file"}:
                try:
                    from pathlib import Path as _Path

                    toks = list(filtered_args or [])
                    i = 0
                    while i < len(toks):
                        t = str(toks[i])
                        low = t.lower().strip()
                        if low in {"-path",
                                   "--path",
                                   "-p"} and i + 1 < len(toks):
                            nxt = str(toks[i + 1])
                            if nxt and ("," not in nxt):
                                p = _Path(nxt)
                                if p.exists() and p.is_dir():
                                    return
                            i += 2
                            continue
                        i += 1
                except Exception:
                    pass

            try:
                quiet_mode = (
                    bool(config.get("_quiet_background_output"))
                    if isinstance(config,
                                  dict) else False
                )
            except Exception:
                quiet_mode = False
            if quiet_mode:
                return

            try:
                import sys as _sys

                if not bool(getattr(_sys.stderr, "isatty", lambda: False)()):
                    return
            except Exception:
                return

            try:
                from SYS.models import PipelineLiveProgress

                progress_ui = PipelineLiveProgress([cmd_name_norm], enabled=True)
                progress_ui.start()
                try:
                    if hasattr(ctx, "set_live_progress"):
                        ctx.set_live_progress(progress_ui)
                except Exception:
                    pass
                try:
                    progress_cb = (
                        ctx.get_progress_event_callback()
                        if hasattr(ctx, "get_progress_event_callback") else None
                    )
                    if callable(progress_cb) and hasattr(progress_ui, "set_event_callback"):
                        progress_ui.set_event_callback(progress_cb)
                except Exception:
                    pass

                pipe_idx = 0

                # Estimate per-item task count for the single pipe.
                total_items = 1
                preview_items: Optional[List[Any]] = None
                try:
                    if isinstance(piped_input, list):
                        total_items = max(1, int(len(piped_input)))
                        preview_items = list(piped_input)
                    elif piped_input is not None:
                        total_items = 1
                        preview_items = [piped_input]
                    else:
                        preview: List[Any] = []
                        toks = list(filtered_args or [])
                        i = 0
                        while i < len(toks):
                            t = str(toks[i])
                            low = t.lower().strip()
                            if (effective_cmd in {"add-file", "add_file"} and low in {"-path",
                                                                          "--path",
                                                                          "-p"}
                                    and i + 1 < len(toks)):
                                nxt = str(toks[i + 1])
                                if nxt:
                                    if "," in nxt:
                                        parts = [
                                            p.strip().strip("\"'")
                                            for p in nxt.split(",")
                                        ]
                                        parts = [p for p in parts if p]
                                        if parts:
                                            preview.extend(parts)
                                            i += 2
                                            continue
                                    else:
                                        preview.append(nxt)
                                        i += 2
                                        continue
                            if low in {"-url",
                                       "--url"} and i + 1 < len(toks):
                                nxt = str(toks[i + 1])
                                if nxt and not nxt.startswith("-"):
                                    preview.append(nxt)
                                i += 2
                                continue
                            if (not t.startswith("-")) and ("://" in low
                                                            or low.startswith(
                                                                ("magnet:",
                                                                 "torrent:"))):
                                preview.append(t)
                            i += 1
                        preview_items = preview if preview else None
                        total_items = max(1, int(len(preview)) if preview else 1)
                except Exception:
                    total_items = 1
                    preview_items = None

                try:
                    progress_ui.begin_pipe(
                        0,
                        total_items=int(total_items),
                        items_preview=preview_items
                    )
                except Exception:
                    pass
            except Exception:
                progress_ui = None
                pipe_idx = None

        filtered_args: List[str] = []
        selected_indices: List[int] = []
        select_all = False
        selection_filters: List[List[Tuple[str, str]]] = []

        value_flags: Set[str] = set()
        try:
            meta = get_cmdlet_metadata(cmd_name)
            raw = meta.get("raw") if isinstance(meta, dict) else None
            arg_specs = getattr(raw, "arg", None) if raw is not None else None
            if isinstance(arg_specs, list):
                for spec in arg_specs:
                    spec_type = str(getattr(spec,
                                            "type",
                                            "string") or "string").strip().lower()
                    if spec_type == "flag":
                        continue
                    spec_name = str(getattr(spec, "name", "") or "")
                    canonical = spec_name.lstrip("-").strip()
                    if not canonical:
                        continue
                    value_flags.add(f"-{canonical}".lower())
                    value_flags.add(f"--{canonical}".lower())
                    alias = str(getattr(spec, "alias", "") or "").strip()
                    if alias:
                        value_flags.add(f"-{alias}".lower())
        except Exception:
            value_flags = set()

        for i, arg in enumerate(args):
            if isinstance(arg, str) and arg.startswith("@"):  # selection candidate
                prev = str(args[i - 1]).lower() if i > 0 else ""
                if prev in value_flags:
                    filtered_args.append(arg)
                    continue

                # Universal selection filter: @"COL:expr" (quotes may be stripped by tokenization)
                filter_spec = SelectionFilterSyntax.parse(arg)
                if filter_spec is not None:
                    selection_filters.append(filter_spec)
                    continue

                if arg.strip() == "@*":
                    select_all = True
                    continue

                selection = SelectionSyntax.parse(arg)
                if selection is not None:
                    zero_based = [idx - 1 for idx in selection]
                    for idx in zero_based:
                        if idx not in selected_indices:
                            selected_indices.append(idx)
                    continue

                filtered_args.append(arg)
                continue

            filtered_args.append(str(arg))

        # IMPORTANT: Do not implicitly feed the previous command's results into
        # a new command unless the user explicitly selected items via @ syntax.
        # Piping should require `|` (or an explicit @ selection).
        piped_items = ctx.get_last_result_items()
        result: Any = None
        effective_selected_indices: List[int] = []
        if piped_items and (select_all or selected_indices or selection_filters):
            candidate_idxs = list(range(len(piped_items)))
            for spec in selection_filters:
                candidate_idxs = [
                    i for i in candidate_idxs
                    if SelectionFilterSyntax.matches(piped_items[i], spec)
                ]

            if select_all:
                effective_selected_indices = list(candidate_idxs)
            elif selected_indices:
                effective_selected_indices = [
                    candidate_idxs[i] for i in selected_indices
                    if 0 <= i < len(candidate_idxs)
                ]
            else:
                effective_selected_indices = list(candidate_idxs)

            result = [piped_items[i] for i in effective_selected_indices]

        worker_manager = WorkerManagerRegistry.ensure(config)
        stage_session = WorkerStages.begin_stage(
            worker_manager,
            cmd_name=cmd_name,
            stage_tokens=[cmd_name,
                          *filtered_args],
            config=config,
            command_text=" ".join([cmd_name,
                                   *filtered_args]).strip() or cmd_name,
        )

        stage_worker_id = stage_session.worker_id if stage_session else None

        # Start live progress after we know the effective cmd + args + piped input.
        cmd_norm = str(cmd_name or "").replace("_", "-").strip().lower()
        _maybe_start_single_live_progress(
            cmd_name_norm=cmd_norm or str(cmd_name or "").strip().lower(),
            filtered_args=filtered_args,
            piped_input=result,
            config=config,
        )

        on_emit = None
        if progress_ui is not None and pipe_idx is not None:
            _ui = progress_ui

            def _on_emit(obj: Any, _progress=_ui) -> None:
                try:
                    _progress.on_emit(0, obj)
                except Exception:
                    pass

            on_emit = _on_emit

        pipeline_ctx = ctx.PipelineStageContext(
            stage_index=0,
            total_stages=1,
            pipe_index=pipe_idx if pipe_idx is not None else 0,
            worker_id=stage_worker_id,
            on_emit=on_emit,
        )
        ctx.set_stage_context(pipeline_ctx)
        stage_status = "completed"
        stage_error = ""

        ctx.set_last_selection(effective_selected_indices)
        try:
            try:
                if hasattr(ctx, "set_current_cmdlet_name"):
                    ctx.set_current_cmdlet_name(cmd_name)
            except Exception:
                pass

            try:
                if hasattr(ctx, "set_current_stage_text"):
                    raw_stage = ""
                    try:
                        raw_stage = (
                            ctx.get_current_command_text("")
                            if hasattr(ctx,
                                       "get_current_command_text") else ""
                        )
                    except Exception:
                        raw_stage = ""
                    if raw_stage:
                        ctx.set_current_stage_text(raw_stage)
                    else:
                        ctx.set_current_stage_text(
                            " ".join([cmd_name,
                                      *filtered_args]).strip() or cmd_name
                        )
            except Exception:
                pass

            ret_code = cmd_fn(result, filtered_args, config)

            if getattr(pipeline_ctx, "emits", None):
                emits = list(pipeline_ctx.emits)

                # Shared `-path` behavior: if the cmdlet emitted temp/PATH file artifacts,
                # move them to the user-specified destination and update emitted paths.
                try:
                    from cmdlet import _shared as sh

                    emits = sh.apply_output_path_from_pipeobjects(
                        cmd_name=cmd_name,
                        args=filtered_args,
                        emits=emits
                    )
                    try:
                        pipeline_ctx.emits = list(emits)
                    except Exception:
                        pass
                except Exception:
                    pass

                # Detect format-selection emits and skip printing (user selects with @N).
                is_format_selection = False
                if emits:
                    first_emit = emits[0]
                    if isinstance(first_emit, dict) and "format_id" in first_emit:
                        is_format_selection = True

                if is_format_selection:
                    ctx.set_last_result_items_only(emits)
                else:
                    table_title = self._get_table_title_for_command(
                        cmd_name,
                        emits,
                        filtered_args
                    )

                    def _effective_cmd_name(name: str, args: List[str]) -> str:
                        norm = str(name or "").replace("_", "-").strip().lower()
                        if norm != "file":
                            return norm
                        lowered = {str(a or "").strip().lower() for a in (args or [])}
                        if "-search" in lowered or "--search" in lowered:
                            return "search-file"
                        if "-download" in lowered or "--download" in lowered or "-dl" in lowered or "--dl" in lowered:
                            return "download-file"
                        if "-add" in lowered or "--add" in lowered:
                            return "add-file"
                        if "-delete" in lowered or "--delete" in lowered or "-del" in lowered or "--del" in lowered:
                            return "delete-file"
                        if "-query" in lowered or "--query" in lowered or any(a.startswith("-query=") or a.startswith("--query=") for a in lowered):
                            return "search-file"
                        return norm

                    effective_cmd = _effective_cmd_name(cmd_name, filtered_args)

                    selectable_commands = {
                        "search-file",
                        "download-data",
                        "download-file",
                        "search_file",
                        "download_data",
                        "download_file",
                        ".config",
                        ".worker",
                    }
                    display_only_commands = {
                        "get-url",
                        "get_url",
                        "get-note",
                        "get_note",
                        "get-relationship",
                        "get_relationship",
                        "get-metadata",
                        "get_metadata",
                    }
                    self_managing_commands = {
                        "tag",
                        "tags",
                        "get-metadata",
                        "get_metadata",
                        "get-url",
                        "get_url",
                        "search-file",
                        "search_file",
                        "add-file",
                        "add_file",
                        "file",
                    }

                    if effective_cmd in self_managing_commands or cmd_name in self_managing_commands:
                        table = (
                            ctx.get_display_table()
                            if hasattr(ctx, "get_display_table") else None
                        )
                        if table is None:
                            table = ctx.get_last_result_table()
                        if table is None:
                            table = Table(table_title)
                            for emitted in emits:
                                table.add_result(emitted)
                    else:
                        table = Table(table_title)
                        for emitted in emits:
                            table.add_result(emitted)

                        if effective_cmd in selectable_commands:
                            table.set_source_command(effective_cmd, filtered_args)
                            ctx.set_last_result_table(table, emits)
                            ctx.set_current_stage_table(None)
                        elif effective_cmd in display_only_commands or cmd_name in display_only_commands:
                            ctx.set_last_result_items_only(emits)
                        else:
                            ctx.set_last_result_items_only(emits)

                    # Stop Live progress before printing tables.
                    if progress_ui is not None:
                        try:
                            if pipe_idx is not None:
                                progress_ui.finish_pipe(
                                    int(pipe_idx),
                                    force_complete=(stage_status == "completed")
                                )
                        except Exception:
                            pass
                        try:
                            progress_ui.complete_all_pipes()
                        except Exception:
                            pass
                        try:
                            progress_ui.stop()
                        except Exception:
                            pass
                        try:
                            if hasattr(ctx, "set_live_progress"):
                                ctx.set_live_progress(None)
                        except Exception:
                            pass
                        progress_ui = None
                        pipe_idx = None

                    if not getattr(table, "_rendered_by_cmdlet", False):
                        stdout_console().print()
                        stdout_console().print(table)

            # If the cmdlet produced a current-stage table without emits (e.g. format selection),
            # render it here for parity with REPL pipeline runner.
            if (not getattr(pipeline_ctx,
                            "emits",
                            None)) and hasattr(ctx,
                                               "get_current_stage_table"):
                try:
                    stage_table = ctx.get_current_stage_table()
                except Exception:
                    stage_table = None
                if stage_table is not None:
                    try:
                        already_rendered = bool(
                            getattr(stage_table,
                                    "_rendered_by_cmdlet",
                                    False)
                        )
                    except Exception:
                        already_rendered = False

                    if already_rendered:
                        try:
                            ctx.set_last_execution_result(
                                status=stage_status,
                                error=stage_error,
                                command_text=" ".join([cmd_name, *filtered_args]).strip() or cmd_name,
                            )
                        except Exception:
                            pass
                        return

                    if progress_ui is not None:
                        try:
                            if pipe_idx is not None:
                                progress_ui.finish_pipe(
                                    int(pipe_idx),
                                    force_complete=(stage_status == "completed")
                                )
                        except Exception:
                            pass
                        try:
                            progress_ui.complete_all_pipes()
                        except Exception:
                            pass
                        try:
                            progress_ui.stop()
                        except Exception:
                            pass
                        try:
                            if hasattr(ctx, "set_live_progress"):
                                ctx.set_live_progress(None)
                        except Exception:
                            pass
                        progress_ui = None
                        pipe_idx = None
                    stdout_console().print()
                    stdout_console().print(stage_table)

            if ret_code != 0:
                stage_status = "failed"
                stage_error = f"exit code {ret_code}"
                # No print here - we want to keep output clean and avoid redundant "exit code" notices.
        except Exception as exc:
            stage_status = "failed"
            stage_error = f"{type(exc).__name__}: {exc}"
            print(f"[error] {type(exc).__name__}: {exc}\n")
        finally:
            if progress_ui is not None:
                try:
                    if pipe_idx is not None:
                        progress_ui.finish_pipe(
                            int(pipe_idx),
                            force_complete=(stage_status == "completed")
                        )
                except Exception:
                    pass
                try:
                    progress_ui.complete_all_pipes()
                except Exception:
                    pass
                try:
                    progress_ui.stop()
                except Exception:
                    pass
                try:
                    if hasattr(ctx, "set_live_progress"):
                        ctx.set_live_progress(None)
                except Exception:
                    pass
            # Do not keep stage tables around after a single command; it can cause
            # later @ selections to bind to stale tables (e.g. old add-file scans).
            try:
                if hasattr(ctx, "set_last_execution_result"):
                    ctx.set_last_execution_result(
                        status=stage_status,
                        error=stage_error,
                        command_text=" ".join([cmd_name, *filtered_args]).strip() or cmd_name,
                    )
            except Exception:
                pass
            try:
                if hasattr(ctx, "set_current_stage_table"):
                    ctx.set_current_stage_table(None)
            except Exception:
                pass
            try:
                if hasattr(ctx, "clear_current_cmdlet_name"):
                    ctx.clear_current_cmdlet_name()
            except Exception:
                pass
            try:
                if hasattr(ctx, "clear_current_stage_text"):
                    ctx.clear_current_stage_text()
            except Exception:
                pass
            ctx.clear_last_selection()
            if stage_session:
                stage_session.close(status=stage_status, error_msg=stage_error)



console = Console()


class CLI:
    """Main CLI application object."""

    ROOT = Path(__file__).resolve().parent

    def __init__(self) -> None:
        self._config_loader = ConfigLoader(root=self.ROOT)

        # Optional dependency auto-install for configured tools (best-effort).
        try:
            from SYS.optional_deps import maybe_auto_install_configured_tools

            maybe_auto_install_configured_tools(self._config_loader.load())
        except Exception:
            pass

        # Initialize the store choices cache at startup (filters disabled stores)
        try:
            from SYS.cmdlet_spec import SharedArgs
            config = self._config_loader.load()
            SharedArgs._refresh_store_choices_cache(config)
        except Exception:
            pass

        self._cmdlet_executor = CmdletExecutor(config_loader=self._config_loader)
        self._pipeline_executor = PipelineExecutor(config_loader=self._config_loader)

    @staticmethod
    def parse_selection_syntax(token: str) -> Optional[List[int]]:
        return SelectionSyntax.parse(token)

    @classmethod
    def get_store_choices(cls) -> List[str]:
        loader = ConfigLoader(root=cls.ROOT)
        return CmdletIntrospection.store_choices(loader.load())

    def build_app(self) -> typer.Typer:
        app = typer.Typer(help="Medeia-Macina CLI")

        def _validate_pipeline_option(
            ctx: typer.Context,
            param: typer.CallbackParam,
            value: str
        ):
            try:
                from SYS.cli_syntax import validate_pipeline_text

                syntax_error = validate_pipeline_text(
                    value,
                    config=self._config_loader.load(),
                )
                if syntax_error:
                    raise typer.BadParameter(syntax_error.message)
            except typer.BadParameter:
                raise
            except Exception:
                pass
            return value

        @app.command("pipeline")
        def pipeline(
            command: str = typer.Option(
                ...,
                "--pipeline",
                "-p",
                help="Pipeline command string to execute",
                callback=_validate_pipeline_option,
            ),
            seeds_json: Optional[str] = typer.Option(
                None,
                "--seeds-json",
                "-s",
                help="JSON string of seed items"
            ),
        ) -> None:
            from SYS import pipeline as ctx

            config = self._config_loader.load()
            debug_enabled = bool(config.get("debug", False))
            set_debug(debug_enabled)

            if seeds_json:
                try:
                    seeds = json.loads(seeds_json)
                    if not isinstance(seeds, list):
                        seeds = [seeds]
                    ctx.set_last_result_items_only(seeds)
                except Exception as exc:
                    print(f"Error parsing seeds JSON: {exc}")
                    return

            try:
                from SYS.cli_syntax import validate_pipeline_text

                syntax_error = validate_pipeline_text(command, config=config)
                if syntax_error:
                    print(syntax_error.message, file=sys.stderr)
                    return
            except Exception:
                pass

            try:
                tokens = shlex.split(command)
            except ValueError as exc:
                print(f"Syntax error: {exc}", file=sys.stderr)
                return

            if not tokens:
                return
            self._pipeline_executor.execute_tokens(tokens)

        @app.command("repl")
        def repl() -> None:
            self.run_repl()

        @app.callback(invoke_without_command=True)
        def main_callback(ctx: typer.Context) -> None:
            if ctx.invoked_subcommand is None:
                self.run_repl()

        _ = (pipeline, repl, main_callback)

        # Dynamically register all cmdlets as top-level Typer commands so users can
        # invoke `mm <cmdlet> [args]` directly from the shell. We use Click/Typer
        # context settings to allow arbitrary flags and options to pass through to
        # the cmdlet system without Typer trying to parse them.
        try:
            names = list_cmdlet_names()
            skip = {"pipeline", "repl"}
            for nm in names:
                if not nm or nm in skip:
                    continue

                # create a scoped handler to capture the command name
                def _make_handler(cmd_name: str):

                    @app.command(
                        cmd_name,
                        context_settings={
                            "ignore_unknown_options": True,
                            "allow_extra_args": True,
                        },
                    )
                    def _handler(ctx: typer.Context):
                        try:
                            args = list(ctx.args or [])
                        except Exception:
                            args = []
                        self._cmdlet_executor.execute(cmd_name, args)

                    return _handler

                _make_handler(nm)
        except Exception:
            # Don't let failure to register dynamic commands break startup
            pass

        return app

    def run(self) -> None:
        # Ensure Rich tracebacks are active even when invoking subcommands.
        try:
            config = self._config_loader.load()
            debug_enabled = bool(config.get("debug",
                                            False)
                                 ) if isinstance(config,
                                                 dict) else False
        except Exception:
            debug_enabled = False

        set_debug(debug_enabled)
        _install_rich_traceback(show_locals=debug_enabled)

        self.build_app()()

    def run_repl(self) -> None:
        # console = Console(width=100)

        # Valid Rich rainbow colors
        RAINBOW = [
            "red",
            "dark_orange",
            "yellow",
            "green",
            "blue",
            "purple",
            "magenta",
        ]

        def rainbow_pillar(colors, height=21, bar_width=36):
            table = RichTable.grid(padding=0)
            table.add_column(no_wrap=True)

            for i in range(height):
                color = colors[i % len(colors)]
                table.add_row(Bar(size=1, begin=0, end=1, width=bar_width, color=color))

            return table

        # Build root layout
        root = Layout(name="root")
        root.split_row(
            Layout(name="left",
                   ratio=2),
            Layout(name="center",
                   ratio=8),
            Layout(name="right",
                   ratio=2),
        )

        # Left pillar → forward rainbow
        root["left"].update(
            Panel(rainbow_pillar(RAINBOW,
                                 height=21,
                                 bar_width=36),
                  title="DELTA")
        )

        # Right pillar → reverse rainbow
        root["right"].update(
            Panel(
                rainbow_pillar(list(reversed(RAINBOW)),
                               height=21,
                               bar_width=36),
                title="LAMBDA"
            )
        )

        # Center content
        center_md = Markdown(
            """
# ******************    Medios Macina    ******************
take what you want | keep what you like | share what you love
_____________________________________________________________
_____________________________________________________________
_____________________________________________________________
For suddenly you may be let loose from the net, and thrown out to sea.
Waving around clutching at gnats, unable to lift the heavy anchor. Lost
and without a map, forgotten things from the past by distracting wind storms.
_____________________________________________________________
_____________________________________________________________
_____________________________________________________________
Light shines a straight path to the golden shores.
Come to love it when others take what you share, as there is no greater joy
"""
        )
        root["center"].update(Panel(center_md, title="KAPPA", height=21))

        console.print(root)

        prompt_text = "<🜂🜄|🜁🜃>"

        startup_table = Table(
            "*********<IGNITIO>*********<NOUSEMPEH>*********<RUGRAPOG>*********<OMEGHAU>*********"
        )
        startup_table._interactive(True)._perseverance(True)
        startup_table.set_value_case("upper")

        def _add_startup_check(
            status: str,
            name: str,
            *,
            provider: str = "",
            instance: str = "",
            files: int | str | None = None,
            detail: str = "",
        ) -> None:
            _shared_add_startup_check(
                startup_table,
                status,
                name,
                provider=provider,
                instance=instance,
                files=files,
                detail=detail,
            )

        config = self._config_loader.load()
        debug_enabled = bool(config.get("debug", False))
        set_debug(debug_enabled)
        _install_rich_traceback(show_locals=debug_enabled)
        _add_startup_check("ENABLED" if debug_enabled else "DISABLED", "DEBUGGING")

        try:
            try:
                from plugins.mpv.mpv_ipc import MPV
                import shutil

                MPV()
                mpv_path = shutil.which("mpv")
                _add_startup_check("ENABLED", "MPV", detail=mpv_path or "Available")
            except Exception as exc:
                _add_startup_check("DISABLED", "MPV", detail=str(exc))

            for check in _collect_plugin_startup_checks(config):
                _add_startup_check(
                    str(check.get("status") or "UNKNOWN"),
                    str(check.get("name") or "Plugin"),
                    provider=str(check.get("plugin") or ""),
                    instance=str(check.get("instance") or ""),
                    detail=str(check.get("detail") or ""),
                    files=check.get("files"),
                )

            # Plugin support checks (configured via [plugin=...])
            if _has_provider(config, "florencevision"):
                try:
                    plugin_cfg = config.get("plugin")
                    fv_cfg = plugin_cfg.get("florencevision") if isinstance(plugin_cfg, dict) else None
                    enabled = bool(fv_cfg.get("enabled")) if isinstance(fv_cfg, dict) else False
                    if not enabled:
                        _add_startup_check(
                            "DISABLED",
                            "FlorenceVision",
                            provider="plugin",
                            detail="Not enabled",
                        )
                    else:
                        from SYS.optional_deps import florencevision_missing_modules

                        missing = florencevision_missing_modules()
                        if missing:
                            _add_startup_check(
                                "DISABLED",
                                "FlorenceVision",
                                provider="plugin",
                                detail="Missing: " + ", ".join(missing),
                            )
                        else:
                            _add_startup_check(
                                "ENABLED",
                                "FlorenceVision",
                                provider="plugin",
                                detail="Ready",
                            )
                except Exception as exc:
                    _add_startup_check(
                        "DISABLED",
                        "FlorenceVision",
                        provider="plugin",
                        detail=str(exc),
                    )
        except Exception as exc:
            _add_startup_check("ERROR", "STARTUP", detail=str(exc))

        if startup_table.rows:
            stdout_console().print()
            stdout_console().print(startup_table)

        style = Style.from_dict(
            {
                "cmdlet": "#ffffff",
                "argument": "#3b8eea",
                "value": "#9a3209",
                "string": "#6d0d93",
                "pipe": "#4caf50",
                "selection_at": "#f1c40f",
                "selection_range": "#4caf50",
                "bottom-toolbar": "noreverse",
            }
        )

        class ToolbarState:
            text: str = ""
            last_update_time: float = 0.0
            clear_timer: Optional[threading.Timer] = None

        toolbar_state = ToolbarState()
        session: Optional[PromptSession] = None

        def get_toolbar() -> Optional[str]:
            if not toolbar_state.text or not toolbar_state.text.strip():
                return None
            if time.time() - toolbar_state.last_update_time > 3:
                toolbar_state.text = ""
                return None
            return toolbar_state.text

        def update_toolbar(text: str) -> None:
            nonlocal session
            text = text.strip()
            toolbar_state.text = text
            toolbar_state.last_update_time = time.time()

            if toolbar_state.clear_timer:
                toolbar_state.clear_timer.cancel()
                toolbar_state.clear_timer = None

            if text:

                def clear_toolbar() -> None:
                    toolbar_state.text = ""
                    toolbar_state.clear_timer = None
                    if session is not None and hasattr(
                            session,
                            "app") and session.app.is_running:
                        session.app.invalidate()

                toolbar_state.clear_timer = threading.Timer(3.0, clear_toolbar)
                toolbar_state.clear_timer.daemon = True
                toolbar_state.clear_timer.start()

            if session is not None and hasattr(session,
                                               "app") and session.app.is_running:
                session.app.invalidate()

        self._pipeline_executor.set_toolbar_output(update_toolbar)

        completer = CmdletCompleter(config_loader=self._config_loader)
        session = PromptSession(
            completer=cast(Any,
                           completer),
            lexer=MedeiaLexer(),
            style=style,
            bottom_toolbar=get_toolbar,
            refresh_interval=0.5,
        )

        queued_inputs: List[Dict[str, Any]] = []
        queued_inputs_lock = threading.Lock()
        repl_queue_stop = threading.Event()
        injected_payload: Optional[Dict[str, Any]] = None
        repl_session_id = uuid.uuid4().hex

        def _drain_repl_queue() -> None:
            try:
                pending = pop_repl_commands(self.ROOT, limit=8)
            except Exception:
                pending = []
            if not pending:
                return
            with queued_inputs_lock:
                queued_inputs.extend(pending)

        def _inject_repl_command(payload: Dict[str, Any]) -> bool:
            nonlocal session, injected_payload
            command_text = str(payload.get("command") or "").strip()
            source_text = str(payload.get("source") or "external").strip() or "external"
            if not command_text or session is None:
                return False

            update_toolbar(f"queued from {source_text}: {command_text[:96]}")
            app = getattr(session, "app", None)
            if app is None or not getattr(app, "is_running", False):
                return False

            injected = False

            def _apply() -> None:
                nonlocal injected, injected_payload
                try:
                    buffer = getattr(session, "default_buffer", None)
                    if buffer is not None:
                        with queued_inputs_lock:
                            injected_payload = payload
                        buffer.document = Document(text=command_text, cursor_position=len(command_text))
                        try:
                            buffer.validate_and_handle()
                            injected = True
                            return
                        except Exception:
                            pass
                    with queued_inputs_lock:
                        injected_payload = payload
                    app.exit(result=command_text)
                    injected = True
                except Exception:
                    with queued_inputs_lock:
                        injected_payload = None
                    injected = False

            try:
                loop = getattr(app, "loop", None)
                if loop is not None and hasattr(loop, "call_soon_threadsafe"):
                    loop.call_soon_threadsafe(_apply)
                    return True
            except Exception:
                pass

            try:
                _apply()
            except Exception:
                injected = False
            return injected

        def _queue_poll_loop() -> None:
            while not repl_queue_stop.is_set():
                try:
                    touch_repl_state(self.ROOT, session_id=repl_session_id)
                except Exception:
                    pass
                _drain_repl_queue()
                with queued_inputs_lock:
                    next_payload = queued_inputs[0] if queued_inputs else None
                if next_payload and _inject_repl_command(next_payload):
                    with queued_inputs_lock:
                        if queued_inputs and queued_inputs[0] is next_payload:
                            queued_inputs.pop(0)
                repl_queue_stop.wait(0.25)

        try:
            touch_repl_state(self.ROOT, session_id=repl_session_id)
        except Exception:
            pass

        _drain_repl_queue()
        repl_queue_thread = threading.Thread(
            target=_queue_poll_loop,
            name="medeia-repl-queue",
            daemon=True,
        )
        repl_queue_thread.start()

        try:
            while True:
                try:
                    with queued_inputs_lock:
                        queued_payload = queued_inputs.pop(0) if queued_inputs else None

                    if queued_payload is not None:
                        source_text = str(queued_payload.get("source") or "external").strip() or "external"
                        user_input = str(queued_payload.get("command") or "").strip()
                        if user_input:
                            print(f"{prompt_text}{user_input}  [queued:{source_text}]")
                        else:
                            user_input = ""
                    else:
                        user_input = session.prompt(prompt_text).strip()
                        if user_input:
                            with queued_inputs_lock:
                                if injected_payload is not None:
                                    queued_payload = injected_payload
                                    injected_payload = None
                except (EOFError, KeyboardInterrupt):
                    print("He who is victorious through deceit is defeated by the truth.")
                    break

                if not user_input:
                    continue

                low = user_input.lower()
                if low in {"exit",
                           "quit",
                           "q"}:
                    print("He who is victorious through deceit is defeated by the truth.")
                    break
                if low in {"help",
                           "?"}:
                    CmdletHelp.show_cmdlet_list()
                    continue

                pipeline_ctx_ref = None
                queued_metadata = (
                    queued_payload.get("metadata")
                    if isinstance(queued_payload, dict) and isinstance(queued_payload.get("metadata"), dict)
                    else None
                )
                progress_event_callback = _build_mpv_progress_callback(queued_metadata) if queued_metadata else None
                try:
                    from SYS import pipeline as ctx

                    ctx.set_current_command_text(user_input)
                    if hasattr(ctx, "set_progress_event_callback"):
                        ctx.set_progress_event_callback(progress_event_callback)
                    pipeline_ctx_ref = ctx
                except Exception:
                    pipeline_ctx_ref = None

                if queued_metadata:
                    try:
                        _send_mpv_callback_event(
                            queued_metadata,
                            {
                                "phase": "started",
                                "event": "command-started",
                                "command_text": user_input,
                            },
                        )
                    except Exception:
                        pass

                execution_result: Dict[str, Any] = {
                    "status": "completed",
                    "success": True,
                    "error": "",
                    "command_text": user_input,
                }

                try:
                    from SYS.cli_syntax import validate_pipeline_text

                    syntax_error = validate_pipeline_text(user_input, config=config)
                    if syntax_error:
                        execution_result = {
                            "status": "failed",
                            "success": False,
                            "error": str(syntax_error.message or "syntax error"),
                            "command_text": user_input,
                        }
                        print(syntax_error.message, file=sys.stderr)
                        if queued_metadata:
                            try:
                                _notify_mpv_completion(queued_metadata, execution_result)
                            except Exception:
                                pass
                        continue
                except Exception:
                    pass

                try:
                    tokens = shlex.split(user_input)
                except ValueError as exc:
                    execution_result = {
                        "status": "failed",
                        "success": False,
                        "error": str(exc),
                        "command_text": user_input,
                    }
                    print(f"Syntax error: {exc}", file=sys.stderr)
                    if queued_metadata:
                        try:
                            _notify_mpv_completion(queued_metadata, execution_result)
                        except Exception:
                            pass
                    continue

                if not tokens:
                    continue

                if len(tokens) == 1 and tokens[0] == "@,,":
                    try:
                        from SYS import pipeline as ctx

                        if ctx.restore_next_result_table():
                            last_table = (
                                ctx.get_display_table()
                                if hasattr(ctx,
                                           "get_display_table") else None
                            )
                            if last_table is None:
                                last_table = ctx.get_last_result_table()
                            if last_table:
                                stdout_console().print()
                                ctx.set_current_stage_table(last_table)
                                stdout_console().print(last_table)
                            else:
                                items = ctx.get_last_result_items()
                                if items:
                                    ctx.set_current_stage_table(None)
                                    print(
                                        f"Restored {len(items)} items (no table format available)"
                                    )
                                else:
                                    print("No forward history available", file=sys.stderr)
                        else:
                            print("No forward history available", file=sys.stderr)
                    except Exception as exc:
                        print(f"Error restoring next table: {exc}", file=sys.stderr)
                    continue

                if len(tokens) == 1 and tokens[0] == "@..":
                    try:
                        from SYS import pipeline as ctx

                        if ctx.restore_previous_result_table():
                            last_table = (
                                ctx.get_display_table()
                                if hasattr(ctx,
                                           "get_display_table") else None
                            )
                            if last_table is None:
                                last_table = ctx.get_last_result_table()

                            # Auto-refresh search-file tables when navigating back,
                            # so row payloads (titles/tags) reflect latest store state.
                            try:
                                src_cmd = (
                                    getattr(last_table,
                                            "source_command",
                                            None) if last_table else None
                                )
                                if (isinstance(src_cmd,
                                               str)
                                        and src_cmd.lower().replace("_",
                                                                    "-") == "search-file"):
                                    src_args = (
                                        getattr(last_table,
                                                "source_args",
                                                None) if last_table else None
                                    )
                                    base_args = list(src_args
                                                     ) if isinstance(src_args,
                                                                     list) else []
                                    cleaned_args = [
                                        str(a) for a in base_args if str(a).strip().lower()
                                        not in {"--refresh", "-refresh"}
                                    ]
                                    if hasattr(ctx, "set_current_command_text"):
                                        try:
                                            title_text = (
                                                getattr(last_table,
                                                        "title",
                                                        None) if last_table else None
                                            )
                                            if isinstance(title_text,
                                                          str) and title_text.strip():
                                                ctx.set_current_command_text(
                                                    title_text.strip()
                                                )
                                            else:
                                                ctx.set_current_command_text(
                                                    " ".join(
                                                        ["search-file",
                                                         *cleaned_args]
                                                    ).strip()
                                                )
                                        except Exception:
                                            pass
                                    try:
                                        self._cmdlet_executor.execute(
                                            "search-file",
                                            cleaned_args + ["--refresh"]
                                        )
                                    finally:
                                        if hasattr(ctx, "clear_current_command_text"):
                                            try:
                                                ctx.clear_current_command_text()
                                            except Exception:
                                                pass
                                    continue
                            except Exception as exc:
                                print(
                                    f"Error refreshing search-file table: {exc}",
                                    file=sys.stderr
                                )

                            if last_table:
                                stdout_console().print()
                                ctx.set_current_stage_table(last_table)
                                stdout_console().print(last_table)
                            else:
                                items = ctx.get_last_result_items()
                                if items:
                                    ctx.set_current_stage_table(None)
                                    print(
                                        f"Restored {len(items)} items (no table format available)"
                                    )
                                else:
                                    print("No previous result table in history")
                        else:
                            print("Result table history is empty")
                    except Exception as exc:
                        print(f"Error restoring previous result table: {exc}")
                    continue

                try:
                    if "|" in tokens or (tokens and tokens[0].startswith("@")):
                        self._pipeline_executor.execute_tokens(tokens)
                    else:
                        cmd_name = tokens[0].replace("_", "-").lower()
                        is_help = any(
                            arg in {"-help",
                                    "--help",
                                    "-h"} for arg in tokens[1:]
                        )
                        if is_help:
                            CmdletHelp.show_cmdlet_help(cmd_name)
                        else:
                            self._cmdlet_executor.execute(cmd_name, tokens[1:])
                finally:
                    if pipeline_ctx_ref and hasattr(pipeline_ctx_ref, "get_last_execution_result"):
                        try:
                            latest = pipeline_ctx_ref.get_last_execution_result()
                            if isinstance(latest, dict) and latest:
                                execution_result = latest
                        except Exception:
                            pass
                    if queued_metadata:
                        try:
                            _notify_mpv_completion(queued_metadata, execution_result)
                        except Exception:
                            pass
                    if pipeline_ctx_ref:
                        pipeline_ctx_ref.clear_current_command_text()
                        if hasattr(pipeline_ctx_ref, "set_progress_event_callback"):
                            try:
                                pipeline_ctx_ref.set_progress_event_callback(None)
                            except Exception:
                                pass
        finally:
            repl_queue_stop.set()
            try:
                repl_queue_thread.join(timeout=1.0)
            except Exception:
                pass
            try:
                clear_repl_state(self.ROOT)
            except Exception:
                pass
