checkdk-cli 0.2.2__tar.gz → 0.2.5__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.
Files changed (24) hide show
  1. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/PKG-INFO +45 -21
  2. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/README.md +44 -20
  3. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdk_cli.egg-info/PKG-INFO +45 -21
  4. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/__init__.py +1 -1
  5. checkdk_cli-0.2.5/checkdkcli/commands/auth.py +110 -0
  6. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/pyproject.toml +1 -1
  7. checkdk_cli-0.2.2/checkdkcli/commands/auth.py +0 -181
  8. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdk_cli.egg-info/SOURCES.txt +0 -0
  9. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdk_cli.egg-info/dependency_links.txt +0 -0
  10. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdk_cli.egg-info/entry_points.txt +0 -0
  11. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdk_cli.egg-info/requires.txt +0 -0
  12. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdk_cli.egg-info/top_level.txt +0 -0
  13. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/client.py +0 -0
  14. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/__init__.py +0 -0
  15. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/chaos.py +0 -0
  16. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/docker.py +0 -0
  17. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/init.py +0 -0
  18. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/kubectl.py +0 -0
  19. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/monitor.py +0 -0
  20. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/playground.py +0 -0
  21. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/commands/predict.py +0 -0
  22. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/display.py +0 -0
  23. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/checkdkcli/main.py +0 -0
  24. {checkdk_cli-0.2.2 → checkdk_cli-0.2.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: checkdk-cli
3
- Version: 0.2.2
3
+ Version: 0.2.5
4
4
  Summary: checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor
5
5
  Author-email: checkDK Team <team@checkdk.app>
6
6
  License: MIT
@@ -50,6 +50,29 @@ dependencies — it is a thin HTTP/WebSocket client with a rich terminal UI.
50
50
 
51
51
  ## Install
52
52
 
53
+ ### npm (no Python required)
54
+
55
+ The easiest way to install for JavaScript / Node.js users.
56
+ Pre-compiled standalone binaries are distributed per-platform — nothing else needs to be installed.
57
+
58
+ ```bash
59
+ npm install -g @checkdk/cli
60
+ ```
61
+
62
+ Supported platforms:
63
+
64
+ | Platform | Package |
65
+ | --------------------------- | --------------------------- |
66
+ | Linux x64 | `@checkdk/cli-linux-x64` |
67
+ | Linux arm64 | `@checkdk/cli-linux-arm64` |
68
+ | macOS x64 (Intel) | `@checkdk/cli-darwin-x64` |
69
+ | macOS arm64 (Apple Silicon) | `@checkdk/cli-darwin-arm64` |
70
+ | Windows x64 | `@checkdk/cli-win32-x64` |
71
+
72
+ After install, `checkdk` is available on your PATH immediately.
73
+
74
+ ### pip / pipx (Python required)
75
+
53
76
  ```bash
54
77
  # Recommended — isolated install, checkdk on PATH globally
55
78
  pipx install checkdk-cli
@@ -58,6 +81,8 @@ pipx install checkdk-cli
58
81
  pip install checkdk-cli
59
82
  ```
60
83
 
84
+ Requires Python 3.10 or later.
85
+
61
86
  The `checkdk` command is available immediately after install.
62
87
  No configuration required — the CLI talks to `https://checkdk.app/api` by default.
63
88
 
@@ -107,21 +132,21 @@ checkdk predict --cpu 93 --memory 91 --restarts 3 \
107
132
  checkdk predict --cpu 85 --memory 70 --json # CI/scripting output
108
133
  ```
109
134
 
110
- | Option | Default | Description |
111
- |---|---|---|
112
- | `--cpu` | required | CPU usage % |
113
- | `--memory` | required | Memory usage % |
114
- | `--disk` | 50 | Disk usage % |
115
- | `--latency` | 10 | Network latency ms |
116
- | `--restarts` | 0 | Container restart count |
117
- | `--probe-failures` | 0 | Liveness/readiness probe failures |
118
- | `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
119
- | `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
120
- | `--age` | 60 | Pod age in minutes |
121
- | `--service` | — | Service/pod name (label only) |
122
- | `--platform` | docker | `docker` or `kubernetes` |
123
- | `--no-ai` | — | Skip LLM, return ML result only |
124
- | `--json` | — | Raw JSON output for scripting |
135
+ | Option | Default | Description |
136
+ | ------------------ | -------- | --------------------------------- |
137
+ | `--cpu` | required | CPU usage % |
138
+ | `--memory` | required | Memory usage % |
139
+ | `--disk` | 50 | Disk usage % |
140
+ | `--latency` | 10 | Network latency ms |
141
+ | `--restarts` | 0 | Container restart count |
142
+ | `--probe-failures` | 0 | Liveness/readiness probe failures |
143
+ | `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
144
+ | `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
145
+ | `--age` | 60 | Pod age in minutes |
146
+ | `--service` | — | Service/pod name (label only) |
147
+ | `--platform` | docker | `docker` or `kubernetes` |
148
+ | `--no-ai` | — | Skip LLM, return ML result only |
149
+ | `--json` | — | Raw JSON output for scripting |
125
150
 
126
151
  ### Monitor (real-time)
127
152
 
@@ -152,10 +177,10 @@ Experiments: `cpu`, `memory`, `disk`, `network`, `pod-kill` (k8s only).
152
177
 
153
178
  ## Environment variables
154
179
 
155
- | Variable | Default | Description |
156
- |---|---|---|
157
- | `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
158
- | `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
180
+ | Variable | Default | Description |
181
+ | ----------------- | ------------------------- | -------------------------------------------- |
182
+ | `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
183
+ | `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
159
184
 
160
185
  The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
161
186
 
@@ -183,4 +208,3 @@ pytest
183
208
  # Lint
184
209
  ruff check .
185
210
  ```
186
-
@@ -12,6 +12,29 @@ dependencies — it is a thin HTTP/WebSocket client with a rich terminal UI.
12
12
 
13
13
  ## Install
14
14
 
15
+ ### npm (no Python required)
16
+
17
+ The easiest way to install for JavaScript / Node.js users.
18
+ Pre-compiled standalone binaries are distributed per-platform — nothing else needs to be installed.
19
+
20
+ ```bash
21
+ npm install -g @checkdk/cli
22
+ ```
23
+
24
+ Supported platforms:
25
+
26
+ | Platform | Package |
27
+ | --------------------------- | --------------------------- |
28
+ | Linux x64 | `@checkdk/cli-linux-x64` |
29
+ | Linux arm64 | `@checkdk/cli-linux-arm64` |
30
+ | macOS x64 (Intel) | `@checkdk/cli-darwin-x64` |
31
+ | macOS arm64 (Apple Silicon) | `@checkdk/cli-darwin-arm64` |
32
+ | Windows x64 | `@checkdk/cli-win32-x64` |
33
+
34
+ After install, `checkdk` is available on your PATH immediately.
35
+
36
+ ### pip / pipx (Python required)
37
+
15
38
  ```bash
16
39
  # Recommended — isolated install, checkdk on PATH globally
17
40
  pipx install checkdk-cli
@@ -20,6 +43,8 @@ pipx install checkdk-cli
20
43
  pip install checkdk-cli
21
44
  ```
22
45
 
46
+ Requires Python 3.10 or later.
47
+
23
48
  The `checkdk` command is available immediately after install.
24
49
  No configuration required — the CLI talks to `https://checkdk.app/api` by default.
25
50
 
@@ -69,21 +94,21 @@ checkdk predict --cpu 93 --memory 91 --restarts 3 \
69
94
  checkdk predict --cpu 85 --memory 70 --json # CI/scripting output
70
95
  ```
71
96
 
72
- | Option | Default | Description |
73
- |---|---|---|
74
- | `--cpu` | required | CPU usage % |
75
- | `--memory` | required | Memory usage % |
76
- | `--disk` | 50 | Disk usage % |
77
- | `--latency` | 10 | Network latency ms |
78
- | `--restarts` | 0 | Container restart count |
79
- | `--probe-failures` | 0 | Liveness/readiness probe failures |
80
- | `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
81
- | `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
82
- | `--age` | 60 | Pod age in minutes |
83
- | `--service` | — | Service/pod name (label only) |
84
- | `--platform` | docker | `docker` or `kubernetes` |
85
- | `--no-ai` | — | Skip LLM, return ML result only |
86
- | `--json` | — | Raw JSON output for scripting |
97
+ | Option | Default | Description |
98
+ | ------------------ | -------- | --------------------------------- |
99
+ | `--cpu` | required | CPU usage % |
100
+ | `--memory` | required | Memory usage % |
101
+ | `--disk` | 50 | Disk usage % |
102
+ | `--latency` | 10 | Network latency ms |
103
+ | `--restarts` | 0 | Container restart count |
104
+ | `--probe-failures` | 0 | Liveness/readiness probe failures |
105
+ | `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
106
+ | `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
107
+ | `--age` | 60 | Pod age in minutes |
108
+ | `--service` | — | Service/pod name (label only) |
109
+ | `--platform` | docker | `docker` or `kubernetes` |
110
+ | `--no-ai` | — | Skip LLM, return ML result only |
111
+ | `--json` | — | Raw JSON output for scripting |
87
112
 
88
113
  ### Monitor (real-time)
89
114
 
@@ -114,10 +139,10 @@ Experiments: `cpu`, `memory`, `disk`, `network`, `pod-kill` (k8s only).
114
139
 
115
140
  ## Environment variables
116
141
 
117
- | Variable | Default | Description |
118
- |---|---|---|
119
- | `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
120
- | `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
142
+ | Variable | Default | Description |
143
+ | ----------------- | ------------------------- | -------------------------------------------- |
144
+ | `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
145
+ | `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
121
146
 
122
147
  The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
123
148
 
@@ -145,4 +170,3 @@ pytest
145
170
  # Lint
146
171
  ruff check .
147
172
  ```
148
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: checkdk-cli
3
- Version: 0.2.2
3
+ Version: 0.2.5
4
4
  Summary: checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor
5
5
  Author-email: checkDK Team <team@checkdk.app>
6
6
  License: MIT
@@ -50,6 +50,29 @@ dependencies — it is a thin HTTP/WebSocket client with a rich terminal UI.
50
50
 
51
51
  ## Install
52
52
 
53
+ ### npm (no Python required)
54
+
55
+ The easiest way to install for JavaScript / Node.js users.
56
+ Pre-compiled standalone binaries are distributed per-platform — nothing else needs to be installed.
57
+
58
+ ```bash
59
+ npm install -g @checkdk/cli
60
+ ```
61
+
62
+ Supported platforms:
63
+
64
+ | Platform | Package |
65
+ | --------------------------- | --------------------------- |
66
+ | Linux x64 | `@checkdk/cli-linux-x64` |
67
+ | Linux arm64 | `@checkdk/cli-linux-arm64` |
68
+ | macOS x64 (Intel) | `@checkdk/cli-darwin-x64` |
69
+ | macOS arm64 (Apple Silicon) | `@checkdk/cli-darwin-arm64` |
70
+ | Windows x64 | `@checkdk/cli-win32-x64` |
71
+
72
+ After install, `checkdk` is available on your PATH immediately.
73
+
74
+ ### pip / pipx (Python required)
75
+
53
76
  ```bash
54
77
  # Recommended — isolated install, checkdk on PATH globally
55
78
  pipx install checkdk-cli
@@ -58,6 +81,8 @@ pipx install checkdk-cli
58
81
  pip install checkdk-cli
59
82
  ```
60
83
 
84
+ Requires Python 3.10 or later.
85
+
61
86
  The `checkdk` command is available immediately after install.
62
87
  No configuration required — the CLI talks to `https://checkdk.app/api` by default.
63
88
 
@@ -107,21 +132,21 @@ checkdk predict --cpu 93 --memory 91 --restarts 3 \
107
132
  checkdk predict --cpu 85 --memory 70 --json # CI/scripting output
108
133
  ```
109
134
 
110
- | Option | Default | Description |
111
- |---|---|---|
112
- | `--cpu` | required | CPU usage % |
113
- | `--memory` | required | Memory usage % |
114
- | `--disk` | 50 | Disk usage % |
115
- | `--latency` | 10 | Network latency ms |
116
- | `--restarts` | 0 | Container restart count |
117
- | `--probe-failures` | 0 | Liveness/readiness probe failures |
118
- | `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
119
- | `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
120
- | `--age` | 60 | Pod age in minutes |
121
- | `--service` | — | Service/pod name (label only) |
122
- | `--platform` | docker | `docker` or `kubernetes` |
123
- | `--no-ai` | — | Skip LLM, return ML result only |
124
- | `--json` | — | Raw JSON output for scripting |
135
+ | Option | Default | Description |
136
+ | ------------------ | -------- | --------------------------------- |
137
+ | `--cpu` | required | CPU usage % |
138
+ | `--memory` | required | Memory usage % |
139
+ | `--disk` | 50 | Disk usage % |
140
+ | `--latency` | 10 | Network latency ms |
141
+ | `--restarts` | 0 | Container restart count |
142
+ | `--probe-failures` | 0 | Liveness/readiness probe failures |
143
+ | `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
144
+ | `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
145
+ | `--age` | 60 | Pod age in minutes |
146
+ | `--service` | — | Service/pod name (label only) |
147
+ | `--platform` | docker | `docker` or `kubernetes` |
148
+ | `--no-ai` | — | Skip LLM, return ML result only |
149
+ | `--json` | — | Raw JSON output for scripting |
125
150
 
126
151
  ### Monitor (real-time)
127
152
 
@@ -152,10 +177,10 @@ Experiments: `cpu`, `memory`, `disk`, `network`, `pod-kill` (k8s only).
152
177
 
153
178
  ## Environment variables
154
179
 
155
- | Variable | Default | Description |
156
- |---|---|---|
157
- | `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
158
- | `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
180
+ | Variable | Default | Description |
181
+ | ----------------- | ------------------------- | -------------------------------------------- |
182
+ | `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
183
+ | `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
159
184
 
160
185
  The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
161
186
 
@@ -183,4 +208,3 @@ pytest
183
208
  # Lint
184
209
  ruff check .
185
210
  ```
186
-
@@ -1,3 +1,3 @@
1
1
  """checkDK CLI package."""
2
2
 
3
- __version__ = "0.2.2"
3
+ __version__ = "0.2.5"
@@ -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"))
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "checkdk-cli"
7
- version = "0.2.2"
7
+ version = "0.2.5"
8
8
  description = "checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,181 +0,0 @@
1
- """checkdk auth commands - login, logout, whoami."""
2
-
3
- from __future__ import annotations
4
-
5
- import os
6
- import socket
7
- import sys
8
- import threading
9
- import time
10
- import urllib.parse
11
- import webbrowser
12
- from http.server import BaseHTTPRequestHandler, HTTPServer
13
- from pathlib import Path
14
-
15
- import click
16
- from rich.console import Console
17
- from rich.panel import Panel
18
- from rich.table import Table
19
-
20
- from ..client import get_api_url, get_current_user, validate_token
21
-
22
- _console = Console()
23
- _ENV_FILE = Path.home() / ".checkdk" / ".env"
24
-
25
-
26
- def _save_token(token: str) -> None:
27
- _ENV_FILE.parent.mkdir(parents=True, exist_ok=True)
28
- lines = _ENV_FILE.read_text().splitlines() if _ENV_FILE.exists() else []
29
- lines = [l for l in lines if not l.startswith("CHECKDK_TOKEN=")]
30
- lines.append(f"CHECKDK_TOKEN={token}")
31
- _ENV_FILE.write_text("\n".join(lines) + "\n")
32
-
33
-
34
- def _remove_token() -> None:
35
- if not _ENV_FILE.exists():
36
- return
37
- lines = [l for l in _ENV_FILE.read_text().splitlines()
38
- if not l.startswith("CHECKDK_TOKEN=")]
39
- _ENV_FILE.write_text("\n".join(lines) + "\n")
40
-
41
-
42
- def _find_free_port() -> int:
43
- """Return an available localhost port."""
44
- with socket.socket() as s:
45
- s.bind(("127.0.0.1", 0))
46
- return s.getsockname()[1]
47
-
48
-
49
- def _wait_for_token(port: int, timeout: int = 120) -> "str | None":
50
- """Start a temporary HTTP server on localhost and wait for the OAuth callback."""
51
- received: dict = {"token": None}
52
- server_ready = threading.Event()
53
-
54
- class _Handler(BaseHTTPRequestHandler):
55
- def do_GET(self) -> None:
56
- parsed = urllib.parse.urlparse(self.path)
57
- params = urllib.parse.parse_qs(parsed.query)
58
- token = (params.get("token") or [None])[0]
59
- received["token"] = token
60
-
61
- if token:
62
- body = (
63
- b"<html><body style=\"font-family:sans-serif;text-align:center;"
64
- b"margin-top:10vh;background:#0f172a;color:#e2e8f0\">"
65
- b"<h2 style=\"color:#818cf8\">checkDK CLI</h2>"
66
- b"<p style=\"font-size:1.2rem\">You\'re logged in!"
67
- b" You can close this tab.</p></body></html>"
68
- )
69
- else:
70
- body = b"<html><body>Authentication failed. Please try again.</body></html>"
71
-
72
- self.send_response(200)
73
- self.send_header("Content-Type", "text/html; charset=utf-8")
74
- self.send_header("Content-Length", str(len(body)))
75
- self.end_headers()
76
- self.wfile.write(body)
77
-
78
- def log_message(self, *_) -> None:
79
- pass # silence access logs
80
-
81
- httpd = HTTPServer(("127.0.0.1", port), _Handler)
82
- httpd.timeout = 1 # poll interval
83
-
84
- def _serve() -> None:
85
- server_ready.set()
86
- deadline = time.time() + timeout
87
- while received["token"] is None and time.time() < deadline:
88
- httpd.handle_request()
89
- httpd.server_close()
90
-
91
- t = threading.Thread(target=_serve, daemon=True)
92
- t.start()
93
- server_ready.wait()
94
- t.join(timeout + 2)
95
- return received["token"]
96
-
97
-
98
- @click.group("auth")
99
- def auth_cmd() -> None:
100
- """Authentication - log in, log out, or check who you are."""
101
-
102
-
103
- @auth_cmd.command("login")
104
- def login_cmd() -> None:
105
- """Log in to checkDK via GitHub or Google OAuth.
106
-
107
- Starts a local callback server, opens the sign-in page in your browser,
108
- and receives the token automatically - no copy-pasting required.
109
- """
110
- port = _find_free_port()
111
- callback_url = f"http://127.0.0.1:{port}/callback"
112
-
113
- api = get_api_url()
114
- base = api[: api.rindex("/api")] if "/api" in api else "https://checkdk.app"
115
- encoded_cb = urllib.parse.quote(callback_url, safe="")
116
- login_url = f"{base}/login?cli_callback={encoded_cb}"
117
-
118
- _console.print("\n[bold]Opening browser for sign-in...[/]")
119
- _console.print(
120
- " [dim]If the browser did not open, visit:[/]\n"
121
- f" [cyan]{login_url}[/]\n"
122
- )
123
-
124
- try:
125
- webbrowser.open(login_url)
126
- except Exception:
127
- _console.print(f"[yellow]Open this URL in your browser:[/] [cyan]{login_url}[/]\n")
128
-
129
- with _console.status("[bold cyan]Waiting for authentication (2-min timeout)...[/]"):
130
- token = _wait_for_token(port, timeout=120)
131
-
132
- if not token:
133
- _console.print("[bold red]Login timed out or was cancelled.[/]")
134
- sys.exit(1)
135
-
136
- try:
137
- user = validate_token(token)
138
- except Exception as exc:
139
- _console.print(f"[bold red]Token validation failed:[/] {exc}")
140
- sys.exit(1)
141
-
142
- _save_token(token)
143
- os.environ["CHECKDK_TOKEN"] = token
144
-
145
- _console.print(Panel(
146
- f"[bold green]Logged in successfully![/]\n\n"
147
- f" Name: {user.get('name', '?\')}\n"
148
- f" Email: {user.get('email', '?\')}\n"
149
- f" Provider: {user.get('provider', '?\')}\n\n"
150
- f"[dim]Token saved to {_ENV_FILE}[/]",
151
- border_style="green",
152
- ))
153
-
154
-
155
- @auth_cmd.command("logout")
156
- def logout_cmd() -> None:
157
- """Remove the stored JWT token."""
158
- _remove_token()
159
- if "CHECKDK_TOKEN" in os.environ:
160
- del os.environ["CHECKDK_TOKEN"]
161
- _console.print("[bold green]Logged out.[/] Token removed from local config.")
162
-
163
-
164
- @auth_cmd.command("whoami")
165
- def whoami_cmd() -> None:
166
- """Show the currently logged-in user."""
167
- try:
168
- user = get_current_user()
169
- except Exception as exc:
170
- _console.print(f"[bold red]Not logged in or API unreachable:[/] {exc}")
171
- _console.print("[dim]Run [bold]checkdk auth login[/] first.[/]")
172
- sys.exit(1)
173
-
174
- t = Table.grid(padding=(0, 2))
175
- t.add_column(style="bold cyan")
176
- t.add_column()
177
- t.add_row("Name:", user.get("name", "?"))
178
- t.add_row("Email:", user.get("email", "?"))
179
- t.add_row("Provider:", user.get("provider", "?"))
180
- t.add_row("User ID:", user.get("userId", "?"))
181
- _console.print(Panel(t, title="Current User", border_style="cyan"))
File without changes