kaos-cli 0.0.1__py3-none-any.whl
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.
- kaos_cli/__init__.py +3 -0
- kaos_cli/install.py +121 -0
- kaos_cli/main.py +117 -0
- kaos_cli/proxy.py +105 -0
- kaos_cli/ui.py +57 -0
- kaos_cli-0.0.1.dist-info/METADATA +75 -0
- kaos_cli-0.0.1.dist-info/RECORD +10 -0
- kaos_cli-0.0.1.dist-info/WHEEL +5 -0
- kaos_cli-0.0.1.dist-info/entry_points.txt +2 -0
- kaos_cli-0.0.1.dist-info/top_level.txt +1 -0
kaos_cli/__init__.py
ADDED
kaos_cli/install.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""KAOS install/uninstall commands for the Kubernetes operator."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
# Helm chart repository URL (hosted on GitHub Pages)
|
|
10
|
+
HELM_REPO_URL = "https://axsaucedo.github.io/kaos/charts"
|
|
11
|
+
HELM_REPO_NAME = "kaos"
|
|
12
|
+
HELM_CHART_NAME = "kaos-operator"
|
|
13
|
+
DEFAULT_NAMESPACE = "kaos-system"
|
|
14
|
+
DEFAULT_RELEASE_NAME = "kaos"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def check_helm_installed() -> bool:
|
|
18
|
+
"""Check if helm is installed and available."""
|
|
19
|
+
return shutil.which("helm") is not None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def run_helm_command(args: list[str], check: bool = True) -> subprocess.CompletedProcess:
|
|
23
|
+
"""Run a helm command and return the result."""
|
|
24
|
+
cmd = ["helm"] + args
|
|
25
|
+
try:
|
|
26
|
+
result = subprocess.run(
|
|
27
|
+
cmd,
|
|
28
|
+
capture_output=True,
|
|
29
|
+
text=True,
|
|
30
|
+
check=check,
|
|
31
|
+
)
|
|
32
|
+
return result
|
|
33
|
+
except subprocess.CalledProcessError as e:
|
|
34
|
+
typer.echo(f"Error running helm: {e.stderr}", err=True)
|
|
35
|
+
raise
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def install_command(
|
|
39
|
+
namespace: str,
|
|
40
|
+
release_name: str,
|
|
41
|
+
version: str | None,
|
|
42
|
+
set_values: list[str],
|
|
43
|
+
wait: bool,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Install the KAOS operator using Helm."""
|
|
46
|
+
if not check_helm_installed():
|
|
47
|
+
typer.echo("Error: helm is not installed. Please install helm first.", err=True)
|
|
48
|
+
typer.echo("See: https://helm.sh/docs/intro/install/", err=True)
|
|
49
|
+
sys.exit(1)
|
|
50
|
+
|
|
51
|
+
typer.echo(f"Installing KAOS operator to namespace '{namespace}'...")
|
|
52
|
+
|
|
53
|
+
# Add the Helm repository
|
|
54
|
+
typer.echo(f"Adding Helm repository '{HELM_REPO_NAME}'...")
|
|
55
|
+
result = run_helm_command(
|
|
56
|
+
["repo", "add", HELM_REPO_NAME, HELM_REPO_URL, "--force-update"],
|
|
57
|
+
check=False,
|
|
58
|
+
)
|
|
59
|
+
if result.returncode != 0 and "already exists" not in result.stderr:
|
|
60
|
+
typer.echo(f"Warning: {result.stderr}", err=True)
|
|
61
|
+
|
|
62
|
+
# Update repositories
|
|
63
|
+
typer.echo("Updating Helm repositories...")
|
|
64
|
+
run_helm_command(["repo", "update"], check=False)
|
|
65
|
+
|
|
66
|
+
# Build helm install command
|
|
67
|
+
helm_args = [
|
|
68
|
+
"upgrade",
|
|
69
|
+
"--install",
|
|
70
|
+
release_name,
|
|
71
|
+
f"{HELM_REPO_NAME}/{HELM_CHART_NAME}",
|
|
72
|
+
"--namespace",
|
|
73
|
+
namespace,
|
|
74
|
+
"--create-namespace",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
if version:
|
|
78
|
+
helm_args.extend(["--version", version])
|
|
79
|
+
|
|
80
|
+
if wait:
|
|
81
|
+
helm_args.append("--wait")
|
|
82
|
+
|
|
83
|
+
for value in set_values:
|
|
84
|
+
helm_args.extend(["--set", value])
|
|
85
|
+
|
|
86
|
+
typer.echo(f"Installing chart {HELM_CHART_NAME}...")
|
|
87
|
+
result = run_helm_command(helm_args)
|
|
88
|
+
|
|
89
|
+
if result.returncode == 0:
|
|
90
|
+
typer.echo("")
|
|
91
|
+
typer.echo("✅ KAOS operator installed successfully!")
|
|
92
|
+
typer.echo("")
|
|
93
|
+
typer.echo("Next steps:")
|
|
94
|
+
typer.echo(f" 1. Check the operator status: kubectl get pods -n {namespace}")
|
|
95
|
+
typer.echo(" 2. Create your first agent: kubectl apply -f your-agent.yaml")
|
|
96
|
+
typer.echo(" 3. Open the UI: kaos ui")
|
|
97
|
+
else:
|
|
98
|
+
typer.echo(f"Error: {result.stderr}", err=True)
|
|
99
|
+
sys.exit(1)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def uninstall_command(namespace: str, release_name: str) -> None:
|
|
103
|
+
"""Uninstall the KAOS operator using Helm."""
|
|
104
|
+
if not check_helm_installed():
|
|
105
|
+
typer.echo("Error: helm is not installed.", err=True)
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
|
|
108
|
+
typer.echo(f"Uninstalling KAOS operator from namespace '{namespace}'...")
|
|
109
|
+
|
|
110
|
+
result = run_helm_command(
|
|
111
|
+
["uninstall", release_name, "--namespace", namespace],
|
|
112
|
+
check=False,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if result.returncode == 0:
|
|
116
|
+
typer.echo("✅ KAOS operator uninstalled successfully!")
|
|
117
|
+
elif "not found" in result.stderr.lower():
|
|
118
|
+
typer.echo(f"Release '{release_name}' not found in namespace '{namespace}'.")
|
|
119
|
+
else:
|
|
120
|
+
typer.echo(f"Error: {result.stderr}", err=True)
|
|
121
|
+
sys.exit(1)
|
kaos_cli/main.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""KAOS CLI main entry point."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from kaos_cli.install import (
|
|
8
|
+
DEFAULT_NAMESPACE,
|
|
9
|
+
DEFAULT_RELEASE_NAME,
|
|
10
|
+
install_command,
|
|
11
|
+
uninstall_command,
|
|
12
|
+
)
|
|
13
|
+
from kaos_cli.ui import ui_command
|
|
14
|
+
|
|
15
|
+
# Disable shell completion message
|
|
16
|
+
app = typer.Typer(
|
|
17
|
+
add_completion=False,
|
|
18
|
+
help="KAOS - K8s Agent Orchestration System CLI",
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.command(name="ui")
|
|
24
|
+
def ui(
|
|
25
|
+
k8s_url: str = typer.Option(
|
|
26
|
+
None,
|
|
27
|
+
"--k8s-url",
|
|
28
|
+
help="Kubernetes API server URL. If not provided, uses kubeconfig.",
|
|
29
|
+
),
|
|
30
|
+
expose_port: int = typer.Option(
|
|
31
|
+
8010,
|
|
32
|
+
"--expose-port",
|
|
33
|
+
help="Port to expose the CORS proxy on.",
|
|
34
|
+
),
|
|
35
|
+
namespace: str = typer.Option(
|
|
36
|
+
"default",
|
|
37
|
+
"--namespace",
|
|
38
|
+
"-n",
|
|
39
|
+
help="Initial namespace to display in the UI.",
|
|
40
|
+
),
|
|
41
|
+
no_browser: bool = typer.Option(
|
|
42
|
+
False,
|
|
43
|
+
"--no-browser",
|
|
44
|
+
help="Don't automatically open the browser.",
|
|
45
|
+
),
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Start a CORS-enabled proxy and open the KAOS UI."""
|
|
48
|
+
ui_command(k8s_url=k8s_url, expose_port=expose_port, namespace=namespace, no_browser=no_browser)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@app.command(name="install")
|
|
52
|
+
def install(
|
|
53
|
+
namespace: str = typer.Option(
|
|
54
|
+
DEFAULT_NAMESPACE,
|
|
55
|
+
"--namespace",
|
|
56
|
+
"-n",
|
|
57
|
+
help="Kubernetes namespace to install into.",
|
|
58
|
+
),
|
|
59
|
+
release_name: str = typer.Option(
|
|
60
|
+
DEFAULT_RELEASE_NAME,
|
|
61
|
+
"--release-name",
|
|
62
|
+
help="Helm release name.",
|
|
63
|
+
),
|
|
64
|
+
version: str = typer.Option(
|
|
65
|
+
None,
|
|
66
|
+
"--version",
|
|
67
|
+
help="Chart version to install. Defaults to latest.",
|
|
68
|
+
),
|
|
69
|
+
set_values: List[str] = typer.Option(
|
|
70
|
+
[],
|
|
71
|
+
"--set",
|
|
72
|
+
help="Set Helm values (can be used multiple times).",
|
|
73
|
+
),
|
|
74
|
+
wait: bool = typer.Option(
|
|
75
|
+
False,
|
|
76
|
+
"--wait",
|
|
77
|
+
help="Wait for pods to be ready before returning.",
|
|
78
|
+
),
|
|
79
|
+
) -> None:
|
|
80
|
+
"""Install the KAOS operator using Helm."""
|
|
81
|
+
install_command(
|
|
82
|
+
namespace=namespace,
|
|
83
|
+
release_name=release_name,
|
|
84
|
+
version=version,
|
|
85
|
+
set_values=list(set_values),
|
|
86
|
+
wait=wait,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@app.command(name="uninstall")
|
|
91
|
+
def uninstall(
|
|
92
|
+
namespace: str = typer.Option(
|
|
93
|
+
DEFAULT_NAMESPACE,
|
|
94
|
+
"--namespace",
|
|
95
|
+
"-n",
|
|
96
|
+
help="Kubernetes namespace to uninstall from.",
|
|
97
|
+
),
|
|
98
|
+
release_name: str = typer.Option(
|
|
99
|
+
DEFAULT_RELEASE_NAME,
|
|
100
|
+
"--release-name",
|
|
101
|
+
help="Helm release name.",
|
|
102
|
+
),
|
|
103
|
+
) -> None:
|
|
104
|
+
"""Uninstall the KAOS operator."""
|
|
105
|
+
uninstall_command(namespace=namespace, release_name=release_name)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@app.command(name="version")
|
|
109
|
+
def version() -> None:
|
|
110
|
+
"""Show the KAOS CLI version."""
|
|
111
|
+
from kaos_cli import __version__
|
|
112
|
+
|
|
113
|
+
typer.echo(f"kaos-cli {__version__}")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
app()
|
kaos_cli/proxy.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""CORS-enabled Kubernetes API proxy."""
|
|
2
|
+
|
|
3
|
+
import ssl
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
from kubernetes import client, config
|
|
7
|
+
from starlette.applications import Starlette
|
|
8
|
+
from starlette.middleware.cors import CORSMiddleware
|
|
9
|
+
from starlette.requests import Request
|
|
10
|
+
from starlette.responses import Response
|
|
11
|
+
from starlette.routing import Route
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_proxy_app(k8s_url: str | None = None) -> Starlette:
|
|
15
|
+
"""Create a Starlette app that proxies requests to the K8s API with CORS."""
|
|
16
|
+
# Load kubernetes config
|
|
17
|
+
try:
|
|
18
|
+
config.load_incluster_config()
|
|
19
|
+
except config.ConfigException:
|
|
20
|
+
config.load_kube_config()
|
|
21
|
+
|
|
22
|
+
configuration = client.Configuration.get_default_copy()
|
|
23
|
+
|
|
24
|
+
# Use provided URL or from kubeconfig
|
|
25
|
+
api_url = k8s_url or configuration.host
|
|
26
|
+
|
|
27
|
+
# Get auth info from configuration
|
|
28
|
+
auth_headers: dict[str, str] = {}
|
|
29
|
+
if configuration.api_key and "authorization" in configuration.api_key:
|
|
30
|
+
auth_headers["Authorization"] = configuration.api_key["authorization"]
|
|
31
|
+
elif configuration.api_key_prefix and configuration.api_key:
|
|
32
|
+
for key, value in configuration.api_key.items():
|
|
33
|
+
prefix = configuration.api_key_prefix.get(key, "")
|
|
34
|
+
auth_headers["Authorization"] = f"{prefix} {value}".strip()
|
|
35
|
+
break
|
|
36
|
+
|
|
37
|
+
# SSL/TLS configuration - handle client certificates
|
|
38
|
+
ssl_context: ssl.SSLContext | bool = False
|
|
39
|
+
if configuration.cert_file and configuration.key_file:
|
|
40
|
+
ssl_context = ssl.create_default_context()
|
|
41
|
+
ssl_context.load_cert_chain(
|
|
42
|
+
certfile=configuration.cert_file,
|
|
43
|
+
keyfile=configuration.key_file,
|
|
44
|
+
)
|
|
45
|
+
if configuration.ssl_ca_cert:
|
|
46
|
+
ssl_context.load_verify_locations(cafile=configuration.ssl_ca_cert)
|
|
47
|
+
else:
|
|
48
|
+
ssl_context.check_hostname = False
|
|
49
|
+
ssl_context.verify_mode = ssl.CERT_NONE
|
|
50
|
+
elif configuration.ssl_ca_cert:
|
|
51
|
+
ssl_context = ssl.create_default_context(cafile=configuration.ssl_ca_cert)
|
|
52
|
+
|
|
53
|
+
async def proxy_request(request: Request) -> Response:
|
|
54
|
+
"""Proxy incoming requests to the Kubernetes API server."""
|
|
55
|
+
path = request.url.path
|
|
56
|
+
query = str(request.url.query) if request.url.query else ""
|
|
57
|
+
target_url = f"{api_url}{path}"
|
|
58
|
+
if query:
|
|
59
|
+
target_url = f"{target_url}?{query}"
|
|
60
|
+
|
|
61
|
+
# Start with auth headers
|
|
62
|
+
headers = dict(auth_headers)
|
|
63
|
+
|
|
64
|
+
# Copy relevant headers from request
|
|
65
|
+
for key in ["content-type", "accept", "mcp-session-id"]:
|
|
66
|
+
if key in request.headers:
|
|
67
|
+
headers[key] = request.headers[key]
|
|
68
|
+
|
|
69
|
+
# Get request body
|
|
70
|
+
body = await request.body()
|
|
71
|
+
|
|
72
|
+
async with httpx.AsyncClient(verify=ssl_context, timeout=120.0) as http_client:
|
|
73
|
+
response = await http_client.request(
|
|
74
|
+
method=request.method,
|
|
75
|
+
url=target_url,
|
|
76
|
+
headers=headers,
|
|
77
|
+
content=body if body else None,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Build response headers
|
|
81
|
+
response_headers = dict(response.headers)
|
|
82
|
+
|
|
83
|
+
return Response(
|
|
84
|
+
content=response.content,
|
|
85
|
+
status_code=response.status_code,
|
|
86
|
+
headers=response_headers,
|
|
87
|
+
media_type=response.headers.get("content-type"),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
routes = [
|
|
91
|
+
Route("/{path:path}", proxy_request, methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]),
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
app = Starlette(routes=routes)
|
|
95
|
+
|
|
96
|
+
# Add CORS middleware with mcp-session-id exposed
|
|
97
|
+
app.add_middleware(
|
|
98
|
+
CORSMiddleware,
|
|
99
|
+
allow_origins=["*"],
|
|
100
|
+
allow_methods=["*"],
|
|
101
|
+
allow_headers=["*"],
|
|
102
|
+
expose_headers=["mcp-session-id"],
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
return app
|
kaos_cli/ui.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""KAOS UI command - starts a CORS-enabled K8s API proxy."""
|
|
2
|
+
|
|
3
|
+
import signal
|
|
4
|
+
import sys
|
|
5
|
+
import threading
|
|
6
|
+
import time
|
|
7
|
+
import webbrowser
|
|
8
|
+
from urllib.parse import urlencode
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
import uvicorn
|
|
12
|
+
|
|
13
|
+
# KAOS UI hosted on GitHub Pages
|
|
14
|
+
KAOS_UI_URL = "https://axsaucedo.github.io/kaos-ui/"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def ui_command(k8s_url: str | None, expose_port: int, namespace: str, no_browser: bool) -> None:
|
|
18
|
+
"""Start a CORS-enabled proxy to the Kubernetes API server."""
|
|
19
|
+
from kaos_cli.proxy import create_proxy_app
|
|
20
|
+
|
|
21
|
+
app = create_proxy_app(k8s_url=k8s_url)
|
|
22
|
+
|
|
23
|
+
typer.echo(f"Starting KAOS UI proxy on http://localhost:{expose_port}")
|
|
24
|
+
|
|
25
|
+
# Build UI URL with query parameters
|
|
26
|
+
query_params = {}
|
|
27
|
+
# Only add kubernetesUrl if not using default port
|
|
28
|
+
if expose_port != 8010:
|
|
29
|
+
query_params["kubernetesUrl"] = f"http://localhost:{expose_port}"
|
|
30
|
+
# Only add namespace if not using default
|
|
31
|
+
if namespace and namespace != "default":
|
|
32
|
+
query_params["namespace"] = namespace
|
|
33
|
+
|
|
34
|
+
ui_url = KAOS_UI_URL
|
|
35
|
+
if query_params:
|
|
36
|
+
ui_url = f"{KAOS_UI_URL}?{urlencode(query_params)}"
|
|
37
|
+
|
|
38
|
+
typer.echo(f"KAOS UI: {ui_url}")
|
|
39
|
+
typer.echo("Press Ctrl+C to stop")
|
|
40
|
+
|
|
41
|
+
def handle_signal(signum: int, frame: object) -> None:
|
|
42
|
+
typer.echo("\nShutting down...")
|
|
43
|
+
sys.exit(0)
|
|
44
|
+
|
|
45
|
+
signal.signal(signal.SIGINT, handle_signal)
|
|
46
|
+
signal.signal(signal.SIGTERM, handle_signal)
|
|
47
|
+
|
|
48
|
+
# Open browser after a short delay to allow server to start
|
|
49
|
+
if not no_browser:
|
|
50
|
+
def open_browser() -> None:
|
|
51
|
+
time.sleep(1.5)
|
|
52
|
+
webbrowser.open(ui_url)
|
|
53
|
+
|
|
54
|
+
browser_thread = threading.Thread(target=open_browser, daemon=True)
|
|
55
|
+
browser_thread.start()
|
|
56
|
+
|
|
57
|
+
uvicorn.run(app, host="0.0.0.0", port=expose_port, log_level="info")
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kaos-cli
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: CLI for KAOS (K8s Agent Orchestration System)
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: typer>=0.9.0
|
|
8
|
+
Requires-Dist: httpx>=0.27.0
|
|
9
|
+
Requires-Dist: uvicorn>=0.30.0
|
|
10
|
+
Requires-Dist: starlette>=0.37.0
|
|
11
|
+
Requires-Dist: kubernetes>=29.0.0
|
|
12
|
+
|
|
13
|
+
# KAOS CLI
|
|
14
|
+
|
|
15
|
+
Command-line interface for KAOS (K8s Agent Orchestration System).
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd kaos-cli
|
|
21
|
+
uv sync
|
|
22
|
+
source .venv/bin/activate
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Start UI Proxy
|
|
28
|
+
|
|
29
|
+
Start a CORS-enabled proxy to the Kubernetes API server:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
kaos ui
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This starts a local proxy on port 8010 that:
|
|
36
|
+
- Proxies requests to the Kubernetes API using your kubeconfig credentials
|
|
37
|
+
- Adds CORS headers to enable browser-based access
|
|
38
|
+
- Exposes the `mcp-session-id` header for MCP protocol support
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
- `--k8s-url`: Override the Kubernetes API URL (default: from kubeconfig)
|
|
42
|
+
- `--expose-port`: Port to expose the proxy on (default: 8010)
|
|
43
|
+
- `--namespace`, `-n`: Initial namespace to display in the UI (default: "default")
|
|
44
|
+
- `--no-browser`: Don't automatically open the browser
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
```bash
|
|
48
|
+
# Use default settings
|
|
49
|
+
kaos ui
|
|
50
|
+
|
|
51
|
+
# Custom port
|
|
52
|
+
kaos ui --expose-port 9000
|
|
53
|
+
|
|
54
|
+
# Start with a specific namespace
|
|
55
|
+
kaos ui --namespace kaos-system
|
|
56
|
+
|
|
57
|
+
# Custom K8s URL
|
|
58
|
+
kaos ui --k8s-url https://my-cluster:6443
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Version
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
kaos version
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Development
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Run tests
|
|
71
|
+
pytest
|
|
72
|
+
|
|
73
|
+
# Run directly
|
|
74
|
+
python -m kaos_cli.main ui
|
|
75
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
kaos_cli/__init__.py,sha256=1Yxq51Ckr8SnrwtSuCn9JKnQIJ0CDEh5CX2-zZh3CHQ,80
|
|
2
|
+
kaos_cli/install.py,sha256=B3n0moEM3RTV62u9p7GVUQYWgz8N2tkbkfJ6LlVMdW0,3693
|
|
3
|
+
kaos_cli/main.py,sha256=UpirI5tN_jgSYSfeRTQZNKzuAqv0A45LqRMLoepAyJ4,2833
|
|
4
|
+
kaos_cli/proxy.py,sha256=wLfxxPGxvv9yHX2mQ-FoLiQIXVJSvb2WwgEsfRVr1Qo,3702
|
|
5
|
+
kaos_cli/ui.py,sha256=PRXjdV58V3XM0Cyb2OuRJKXJxPigsCDvyiB5J5XAyGU,1764
|
|
6
|
+
kaos_cli-0.0.1.dist-info/METADATA,sha256=8IAz5Fk4j93JKiBA-m5WD1AA2m0sRKYad5CQdzilNRc,1462
|
|
7
|
+
kaos_cli-0.0.1.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
8
|
+
kaos_cli-0.0.1.dist-info/entry_points.txt,sha256=UhLExeu2qKkwddNEEm0o5TKtVqOkcIEcrWqyyt_UVl4,43
|
|
9
|
+
kaos_cli-0.0.1.dist-info/top_level.txt,sha256=33XlAB5b22FEtftzn0QyWXr6f8TNyh-XBIoRcQp0NRA,9
|
|
10
|
+
kaos_cli-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kaos_cli
|