proxima-cli 1.0.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,35 @@
1
+ # Synthetic data (generated, ~1.3GB)
2
+ agents/supply-chain/demand-forecasting/data/synthetic/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.pyc
7
+ *.pyo
8
+ .venv/
9
+ venv/
10
+ env/
11
+ *.egg-info/
12
+
13
+ # Environment
14
+ .env
15
+ .env.local
16
+
17
+ # IDE
18
+ .vscode/
19
+ .idea/
20
+ *.swp
21
+
22
+ # OS
23
+ .DS_Store
24
+ Thumbs.db
25
+
26
+ # Original reference docs (large PDFs, keep .md conversions only)
27
+ docs/reference/daimler/*.pdf
28
+ docs/reference/daimler/*.pptx
29
+ docs/reference/daimler/*.docx
30
+ docs/reference/daimler/*.msg
31
+ docs/reference/daimler/*.xlsx
32
+ docs/reference/daimler/*.zip
33
+ docs/reference/daimler/SAP Proposal - Supply Chain RFP/*.pdf
34
+ docs/reference/daimler/SAP Proposal - Supply Chain RFP/*.xlsx
35
+ platform/data/secrets.json
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.4
2
+ Name: proxima-cli
3
+ Version: 1.0.0
4
+ Summary: Proxima AIP CLI — manage your Proxima Intelligence platform
5
+ Project-URL: Homepage, https://proximaintel.com/aip
6
+ Project-URL: Documentation, https://docs.proximaintel.com/cli
7
+ Project-URL: Repository, https://github.com/proximaintel/proxima-cli
8
+ Author-email: Proxima Intelligence <hello@proximaintel.com>
9
+ License-Expression: MIT
10
+ Keywords: agents,ai,cli,platform,proxima
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: httpx>=0.27
18
+ Requires-Dist: pyyaml>=6
19
+ Requires-Dist: rich>=13
20
+ Requires-Dist: typer[all]>=0.12
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Proxima CLI
24
+
25
+ The official command-line interface for **Proxima AIP** — manage your AI agent platform from the terminal.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pipx install proxima-cli
31
+ # or
32
+ pip install proxima-cli
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ```bash
38
+ # Login (opens browser for SSO)
39
+ prox login
40
+
41
+ # Check connection
42
+ prox whoami
43
+
44
+ # List agents
45
+ prox agent list
46
+
47
+ # Create a domain
48
+ prox domain create --id finance --name "Finance"
49
+
50
+ # Deploy an agent from a package
51
+ prox agent deploy --from ./my-agent/
52
+ ```
53
+
54
+ ## Configuration
55
+
56
+ ```bash
57
+ # Set your platform gateway URL
58
+ prox config set gateway https://gateway.your-platform.com
59
+
60
+ # Set catalog (for pulling pre-built agents)
61
+ prox config set catalog https://catalog.proximaintel.com
62
+
63
+ # View config
64
+ prox config list
65
+ ```
66
+
67
+ ## Commands
68
+
69
+ | Command Group | Description |
70
+ |---|---|
71
+ | `prox login / logout / whoami` | Authentication |
72
+ | `prox config` | Environment configuration |
73
+ | `prox catalog` | Browse and pull agents from Proxima Catalog |
74
+ | `prox agent` | Create, configure, deploy, publish agents |
75
+ | `prox toolbox` | Build and register toolboxes |
76
+ | `prox knowledge` | Manage data sources and knowledge bases |
77
+ | `prox secret` | Manage credentials |
78
+ | `prox model` | Register LLM providers |
79
+ | `prox ontology` | Manage entity models |
80
+ | `prox routine` | Schedule autonomous agent execution |
81
+ | `prox workflow` | Multi-agent orchestration pipelines |
82
+ | `prox governance` | Audit logs and usage stats |
83
+ | `prox platform` | Health checks and service management |
84
+
85
+ ## Agent Deployment
86
+
87
+ ```bash
88
+ prox agent deploy --from ./my-agent/
89
+ ```
90
+
91
+ Expects:
92
+ ```
93
+ my-agent/
94
+ ├── agent.yaml # Agent config
95
+ ├── toolbox/ # Optional: custom tools
96
+ │ ├── tools.py
97
+ │ ├── Dockerfile
98
+ │ └── requirements.txt
99
+ ├── knowledge.yaml # Data source requirements
100
+ └── workspace.json # Dashboard layout
101
+ ```
102
+
103
+ One command. Full agent. Production-ready.
104
+
105
+ ## CI/CD
106
+
107
+ ```bash
108
+ prox login --api-key $PLATFORM_API_KEY
109
+ prox config set gateway $GATEWAY_URL
110
+ prox agent deploy --from ./agents/my-agent/
111
+ ```
112
+
113
+ ## Documentation
114
+
115
+ Full docs at [docs.proximaintel.com/cli](https://docs.proximaintel.com/cli)
@@ -0,0 +1,93 @@
1
+ # Proxima CLI
2
+
3
+ The official command-line interface for **Proxima AIP** — manage your AI agent platform from the terminal.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pipx install proxima-cli
9
+ # or
10
+ pip install proxima-cli
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Login (opens browser for SSO)
17
+ prox login
18
+
19
+ # Check connection
20
+ prox whoami
21
+
22
+ # List agents
23
+ prox agent list
24
+
25
+ # Create a domain
26
+ prox domain create --id finance --name "Finance"
27
+
28
+ # Deploy an agent from a package
29
+ prox agent deploy --from ./my-agent/
30
+ ```
31
+
32
+ ## Configuration
33
+
34
+ ```bash
35
+ # Set your platform gateway URL
36
+ prox config set gateway https://gateway.your-platform.com
37
+
38
+ # Set catalog (for pulling pre-built agents)
39
+ prox config set catalog https://catalog.proximaintel.com
40
+
41
+ # View config
42
+ prox config list
43
+ ```
44
+
45
+ ## Commands
46
+
47
+ | Command Group | Description |
48
+ |---|---|
49
+ | `prox login / logout / whoami` | Authentication |
50
+ | `prox config` | Environment configuration |
51
+ | `prox catalog` | Browse and pull agents from Proxima Catalog |
52
+ | `prox agent` | Create, configure, deploy, publish agents |
53
+ | `prox toolbox` | Build and register toolboxes |
54
+ | `prox knowledge` | Manage data sources and knowledge bases |
55
+ | `prox secret` | Manage credentials |
56
+ | `prox model` | Register LLM providers |
57
+ | `prox ontology` | Manage entity models |
58
+ | `prox routine` | Schedule autonomous agent execution |
59
+ | `prox workflow` | Multi-agent orchestration pipelines |
60
+ | `prox governance` | Audit logs and usage stats |
61
+ | `prox platform` | Health checks and service management |
62
+
63
+ ## Agent Deployment
64
+
65
+ ```bash
66
+ prox agent deploy --from ./my-agent/
67
+ ```
68
+
69
+ Expects:
70
+ ```
71
+ my-agent/
72
+ ├── agent.yaml # Agent config
73
+ ├── toolbox/ # Optional: custom tools
74
+ │ ├── tools.py
75
+ │ ├── Dockerfile
76
+ │ └── requirements.txt
77
+ ├── knowledge.yaml # Data source requirements
78
+ └── workspace.json # Dashboard layout
79
+ ```
80
+
81
+ One command. Full agent. Production-ready.
82
+
83
+ ## CI/CD
84
+
85
+ ```bash
86
+ prox login --api-key $PLATFORM_API_KEY
87
+ prox config set gateway $GATEWAY_URL
88
+ prox agent deploy --from ./agents/my-agent/
89
+ ```
90
+
91
+ ## Documentation
92
+
93
+ Full docs at [docs.proximaintel.com/cli](https://docs.proximaintel.com/cli)
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "proxima-cli"
7
+ version = "1.0.0"
8
+ description = "Proxima AIP CLI — manage your Proxima Intelligence platform"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ { name = "Proxima Intelligence", email = "hello@proximaintel.com" },
14
+ ]
15
+ keywords = ["ai", "agents", "platform", "cli", "proxima"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ ]
23
+ dependencies = [
24
+ "typer[all]>=0.12",
25
+ "httpx>=0.27",
26
+ "rich>=13",
27
+ "pyyaml>=6",
28
+ ]
29
+
30
+ [project.scripts]
31
+ prox = "prox.cli:app"
32
+
33
+ [project.urls]
34
+ Homepage = "https://proximaintel.com/aip"
35
+ Documentation = "https://docs.proximaintel.com/cli"
36
+ Repository = "https://github.com/proximaintel/proxima-cli"
37
+
38
+ [tool.hatch.build.targets.wheel]
39
+ packages = ["src/prox"]
@@ -0,0 +1,3 @@
1
+ """Proxima Intelligence Platform CLI."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,107 @@
1
+ """HTTP client for gateway and catalog APIs."""
2
+
3
+ import httpx
4
+ from typing import Optional
5
+ from . import config
6
+
7
+
8
+ class APIError(Exception):
9
+ def __init__(self, status: int, detail: str):
10
+ self.status = status
11
+ self.detail = detail
12
+ super().__init__(f"[{status}] {detail}")
13
+
14
+
15
+ def _gateway_url() -> str:
16
+ url = config.get_value("gateway")
17
+ if not url:
18
+ raise APIError(0, "Gateway URL not configured. Run: prox config set gateway <url>")
19
+ return url.rstrip("/")
20
+
21
+
22
+ def _catalog_url() -> str:
23
+ url = config.get_value("catalog") or "https://catalog.proximaintel.com"
24
+ return url.rstrip("/")
25
+
26
+
27
+ def _headers() -> dict:
28
+ headers = {"Content-Type": "application/json"}
29
+ token = config.get_token()
30
+ if token:
31
+ headers["Authorization"] = f"Bearer {token}"
32
+ return headers
33
+
34
+
35
+ def _catalog_headers() -> dict:
36
+ headers = {"Content-Type": "application/json"}
37
+ master = config.get_master_key()
38
+ if master:
39
+ headers["X-Master-Key"] = master
40
+ else:
41
+ lic = config.get_license_key()
42
+ if lic:
43
+ headers["X-License-Key"] = lic
44
+ return headers
45
+
46
+
47
+ # --- Gateway calls ---
48
+
49
+ def gateway_get(path: str, params: Optional[dict] = None) -> dict:
50
+ url = f"{_gateway_url()}{path}"
51
+ r = httpx.get(url, headers=_headers(), params=params, timeout=30, verify=False)
52
+ if r.status_code >= 400:
53
+ raise APIError(r.status_code, r.text[:500])
54
+ return r.json()
55
+
56
+
57
+ def gateway_post(path: str, data: Optional[dict] = None) -> dict:
58
+ url = f"{_gateway_url()}{path}"
59
+ r = httpx.post(url, headers=_headers(), json=data, timeout=60, verify=False)
60
+ if r.status_code >= 400:
61
+ raise APIError(r.status_code, r.text[:500])
62
+ return r.json()
63
+
64
+
65
+ def gateway_put(path: str, data: Optional[dict] = None) -> dict:
66
+ url = f"{_gateway_url()}{path}"
67
+ r = httpx.put(url, headers=_headers(), json=data, timeout=60, verify=False)
68
+ if r.status_code >= 400:
69
+ raise APIError(r.status_code, r.text[:500])
70
+ return r.json()
71
+
72
+
73
+ def gateway_delete(path: str) -> dict:
74
+ url = f"{_gateway_url()}{path}"
75
+ r = httpx.delete(url, headers=_headers(), timeout=30, verify=False)
76
+ if r.status_code >= 400:
77
+ raise APIError(r.status_code, r.text[:500])
78
+ return r.json()
79
+
80
+
81
+ # --- Catalog calls ---
82
+
83
+ def catalog_get(path: str, params: Optional[dict] = None) -> dict:
84
+ url = f"{_catalog_url()}{path}"
85
+ r = httpx.get(url, headers=_catalog_headers(), params=params, timeout=30)
86
+ if r.status_code >= 400:
87
+ raise APIError(r.status_code, r.text[:500])
88
+ return r.json()
89
+
90
+
91
+ def catalog_post(path: str, data: Optional[dict] = None) -> dict:
92
+ url = f"{_catalog_url()}{path}"
93
+ r = httpx.post(url, headers=_catalog_headers(), json=data, timeout=60)
94
+ if r.status_code >= 400:
95
+ raise APIError(r.status_code, r.text[:500])
96
+ return r.json()
97
+
98
+
99
+ def catalog_download(path: str, dest: str):
100
+ """Download a file from the catalog to a local path."""
101
+ url = f"{_catalog_url()}{path}"
102
+ with httpx.stream("GET", url, headers=_catalog_headers(), timeout=120) as r:
103
+ if r.status_code >= 400:
104
+ raise APIError(r.status_code, f"Download failed: {r.status_code}")
105
+ with open(dest, "wb") as f:
106
+ for chunk in r.iter_bytes(chunk_size=8192):
107
+ f.write(chunk)
@@ -0,0 +1,157 @@
1
+ """Authentication — login, logout, token management."""
2
+
3
+ import http.server
4
+ import json
5
+ import threading
6
+ import time
7
+ import urllib.parse
8
+ import webbrowser
9
+ from typing import Optional
10
+
11
+ from . import config
12
+ from .api import gateway_get
13
+
14
+
15
+ def login_sso():
16
+ """Open browser for SSO login, capture token via local callback server."""
17
+ # Get auth config from gateway
18
+ gateway = config.get_value("gateway")
19
+ if not gateway:
20
+ raise RuntimeError("Gateway not configured. Run: prox config set gateway <url>")
21
+
22
+ try:
23
+ auth_config = gateway_get("/auth/config")
24
+ except Exception as e:
25
+ raise RuntimeError(f"Cannot reach gateway: {e}")
26
+
27
+ if not auth_config.get("enabled"):
28
+ raise RuntimeError("SSO not enabled on this gateway (dev mode). Use --api-key instead.")
29
+
30
+ authority = auth_config.get("authority", "")
31
+ client_id = auth_config.get("client_id", "")
32
+ scopes = auth_config.get("scopes", "openid profile email")
33
+
34
+ if not authority or not client_id:
35
+ raise RuntimeError("Gateway auth config missing authority or client_id")
36
+
37
+ # Start local server to receive the callback
38
+ token_result = {"token": None}
39
+ port = 8399
40
+ redirect_uri = f"http://localhost:{port}/callback"
41
+
42
+ class CallbackHandler(http.server.BaseHTTPRequestHandler):
43
+ def do_GET(self):
44
+ parsed = urllib.parse.urlparse(self.path)
45
+ if parsed.path == "/callback":
46
+ # Token comes in fragment (implicit) — serve a page that sends it back
47
+ self.send_response(200)
48
+ self.send_header("Content-Type", "text/html; charset=utf-8")
49
+ self.end_headers()
50
+ html = """
51
+ <html><head><meta charset="utf-8"></head><body><script>
52
+ const hash = window.location.hash.substring(1);
53
+ const params = new URLSearchParams(hash);
54
+ const token = params.get('access_token');
55
+ if (token) {
56
+ fetch('/token?t=' + token).then(() => {
57
+ document.body.innerHTML = '<h2>Authenticated. You can close this tab.</h2>';
58
+ });
59
+ } else {
60
+ document.body.innerHTML = '<h2>No token received.</h2>';
61
+ }
62
+ </script><p>Authenticating...</p></body></html>
63
+ """
64
+ self.wfile.write(html.encode("utf-8"))
65
+ elif parsed.path == "/token":
66
+ qs = urllib.parse.parse_qs(parsed.query)
67
+ token_result["token"] = qs.get("t", [None])[0]
68
+ self.send_response(200)
69
+ self.end_headers()
70
+ self.wfile.write(b"ok")
71
+ else:
72
+ self.send_response(404)
73
+ self.end_headers()
74
+
75
+ def log_message(self, format, *args):
76
+ pass # Suppress server logs
77
+
78
+ server = http.server.HTTPServer(("localhost", port), CallbackHandler)
79
+ thread = threading.Thread(target=server.handle_request) # Handle callback page
80
+ thread.daemon = True
81
+ thread.start()
82
+
83
+ # Also need to handle the /token request
84
+ thread2 = threading.Thread(target=server.handle_request)
85
+ thread2.daemon = True
86
+ thread2.start()
87
+
88
+ # Build auth URL (implicit grant)
89
+ auth_url = (
90
+ f"{authority}/oauth2/v2.0/authorize?"
91
+ f"client_id={client_id}"
92
+ f"&response_type=token"
93
+ f"&redirect_uri={urllib.parse.quote(redirect_uri)}"
94
+ f"&scope={urllib.parse.quote(scopes)}"
95
+ f"&response_mode=fragment"
96
+ )
97
+
98
+ webbrowser.open(auth_url)
99
+
100
+ # Wait for token (timeout 120s)
101
+ deadline = time.time() + 120
102
+ while not token_result["token"] and time.time() < deadline:
103
+ time.sleep(0.5)
104
+
105
+ server.server_close()
106
+
107
+ if not token_result["token"]:
108
+ raise RuntimeError("Login timed out. No token received within 120 seconds.")
109
+
110
+ # Store token
111
+ creds = config.load_credentials()
112
+ creds["token"] = token_result["token"]
113
+ creds["method"] = "sso"
114
+ creds["authenticated_at"] = time.time()
115
+ config.save_credentials(creds)
116
+ return token_result["token"]
117
+
118
+
119
+ def login_api_key(api_key: str):
120
+ """Login with a platform API key."""
121
+ creds = config.load_credentials()
122
+ creds["token"] = api_key
123
+ creds["method"] = "api_key"
124
+ config.save_credentials(creds)
125
+
126
+
127
+ def login_license_key(license_key: str):
128
+ """Store catalog license key."""
129
+ creds = config.load_credentials()
130
+ creds["license_key"] = license_key
131
+ config.save_credentials(creds)
132
+
133
+
134
+ def login_master_key(master_key: str):
135
+ """Store catalog master key (Proxima team only)."""
136
+ creds = config.load_credentials()
137
+ creds["master_key"] = master_key
138
+ config.save_credentials(creds)
139
+
140
+
141
+ def logout():
142
+ """Clear all stored credentials."""
143
+ config.save_credentials({})
144
+
145
+
146
+ def whoami() -> dict:
147
+ """Get current auth state."""
148
+ creds = config.load_credentials()
149
+ return {
150
+ "authenticated": bool(creds.get("token") or creds.get("master_key")),
151
+ "method": creds.get("method", "none"),
152
+ "has_license_key": bool(creds.get("license_key")),
153
+ "has_master_key": bool(creds.get("master_key")),
154
+ "environment": config.current_environment(),
155
+ "gateway": config.get_value("gateway"),
156
+ "catalog": config.get_value("catalog"),
157
+ }
@@ -0,0 +1,121 @@
1
+ """Proxima Platform CLI — entry point."""
2
+
3
+ import typer
4
+ from rich.console import Console
5
+
6
+ from . import __version__, auth, config
7
+ from .commands import catalog, agent, toolbox, knowledge, secret, model, routine, workflow, governance, platform, ontology, team
8
+
9
+ app = typer.Typer(
10
+ name="prox",
11
+ help="Proxima Intelligence Platform CLI",
12
+ no_args_is_help=True,
13
+ pretty_exceptions_enable=False,
14
+ )
15
+ console = Console()
16
+
17
+ # --- Command groups ---
18
+ app.add_typer(catalog.app, name="catalog")
19
+ app.add_typer(agent.app, name="agent")
20
+ app.add_typer(toolbox.app, name="toolbox")
21
+ app.add_typer(knowledge.app, name="knowledge")
22
+ app.add_typer(ontology.app, name="ontology")
23
+ app.add_typer(secret.app, name="secret")
24
+ app.add_typer(model.app, name="model")
25
+ app.add_typer(routine.app, name="routine")
26
+ app.add_typer(workflow.app, name="workflow")
27
+ app.add_typer(governance.app, name="governance")
28
+ app.add_typer(platform.app, name="platform")
29
+ app.add_typer(team.app, name="team")
30
+
31
+
32
+ # --- Top-level commands ---
33
+
34
+ @app.command()
35
+ def login(
36
+ api_key: str = typer.Option(None, "--api-key", help="Platform API key"),
37
+ license_key: str = typer.Option(None, "--license-key", help="Catalog license key"),
38
+ master_key: str = typer.Option(None, "--master-key", help="Catalog master key (Proxima only)"),
39
+ ):
40
+ """Authenticate with the platform and/or catalog.
41
+
42
+ With no flags: opens browser for SSO login.
43
+ """
44
+ if not api_key and not license_key and not master_key:
45
+ # SSO flow
46
+ console.print("Opening browser for SSO login...")
47
+ try:
48
+ auth.login_sso()
49
+ console.print("[green]✓[/green] Authenticated via SSO")
50
+ except RuntimeError as e:
51
+ console.print(f"[red]Error:[/red] {e}")
52
+ raise typer.Exit(1)
53
+ return
54
+ if api_key:
55
+ auth.login_api_key(api_key)
56
+ console.print("[green]✓[/green] Platform API key stored")
57
+ if license_key:
58
+ auth.login_license_key(license_key)
59
+ console.print("[green]✓[/green] Catalog license key stored")
60
+ if master_key:
61
+ auth.login_master_key(master_key)
62
+ console.print("[green]✓[/green] Catalog master key stored")
63
+
64
+
65
+ @app.command()
66
+ def logout():
67
+ """Clear all stored credentials."""
68
+ auth.logout()
69
+ console.print("[green]✓[/green] Logged out")
70
+
71
+
72
+ @app.command()
73
+ def whoami():
74
+ """Show current authentication state."""
75
+ info = auth.whoami()
76
+ console.print(f"\n Environment: [bold]{info['environment']}[/bold]")
77
+ console.print(f" Gateway: {info['gateway'] or '[dim]not set[/dim]'}")
78
+ console.print(f" Catalog: {info['catalog'] or '[dim]not set[/dim]'}")
79
+ console.print(f" Auth: {'[green]authenticated[/green]' if info['authenticated'] else '[yellow]not authenticated[/yellow]'} ({info['method']})")
80
+ console.print(f" License key: {'[green]✓[/green]' if info['has_license_key'] else '[dim]—[/dim]'}")
81
+ console.print(f" Master key: {'[green]✓[/green]' if info['has_master_key'] else '[dim]—[/dim]'}")
82
+ console.print()
83
+
84
+
85
+ # --- Config commands ---
86
+
87
+ config_app = typer.Typer(help="Manage CLI configuration.")
88
+ app.add_typer(config_app, name="config")
89
+
90
+
91
+ @config_app.command("set")
92
+ def config_set(key: str = typer.Argument(help="Config key"), value: str = typer.Argument(help="Config value")):
93
+ """Set a configuration value for the current environment."""
94
+ config.set_value(key, value)
95
+ console.print(f"[green]✓[/green] {key} = {value} (env: {config.current_environment()})")
96
+
97
+
98
+ @config_app.command("list")
99
+ def config_list():
100
+ """Show current configuration."""
101
+ env = config.current_environment()
102
+ env_config = config.get_env_config()
103
+ console.print(f"\n [bold]Environment:[/bold] {env}\n")
104
+ for k, v in env_config.items():
105
+ console.print(f" {k}: {v or '[dim]not set[/dim]'}")
106
+ console.print()
107
+
108
+
109
+ @config_app.command("use")
110
+ def config_use(environment: str = typer.Argument(help="Environment name")):
111
+ """Switch to a different environment."""
112
+ config.use_environment(environment)
113
+ console.print(f"[green]✓[/green] Switched to: {environment}")
114
+
115
+
116
+ # --- Version ---
117
+
118
+ @app.command()
119
+ def version():
120
+ """Show CLI version."""
121
+ console.print(f"prox {__version__}")
File without changes