tyta-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,267 @@
1
+ Metadata-Version: 2.4
2
+ Name: tyta-cli
3
+ Version: 0.1.0
4
+ Summary: CLI tool for Toyota Connected Services (EU)
5
+ License: MIT
6
+ Author: Stepan Bolotnikov
7
+ Requires-Python: >=3.10,<4.0
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Dist: httpx (>=0.27)
16
+ Requires-Dist: loguru (>=0.7)
17
+ Requires-Dist: pydantic (>=2.0)
18
+ Requires-Dist: pyjwt (>=2.8)
19
+ Requires-Dist: typer[all] (>=0.9)
20
+ Description-Content-Type: text/markdown
21
+
22
+ # tyta-cli
23
+
24
+ A command-line interface for Toyota Connected Services (EU). Communicate with your Toyota vehicle
25
+ directly from the terminal or from automation scripts.
26
+
27
+ > **Note:** EU region only. Requires a Toyota Connected Services account.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pipx install tyta-cli
33
+ ```
34
+
35
+ Or for development:
36
+
37
+ ```bash
38
+ pipx install --editable .
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```bash
44
+ # Authenticate
45
+ tyta auth login
46
+
47
+ # Check auth status
48
+ tyta auth status
49
+
50
+ # List your vehicles
51
+ tyta vehicles list
52
+
53
+ # Set a default vehicle (so you don't need --vin on every command)
54
+ tyta vehicles use JTDKB3FU803012345
55
+
56
+ # Show vehicle status
57
+ tyta status
58
+ ```
59
+
60
+ ## Global Options
61
+
62
+ These options are accepted by every command:
63
+
64
+ | Option | Env Var | Default | Description |
65
+ |---|---|---|---|
66
+ | `--auth-file PATH` | `TOYOTA_AUTH_FILE` | `~/.config/tyta-cli/auth.json` | Path to auth token file |
67
+ | `--config-file PATH` | `TOYOTA_CONFIG_FILE` | `~/.config/tyta-cli/config.json` | Path to config file |
68
+ | `--debug` | — | off | Enable debug logs to stderr; show tracebacks on error |
69
+
70
+ ## Environment Variables
71
+
72
+ | Variable | Description |
73
+ |---|---|
74
+ | `TOYOTA_USERNAME` | Toyota account email. Used for non-interactive login and headless re-auth. |
75
+ | `TOYOTA_PASSWORD` | Toyota account password. Used for non-interactive login and headless re-auth. |
76
+ | `TOYOTA_AUTH_FILE` | Override path to the auth token file. |
77
+ | `TOYOTA_CONFIG_FILE` | Override path to the config file. |
78
+ | `TOYOTA_VIN` | Default VIN for per-vehicle commands. Overridden by `--vin` flag; overrides config default. |
79
+
80
+ ### Headless / CI environments
81
+
82
+ If `TOYOTA_USERNAME` and `TOYOTA_PASSWORD` are both set, the CLI will re-authenticate
83
+ automatically whenever tokens expire — no manual intervention needed.
84
+
85
+ ```bash
86
+ export TOYOTA_USERNAME="user@example.com"
87
+ export TOYOTA_PASSWORD="secret"
88
+ tyta status # re-auths silently if tokens have expired
89
+ ```
90
+
91
+ ## Commands
92
+
93
+ ### Auth
94
+
95
+ ```bash
96
+ tyta auth login # Authenticate and save tokens
97
+ tyta auth logout # Delete saved tokens
98
+ tyta auth status # Show authentication state and token expiry
99
+ ```
100
+
101
+ `tyta auth login` supports non-interactive mode via `TOYOTA_USERNAME` and `TOYOTA_PASSWORD`
102
+ environment variables.
103
+
104
+ ### Vehicles
105
+
106
+ ```bash
107
+ tyta vehicles list # List all vehicles linked to the account
108
+ tyta vehicles use <VIN> # Set the default VIN (validates against API)
109
+ ```
110
+
111
+ ### Status
112
+
113
+ ```bash
114
+ tyta status [--vin VIN]
115
+ ```
116
+
117
+ Returns dashboard (odometer, fuel level), location, lock status, and vehicle health.
118
+
119
+ ### Electric
120
+
121
+ ```bash
122
+ tyta electric status [--vin VIN]
123
+ tyta electric refresh [--vin VIN] # Real-time refresh (warns about 12V drain)
124
+ tyta electric charge-now [--vin VIN]
125
+
126
+ tyta electric reserve-charge \
127
+ --day MONDAY --start 07:00 [--end 08:00] [--charge-type startOnly|startEnd] \
128
+ [--vin VIN]
129
+
130
+ tyta electric set-charging-time \
131
+ --day MONDAY --start 07:00 [--end 08:00] [--charge-type startOnly|startEnd] \
132
+ [--vin VIN]
133
+ ```
134
+
135
+ `--day` accepts uppercase weekday names: `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`,
136
+ `SATURDAY`, `SUNDAY`.
137
+
138
+ `--start` / `--end` accept 24-hour time as `HH:MM` (e.g. `07:30`).
139
+
140
+ `--charge-type` defaults to `startOnly`; use `startEnd` when `--end` is provided.
141
+
142
+ ### Climate
143
+
144
+ ```bash
145
+ tyta climate status [--vin VIN]
146
+ tyta climate settings [--vin VIN]
147
+ tyta climate set [--temperature FLOAT] [--unit C|F] [--on | --off] [--vin VIN]
148
+ tyta climate on [--vin VIN]
149
+ tyta climate off [--vin VIN]
150
+ ```
151
+
152
+ `tyta climate set` performs a read-modify-write: it fetches current settings, applies your
153
+ changes, and POSTs them back. All flags are optional; omitting `--on`/`--off` leaves the on/off
154
+ state unchanged.
155
+
156
+ ### Trips
157
+
158
+ ```bash
159
+ tyta trips list [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--routes] [--vin VIN]
160
+ tyta trips summary [--period day|week|month|year] [--vin VIN]
161
+ ```
162
+
163
+ `trips list` defaults to the last 30 days. `--routes` includes per-trip route geometry.
164
+
165
+ `trips summary` defaults to the current month. Other periods:
166
+ - `day` — today only
167
+ - `week` — Monday through Sunday of the current week
168
+ - `month` — first to last day of the current month
169
+ - `year` — 1 January to 31 December of the current year
170
+
171
+ ### Remote
172
+
173
+ All remote commands are fire-and-forget. The API acknowledges immediately; vehicle execution is
174
+ asynchronous.
175
+
176
+ ```bash
177
+ tyta remote lock [--vin VIN]
178
+ tyta remote unlock [--vin VIN]
179
+ tyta remote horn [--vin VIN]
180
+ tyta remote find [--vin VIN] # Flash lights + sound horn
181
+ tyta remote headlights on [--vin VIN]
182
+ tyta remote headlights off [--vin VIN]
183
+ tyta remote hazard on [--vin VIN]
184
+ tyta remote hazard off [--vin VIN]
185
+ ```
186
+
187
+ ## VIN Resolution
188
+
189
+ For all per-vehicle commands, the VIN is resolved in this order:
190
+
191
+ 1. `--vin` flag on the command
192
+ 2. `TOYOTA_VIN` environment variable
193
+ 3. `default_vin` from config file (set via `tyta vehicles use <vin>`)
194
+ 4. Auto-select if the account has exactly one vehicle (emits a warning)
195
+
196
+ ## Output Format
197
+
198
+ All output is **JSON** printed to stdout. Scripts and LLMs always receive parseable output.
199
+
200
+ ### Success
201
+
202
+ ```json
203
+ {
204
+ "ok": true,
205
+ "warnings": [],
206
+ "data": { ... }
207
+ }
208
+ ```
209
+
210
+ ### Success with warnings
211
+
212
+ ```json
213
+ {
214
+ "ok": true,
215
+ "warnings": ["No default vehicle set, using only available vehicle: VIN XXXXXXX"],
216
+ "data": { ... }
217
+ }
218
+ ```
219
+
220
+ ### Error
221
+
222
+ ```json
223
+ {
224
+ "ok": false,
225
+ "error": {
226
+ "code": "not_authenticated",
227
+ "message": "Not authenticated. Run `tyta auth login`."
228
+ }
229
+ }
230
+ ```
231
+
232
+ ### Error Codes
233
+
234
+ | Code | Meaning |
235
+ |---|---|
236
+ | `not_authenticated` | No token file found |
237
+ | `token_expired` | Tokens expired and refresh failed |
238
+ | `api_error` | Toyota API returned a non-2xx response |
239
+ | `vehicle_not_found` | Specified VIN not found in account |
240
+ | `no_vehicles` | Account has no linked vehicles |
241
+ | `invalid_config` | Config or token file is malformed |
242
+ | `invalid_input` | User-supplied input is invalid |
243
+ | `unknown_error` | Unexpected exception |
244
+
245
+ ### Exit Codes
246
+
247
+ | Code | Meaning |
248
+ |---|---|
249
+ | `0` | Success |
250
+ | `1` | Operational error (`ok: false`) |
251
+ | `2` | Usage error (bad arguments) |
252
+
253
+ ## Debugging
254
+
255
+ Pass `--debug` to enable verbose logs on stderr and print tracebacks on error:
256
+
257
+ ```bash
258
+ tyta --debug status
259
+ tyta --debug auth login
260
+ ```
261
+
262
+ Logs go to **stderr**; JSON output always goes to **stdout**.
263
+
264
+ ## License
265
+
266
+ MIT
267
+
@@ -0,0 +1,245 @@
1
+ # tyta-cli
2
+
3
+ A command-line interface for Toyota Connected Services (EU). Communicate with your Toyota vehicle
4
+ directly from the terminal or from automation scripts.
5
+
6
+ > **Note:** EU region only. Requires a Toyota Connected Services account.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ pipx install tyta-cli
12
+ ```
13
+
14
+ Or for development:
15
+
16
+ ```bash
17
+ pipx install --editable .
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ # Authenticate
24
+ tyta auth login
25
+
26
+ # Check auth status
27
+ tyta auth status
28
+
29
+ # List your vehicles
30
+ tyta vehicles list
31
+
32
+ # Set a default vehicle (so you don't need --vin on every command)
33
+ tyta vehicles use JTDKB3FU803012345
34
+
35
+ # Show vehicle status
36
+ tyta status
37
+ ```
38
+
39
+ ## Global Options
40
+
41
+ These options are accepted by every command:
42
+
43
+ | Option | Env Var | Default | Description |
44
+ |---|---|---|---|
45
+ | `--auth-file PATH` | `TOYOTA_AUTH_FILE` | `~/.config/tyta-cli/auth.json` | Path to auth token file |
46
+ | `--config-file PATH` | `TOYOTA_CONFIG_FILE` | `~/.config/tyta-cli/config.json` | Path to config file |
47
+ | `--debug` | — | off | Enable debug logs to stderr; show tracebacks on error |
48
+
49
+ ## Environment Variables
50
+
51
+ | Variable | Description |
52
+ |---|---|
53
+ | `TOYOTA_USERNAME` | Toyota account email. Used for non-interactive login and headless re-auth. |
54
+ | `TOYOTA_PASSWORD` | Toyota account password. Used for non-interactive login and headless re-auth. |
55
+ | `TOYOTA_AUTH_FILE` | Override path to the auth token file. |
56
+ | `TOYOTA_CONFIG_FILE` | Override path to the config file. |
57
+ | `TOYOTA_VIN` | Default VIN for per-vehicle commands. Overridden by `--vin` flag; overrides config default. |
58
+
59
+ ### Headless / CI environments
60
+
61
+ If `TOYOTA_USERNAME` and `TOYOTA_PASSWORD` are both set, the CLI will re-authenticate
62
+ automatically whenever tokens expire — no manual intervention needed.
63
+
64
+ ```bash
65
+ export TOYOTA_USERNAME="user@example.com"
66
+ export TOYOTA_PASSWORD="secret"
67
+ tyta status # re-auths silently if tokens have expired
68
+ ```
69
+
70
+ ## Commands
71
+
72
+ ### Auth
73
+
74
+ ```bash
75
+ tyta auth login # Authenticate and save tokens
76
+ tyta auth logout # Delete saved tokens
77
+ tyta auth status # Show authentication state and token expiry
78
+ ```
79
+
80
+ `tyta auth login` supports non-interactive mode via `TOYOTA_USERNAME` and `TOYOTA_PASSWORD`
81
+ environment variables.
82
+
83
+ ### Vehicles
84
+
85
+ ```bash
86
+ tyta vehicles list # List all vehicles linked to the account
87
+ tyta vehicles use <VIN> # Set the default VIN (validates against API)
88
+ ```
89
+
90
+ ### Status
91
+
92
+ ```bash
93
+ tyta status [--vin VIN]
94
+ ```
95
+
96
+ Returns dashboard (odometer, fuel level), location, lock status, and vehicle health.
97
+
98
+ ### Electric
99
+
100
+ ```bash
101
+ tyta electric status [--vin VIN]
102
+ tyta electric refresh [--vin VIN] # Real-time refresh (warns about 12V drain)
103
+ tyta electric charge-now [--vin VIN]
104
+
105
+ tyta electric reserve-charge \
106
+ --day MONDAY --start 07:00 [--end 08:00] [--charge-type startOnly|startEnd] \
107
+ [--vin VIN]
108
+
109
+ tyta electric set-charging-time \
110
+ --day MONDAY --start 07:00 [--end 08:00] [--charge-type startOnly|startEnd] \
111
+ [--vin VIN]
112
+ ```
113
+
114
+ `--day` accepts uppercase weekday names: `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`,
115
+ `SATURDAY`, `SUNDAY`.
116
+
117
+ `--start` / `--end` accept 24-hour time as `HH:MM` (e.g. `07:30`).
118
+
119
+ `--charge-type` defaults to `startOnly`; use `startEnd` when `--end` is provided.
120
+
121
+ ### Climate
122
+
123
+ ```bash
124
+ tyta climate status [--vin VIN]
125
+ tyta climate settings [--vin VIN]
126
+ tyta climate set [--temperature FLOAT] [--unit C|F] [--on | --off] [--vin VIN]
127
+ tyta climate on [--vin VIN]
128
+ tyta climate off [--vin VIN]
129
+ ```
130
+
131
+ `tyta climate set` performs a read-modify-write: it fetches current settings, applies your
132
+ changes, and POSTs them back. All flags are optional; omitting `--on`/`--off` leaves the on/off
133
+ state unchanged.
134
+
135
+ ### Trips
136
+
137
+ ```bash
138
+ tyta trips list [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--routes] [--vin VIN]
139
+ tyta trips summary [--period day|week|month|year] [--vin VIN]
140
+ ```
141
+
142
+ `trips list` defaults to the last 30 days. `--routes` includes per-trip route geometry.
143
+
144
+ `trips summary` defaults to the current month. Other periods:
145
+ - `day` — today only
146
+ - `week` — Monday through Sunday of the current week
147
+ - `month` — first to last day of the current month
148
+ - `year` — 1 January to 31 December of the current year
149
+
150
+ ### Remote
151
+
152
+ All remote commands are fire-and-forget. The API acknowledges immediately; vehicle execution is
153
+ asynchronous.
154
+
155
+ ```bash
156
+ tyta remote lock [--vin VIN]
157
+ tyta remote unlock [--vin VIN]
158
+ tyta remote horn [--vin VIN]
159
+ tyta remote find [--vin VIN] # Flash lights + sound horn
160
+ tyta remote headlights on [--vin VIN]
161
+ tyta remote headlights off [--vin VIN]
162
+ tyta remote hazard on [--vin VIN]
163
+ tyta remote hazard off [--vin VIN]
164
+ ```
165
+
166
+ ## VIN Resolution
167
+
168
+ For all per-vehicle commands, the VIN is resolved in this order:
169
+
170
+ 1. `--vin` flag on the command
171
+ 2. `TOYOTA_VIN` environment variable
172
+ 3. `default_vin` from config file (set via `tyta vehicles use <vin>`)
173
+ 4. Auto-select if the account has exactly one vehicle (emits a warning)
174
+
175
+ ## Output Format
176
+
177
+ All output is **JSON** printed to stdout. Scripts and LLMs always receive parseable output.
178
+
179
+ ### Success
180
+
181
+ ```json
182
+ {
183
+ "ok": true,
184
+ "warnings": [],
185
+ "data": { ... }
186
+ }
187
+ ```
188
+
189
+ ### Success with warnings
190
+
191
+ ```json
192
+ {
193
+ "ok": true,
194
+ "warnings": ["No default vehicle set, using only available vehicle: VIN XXXXXXX"],
195
+ "data": { ... }
196
+ }
197
+ ```
198
+
199
+ ### Error
200
+
201
+ ```json
202
+ {
203
+ "ok": false,
204
+ "error": {
205
+ "code": "not_authenticated",
206
+ "message": "Not authenticated. Run `tyta auth login`."
207
+ }
208
+ }
209
+ ```
210
+
211
+ ### Error Codes
212
+
213
+ | Code | Meaning |
214
+ |---|---|
215
+ | `not_authenticated` | No token file found |
216
+ | `token_expired` | Tokens expired and refresh failed |
217
+ | `api_error` | Toyota API returned a non-2xx response |
218
+ | `vehicle_not_found` | Specified VIN not found in account |
219
+ | `no_vehicles` | Account has no linked vehicles |
220
+ | `invalid_config` | Config or token file is malformed |
221
+ | `invalid_input` | User-supplied input is invalid |
222
+ | `unknown_error` | Unexpected exception |
223
+
224
+ ### Exit Codes
225
+
226
+ | Code | Meaning |
227
+ |---|---|
228
+ | `0` | Success |
229
+ | `1` | Operational error (`ok: false`) |
230
+ | `2` | Usage error (bad arguments) |
231
+
232
+ ## Debugging
233
+
234
+ Pass `--debug` to enable verbose logs on stderr and print tracebacks on error:
235
+
236
+ ```bash
237
+ tyta --debug status
238
+ tyta --debug auth login
239
+ ```
240
+
241
+ Logs go to **stderr**; JSON output always goes to **stdout**.
242
+
243
+ ## License
244
+
245
+ MIT
@@ -0,0 +1,43 @@
1
+ [project]
2
+ name = "tyta-cli"
3
+ version = "0.1.0"
4
+ description = "CLI tool for Toyota Connected Services (EU)"
5
+ authors = [{ name = "Stepan Bolotnikov" }]
6
+ license = { text = "MIT" }
7
+ readme = "README.md"
8
+ requires-python = ">=3.10,<4.0"
9
+ dependencies = [
10
+ "typer[all]>=0.9",
11
+ "httpx>=0.27",
12
+ "pyjwt>=2.8",
13
+ "pydantic>=2.0",
14
+ "loguru>=0.7",
15
+ ]
16
+
17
+ [project.scripts]
18
+ tyta = "tyta.cli.main:app"
19
+
20
+ [tool.poetry]
21
+ packages = [{ include = "tyta" }]
22
+
23
+ [tool.poetry.group.dev.dependencies]
24
+ pytest = ">=8.0"
25
+ pytest-asyncio = ">=0.23"
26
+ pytest-cov = ">=5.0"
27
+ respx = ">=0.21"
28
+ ruff = ">=0.9"
29
+
30
+ [tool.pytest.ini_options]
31
+ asyncio_mode = "auto"
32
+
33
+ [tool.ruff]
34
+ line-length = 100
35
+ target-version = "py310"
36
+
37
+ [tool.ruff.lint]
38
+ select = ["E", "F", "I", "UP", "B", "SIM"]
39
+ ignore = ["E501"]
40
+
41
+ [build-system]
42
+ requires = ["poetry-core"]
43
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,3 @@
1
+ """tyta-cli — Toyota Connected Services CLI."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1 @@
1
+ """CLI layer for tyta-cli."""
@@ -0,0 +1,140 @@
1
+ """tyta auth subcommands: login, logout, status."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import getpass
7
+ import json
8
+ import os
9
+ import sys
10
+
11
+ import typer
12
+ from loguru import logger
13
+
14
+ from tyta.core import auth as core_auth
15
+ from tyta.core import envelope as env
16
+
17
+ app = typer.Typer(
18
+ name="auth",
19
+ help="Manage Toyota account authentication.",
20
+ no_args_is_help=True,
21
+ )
22
+
23
+
24
+ def _get_debug() -> bool:
25
+ from tyta.cli.main import _get_state
26
+
27
+ return _get_state().get("debug", False)
28
+
29
+
30
+ def _get_auth_path_override() -> str | None:
31
+ from tyta.cli.main import _get_state
32
+
33
+ return _get_state().get("auth_file")
34
+
35
+
36
+ def _emit_and_exit(data: dict, exit_code: int = 0) -> None:
37
+ """Print JSON envelope and raise SystemExit directly."""
38
+ print(json.dumps(data, indent=2))
39
+ sys.exit(exit_code)
40
+
41
+
42
+ @app.command("login")
43
+ def login() -> None:
44
+ """Authenticate with Toyota and save credentials."""
45
+ debug = _get_debug()
46
+ auth_path = core_auth.get_auth_path(_get_auth_path_override())
47
+
48
+ # Collect credentials — use env vars if available
49
+ username = os.environ.get("TOYOTA_USERNAME")
50
+ password = os.environ.get("TOYOTA_PASSWORD")
51
+
52
+ if not username:
53
+ username = typer.prompt("Toyota username (email)")
54
+ if not password:
55
+ password = getpass.getpass("Toyota password: ")
56
+
57
+ try:
58
+ token_data = asyncio.run(core_auth.login(username, password, auth_path))
59
+ except core_auth.InvalidUsernameError as exc:
60
+ if debug:
61
+ import traceback
62
+
63
+ traceback.print_exc(file=sys.stderr)
64
+ _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
65
+ return
66
+ except core_auth.AuthError as exc:
67
+ if debug:
68
+ import traceback
69
+
70
+ traceback.print_exc(file=sys.stderr)
71
+ _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
72
+ return
73
+ except json.JSONDecodeError:
74
+ if debug:
75
+ import traceback
76
+
77
+ traceback.print_exc(file=sys.stderr)
78
+ _emit_and_exit(
79
+ env.error("invalid_config", "Received malformed JSON from Toyota API."), exit_code=1
80
+ )
81
+ return
82
+ except Exception as exc:
83
+ if debug:
84
+ import traceback
85
+
86
+ traceback.print_exc(file=sys.stderr)
87
+ logger.debug(f"Unexpected error during login: {exc}")
88
+ _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
89
+ return
90
+
91
+ _emit_and_exit(
92
+ env.ok(
93
+ {
94
+ "message": "Logged in successfully.",
95
+ "username": token_data["username"],
96
+ "expires_at": token_data["expires_at"],
97
+ }
98
+ )
99
+ )
100
+
101
+
102
+ @app.command("logout")
103
+ def logout() -> None:
104
+ """Delete saved credentials."""
105
+ debug = _get_debug()
106
+ auth_path = core_auth.get_auth_path(_get_auth_path_override())
107
+
108
+ try:
109
+ deleted = core_auth.logout(auth_path)
110
+ except Exception as exc:
111
+ if debug:
112
+ import traceback
113
+
114
+ traceback.print_exc(file=sys.stderr)
115
+ _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
116
+ return
117
+
118
+ if deleted:
119
+ _emit_and_exit(env.ok({"message": "Logged out successfully."}))
120
+ else:
121
+ _emit_and_exit(env.ok({"message": "Already logged out (no token file found)."}))
122
+
123
+
124
+ @app.command("status")
125
+ def auth_status() -> None:
126
+ """Show current authentication status."""
127
+ debug = _get_debug()
128
+ auth_path = core_auth.get_auth_path(_get_auth_path_override())
129
+
130
+ try:
131
+ result = core_auth.status(auth_path)
132
+ except Exception as exc:
133
+ if debug:
134
+ import traceback
135
+
136
+ traceback.print_exc(file=sys.stderr)
137
+ _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
138
+ return
139
+
140
+ _emit_and_exit(env.ok(result))