hanzo 0.3.24__tar.gz → 0.3.25__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.
Potentially problematic release.
This version of hanzo might be problematic. Click here for more details.
- {hanzo-0.3.24 → hanzo-0.3.25}/PKG-INFO +1 -1
- {hanzo-0.3.24 → hanzo-0.3.25}/pyproject.toml +1 -1
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/__init__.py +2 -2
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/cli.py +13 -5
- hanzo-0.3.25/src/hanzo/commands/auth.py +268 -0
- hanzo-0.3.24/src/hanzo/commands/auth.py → hanzo-0.3.25/src/hanzo/commands/auth_broken.py +80 -31
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/chat.py +3 -0
- hanzo-0.3.25/src/hanzo/interactive/enhanced_repl.py +513 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/interactive/repl.py +2 -2
- hanzo-0.3.25/src/hanzo/ui/__init__.py +13 -0
- hanzo-0.3.25/src/hanzo/ui/inline_startup.py +136 -0
- hanzo-0.3.25/src/hanzo/ui/startup.py +350 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/.gitignore +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/README.md +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/__main__.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/base_agent.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/batch_orchestrator.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/__init__.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/agent.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/config.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/mcp.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/miner.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/network.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/node.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/repl.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/router.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/commands/tools.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/dev.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/fallback_handler.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/interactive/__init__.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/interactive/dashboard.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/mcp_server.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/memory_manager.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/model_registry.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/orchestrator_config.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/rate_limiter.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/repl.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/router/__init__.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/streaming.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/utils/__init__.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/utils/config.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/utils/net_check.py +0 -0
- {hanzo-0.3.24 → hanzo-0.3.25}/src/hanzo/utils/output.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanzo
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.25
|
|
4
4
|
Summary: Hanzo AI - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime
|
|
5
5
|
Project-URL: Homepage, https://hanzo.ai
|
|
6
6
|
Project-URL: Repository, https://github.com/hanzoai/python-sdk
|
|
@@ -25,9 +25,11 @@ from .commands import (
|
|
|
25
25
|
)
|
|
26
26
|
from .utils.output import console
|
|
27
27
|
from .interactive.repl import HanzoREPL
|
|
28
|
+
from .interactive.enhanced_repl import EnhancedHanzoREPL
|
|
29
|
+
from .ui.startup import show_startup
|
|
28
30
|
|
|
29
31
|
# Version
|
|
30
|
-
__version__ = "0.3.
|
|
32
|
+
__version__ = "0.3.23"
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
@click.group(invoke_without_command=True)
|
|
@@ -55,14 +57,20 @@ def cli(ctx, verbose: bool, json: bool, config: Optional[str]):
|
|
|
55
57
|
|
|
56
58
|
if os.environ.get("HANZO_COMPUTE_NODE") == "1":
|
|
57
59
|
# Start as a compute node
|
|
58
|
-
|
|
59
60
|
asyncio.run(start_compute_node(ctx))
|
|
60
61
|
else:
|
|
62
|
+
# Show startup UI (unless in quiet mode)
|
|
63
|
+
if not ctx.obj.get("quiet") and not os.environ.get("HANZO_NO_STARTUP"):
|
|
64
|
+
show_startup(minimal=os.environ.get("HANZO_MINIMAL_UI") == "1")
|
|
65
|
+
|
|
61
66
|
# Enter interactive REPL mode
|
|
62
|
-
console.print("[bold cyan]Hanzo AI - Interactive Mode[/bold cyan]")
|
|
63
|
-
console.print("Type 'help' for commands, 'exit' to quit\n")
|
|
64
67
|
try:
|
|
65
|
-
|
|
68
|
+
# Use enhanced REPL if available, otherwise fallback
|
|
69
|
+
use_enhanced = os.environ.get("HANZO_ENHANCED_REPL", "1") == "1"
|
|
70
|
+
if use_enhanced:
|
|
71
|
+
repl = EnhancedHanzoREPL(console=console)
|
|
72
|
+
else:
|
|
73
|
+
repl = HanzoREPL(console=console)
|
|
66
74
|
asyncio.run(repl.run())
|
|
67
75
|
except KeyboardInterrupt:
|
|
68
76
|
console.print("\n[yellow]Interrupted[/yellow]")
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""Authentication commands for Hanzo CLI."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from rich.prompt import Prompt
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
from rich import box
|
|
14
|
+
|
|
15
|
+
from ..utils.output import console
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AuthManager:
|
|
19
|
+
"""Manage Hanzo authentication."""
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.config_dir = Path.home() / ".hanzo"
|
|
23
|
+
self.auth_file = self.config_dir / "auth.json"
|
|
24
|
+
|
|
25
|
+
def load_auth(self) -> dict:
|
|
26
|
+
"""Load authentication data."""
|
|
27
|
+
if self.auth_file.exists():
|
|
28
|
+
try:
|
|
29
|
+
return json.loads(self.auth_file.read_text())
|
|
30
|
+
except:
|
|
31
|
+
pass
|
|
32
|
+
return {}
|
|
33
|
+
|
|
34
|
+
def save_auth(self, auth: dict):
|
|
35
|
+
"""Save authentication data."""
|
|
36
|
+
self.config_dir.mkdir(exist_ok=True)
|
|
37
|
+
self.auth_file.write_text(json.dumps(auth, indent=2))
|
|
38
|
+
|
|
39
|
+
def is_authenticated(self) -> bool:
|
|
40
|
+
"""Check if authenticated."""
|
|
41
|
+
if os.getenv("HANZO_API_KEY"):
|
|
42
|
+
return True
|
|
43
|
+
auth = self.load_auth()
|
|
44
|
+
return bool(auth.get("api_key") or auth.get("logged_in"))
|
|
45
|
+
|
|
46
|
+
def get_api_key(self) -> Optional[str]:
|
|
47
|
+
"""Get API key."""
|
|
48
|
+
if os.getenv("HANZO_API_KEY"):
|
|
49
|
+
return os.getenv("HANZO_API_KEY")
|
|
50
|
+
auth = self.load_auth()
|
|
51
|
+
return auth.get("api_key")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@click.group(name="auth")
|
|
55
|
+
def auth_group():
|
|
56
|
+
"""Manage Hanzo authentication."""
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@auth_group.command()
|
|
61
|
+
@click.option("--email", "-e", help="Email address")
|
|
62
|
+
@click.option("--password", "-p", help="Password (not recommended, use prompt)")
|
|
63
|
+
@click.option("--api-key", "-k", help="API key for direct authentication")
|
|
64
|
+
@click.option("--sso", is_flag=True, help="Use SSO authentication")
|
|
65
|
+
@click.pass_context
|
|
66
|
+
def login(ctx, email: str, password: str, api_key: str, sso: bool):
|
|
67
|
+
"""Login to Hanzo AI."""
|
|
68
|
+
auth_mgr = AuthManager()
|
|
69
|
+
|
|
70
|
+
# Check if already authenticated
|
|
71
|
+
if auth_mgr.is_authenticated():
|
|
72
|
+
console.print("[yellow]Already authenticated[/yellow]")
|
|
73
|
+
auth = auth_mgr.load_auth()
|
|
74
|
+
if auth.get("email"):
|
|
75
|
+
console.print(f"Logged in as: {auth['email']}")
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
if api_key:
|
|
80
|
+
# Direct API key authentication
|
|
81
|
+
console.print("Authenticating with API key...")
|
|
82
|
+
auth = {
|
|
83
|
+
"api_key": api_key,
|
|
84
|
+
"logged_in": True,
|
|
85
|
+
"last_login": datetime.now().isoformat()
|
|
86
|
+
}
|
|
87
|
+
auth_mgr.save_auth(auth)
|
|
88
|
+
console.print("[green]✓[/green] Successfully authenticated with API key")
|
|
89
|
+
|
|
90
|
+
elif sso:
|
|
91
|
+
# SSO authentication via browser
|
|
92
|
+
console.print("Opening browser for SSO login...")
|
|
93
|
+
console.print("If browser doesn't open, visit: https://iam.hanzo.ai/login")
|
|
94
|
+
|
|
95
|
+
# Try using hanzoai if available
|
|
96
|
+
try:
|
|
97
|
+
from hanzoai.auth import HanzoAuth
|
|
98
|
+
hanzo_auth = HanzoAuth()
|
|
99
|
+
# SSO not implemented yet
|
|
100
|
+
console.print("[yellow]SSO authentication not yet implemented[/yellow]")
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
auth = {
|
|
104
|
+
"email": result.get("email"),
|
|
105
|
+
"logged_in": True,
|
|
106
|
+
"last_login": datetime.now().isoformat()
|
|
107
|
+
}
|
|
108
|
+
auth_mgr.save_auth(auth)
|
|
109
|
+
console.print(f"[green]✓[/green] Logged in as {result.get('email')}")
|
|
110
|
+
except ImportError:
|
|
111
|
+
console.print("[yellow]SSO requires hanzoai package[/yellow]")
|
|
112
|
+
console.print("Install with: pip install hanzoai")
|
|
113
|
+
|
|
114
|
+
else:
|
|
115
|
+
# Email/password authentication
|
|
116
|
+
if not email:
|
|
117
|
+
email = Prompt.ask("Email")
|
|
118
|
+
if not password:
|
|
119
|
+
password = Prompt.ask("Password", password=True)
|
|
120
|
+
|
|
121
|
+
console.print("Authenticating...")
|
|
122
|
+
|
|
123
|
+
# Try using hanzoai if available
|
|
124
|
+
try:
|
|
125
|
+
from hanzoai.auth import HanzoAuth
|
|
126
|
+
hanzo_auth = HanzoAuth()
|
|
127
|
+
# Email auth not implemented yet
|
|
128
|
+
console.print("[yellow]Email authentication not yet implemented[/yellow]")
|
|
129
|
+
console.print("[dim]Saving credentials locally for development[/dim]")
|
|
130
|
+
|
|
131
|
+
auth = {
|
|
132
|
+
"email": email,
|
|
133
|
+
"logged_in": True,
|
|
134
|
+
"last_login": datetime.now().isoformat()
|
|
135
|
+
}
|
|
136
|
+
auth_mgr.save_auth(auth)
|
|
137
|
+
console.print(f"[green]✓[/green] Logged in as {email}")
|
|
138
|
+
except ImportError:
|
|
139
|
+
# Fallback to saving credentials locally
|
|
140
|
+
auth = {
|
|
141
|
+
"email": email,
|
|
142
|
+
"logged_in": True,
|
|
143
|
+
"last_login": datetime.now().isoformat()
|
|
144
|
+
}
|
|
145
|
+
auth_mgr.save_auth(auth)
|
|
146
|
+
console.print(f"[green]✓[/green] Credentials saved for {email}")
|
|
147
|
+
|
|
148
|
+
except Exception as e:
|
|
149
|
+
console.print(f"[red]Login failed: {e}[/red]")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@auth_group.command()
|
|
153
|
+
@click.pass_context
|
|
154
|
+
def logout(ctx):
|
|
155
|
+
"""Logout from Hanzo AI."""
|
|
156
|
+
auth_mgr = AuthManager()
|
|
157
|
+
|
|
158
|
+
if not auth_mgr.is_authenticated():
|
|
159
|
+
console.print("[yellow]Not logged in[/yellow]")
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
# Try using hanzoai if available
|
|
164
|
+
try:
|
|
165
|
+
from hanzoai.auth import HanzoAuth
|
|
166
|
+
hanzo_auth = HanzoAuth()
|
|
167
|
+
# Logout not implemented yet
|
|
168
|
+
pass
|
|
169
|
+
except ImportError:
|
|
170
|
+
pass # hanzoai not installed, just clear local auth
|
|
171
|
+
|
|
172
|
+
# Clear local auth
|
|
173
|
+
auth_mgr.save_auth({})
|
|
174
|
+
|
|
175
|
+
console.print("[green]✓[/green] Logged out successfully")
|
|
176
|
+
|
|
177
|
+
except Exception as e:
|
|
178
|
+
console.print(f"[red]Logout failed: {e}[/red]")
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@auth_group.command()
|
|
182
|
+
@click.pass_context
|
|
183
|
+
def status(ctx):
|
|
184
|
+
"""Show authentication status."""
|
|
185
|
+
auth_mgr = AuthManager()
|
|
186
|
+
|
|
187
|
+
# Create status table
|
|
188
|
+
table = Table(title="Authentication Status", box=box.ROUNDED)
|
|
189
|
+
table.add_column("Property", style="cyan")
|
|
190
|
+
table.add_column("Value", style="white")
|
|
191
|
+
|
|
192
|
+
if auth_mgr.is_authenticated():
|
|
193
|
+
auth = auth_mgr.load_auth()
|
|
194
|
+
|
|
195
|
+
table.add_row("Status", "✅ Authenticated")
|
|
196
|
+
|
|
197
|
+
# Show auth method
|
|
198
|
+
if os.getenv("HANZO_API_KEY"):
|
|
199
|
+
table.add_row("Method", "Environment Variable")
|
|
200
|
+
api_key = os.getenv("HANZO_API_KEY")
|
|
201
|
+
table.add_row("API Key", f"{api_key[:8]}...{api_key[-4:]}")
|
|
202
|
+
elif auth.get("api_key"):
|
|
203
|
+
table.add_row("Method", "API Key")
|
|
204
|
+
table.add_row("API Key", f"{auth['api_key'][:8]}...")
|
|
205
|
+
elif auth.get("email"):
|
|
206
|
+
table.add_row("Method", "Email/Password")
|
|
207
|
+
table.add_row("Email", auth['email'])
|
|
208
|
+
|
|
209
|
+
if auth.get("last_login"):
|
|
210
|
+
table.add_row("Last Login", auth['last_login'])
|
|
211
|
+
|
|
212
|
+
else:
|
|
213
|
+
table.add_row("Status", "❌ Not authenticated")
|
|
214
|
+
table.add_row("Action", "Run 'hanzo auth login' to authenticate")
|
|
215
|
+
|
|
216
|
+
console.print(table)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@auth_group.command()
|
|
220
|
+
def whoami():
|
|
221
|
+
"""Show current user information."""
|
|
222
|
+
auth_mgr = AuthManager()
|
|
223
|
+
|
|
224
|
+
if not auth_mgr.is_authenticated():
|
|
225
|
+
console.print("[yellow]Not logged in[/yellow]")
|
|
226
|
+
console.print("[dim]Run 'hanzo auth login' to authenticate[/dim]")
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
auth = auth_mgr.load_auth()
|
|
230
|
+
|
|
231
|
+
# Create user info panel
|
|
232
|
+
lines = []
|
|
233
|
+
|
|
234
|
+
if auth.get("email"):
|
|
235
|
+
lines.append(f"[cyan]Email:[/cyan] {auth['email']}")
|
|
236
|
+
|
|
237
|
+
if os.getenv("HANZO_API_KEY"):
|
|
238
|
+
lines.append("[cyan]API Key:[/cyan] Set via environment")
|
|
239
|
+
elif auth.get("api_key"):
|
|
240
|
+
lines.append(f"[cyan]API Key:[/cyan] {auth['api_key'][:8]}...")
|
|
241
|
+
|
|
242
|
+
if auth.get("last_login"):
|
|
243
|
+
lines.append(f"[cyan]Last Login:[/cyan] {auth['last_login']}")
|
|
244
|
+
|
|
245
|
+
content = "\n".join(lines) if lines else "[dim]No user information available[/dim]"
|
|
246
|
+
|
|
247
|
+
console.print(Panel(
|
|
248
|
+
content,
|
|
249
|
+
title="[bold cyan]User Information[/bold cyan]",
|
|
250
|
+
box=box.ROUNDED
|
|
251
|
+
))
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@auth_group.command(name="set-key")
|
|
255
|
+
@click.argument("api_key")
|
|
256
|
+
def set_key(api_key: str):
|
|
257
|
+
"""Set API key for authentication."""
|
|
258
|
+
auth_mgr = AuthManager()
|
|
259
|
+
|
|
260
|
+
auth = auth_mgr.load_auth()
|
|
261
|
+
auth["api_key"] = api_key
|
|
262
|
+
auth["logged_in"] = True
|
|
263
|
+
auth["last_login"] = datetime.now().isoformat()
|
|
264
|
+
|
|
265
|
+
auth_mgr.save_auth(auth)
|
|
266
|
+
|
|
267
|
+
console.print("[green]✓[/green] API key saved successfully")
|
|
268
|
+
console.print("[dim]You can now use Hanzo Cloud services[/dim]")
|
|
@@ -1,14 +1,56 @@
|
|
|
1
1
|
"""Authentication commands."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import json
|
|
4
5
|
from pathlib import Path
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Optional
|
|
5
8
|
|
|
6
9
|
import click
|
|
7
10
|
from rich.prompt import Prompt
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
from rich import box
|
|
8
14
|
|
|
9
15
|
from ..utils.output import console
|
|
10
16
|
|
|
11
17
|
|
|
18
|
+
class AuthManager:
|
|
19
|
+
"""Manage Hanzo authentication."""
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.config_dir = Path.home() / ".hanzo"
|
|
23
|
+
self.auth_file = self.config_dir / "auth.json"
|
|
24
|
+
|
|
25
|
+
def load_auth(self) -> dict:
|
|
26
|
+
"""Load authentication data."""
|
|
27
|
+
if self.auth_file.exists():
|
|
28
|
+
try:
|
|
29
|
+
return json.loads(self.auth_file.read_text())
|
|
30
|
+
except:
|
|
31
|
+
pass
|
|
32
|
+
return {}
|
|
33
|
+
|
|
34
|
+
def save_auth(self, auth: dict):
|
|
35
|
+
"""Save authentication data."""
|
|
36
|
+
self.config_dir.mkdir(exist_ok=True)
|
|
37
|
+
self.auth_file.write_text(json.dumps(auth, indent=2))
|
|
38
|
+
|
|
39
|
+
def is_authenticated(self) -> bool:
|
|
40
|
+
"""Check if authenticated."""
|
|
41
|
+
if os.getenv("HANZO_API_KEY"):
|
|
42
|
+
return True
|
|
43
|
+
auth = self.load_auth()
|
|
44
|
+
return bool(auth.get("api_key") or auth.get("logged_in"))
|
|
45
|
+
|
|
46
|
+
def get_api_key(self) -> Optional[str]:
|
|
47
|
+
"""Get API key."""
|
|
48
|
+
if os.getenv("HANZO_API_KEY"):
|
|
49
|
+
return os.getenv("HANZO_API_KEY")
|
|
50
|
+
auth = self.load_auth()
|
|
51
|
+
return auth.get("api_key")
|
|
52
|
+
|
|
53
|
+
|
|
12
54
|
@click.group(name="auth")
|
|
13
55
|
def auth_group():
|
|
14
56
|
"""Manage Hanzo authentication."""
|
|
@@ -83,24 +125,26 @@ async def login(ctx, email: str, password: str, api_key: str, sso: bool):
|
|
|
83
125
|
@click.pass_context
|
|
84
126
|
async def logout(ctx):
|
|
85
127
|
"""Logout from Hanzo AI."""
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.print("[
|
|
128
|
+
auth_mgr = AuthManager()
|
|
129
|
+
|
|
130
|
+
if not auth_mgr.is_authenticated():
|
|
131
|
+
console.print("[yellow]Not logged in[/yellow]")
|
|
90
132
|
return
|
|
91
|
-
|
|
92
|
-
auth = HanzoAuth()
|
|
93
|
-
|
|
133
|
+
|
|
94
134
|
try:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
135
|
+
# Try using hanzoai if available
|
|
136
|
+
try:
|
|
137
|
+
from hanzoai.auth import HanzoAuth
|
|
138
|
+
hanzo_auth = HanzoAuth()
|
|
139
|
+
await hanzo_auth.logout()
|
|
140
|
+
except ImportError:
|
|
141
|
+
pass # hanzoai not installed, just clear local auth
|
|
142
|
+
|
|
143
|
+
# Clear local auth
|
|
144
|
+
auth_mgr.save_auth({})
|
|
145
|
+
|
|
102
146
|
console.print("[green]✓[/green] Logged out successfully")
|
|
103
|
-
|
|
147
|
+
|
|
104
148
|
except Exception as e:
|
|
105
149
|
console.print(f"[red]Logout failed: {e}[/red]")
|
|
106
150
|
|
|
@@ -109,22 +153,27 @@ async def logout(ctx):
|
|
|
109
153
|
@click.pass_context
|
|
110
154
|
async def status(ctx):
|
|
111
155
|
"""Show authentication status."""
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
156
|
+
auth_mgr = AuthManager()
|
|
157
|
+
|
|
158
|
+
# Create status table
|
|
159
|
+
table = Table(title="Authentication Status", box=box.ROUNDED)
|
|
160
|
+
table.add_column("Property", style="cyan")
|
|
161
|
+
table.add_column("Value", style="white")
|
|
162
|
+
|
|
163
|
+
if auth_mgr.is_authenticated():
|
|
164
|
+
auth = auth_mgr.load_auth()
|
|
165
|
+
|
|
166
|
+
table.add_row("Status", "✅ Authenticated")
|
|
167
|
+
|
|
168
|
+
# Show auth method
|
|
169
|
+
if os.getenv("HANZO_API_KEY"):
|
|
170
|
+
table.add_row("Method", "Environment Variable")
|
|
171
|
+
api_key = os.getenv("HANZO_API_KEY")
|
|
172
|
+
table.add_row("API Key", f"{api_key[:8]}...{api_key[-4:]}")
|
|
173
|
+
elif auth.get("api_key"):
|
|
174
|
+
table.add_row("Method", "API Key")
|
|
175
|
+
table.add_row("API Key", f"{auth['api_key'][:8]}...")
|
|
176
|
+
elif auth.get("email"):
|
|
128
177
|
console.print(f" Email: {email}")
|
|
129
178
|
if org := creds.get("organization"):
|
|
130
179
|
console.print(f" Organization: {org}")
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
"""Chat command for interactive AI conversations."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import os
|
|
4
5
|
from typing import Optional
|
|
5
6
|
|
|
6
7
|
import click
|
|
7
8
|
import httpx
|
|
8
9
|
from rich.markdown import Markdown
|
|
10
|
+
from rich.panel import Panel
|
|
11
|
+
from rich import box
|
|
9
12
|
|
|
10
13
|
from ..utils.output import console
|
|
11
14
|
|