Terminal UI components for the oc_ui package.
Purpose
-------
Re-exports the concrete presenter classes and prompt driver that make
up OC Chat's terminal frontend. Importing ``oc_ui.terminal`` is the
canonical way for the engine to obtain a presenter without naming the
specific implementation.
Responsibilities
----------------
- Re-export :class:`ConsolePresenter`, :class:`RichPresenter`,
:class:`LoggingPresenter`, :class:`PromptDriver`, and
:class:`CommandCompleter` (alias for :class:`OCChatCompleter`).
- Define ``__all__`` so ``from oc_ui.terminal import *`` works as
documented, and ``__dir__`` so the lazy names stay discoverable.
- Keep the names backed by an OPTIONAL distribution out of the import
path until something actually asks for them.
Eager / lazy split (plan 233)
-----------------------------
Python executes a package ``__init__`` before any of its submodules,
so an eager re-export here decides whether the whole package is
importable. The split is therefore per-submodule, decided by what that
submodule imports at MODULE level:
===================== ========= ====================================
Submodule Binding Why
===================== ========= ====================================
``presenter`` eager stdlib + oc_diagnostics + oc_ui only
``input`` eager stdlib + oc_diagnostics + oc_ui only;
``prompt_toolkit`` is imported inside
``PromptDriver.__init__``, behind its
own ``except ImportError`` guard
``logging_presenter`` eager stdlib + oc_diagnostics + oc_ui only
``rich_presenter`` lazy imports ``rich`` at module level
``completers`` lazy imports ``prompt_toolkit`` at module
level
===================== ========= ====================================
Keeping ``presenter`` eager is the point of the exercise:
:class:`ConsolePresenter` is the deliberately rich-free fallback, and
``oc_chat.cli`` imports it at module level. It must stay importable
with zero optional dependencies installed.
Diagnostics
-----------
Domain: OC_UI.TERMINAL
Levels:
L2 — lifecycle events
L3 — semantic details
L4 — deep tracing
Contracts
---------
- This module has no logic of its own beyond name resolution — the
eager re-imports, plus the PEP 562 ``__getattr__``/``__dir__`` pair
that resolves the lazy ones.
- Importing it must not start any threads, open any files, or import
any optional distribution.
- A lazy name resolves to the SAME object as an import from its
defining module, and is cached in the module globals on first
access, so ``oc_ui.terminal.RichPresenter is
oc_ui.terminal.rich_presenter.RichPresenter`` holds and the import
runs once.
- When the backing distribution is absent, resolving a lazy name
raises :exc:`ImportError` AT THE ACCESS SITE — deliberately, so the
callers that already catch it (``oc_chat/cli.py``) can fall back to
the plain presenter instead of the process dying at import.
Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)
- oc_ui.terminal.presenter (ConsolePresenter, re-exported eagerly)
- oc_ui.terminal.input (PromptDriver, re-exported eagerly)
- oc_ui.terminal.logging_presenter (LoggingPresenter, re-exported eagerly)
- oc_ui.terminal.completers (lazy; OCChatCompleter, re-exported as CommandCompleter on first access)
- oc_ui.terminal.rich_presenter (lazy; RichPresenter, re-exported on first access)