whoami.py
python
| 1 | """``muse whoami`` — show the current identity. |
| 2 | |
| 3 | A top-level convenience shortcut for ``muse auth whoami``. Returns the |
| 4 | identity stored in ``~/.muse/identity.toml`` for the currently configured |
| 5 | hub, or exits non-zero when no identity is stored. |
| 6 | |
| 7 | Usage:: |
| 8 | |
| 9 | muse whoami # human-readable |
| 10 | muse whoami --json # JSON for agent consumers |
| 11 | muse whoami --all # all hubs |
| 12 | |
| 13 | Exit codes:: |
| 14 | |
| 15 | 0 — identity found and printed |
| 16 | 1 — no identity stored (not authenticated) |
| 17 | """ |
| 18 | |
| 19 | from __future__ import annotations |
| 20 | |
| 21 | import logging |
| 22 | from typing import Annotated |
| 23 | |
| 24 | import typer |
| 25 | |
| 26 | from muse.core.errors import ExitCode |
| 27 | from muse.core.identity import IdentityEntry, list_all_identities, load_identity |
| 28 | from muse.core.validation import sanitize_display |
| 29 | from muse.cli.config import get_hub_url |
| 30 | |
| 31 | logger = logging.getLogger(__name__) |
| 32 | |
| 33 | app = typer.Typer(help="Show the current identity (shortcut for muse auth whoami).") |
| 34 | |
| 35 | |
| 36 | def _display(hub: str, entry: IdentityEntry, *, json_output: bool) -> None: |
| 37 | import json as _json |
| 38 | if json_output: |
| 39 | out: dict[str, str | list[str]] = {"hub": hub} |
| 40 | for key in ("type", "name", "id"): |
| 41 | val = entry.get(key, "") |
| 42 | if isinstance(val, str) and val: |
| 43 | out[key] = val |
| 44 | token = entry.get("token", "") |
| 45 | out["token_set"] = "true" if (isinstance(token, str) and token) else "false" |
| 46 | caps: list[str] = entry.get("capabilities") or [] |
| 47 | if caps: |
| 48 | out["capabilities"] = caps |
| 49 | typer.echo(_json.dumps(out, indent=2)) |
| 50 | else: |
| 51 | itype = entry.get("type") or "unknown" |
| 52 | name = entry.get("name") or "—" |
| 53 | uid = entry.get("id") or "—" |
| 54 | token = entry.get("token", "") |
| 55 | token_status = "set" if (isinstance(token, str) and token) else "not set" |
| 56 | typer.echo(f" hub: {sanitize_display(hub)}") |
| 57 | typer.echo(f" type: {sanitize_display(str(itype))}") |
| 58 | typer.echo(f" name: {sanitize_display(str(name))}") |
| 59 | typer.echo(f" id: {sanitize_display(str(uid))}") |
| 60 | typer.echo(f" token: {token_status}") |
| 61 | |
| 62 | |
| 63 | @app.callback(invoke_without_command=True) |
| 64 | def whoami( |
| 65 | json_output: Annotated[ |
| 66 | bool, |
| 67 | typer.Option("--json", "-j", help="Emit JSON instead of human-readable output."), |
| 68 | ] = False, |
| 69 | all_hubs: Annotated[ |
| 70 | bool, |
| 71 | typer.Option("--all", "-a", help="Show identities for all configured hubs."), |
| 72 | ] = False, |
| 73 | fmt: Annotated[ |
| 74 | str, |
| 75 | typer.Option("--format", "-f", help="Output format: text or json (alias for --json)."), |
| 76 | ] = "text", |
| 77 | ) -> None: |
| 78 | """Show the current identity stored in ~/.muse/identity.toml. |
| 79 | |
| 80 | Exits non-zero when no identity is stored so agents can branch on |
| 81 | authentication status:: |
| 82 | |
| 83 | muse whoami --json || muse auth login --agent ... |
| 84 | muse whoami --format json # same as --json |
| 85 | |
| 86 | Examples:: |
| 87 | |
| 88 | muse whoami |
| 89 | muse whoami --json |
| 90 | muse whoami --format json |
| 91 | muse whoami --all |
| 92 | """ |
| 93 | # --format json is an alias for --json for CLI consistency across all commands. |
| 94 | if fmt == "json": |
| 95 | json_output = True |
| 96 | if all_hubs: |
| 97 | identities = list_all_identities() |
| 98 | if not identities: |
| 99 | typer.echo("No identities stored. Run `muse auth login` to authenticate.") |
| 100 | raise typer.Exit(code=ExitCode.USER_ERROR) |
| 101 | for hostname, entry in sorted(identities.items()): |
| 102 | _display(hostname, entry, json_output=json_output) |
| 103 | return |
| 104 | |
| 105 | hub_url = get_hub_url(None) |
| 106 | if hub_url is None: |
| 107 | typer.echo( |
| 108 | "No hub configured. Run `muse hub connect <url>` or `muse auth login --hub <url>`." |
| 109 | ) |
| 110 | raise typer.Exit(code=ExitCode.USER_ERROR) |
| 111 | |
| 112 | loaded = load_identity(hub_url) |
| 113 | if loaded is None: |
| 114 | typer.echo( |
| 115 | f"No identity stored for {hub_url}.\n" |
| 116 | f"Run: muse auth login --hub {hub_url}" |
| 117 | ) |
| 118 | raise typer.Exit(code=ExitCode.USER_ERROR) |
| 119 | |
| 120 | hub_display = hub_url.rstrip("/").split("://")[-1].split("/")[0] |
| 121 | _display(hub_display, loaded, json_output=json_output) |