Check system health and report issues.
(
verbose: bool = _typer.Option(
False,
"-v",
"--verbose",
help="Show full exception tracebacks for failed checks.",
),
)
| 869 | @app.command() |
| 870 | @_catch_daemon_start_error |
| 871 | def doctor( |
| 872 | verbose: bool = _typer.Option( |
| 873 | False, |
| 874 | "-v", |
| 875 | "--verbose", |
| 876 | help="Show full exception tracebacks for failed checks.", |
| 877 | ), |
| 878 | ) -> None: |
| 879 | """Check system health and report issues.""" |
| 880 | from . import client as _client |
| 881 | from .settings import ( |
| 882 | load_project_settings as _load_project_settings, |
| 883 | ) |
| 884 | from .settings import ( |
| 885 | load_user_settings as _load_user_settings, |
| 886 | ) |
| 887 | |
| 888 | def _on_result(result: DoctorCheckResult) -> None: |
| 889 | _print_doctor_result(result, verbose=verbose) |
| 890 | |
| 891 | # --- 1. Global settings (local, no daemon needed) --- |
| 892 | _print_section("Global Settings") |
| 893 | settings_path = user_settings_path() |
| 894 | _typer.echo(f" Settings: {format_path_for_display(settings_path)}") |
| 895 | try: |
| 896 | user_settings = _load_user_settings() |
| 897 | emb = user_settings.embedding |
| 898 | device_str = f", device={emb.device}" if emb.device else "" |
| 899 | _typer.echo(f" Embedding: provider={emb.provider}, model={emb.model}{device_str}") |
| 900 | if user_settings.envs: |
| 901 | _typer.echo( |
| 902 | f" Env vars (from settings): {', '.join(sorted(user_settings.envs.keys()))}" |
| 903 | ) |
| 904 | except (FileNotFoundError, ValueError) as e: |
| 905 | _print_error(str(e)) |
| 906 | |
| 907 | # --- 2. Connect to daemon (handshake with auto-start/restart) --- |
| 908 | _print_section("Daemon") |
| 909 | daemon_ok = False |
| 910 | try: |
| 911 | status = _client.daemon_status() |
| 912 | _typer.echo(f" Version: {status.version}") |
| 913 | _typer.echo(f" Uptime: {status.uptime_seconds:.1f}s") |
| 914 | _typer.echo(f" Loaded projects: {len(status.projects)}") |
| 915 | daemon_ok = True |
| 916 | except Exception as e: |
| 917 | _print_error(f"Cannot connect to daemon: {e}") |
| 918 | _typer.echo(" Remaining daemon-side checks will be skipped.") |
| 919 | |
| 920 | # --- 3. Daemon environment (requires daemon) --- |
| 921 | if daemon_ok: |
| 922 | try: |
| 923 | env_resp = _client.daemon_env() |
| 924 | settings_keys = set(env_resp.settings_env_names) |
| 925 | other_keys = [k for k in env_resp.env_names if k not in settings_keys] |
| 926 | if other_keys: |
| 927 | _typer.echo(f" Other env vars in daemon: {', '.join(sorted(other_keys))}") |
| 928 | if env_resp.db_path_mappings: |
nothing calls this directly
no test coverage detected