Coverage for src / lilbee / runtime / launcher.py: 100%
35 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-06-28 01:01 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-06-28 01:01 +0000
1"""Thin CLI entry point: shows splash animation while heavy deps load.
3This module imports only ``splash`` (which uses only stdlib + subprocess),
4launches the animation process, then performs the heavy
5``from lilbee.cli import app`` import while the bee animates on stderr.
6"""
8from __future__ import annotations
10import contextlib
11import io
12import os
13import sys
15# Shells fetch tab completions by running the console script with
16# ``_<PROG>_COMPLETE=...`` set (and an empty argv); click answers those itself.
17_COMPLETION_ENV_SUFFIX = "_COMPLETE"
20def _shell_completion_active() -> bool:
21 """True when this process was spawned by a shell's tab-completion."""
22 return any(
23 name.startswith("_") and name.endswith(_COMPLETION_ENV_SUFFIX) for name in os.environ
24 )
27def _force_utf8_stdio() -> None:
28 """Make stdio UTF-8 so a no-locale (GUI-spawned) launch can't crash on non-ASCII output."""
29 for stream in (sys.stdout, sys.stderr):
30 if isinstance(stream, io.TextIOWrapper):
31 # Swallow on an already-detached stream; non-TextIOWrapper streams
32 # (StringIO redirects, capture shims) need no reconfiguration.
33 with contextlib.suppress(ValueError, OSError):
34 stream.reconfigure(encoding="utf-8", errors="backslashreplace")
37def main() -> None:
38 """Entry point for the ``lilbee`` console script."""
39 _force_utf8_stdio()
40 args = sys.argv[1:]
41 is_interactive = (not args or args[0] in ("chat", "")) and not _shell_completion_active()
43 if not is_interactive:
44 from lilbee.cli import app
46 app()
47 return
49 from lilbee.runtime.splash import start, stop
51 handle = start()
53 try:
54 from lilbee.cli import app
55 except BaseException:
56 stop(handle)
57 raise
58 else:
59 # Stop the splash BEFORE the TUI takes over the terminal so the
60 # subprocess's final writes don't land on Textual's alt-screen.
61 stop(handle)
63 try:
64 app()
65 except KeyboardInterrupt:
66 sys.stderr.write("\033[?25h")
67 sys.stderr.flush()
68 raise SystemExit(130) from None