checkdk-cli 0.2.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,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: checkdk-cli
3
+ Version: 0.2.0
4
+ Summary: checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor
5
+ Author-email: checkDK Team <team@checkdk.app>
6
+ License: MIT
7
+ Project-URL: Homepage, https://checkdk.app
8
+ Project-URL: Documentation, https://checkdk.app/docs
9
+ Project-URL: Repository, https://github.com/your-org/checkDK_AWS
10
+ Project-URL: Bug Tracker, https://github.com/your-org/checkDK_AWS/issues
11
+ Project-URL: Changelog, https://github.com/your-org/checkDK_AWS/releases
12
+ Keywords: docker,kubernetes,devops,cli,ai,chaos-engineering,monitoring
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: System Administrators
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Software Development :: Build Tools
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ Requires-Dist: click>=8.1.0
29
+ Requires-Dist: rich>=13.0.0
30
+ Requires-Dist: requests>=2.31.0
31
+ Requires-Dist: pyyaml>=6.0
32
+ Requires-Dist: python-dotenv>=1.0.0
33
+ Requires-Dist: websocket-client>=1.6.0
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
36
+ Requires-Dist: black>=23.0.0; extra == "dev"
37
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
38
+
39
+ # checkDK CLI
40
+
41
+ Thin CLI tool that wraps `docker` and `kubectl` commands with pre-execution
42
+ analysis, and provides a `predict` command for pod failure detection.
43
+
44
+ All analysis is delegated to the **checkDK backend API** running in Docker.
45
+ The CLI itself has no ML or LLM dependencies — it is just an HTTP client with
46
+ a rich terminal UI.
47
+
48
+ ---
49
+
50
+ ## Quick start
51
+
52
+ ```bash
53
+ # 1. Clone and enter the cli folder
54
+ cd cli
55
+
56
+ # 2. Run the setup script (creates .venv + installs the package)
57
+ bash setup.sh
58
+
59
+ # 3. Activate the virtual environment
60
+ source .venv/bin/activate
61
+
62
+ # 4. Point at the backend (start it first with docker compose)
63
+ export CHECKDK_API_URL=http://localhost:8000
64
+ # — or save it permanently:
65
+ checkdk init
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Start the backend first
71
+
72
+ ```bash
73
+ # From the repo root
74
+ cp .env.example .env # add GROQ_API_KEY / GEMINI_API_KEY
75
+ docker compose up --build # starts backend on :8000, frontend on :3000
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Commands
81
+
82
+ | Command | Description |
83
+ |---|---|
84
+ | `checkdk init` | Save API URL + keys to `~/.checkdk/.env` |
85
+ | `checkdk docker compose up -d` | Analyse `docker-compose.yml`, then run the command |
86
+ | `checkdk docker compose up --dry-run` | Analyse only, do not execute |
87
+ | `checkdk kubectl apply -f deploy.yaml` | Analyse Kubernetes manifest, then apply |
88
+ | `checkdk predict --cpu 93 --memory 91` | Predict pod failure risk |
89
+ | `checkdk predict --cpu 93 --memory 91 --no-ai` | ML prediction only, skip LLM |
90
+
91
+ ### Predict options
92
+
93
+ ```
94
+ --cpu CPU usage % (required)
95
+ --memory Memory usage % (required)
96
+ --disk Disk usage % (default 50)
97
+ --latency Network latency ms (default 10)
98
+ --restarts Restart count (default 0)
99
+ --probe-failures Probe failure count (default 0)
100
+ --cpu-pressure Node CPU pressure 0/1 (default 0)
101
+ --mem-pressure Node memory pressure 0/1 (default 0)
102
+ --age Pod age in minutes (default 60)
103
+ --service Service/pod name (optional label)
104
+ --platform docker | kubernetes (default docker)
105
+ --no-ai Skip LLM analysis
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Environment variables
111
+
112
+ | Variable | Default | Description |
113
+ |---|---|---|
114
+ | `CHECKDK_API_URL` | `http://localhost:8000` | Backend API base URL |
115
+
116
+ The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
117
+
118
+ ---
119
+
120
+ ## Development
121
+
122
+ ```bash
123
+ # Install with dev extras
124
+ pip install -e ".[dev]"
125
+
126
+ # Run tests
127
+ pytest
128
+
129
+ # Lint
130
+ ruff check .
131
+ ```
@@ -0,0 +1,93 @@
1
+ # checkDK CLI
2
+
3
+ Thin CLI tool that wraps `docker` and `kubectl` commands with pre-execution
4
+ analysis, and provides a `predict` command for pod failure detection.
5
+
6
+ All analysis is delegated to the **checkDK backend API** running in Docker.
7
+ The CLI itself has no ML or LLM dependencies — it is just an HTTP client with
8
+ a rich terminal UI.
9
+
10
+ ---
11
+
12
+ ## Quick start
13
+
14
+ ```bash
15
+ # 1. Clone and enter the cli folder
16
+ cd cli
17
+
18
+ # 2. Run the setup script (creates .venv + installs the package)
19
+ bash setup.sh
20
+
21
+ # 3. Activate the virtual environment
22
+ source .venv/bin/activate
23
+
24
+ # 4. Point at the backend (start it first with docker compose)
25
+ export CHECKDK_API_URL=http://localhost:8000
26
+ # — or save it permanently:
27
+ checkdk init
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Start the backend first
33
+
34
+ ```bash
35
+ # From the repo root
36
+ cp .env.example .env # add GROQ_API_KEY / GEMINI_API_KEY
37
+ docker compose up --build # starts backend on :8000, frontend on :3000
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Commands
43
+
44
+ | Command | Description |
45
+ |---|---|
46
+ | `checkdk init` | Save API URL + keys to `~/.checkdk/.env` |
47
+ | `checkdk docker compose up -d` | Analyse `docker-compose.yml`, then run the command |
48
+ | `checkdk docker compose up --dry-run` | Analyse only, do not execute |
49
+ | `checkdk kubectl apply -f deploy.yaml` | Analyse Kubernetes manifest, then apply |
50
+ | `checkdk predict --cpu 93 --memory 91` | Predict pod failure risk |
51
+ | `checkdk predict --cpu 93 --memory 91 --no-ai` | ML prediction only, skip LLM |
52
+
53
+ ### Predict options
54
+
55
+ ```
56
+ --cpu CPU usage % (required)
57
+ --memory Memory usage % (required)
58
+ --disk Disk usage % (default 50)
59
+ --latency Network latency ms (default 10)
60
+ --restarts Restart count (default 0)
61
+ --probe-failures Probe failure count (default 0)
62
+ --cpu-pressure Node CPU pressure 0/1 (default 0)
63
+ --mem-pressure Node memory pressure 0/1 (default 0)
64
+ --age Pod age in minutes (default 60)
65
+ --service Service/pod name (optional label)
66
+ --platform docker | kubernetes (default docker)
67
+ --no-ai Skip LLM analysis
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Environment variables
73
+
74
+ | Variable | Default | Description |
75
+ |---|---|---|
76
+ | `CHECKDK_API_URL` | `http://localhost:8000` | Backend API base URL |
77
+
78
+ The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
79
+
80
+ ---
81
+
82
+ ## Development
83
+
84
+ ```bash
85
+ # Install with dev extras
86
+ pip install -e ".[dev]"
87
+
88
+ # Run tests
89
+ pytest
90
+
91
+ # Lint
92
+ ruff check .
93
+ ```
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: checkdk-cli
3
+ Version: 0.2.0
4
+ Summary: checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor
5
+ Author-email: checkDK Team <team@checkdk.app>
6
+ License: MIT
7
+ Project-URL: Homepage, https://checkdk.app
8
+ Project-URL: Documentation, https://checkdk.app/docs
9
+ Project-URL: Repository, https://github.com/your-org/checkDK_AWS
10
+ Project-URL: Bug Tracker, https://github.com/your-org/checkDK_AWS/issues
11
+ Project-URL: Changelog, https://github.com/your-org/checkDK_AWS/releases
12
+ Keywords: docker,kubernetes,devops,cli,ai,chaos-engineering,monitoring
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: System Administrators
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Software Development :: Build Tools
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ Requires-Dist: click>=8.1.0
29
+ Requires-Dist: rich>=13.0.0
30
+ Requires-Dist: requests>=2.31.0
31
+ Requires-Dist: pyyaml>=6.0
32
+ Requires-Dist: python-dotenv>=1.0.0
33
+ Requires-Dist: websocket-client>=1.6.0
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
36
+ Requires-Dist: black>=23.0.0; extra == "dev"
37
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
38
+
39
+ # checkDK CLI
40
+
41
+ Thin CLI tool that wraps `docker` and `kubectl` commands with pre-execution
42
+ analysis, and provides a `predict` command for pod failure detection.
43
+
44
+ All analysis is delegated to the **checkDK backend API** running in Docker.
45
+ The CLI itself has no ML or LLM dependencies — it is just an HTTP client with
46
+ a rich terminal UI.
47
+
48
+ ---
49
+
50
+ ## Quick start
51
+
52
+ ```bash
53
+ # 1. Clone and enter the cli folder
54
+ cd cli
55
+
56
+ # 2. Run the setup script (creates .venv + installs the package)
57
+ bash setup.sh
58
+
59
+ # 3. Activate the virtual environment
60
+ source .venv/bin/activate
61
+
62
+ # 4. Point at the backend (start it first with docker compose)
63
+ export CHECKDK_API_URL=http://localhost:8000
64
+ # — or save it permanently:
65
+ checkdk init
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Start the backend first
71
+
72
+ ```bash
73
+ # From the repo root
74
+ cp .env.example .env # add GROQ_API_KEY / GEMINI_API_KEY
75
+ docker compose up --build # starts backend on :8000, frontend on :3000
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Commands
81
+
82
+ | Command | Description |
83
+ |---|---|
84
+ | `checkdk init` | Save API URL + keys to `~/.checkdk/.env` |
85
+ | `checkdk docker compose up -d` | Analyse `docker-compose.yml`, then run the command |
86
+ | `checkdk docker compose up --dry-run` | Analyse only, do not execute |
87
+ | `checkdk kubectl apply -f deploy.yaml` | Analyse Kubernetes manifest, then apply |
88
+ | `checkdk predict --cpu 93 --memory 91` | Predict pod failure risk |
89
+ | `checkdk predict --cpu 93 --memory 91 --no-ai` | ML prediction only, skip LLM |
90
+
91
+ ### Predict options
92
+
93
+ ```
94
+ --cpu CPU usage % (required)
95
+ --memory Memory usage % (required)
96
+ --disk Disk usage % (default 50)
97
+ --latency Network latency ms (default 10)
98
+ --restarts Restart count (default 0)
99
+ --probe-failures Probe failure count (default 0)
100
+ --cpu-pressure Node CPU pressure 0/1 (default 0)
101
+ --mem-pressure Node memory pressure 0/1 (default 0)
102
+ --age Pod age in minutes (default 60)
103
+ --service Service/pod name (optional label)
104
+ --platform docker | kubernetes (default docker)
105
+ --no-ai Skip LLM analysis
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Environment variables
111
+
112
+ | Variable | Default | Description |
113
+ |---|---|---|
114
+ | `CHECKDK_API_URL` | `http://localhost:8000` | Backend API base URL |
115
+
116
+ The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
117
+
118
+ ---
119
+
120
+ ## Development
121
+
122
+ ```bash
123
+ # Install with dev extras
124
+ pip install -e ".[dev]"
125
+
126
+ # Run tests
127
+ pytest
128
+
129
+ # Lint
130
+ ruff check .
131
+ ```
@@ -0,0 +1,21 @@
1
+ README.md
2
+ pyproject.toml
3
+ checkdk_cli.egg-info/PKG-INFO
4
+ checkdk_cli.egg-info/SOURCES.txt
5
+ checkdk_cli.egg-info/dependency_links.txt
6
+ checkdk_cli.egg-info/entry_points.txt
7
+ checkdk_cli.egg-info/requires.txt
8
+ checkdk_cli.egg-info/top_level.txt
9
+ checkdkcli/__init__.py
10
+ checkdkcli/client.py
11
+ checkdkcli/display.py
12
+ checkdkcli/main.py
13
+ checkdkcli/commands/__init__.py
14
+ checkdkcli/commands/auth.py
15
+ checkdkcli/commands/chaos.py
16
+ checkdkcli/commands/docker.py
17
+ checkdkcli/commands/init.py
18
+ checkdkcli/commands/kubectl.py
19
+ checkdkcli/commands/monitor.py
20
+ checkdkcli/commands/playground.py
21
+ checkdkcli/commands/predict.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ checkdk = checkdkcli.main:main
@@ -0,0 +1,11 @@
1
+ click>=8.1.0
2
+ rich>=13.0.0
3
+ requests>=2.31.0
4
+ pyyaml>=6.0
5
+ python-dotenv>=1.0.0
6
+ websocket-client>=1.6.0
7
+
8
+ [dev]
9
+ pytest>=7.4.0
10
+ black>=23.0.0
11
+ ruff>=0.1.0
@@ -0,0 +1 @@
1
+ checkdkcli
@@ -0,0 +1,3 @@
1
+ """checkDK CLI package."""
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,160 @@
1
+ """HTTP client for the checkDK backend API.
2
+
3
+ All communication between the CLI and the backend happens here.
4
+ The base URL is read from $CHECKDK_API_URL (required).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from pathlib import Path
11
+ from typing import Optional
12
+
13
+ import requests
14
+
15
+ _DEFAULT_TIMEOUT = 60 # seconds
16
+
17
+
18
+ def get_api_url() -> str:
19
+ """Return the backend API base URL.
20
+
21
+ Priority:
22
+ 1. $CHECKDK_API_URL environment variable
23
+ 2. ~/.checkdk/.env (loaded by python-dotenv at startup)
24
+ 3. Fallback to http://localhost:8000 so local dev works without config
25
+ """
26
+ url = os.getenv("CHECKDK_API_URL", "http://localhost:8000").strip().rstrip("/")
27
+ return url
28
+
29
+
30
+ def get_stored_token() -> Optional[str]:
31
+ """Read a stored JWT from ~/.checkdk/.env, if present."""
32
+ token = os.getenv("CHECKDK_TOKEN")
33
+ if token:
34
+ return token.strip()
35
+ env_file = Path.home() / ".checkdk" / ".env"
36
+ if env_file.exists():
37
+ for line in env_file.read_text().splitlines():
38
+ if line.startswith("CHECKDK_TOKEN="):
39
+ return line.split("=", 1)[1].strip().strip('"').strip("'")
40
+ return None
41
+
42
+
43
+ def _auth_headers() -> dict:
44
+ """Return Authorization header dict if a token is stored, else empty dict."""
45
+ token = get_stored_token()
46
+ return {"Authorization": f"Bearer {token}"} if token else {}
47
+
48
+
49
+ def _post(path: str, payload: dict, timeout: int = _DEFAULT_TIMEOUT) -> dict:
50
+ """POST to the API and return the parsed JSON body.
51
+
52
+ Raises requests.HTTPError on non-2xx responses.
53
+ """
54
+ url = f"{get_api_url()}{path}"
55
+ resp = requests.post(url, json=payload, headers=_auth_headers(), timeout=timeout)
56
+ resp.raise_for_status()
57
+ return resp.json()
58
+
59
+
60
+ def _get(path: str, timeout: int = _DEFAULT_TIMEOUT) -> dict:
61
+ """GET from the API and return the parsed JSON body."""
62
+ url = f"{get_api_url()}{path}"
63
+ resp = requests.get(url, headers=_auth_headers(), timeout=timeout)
64
+ resp.raise_for_status()
65
+ return resp.json()
66
+
67
+
68
+ def health_check() -> bool:
69
+ """Return True if the backend is reachable and healthy."""
70
+ try:
71
+ resp = requests.get(f"{get_api_url()}/health", timeout=5)
72
+ return resp.status_code == 200
73
+ except Exception:
74
+ return False
75
+
76
+
77
+ # ── Analysis helpers ──────────────────────────────────────────────────────────
78
+
79
+ def analyze_docker_compose(content: str, filename: Optional[str] = None,
80
+ timeout: int = _DEFAULT_TIMEOUT) -> dict:
81
+ """POST docker-compose YAML content and return the analysis result dict."""
82
+ payload: dict = {"content": content}
83
+ if filename:
84
+ payload["filename"] = filename
85
+ return _post("/analyze/docker-compose", payload, timeout=timeout)
86
+
87
+
88
+ def analyze_kubernetes(content: str, filename: Optional[str] = None,
89
+ timeout: int = _DEFAULT_TIMEOUT) -> dict:
90
+ """POST Kubernetes manifest YAML content and return the analysis result dict."""
91
+ payload: dict = {"content": content}
92
+ if filename:
93
+ payload["filename"] = filename
94
+ return _post("/analyze/kubernetes", payload, timeout=timeout)
95
+
96
+
97
+ def analyze_playground(content: str, filename: Optional[str] = None,
98
+ timeout: int = _DEFAULT_TIMEOUT) -> dict:
99
+ """POST any config to the hybrid AI+rules playground endpoint."""
100
+ payload: dict = {"content": content}
101
+ if filename:
102
+ payload["filename"] = filename
103
+ return _post("/analyze/playground", payload, timeout=timeout)
104
+
105
+
106
+ # ── Auth helpers ──────────────────────────────────────────────────────────────
107
+
108
+ def validate_token(token: str) -> dict:
109
+ """POST a JWT to /auth/cli-token to validate it; returns user info dict."""
110
+ url = f"{get_api_url()}/auth/cli-token"
111
+ resp = requests.post(
112
+ url, json={"token": token},
113
+ headers={"Authorization": f"Bearer {token}"},
114
+ timeout=10,
115
+ )
116
+ resp.raise_for_status()
117
+ return resp.json()
118
+
119
+
120
+ def get_current_user() -> dict:
121
+ """GET /auth/me — returns current user info (requires stored token)."""
122
+ return _get("/auth/me", timeout=10)
123
+
124
+
125
+ # ── Pod health prediction ─────────────────────────────────────────────────────
126
+
127
+ def predict_pod_health(
128
+ cpu: float,
129
+ memory: float,
130
+ disk: float = 50.0,
131
+ latency: float = 10.0,
132
+ restarts: int = 0,
133
+ probe_failures: int = 0,
134
+ cpu_pressure: int = 0,
135
+ mem_pressure: int = 0,
136
+ age: int = 60,
137
+ service: Optional[str] = None,
138
+ platform: str = "docker",
139
+ no_ai: bool = False,
140
+ timeout: int = 30,
141
+ ) -> dict:
142
+ """POST pod metrics to the /predict endpoint and return the result dict."""
143
+ return _post(
144
+ "/predict",
145
+ {
146
+ "cpu": cpu,
147
+ "memory": memory,
148
+ "disk": disk,
149
+ "latency": latency,
150
+ "restarts": restarts,
151
+ "probe_failures": probe_failures,
152
+ "cpu_pressure": cpu_pressure,
153
+ "mem_pressure": mem_pressure,
154
+ "age": age,
155
+ "service": service,
156
+ "platform": platform,
157
+ "no_ai": no_ai,
158
+ },
159
+ timeout=timeout,
160
+ )
@@ -0,0 +1 @@
1
+ """CLI commands package."""
@@ -0,0 +1,110 @@
1
+ """checkdk auth commands - login, logout, whoami."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+ import webbrowser
8
+ from pathlib import Path
9
+
10
+ import click
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.table import Table
14
+
15
+ from ..client import get_api_url, get_current_user, validate_token
16
+
17
+ _console = Console()
18
+ _ENV_FILE = Path.home() / ".checkdk" / ".env"
19
+
20
+
21
+ def _save_token(token: str) -> None:
22
+ _ENV_FILE.parent.mkdir(parents=True, exist_ok=True)
23
+ lines = _ENV_FILE.read_text().splitlines() if _ENV_FILE.exists() else []
24
+ lines = [l for l in lines if not l.startswith("CHECKDK_TOKEN=")]
25
+ lines.append(f"CHECKDK_TOKEN={token}")
26
+ _ENV_FILE.write_text("\n".join(lines) + "\n")
27
+
28
+
29
+ def _remove_token() -> None:
30
+ if not _ENV_FILE.exists():
31
+ return
32
+ lines = [l for l in _ENV_FILE.read_text().splitlines()
33
+ if not l.startswith("CHECKDK_TOKEN=")]
34
+ _ENV_FILE.write_text("\n".join(lines) + "\n")
35
+
36
+
37
+ @click.group("auth")
38
+ def auth_cmd() -> None:
39
+ """Authentication - log in, log out, or check who you are."""
40
+
41
+
42
+ @auth_cmd.command("login")
43
+ def login_cmd() -> None:
44
+ """Log in to checkDK via GitHub or Google OAuth.
45
+
46
+ Opens the sign-in page in your browser, then prompts you to paste
47
+ the JWT token shown after a successful login.
48
+ """
49
+ login_url = f"{get_api_url().replace('/api', '')}/login" if "/api" in get_api_url() else "https://checkdk.app/login"
50
+ _console.print(f"\n[bold]Opening sign-in page:[/] [cyan]{login_url}[/]")
51
+ _console.print("[dim]Sign in with GitHub or Google, then copy the token from the page.[/]\n")
52
+
53
+ try:
54
+ webbrowser.open(login_url)
55
+ except Exception:
56
+ _console.print("[yellow]Could not open browser automatically.[/]")
57
+ _console.print(f"Please visit: [cyan]{login_url}[/]\n")
58
+
59
+ token = _console.input("[bold]Paste your JWT token here:[/] ").strip()
60
+ if not token:
61
+ _console.print("[red]No token provided. Login cancelled.[/]")
62
+ sys.exit(1)
63
+
64
+ try:
65
+ user = validate_token(token)
66
+ except Exception as exc:
67
+ _console.print(f"[bold red]Token validation failed:[/] {exc}")
68
+ _console.print("[yellow]Make sure CHECKDK_API_URL points to a running backend.[/]")
69
+ sys.exit(1)
70
+
71
+ _save_token(token)
72
+ os.environ["CHECKDK_TOKEN"] = token
73
+
74
+ _console.print(Panel(
75
+ f"[bold green]Logged in successfully![/]\n\n"
76
+ f" Name: {user.get('name', '?')}\n"
77
+ f" Email: {user.get('email', '?')}\n"
78
+ f" Provider: {user.get('provider', '?')}\n\n"
79
+ f"[dim]Token saved to {_ENV_FILE}[/]",
80
+ border_style="green",
81
+ ))
82
+
83
+
84
+ @auth_cmd.command("logout")
85
+ def logout_cmd() -> None:
86
+ """Remove the stored JWT token."""
87
+ _remove_token()
88
+ if "CHECKDK_TOKEN" in os.environ:
89
+ del os.environ["CHECKDK_TOKEN"]
90
+ _console.print("[bold green]Logged out.[/] Token removed from local config.")
91
+
92
+
93
+ @auth_cmd.command("whoami")
94
+ def whoami_cmd() -> None:
95
+ """Show the currently logged-in user."""
96
+ try:
97
+ user = get_current_user()
98
+ except Exception as exc:
99
+ _console.print(f"[bold red]Not logged in or API unreachable:[/] {exc}")
100
+ _console.print("[dim]Run [bold]checkdk auth login[/] first.[/]")
101
+ sys.exit(1)
102
+
103
+ t = Table.grid(padding=(0, 2))
104
+ t.add_column(style="bold cyan")
105
+ t.add_column()
106
+ t.add_row("Name:", user.get("name", "?"))
107
+ t.add_row("Email:", user.get("email", "?"))
108
+ t.add_row("Provider:", user.get("provider", "?"))
109
+ t.add_row("User ID:", user.get("userId", "?"))
110
+ _console.print(Panel(t, title="Current User", border_style="cyan"))