[cli] refactor: migrate to typer 0.26 (vendored click)
Summary
Typer 0.26 vendors Click (breaking change), so exceptions raised by Typer are no longer instances of the external click package's classes — the reason for our previous typer <0.26 cap. Instead of staying frozen on 0.25 forever, this migrates the CLI off direct import click entirely and moves to typer>=0.26,<0.27.
Closes #243 (supersedes the Dependabot range widening; that PR would have broken the CLI's top-level error handling).
Changes
- New
cli/_click_compat.py— single import point for the vendored symbols Typer does not publicly re-export yet (UsageError,ClickException,NoArgsIsHelpError,Context,Command,get_current_context; see fastapi/typer#1868). The<0.27cap keeps these private paths stable; the module is deleted once upstream exports them. Everything else uses public typer API (typer.Exit,typer.Abort). main()error handling — the fragile "empty-message UsageError means help was already printed" hack is replaced with an explicitexcept NoArgsIsHelpError.get_output_context()— the ContextVar set byinstall_output_context()is now the source of truth; the redundant reach into Click's threadlocal context stack is gone.OsmosisGroupis kept unchanged — tests pin its deliberate behaviors (single-candidate suggestion format, hidden-command filtering, theosmosis helpnudge). Typer's nativesuggest_commandsis explicitly disabled so it cannot double-append its own (unfiltered, multi-candidate) suggestions.- Tests — construct vendored objects (
typer.core.TyperCommand; the vendoredCommandis now abstract) and usetyper.testing.CliRunner; the removed ctx.obj resolution layer's test is replaced by two tests asserting the new ContextVar contract.
Behavior
No user-facing behavior changes. Verified via the full suite plus real-process smoke tests: bare osmosis (rich help, exit 0), typo suggestions, osmosis help nudge, --version, and the --json structured error envelope.
CLI code no longer depends on the external click package at all, which also ends click version conflicts with other click-dependent dependencies in user environments.
Verification
pytest: 1721 passedruff check/ruff format --check: cleanpyright osmosis_ai/: 0 errors;--verifytypes: no unexpected public API errors
Note for local editable installs
Dependencies of editable installs do not auto-update: run pip install -e ".[dev]" (or uv sync) after pulling this change to pick up typer 0.26.
Summary by cubic
Migrate the CLI to typer 0.26 (vendored Click) and remove direct click usage to keep error handling correct and avoid version conflicts. Add a hard guard against typer-slim overlays and fail fast with a clear ImportError if a corrupted typer install is detected; no user-facing changes otherwise.
-
Refactors
- Add
osmosis_ai/cli/_click_compat.pyto import vendored types (UsageError,ClickException,NoArgsIsHelpError,Context,Command,get_current_context). - Replace the empty-message
UsageErrorhack withNoArgsIsHelpError; usetyper.Exit/typer.Abort. - Make the ContextVar set by
install_output_context()the source of truth inget_output_context(); remove threadlocal lookups. - Preserve
OsmosisGroupsuggestions and disable Typer’ssuggest_commands; tests updated totyper.coreandtyper.testing. - Assert Typer↔vendored Click lineage at import and raise an actionable ImportError if
typerfiles were overlaid (guides reinstall).
- Add
-
Dependencies
- Pin
typer>=0.26,<0.27and addtyper-slim>=0.22to prevent overlay corruption; CLI no longer importsclick. - For editable installs, run
pip install -e ".[dev]"oruv syncto pick up the new versions.
- Pin