hac-client-cli 0.1.0__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.
@@ -0,0 +1,219 @@
1
+ """Environment management commands."""
2
+
3
+ import sys
4
+ import json
5
+ import typer
6
+ from typing import Optional
7
+ from rich.console import Console
8
+ from rich.table import Table
9
+
10
+ from hac_client_cli.environment_manager import EnvironmentManager
11
+
12
+ env_app = typer.Typer(help="Manage HAC environments", no_args_is_help=True)
13
+ console = Console()
14
+
15
+
16
+ @env_app.command("list")
17
+ def list_environments(
18
+ format: str = typer.Option("table", "--format", "-f", help="Output format: table, json"),
19
+ no_headers: bool = typer.Option(False, "--no-headers", help="Suppress column headers"),
20
+ quiet: bool = typer.Option(False, "--quiet", "-q", help="Minimal output (names only)")
21
+ ):
22
+ """List all configured environments."""
23
+ try:
24
+ manager = EnvironmentManager()
25
+ environments = manager.list_environments()
26
+ default = manager.get_default_environment()
27
+
28
+ if not environments:
29
+ if format != "json":
30
+ console.print("[yellow]No environments configured[/yellow]")
31
+ console.print("\nAdd an environment with endpoints:")
32
+ console.print(" hac env add local")
33
+ console.print(" hac endpoint add local hac --url https://localhost:9002")
34
+ else:
35
+ print("[]")
36
+ return
37
+
38
+ # JSON output
39
+ if format == "json":
40
+ output = [
41
+ {
42
+ "name": env.name,
43
+ "endpoints": {
44
+ ep_name: {
45
+ "url": ep.url,
46
+ "ignore_ssl": ep.ignore_ssl,
47
+ "timeout": ep.timeout
48
+ }
49
+ for ep_name, ep in env.endpoints.items()
50
+ },
51
+ "default_endpoint": env.default_endpoint,
52
+ "is_default": env.name == default
53
+ }
54
+ for env in environments
55
+ ]
56
+ print(json.dumps(output, indent=2))
57
+ return
58
+
59
+ # Quiet output (names only)
60
+ if quiet:
61
+ for env in environments:
62
+ print(env.name)
63
+ return
64
+
65
+ # Table format (default)
66
+ table = Table(show_header=not no_headers)
67
+ table.add_column("NAME", style="cyan")
68
+ table.add_column("ENDPOINTS", justify="right")
69
+ table.add_column("DEFAULT-ENDPOINT")
70
+ table.add_column("DEFAULT", justify="center")
71
+
72
+ for env in environments:
73
+ default_marker = "✓" if env.name == default else ""
74
+ endpoint_count = str(len(env.endpoints))
75
+ default_ep = env.default_endpoint or "-"
76
+
77
+ table.add_row(
78
+ env.name,
79
+ endpoint_count,
80
+ default_ep,
81
+ default_marker
82
+ )
83
+
84
+ console.print(table)
85
+
86
+ except Exception as e:
87
+ console.print(f"[red]ERROR: {e}[/red]", file=sys.stderr)
88
+ raise typer.Exit(1)
89
+
90
+
91
+ @env_app.command("show")
92
+ def show_environment(
93
+ name: str = typer.Argument(..., help="Environment name"),
94
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON")
95
+ ):
96
+ """Show details of a specific environment with all endpoints."""
97
+ try:
98
+ manager = EnvironmentManager()
99
+ env = manager.get_environment(name)
100
+
101
+ if not env:
102
+ print(f"ERROR: Environment '{name}' not found", file=sys.stderr)
103
+ raise typer.Exit(1)
104
+
105
+ default = manager.get_default_environment()
106
+
107
+ if json_output:
108
+ output = {
109
+ "name": env.name,
110
+ "endpoints": {
111
+ ep_name: {
112
+ "url": ep.url,
113
+ "username": ep.username,
114
+ "ignore_ssl": ep.ignore_ssl,
115
+ "timeout": ep.timeout
116
+ }
117
+ for ep_name, ep in env.endpoints.items()
118
+ },
119
+ "default_endpoint": env.default_endpoint,
120
+ "is_default": env.name == default
121
+ }
122
+ print(json.dumps(output, indent=2))
123
+ else:
124
+ marker = " (default)" if env.name == default else ""
125
+ print(f"Environment: {env.name}{marker}")
126
+ print()
127
+
128
+ if not env.endpoints:
129
+ print(" No endpoints configured")
130
+ print(f"\n Add an endpoint: hac endpoint add {env.name} hac --url https://...")
131
+ else:
132
+ print(f" Endpoints ({len(env.endpoints)}):")
133
+ print()
134
+ for ep_name, ep in sorted(env.endpoints.items()):
135
+ default_marker = " (default)" if ep_name == env.default_endpoint else ""
136
+ print(f" {ep_name}{default_marker}")
137
+ print(f" URL: {ep.url}")
138
+ print(f" Ignore SSL: {ep.ignore_ssl}")
139
+ print(f" Timeout: {ep.timeout}s")
140
+ print()
141
+
142
+ if env.default_endpoint:
143
+ print(f" Start session: hac session start {env.name} --username <user>")
144
+ else:
145
+ print(f" Start session: hac session start {env.name} --endpoint <endpoint-name> --username <user>")
146
+
147
+ except Exception as e:
148
+ print(f"ERROR: {e}", file=sys.stderr)
149
+ raise typer.Exit(1)
150
+
151
+
152
+ @env_app.command("add")
153
+ def add_environment(
154
+ name: str = typer.Argument(..., help="Environment name"),
155
+ set_default: bool = typer.Option(False, "--set-default", "-d", help="Set as default environment")
156
+ ):
157
+ """Add a new environment (add endpoints separately with 'hac endpoint add')."""
158
+ try:
159
+ manager = EnvironmentManager()
160
+ manager.add_environment(
161
+ name=name,
162
+ set_default=set_default
163
+ )
164
+
165
+ marker = " (set as default)" if set_default else ""
166
+ print(f"✓ Environment '{name}' added{marker}")
167
+ print(f"\nNext: Add endpoints to this environment")
168
+ print(f" hac endpoint add {name} <endpoint-name> --url https://...")
169
+
170
+ except ValueError as e:
171
+ print(f"ERROR: {e}", file=sys.stderr)
172
+ raise typer.Exit(1)
173
+ except Exception as e:
174
+ print(f"ERROR: {e}", file=sys.stderr)
175
+ raise typer.Exit(1)
176
+
177
+
178
+
179
+
180
+ @env_app.command("remove")
181
+ def remove_environment(
182
+ name: str = typer.Argument(..., help="Environment name")
183
+ ):
184
+ """Remove an environment."""
185
+ try:
186
+ manager = EnvironmentManager()
187
+
188
+ if not manager.get_environment(name):
189
+ print(f"ERROR: Environment '{name}' not found", file=sys.stderr)
190
+ raise typer.Exit(1)
191
+
192
+ manager.remove_environment(name)
193
+ print(f"✓ Environment '{name}' removed")
194
+
195
+ except ValueError as e:
196
+ print(f"ERROR: {e}", file=sys.stderr)
197
+ raise typer.Exit(1)
198
+ except Exception as e:
199
+ print(f"ERROR: {e}", file=sys.stderr)
200
+ raise typer.Exit(1)
201
+
202
+
203
+ @env_app.command("set-default")
204
+ def set_default(
205
+ name: str = typer.Argument(..., help="Environment name")
206
+ ):
207
+ """Set the default environment."""
208
+ try:
209
+ manager = EnvironmentManager()
210
+ manager.set_default_environment(name)
211
+ print(f"✓ Default environment set to '{name}'")
212
+
213
+ except ValueError as e:
214
+ print(f"ERROR: {e}", file=sys.stderr)
215
+ raise typer.Exit(1)
216
+ except Exception as e:
217
+ print(f"ERROR: {e}", file=sys.stderr)
218
+ raise typer.Exit(1)
219
+
@@ -0,0 +1,417 @@
1
+ """Session management commands."""
2
+
3
+ import sys
4
+ import json
5
+ import os
6
+ import typer
7
+ from typing import Optional
8
+ from datetime import timedelta
9
+ from rich.console import Console
10
+ from rich.table import Table
11
+
12
+ from hac_client_core.session import SessionManager
13
+ from hac_client_core.client import HacClient
14
+ from hac_client_core.auth import BasicAuthHandler
15
+
16
+ session_app = typer.Typer(help="Manage HAC sessions", no_args_is_help=True)
17
+ console = Console()
18
+
19
+
20
+ def format_duration(seconds: float) -> str:
21
+ """Format duration in human-readable format."""
22
+ if seconds < 60:
23
+ return f"{int(seconds)}s"
24
+ elif seconds < 3600:
25
+ return f"{int(seconds/60)}m {int(seconds%60)}s"
26
+ else:
27
+ hours = int(seconds / 3600)
28
+ minutes = int((seconds % 3600) / 60)
29
+ return f"{hours}h {minutes}m"
30
+
31
+
32
+ @session_app.command("start")
33
+ def start_session(
34
+ environment: str = typer.Argument(..., help="Environment name"),
35
+ endpoint: Optional[str] = typer.Option(None, "--endpoint", "-n", help="Endpoint name (uses default if not specified)"),
36
+ username: Optional[str] = typer.Option(None, "--username", "-u", help="Username (or use env var)"),
37
+ password: Optional[str] = typer.Option(None, "--password", "-p", help="Password (or use stdin/env var)")
38
+ ):
39
+ """Start a new HAC session (authenticate and create session).
40
+
41
+ Username can be provided via:
42
+ - Command option: --username <user>
43
+ - Environment variable: HAC_USERNAME or HAC_USERNAME_<ENV>_<ENDPOINT>
44
+ - Interactive prompt: if not provided
45
+
46
+ Password can be provided via:
47
+ - Command option: --password <pass> (not recommended)
48
+ - Environment variable: HAC_PASSWORD or HAC_PASSWORD_<ENV>_<ENDPOINT>
49
+ - Standard input: echo 'password' | hac session start <env> --username <user>
50
+ - Interactive prompt: if none of the above
51
+
52
+ Examples:
53
+ hac session start local --username admin
54
+ hac session start local --endpoint hac --username admin
55
+ HAC_USERNAME=admin HAC_PASSWORD=secret hac session start local
56
+ echo 'secret' | hac session start local --username admin
57
+ """
58
+ try:
59
+ from hac_client_cli.config_loader import get_endpoint_config
60
+
61
+ # Get endpoint configuration
62
+ env_name, endpoint_name, ep_config = get_endpoint_config(environment, endpoint)
63
+
64
+ # Create session identifier
65
+ session_id = f"{env_name}/{endpoint_name}"
66
+
67
+ # Get username from various sources
68
+ if not username:
69
+ # Try environment variable (specific to env/endpoint, then env, then generic)
70
+ env_ep_var = f"HAC_USERNAME_{env_name.upper()}_{endpoint_name.upper()}"
71
+ env_var = f"HAC_USERNAME_{env_name.upper()}"
72
+ username = os.environ.get(env_ep_var) or os.environ.get(env_var) or os.environ.get("HAC_USERNAME")
73
+
74
+ if not username:
75
+ print("ERROR: Username not provided", file=sys.stderr)
76
+ print("\nProvide username via:", file=sys.stderr)
77
+ print(f" --username <user>", file=sys.stderr)
78
+ print(f" HAC_USERNAME environment variable", file=sys.stderr)
79
+ print(f" HAC_USERNAME_{env_name.upper()}_{endpoint_name.upper()} environment variable", file=sys.stderr)
80
+ raise typer.Exit(1)
81
+
82
+ # Get password from various sources
83
+ if not password:
84
+ # Try environment variable (specific to env/endpoint, then env, then generic)
85
+ env_ep_var = f"HAC_PASSWORD_{env_name.upper()}_{endpoint_name.upper()}"
86
+ env_var = f"HAC_PASSWORD_{env_name.upper()}"
87
+ password = os.environ.get(env_ep_var) or os.environ.get(env_var) or os.environ.get("HAC_PASSWORD")
88
+
89
+ if not password:
90
+ # Try stdin (non-interactive)
91
+ if not sys.stdin.isatty():
92
+ password = sys.stdin.read().strip()
93
+
94
+ if not password:
95
+ print("ERROR: Password not provided", file=sys.stderr)
96
+ print("\nProvide password via:", file=sys.stderr)
97
+ print(f" HAC_PASSWORD environment variable", file=sys.stderr)
98
+ print(f" HAC_PASSWORD_{env_name.upper()}_{endpoint_name.upper()} environment variable", file=sys.stderr)
99
+ print(f" stdin: echo 'password' | hac session start {env_name} --endpoint {endpoint_name} --username {username}", file=sys.stderr)
100
+ raise typer.Exit(1)
101
+
102
+ try:
103
+ # Create client and authenticate
104
+ auth = BasicAuthHandler(username, password)
105
+ client = HacClient(
106
+ base_url=ep_config.url,
107
+ auth_handler=auth,
108
+ environment=session_id, # Use composite key
109
+ timeout=ep_config.timeout,
110
+ ignore_ssl=ep_config.ignore_ssl,
111
+ session_persistence=True,
112
+ quiet=False
113
+ )
114
+
115
+ # Force login to create session
116
+ client.login()
117
+
118
+ print(f"✓ Session started for '{session_id}'")
119
+ print(f" User: {username}")
120
+ print(f" URL: {ep_config.url}")
121
+
122
+ finally:
123
+ # Clear password from memory immediately
124
+ if password:
125
+ password = None
126
+ del password
127
+
128
+ except Exception as e:
129
+ print(f"ERROR: {e}", file=sys.stderr)
130
+ raise typer.Exit(1)
131
+
132
+
133
+ @session_app.command("import")
134
+ def import_session(
135
+ environment: str = typer.Argument(..., help="Environment name"),
136
+ endpoint: Optional[str] = typer.Option(None, "--endpoint", "-n", help="Endpoint name (uses default if not specified)"),
137
+ username: Optional[str] = typer.Option(None, "--username", "-u", help="Username (or use env var)"),
138
+ session_id: Optional[str] = typer.Option(None, "--session-id", help="Session ID (JSESSIONID)"),
139
+ csrf_token: Optional[str] = typer.Option(None, "--csrf-token", help="CSRF token"),
140
+ route_cookie: Optional[str] = typer.Option(None, "--route-cookie", help="ROUTE cookie (optional)")
141
+ ):
142
+ """Import an existing HAC session from tokens.
143
+
144
+ Username can be provided via:
145
+ - Command option: --username <user>
146
+ - Environment variable: HAC_USERNAME or HAC_USERNAME_<ENV>_<ENDPOINT>
147
+
148
+ Tokens can be provided via:
149
+ - Command options (not recommended for security)
150
+ - Environment variables:
151
+ - HAC_SESSION_ID or HAC_SESSION_ID_<ENV>_<ENDPOINT>
152
+ - HAC_CSRF_TOKEN or HAC_CSRF_TOKEN_<ENV>_<ENDPOINT>
153
+ - HAC_ROUTE_COOKIE or HAC_ROUTE_COOKIE_<ENV>_<ENDPOINT>
154
+ - Standard input (JSON format with username, session_id, csrf_token fields)
155
+
156
+ Examples:
157
+ # Via environment variables
158
+ HAC_USERNAME=admin HAC_SESSION_ID=abc123 HAC_CSRF_TOKEN=def456 hac session import local
159
+
160
+ # Via stdin (JSON)
161
+ echo '{"username":"admin","session_id":"abc","csrf_token":"def"}' | hac session import local --endpoint hac
162
+
163
+ # Via command options
164
+ hac session import local --endpoint hac --username admin --session-id abc123 --csrf-token def456
165
+ """
166
+ try:
167
+ from hac_client_cli.config_loader import get_endpoint_config
168
+
169
+ # Get endpoint configuration
170
+ env_name, endpoint_name, ep_config = get_endpoint_config(environment, endpoint)
171
+
172
+ # Create session identifier
173
+ sess_id = f"{env_name}/{endpoint_name}"
174
+
175
+ # Get username from various sources
176
+ if not username:
177
+ # Try environment variables
178
+ env_ep_var = f"HAC_USERNAME_{env_name.upper()}_{endpoint_name.upper()}"
179
+ env_var = f"HAC_USERNAME_{env_name.upper()}"
180
+ username = os.environ.get(env_ep_var) or os.environ.get(env_var) or os.environ.get("HAC_USERNAME")
181
+
182
+ # Get tokens from various sources
183
+ if not session_id or not csrf_token or not username:
184
+ # Try stdin (JSON)
185
+ if not sys.stdin.isatty():
186
+ import json
187
+ data = json.load(sys.stdin)
188
+ username = username or data.get("username")
189
+ session_id = session_id or data.get("session_id")
190
+ csrf_token = csrf_token or data.get("csrf_token")
191
+ route_cookie = route_cookie or data.get("route_cookie")
192
+
193
+ if not session_id or not csrf_token:
194
+ # Try environment variables
195
+ env_ep_prefix = f"{env_name.upper()}_{endpoint_name.upper()}"
196
+ env_prefix = env_name.upper()
197
+ session_id = session_id or os.environ.get(f"HAC_SESSION_ID_{env_ep_prefix}") or os.environ.get(f"HAC_SESSION_ID_{env_prefix}") or os.environ.get("HAC_SESSION_ID")
198
+ csrf_token = csrf_token or os.environ.get(f"HAC_CSRF_TOKEN_{env_ep_prefix}") or os.environ.get(f"HAC_CSRF_TOKEN_{env_prefix}") or os.environ.get("HAC_CSRF_TOKEN")
199
+ route_cookie = route_cookie or os.environ.get(f"HAC_ROUTE_COOKIE_{env_ep_prefix}") or os.environ.get(f"HAC_ROUTE_COOKIE_{env_prefix}") or os.environ.get("HAC_ROUTE_COOKIE")
200
+
201
+ if not username:
202
+ print("ERROR: Username not provided", file=sys.stderr)
203
+ print("Provide via --username, HAC_USERNAME env var, or stdin (JSON)", file=sys.stderr)
204
+ raise typer.Exit(1)
205
+
206
+ if not session_id:
207
+ print("ERROR: Session ID not provided", file=sys.stderr)
208
+ print("Provide via --session-id, HAC_SESSION_ID env var, or stdin (JSON)", file=sys.stderr)
209
+ raise typer.Exit(1)
210
+
211
+ if not csrf_token:
212
+ print("ERROR: CSRF token not provided", file=sys.stderr)
213
+ print("Provide via --csrf-token, HAC_CSRF_TOKEN env var, or stdin (JSON)", file=sys.stderr)
214
+ raise typer.Exit(1)
215
+
216
+ # Import session
217
+ session_manager = SessionManager()
218
+ session_manager.save_session(
219
+ base_url=ep_config.url,
220
+ username=username,
221
+ environment=sess_id, # Use composite key
222
+ session_id=session_id,
223
+ csrf_token=csrf_token,
224
+ route_cookie=route_cookie
225
+ )
226
+
227
+ print(f"✓ Session imported for '{sess_id}'")
228
+ print(f" User: {username}")
229
+ print(f" URL: {ep_config.url}")
230
+ print(f" Session ID: {session_id[:16]}...")
231
+
232
+ except Exception as e:
233
+ print(f"ERROR: {e}", file=sys.stderr)
234
+ raise typer.Exit(1)
235
+
236
+
237
+ @session_app.command("list")
238
+ def list_sessions(
239
+ format: str = typer.Option("table", "--format", "-f", help="Output format: table, json"),
240
+ no_headers: bool = typer.Option(False, "--no-headers", help="Suppress column headers"),
241
+ quiet: bool = typer.Option(False, "--quiet", "-q", help="Minimal output (environment IDs only)")
242
+ ):
243
+ """List all active sessions."""
244
+ try:
245
+ manager = SessionManager()
246
+ sessions = manager.list_sessions()
247
+
248
+ if not sessions:
249
+ if format != "json":
250
+ console.print("[yellow]No active sessions[/yellow]")
251
+ console.print("\nCreate a session: hac session start <environment> --username <user>")
252
+ else:
253
+ print("[]")
254
+ return
255
+
256
+ # JSON output
257
+ if format == "json":
258
+ output = [
259
+ {
260
+ "environment": s.environment,
261
+ "url": s.base_url,
262
+ "username": s.username,
263
+ "session_id": s.session_id[:16] + "...",
264
+ "created_at": s.created_at_formatted,
265
+ "last_used_at": s.last_used_at_formatted,
266
+ "age_seconds": s.age_seconds,
267
+ "idle_seconds": s.idle_seconds,
268
+ "is_authenticated": s.is_authenticated
269
+ }
270
+ for s in sessions
271
+ ]
272
+ print(json.dumps(output, indent=2))
273
+ return
274
+
275
+ # Quiet output (environment IDs only)
276
+ if quiet:
277
+ for s in sessions:
278
+ print(s.environment)
279
+ return
280
+
281
+ # Table format (default)
282
+ table = Table(show_header=not no_headers)
283
+ table.add_column("ENVIRONMENT", style="cyan")
284
+ table.add_column("USERNAME")
285
+ table.add_column("URL")
286
+ table.add_column("AUTH", justify="center")
287
+ table.add_column("AGE", justify="right")
288
+ table.add_column("IDLE", justify="right")
289
+
290
+ for s in sessions:
291
+ age = format_duration(s.age_seconds)
292
+ idle = format_duration(s.idle_seconds)
293
+ auth_marker = "[green]✓[/green]" if s.is_authenticated else "[red]✗[/red]"
294
+
295
+ table.add_row(
296
+ s.environment,
297
+ s.username,
298
+ s.base_url,
299
+ auth_marker,
300
+ age,
301
+ idle
302
+ )
303
+
304
+ console.print(table)
305
+
306
+ except Exception as e:
307
+ console.print(f"[red]ERROR: {e}[/red]", file=sys.stderr)
308
+ raise typer.Exit(1)
309
+
310
+
311
+ @session_app.command("show")
312
+ def show_session(
313
+ environment: str = typer.Argument(..., help="Environment name"),
314
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON")
315
+ ):
316
+ """Show details of a specific session."""
317
+ try:
318
+ from hac_client_cli.environment_manager import EnvironmentManager
319
+
320
+ env_manager = EnvironmentManager()
321
+ env = env_manager.get_environment(environment)
322
+
323
+ if not env:
324
+ print(f"ERROR: Environment '{environment}' not found", file=sys.stderr)
325
+ raise typer.Exit(1)
326
+
327
+ session_manager = SessionManager()
328
+ session = session_manager.load_session(env.url, env.username, environment)
329
+
330
+ if not session:
331
+ print(f"No active session for environment '{environment}'")
332
+ return
333
+
334
+ if json_output:
335
+ output = {
336
+ "environment": session.environment,
337
+ "url": session.base_url,
338
+ "username": session.username,
339
+ "session_id": session.session_id,
340
+ "csrf_token": session.csrf_token[:16] + "...",
341
+ "route_cookie": session.route_cookie,
342
+ "created_at": session.created_at_formatted,
343
+ "last_used_at": session.last_used_at_formatted,
344
+ "age_seconds": session.age_seconds,
345
+ "idle_seconds": session.idle_seconds,
346
+ "is_authenticated": session.is_authenticated
347
+ }
348
+ print(json.dumps(output, indent=2))
349
+ else:
350
+ age = format_duration(session.age_seconds)
351
+ idle = format_duration(session.idle_seconds)
352
+ auth_marker = "✓ authenticated" if session.is_authenticated else "✗ not authenticated"
353
+
354
+ print(f"Session: {session.environment}")
355
+ print(f" URL: {session.base_url}")
356
+ print(f" Username: {session.username}")
357
+ print(f" Status: {auth_marker}")
358
+ print(f" Session ID: {session.session_id}")
359
+ print(f" CSRF Token: {session.csrf_token[:32]}...")
360
+ if session.route_cookie:
361
+ print(f" Route Cookie: {session.route_cookie}")
362
+ print(f"\n Created: {session.created_at_formatted}")
363
+ print(f" Last used: {session.last_used_at_formatted}")
364
+ print(f" Age: {age}")
365
+ print(f" Idle: {idle}")
366
+
367
+ except Exception as e:
368
+ print(f"ERROR: {e}", file=sys.stderr)
369
+ raise typer.Exit(1)
370
+
371
+
372
+ @session_app.command("clear")
373
+ def clear_session(
374
+ environment: str = typer.Argument(..., help="Environment name")
375
+ ):
376
+ """Clear session for a specific environment."""
377
+ try:
378
+ from hac_client_cli.environment_manager import EnvironmentManager
379
+
380
+ env_manager = EnvironmentManager()
381
+ env = env_manager.get_environment(environment)
382
+
383
+ if not env:
384
+ print(f"ERROR: Environment '{environment}' not found", file=sys.stderr)
385
+ raise typer.Exit(1)
386
+
387
+ session_manager = SessionManager()
388
+ session_manager.remove_session(env.url, env.username, environment)
389
+
390
+ print(f"✓ Session cleared for environment '{environment}'")
391
+
392
+ except Exception as e:
393
+ print(f"ERROR: {e}", file=sys.stderr)
394
+ raise typer.Exit(1)
395
+
396
+
397
+ @session_app.command("clear-all")
398
+ def clear_all_sessions(
399
+ force: bool = typer.Option(False, "--force", "-f", help="Force without confirmation")
400
+ ):
401
+ """Clear all sessions."""
402
+ try:
403
+ if not force:
404
+ confirm = typer.confirm("Clear all sessions?")
405
+ if not confirm:
406
+ print("Cancelled")
407
+ return
408
+
409
+ session_manager = SessionManager()
410
+ count = session_manager.clear_all_sessions()
411
+
412
+ print(f"✓ Cleared {count} session(s)")
413
+
414
+ except Exception as e:
415
+ print(f"ERROR: {e}", file=sys.stderr)
416
+ raise typer.Exit(1)
417
+