cli.main

Top-level otto CLI: callback, subcommand dispatch, and eager option handlers.

otto.cli.main.version_callback(version: bool) None

Print the otto version string and exit when --version is passed.

otto.cli.main.clear_autocomplete_cache_callback(value: bool) None

Delete the shell-completion cache file and exit when the flag is set.

otto.cli.main.list_labs_callback(value: bool) None

Print all available lab names (one panel per repo) and exit when the flag is set.

otto.cli.main.log_level_callback(value: str) str

Normalise the --log-level value to upper-case before Typer stores it.

otto.cli.main.main(ctx: ~typer.models.Context, labs: ~types.Annotated[list[str] | None, <typer.models.OptionInfo object at 0x730179a1f100>] | None = None, xdir: ~pathlib.Annotated[~pathlib.Path, <typer.models.OptionInfo object at 0x730179a1e1a0>] = PosixPath('.'), debug: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1df90>] = False, log_days: ~typing.Annotated[int, <typer.models.OptionInfo object at 0x730179a1f6a0>] = 30, log_level: ~typing.Annotated[str, <typer.models.OptionInfo object at 0x730179a1dc60>] = 'INFO', rich_log_file: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1cf10>] = False, show_time: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1e050>] = False, lab_depth: ~typing.Annotated[int, <typer.models.OptionInfo object at 0x730179a1e170>] = 3, list_labs: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1ea10>] = False, show_lab: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1f970>] = False, list_hosts: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1da80>] = False, dry_run: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1fb20>] = False, version: ~types.Annotated[bool | None, <typer.models.OptionInfo object at 0x730179a1fca0>] | None = None, clear_autocomplete_cache: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1edd0>] = False, as_user: ~types.Annotated[str | None, <typer.models.OptionInfo object at 0x730179a1ee30>] | None = None, skip_reservation_check: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x730179a1d1e0>] = False) None

Record root options for lazy lab loading; handle inline root-flag actions.

This is the Typer root callback executed before every otto subcommand. It no longer loads the lab or initialises logging: it stashes the root options on ctx.meta and returns. The real work (lab load, session setup, output dir, reservation gate) runs lazily in the leaf-invoke command_preamble(), so --help / discovery paths are structurally incapable of touching host state. The only exceptions are --show-lab / --list-hosts, which inspect live lab state and so load it inline here before printing and exiting.

otto.cli.main.entry() None

Console-script entry: composition root, then the Typer app.

Completion invocations take the cache fast path (zero user code); everything else runs otto.bootstrap.bootstrap() before argv parsing so registered third-party commands exist when the root group is consulted. Contained user-code failures print one framed warning line each; real command dispatch fails loud in the invoke preamble.