llamactl 0.3.0a4__py3-none-any.whl → 0.3.0a6__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.
- llama_deploy/cli/__init__.py +7 -25
- llama_deploy/cli/app.py +71 -0
- llama_deploy/cli/client.py +6 -11
- llama_deploy/cli/commands/aliased_group.py +31 -0
- llama_deploy/cli/commands/deployment.py +255 -0
- llama_deploy/cli/commands/profile.py +217 -0
- llama_deploy/cli/commands/serve.py +68 -0
- llama_deploy/cli/config.py +11 -11
- llama_deploy/cli/env.py +3 -2
- llama_deploy/cli/interactive_prompts/utils.py +2 -2
- llama_deploy/cli/options.py +2 -0
- llama_deploy/cli/textual/deployment_form.py +147 -12
- llama_deploy/cli/textual/deployment_help.py +53 -0
- llama_deploy/cli/textual/git_validation.py +6 -7
- llama_deploy/cli/textual/github_callback_server.py +1 -1
- llama_deploy/cli/textual/llama_loader.py +1 -0
- llama_deploy/cli/textual/profile_form.py +6 -7
- llama_deploy/cli/textual/secrets_form.py +24 -8
- llama_deploy/cli/textual/styles.tcss +23 -0
- {llamactl-0.3.0a4.dist-info → llamactl-0.3.0a6.dist-info}/METADATA +3 -3
- llamactl-0.3.0a6.dist-info/RECORD +24 -0
- llama_deploy/cli/commands.py +0 -577
- llamactl-0.3.0a4.dist-info/RECORD +0 -19
- {llamactl-0.3.0a4.dist-info → llamactl-0.3.0a6.dist-info}/WHEEL +0 -0
- {llamactl-0.3.0a4.dist-info → llamactl-0.3.0a6.dist-info}/entry_points.txt +0 -0
|
@@ -138,6 +138,10 @@ Input.disabled {
|
|
|
138
138
|
layout: vertical;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
.flex-1 {
|
|
142
|
+
width: 1fr;
|
|
143
|
+
}
|
|
144
|
+
|
|
141
145
|
/* =============================================== */
|
|
142
146
|
/* BUTTONS & ACTIONS */
|
|
143
147
|
/* =============================================== */
|
|
@@ -160,3 +164,22 @@ Button.secondary {
|
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
|
|
167
|
+
/* Centered button row for help back button */
|
|
168
|
+
.centered-button-row {
|
|
169
|
+
align: center middle;
|
|
170
|
+
margin-top: 1;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Link-styled button */
|
|
174
|
+
.link-button {
|
|
175
|
+
background: transparent;
|
|
176
|
+
color: $accent;
|
|
177
|
+
text-style: underline;
|
|
178
|
+
border: none;
|
|
179
|
+
padding: 0 1;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.info-message {
|
|
183
|
+
align: left middle;
|
|
184
|
+
}
|
|
185
|
+
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: llamactl
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.0a6
|
|
4
4
|
Summary: A command-line interface for managing LlamaDeploy projects and deployments
|
|
5
5
|
Author: Adrian Lyjak
|
|
6
6
|
Author-email: Adrian Lyjak <adrianlyjak@gmail.com>
|
|
7
7
|
License: MIT
|
|
8
|
-
Requires-Dist: llama-deploy-core>=0.3.
|
|
9
|
-
Requires-Dist: llama-deploy-appserver>=0.3.
|
|
8
|
+
Requires-Dist: llama-deploy-core>=0.3.0a6,<0.4.0
|
|
9
|
+
Requires-Dist: llama-deploy-appserver>=0.3.0a6,<0.4.0
|
|
10
10
|
Requires-Dist: httpx>=0.24.0
|
|
11
11
|
Requires-Dist: rich>=13.0.0
|
|
12
12
|
Requires-Dist: questionary>=2.0.0
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
llama_deploy/cli/__init__.py,sha256=a7ac1d286680f8b95d046ed3f116c54d6301cf524ba39f0c19b39f9c95978d22,366
|
|
2
|
+
llama_deploy/cli/app.py,sha256=5200b4ac01b0ad0c405ce841fc01a12ed32f7b6474472f00a7d6c75fe274ea45,2324
|
|
3
|
+
llama_deploy/cli/client.py,sha256=b0a1f002bd3feab188459c6e56f75a995048016d135666a17e53c4588beea9cc,6911
|
|
4
|
+
llama_deploy/cli/commands/aliased_group.py,sha256=6e2457cdea51de83bb7f02b37abb77cb9b5bff0a61bdddd66c43240b66b13f13,986
|
|
5
|
+
llama_deploy/cli/commands/deployment.py,sha256=d1aacc8c6cbe4d73b3284d04e805fb044af591f9b323cc5c4acb2c07b0ad649c,8463
|
|
6
|
+
llama_deploy/cli/commands/profile.py,sha256=933d7a434c2684c7b47bfbd7340a09e4b34d56d20624886e15fdb4e0af97ce0b,6765
|
|
7
|
+
llama_deploy/cli/commands/serve.py,sha256=38e29816529af97bf00b8abea3ba6eb39e9a51e6b03616c2d8611b557079ddf2,1945
|
|
8
|
+
llama_deploy/cli/config.py,sha256=1759e502ee77e72cce5358a4a85296f3e4182dd1495d21a3d9f308f92690e702,6251
|
|
9
|
+
llama_deploy/cli/debug.py,sha256=e85a72d473bbe1645eb31772f7349bde703d45704166f767385895c440afc762,496
|
|
10
|
+
llama_deploy/cli/env.py,sha256=6ebc24579815b3787829c81fd5bb9f31698a06e62c0128a788559f962b33a7af,1016
|
|
11
|
+
llama_deploy/cli/interactive_prompts/utils.py,sha256=4ecab983c3f4869e7b8fcbb385e3ea91fde3bf86e8db7afe72d2febfd45d551e,2492
|
|
12
|
+
llama_deploy/cli/options.py,sha256=38bb4a231ad0436d8b910c98ff659c0736f619efdf56c402d60bb3f755df38e0,598
|
|
13
|
+
llama_deploy/cli/textual/deployment_form.py,sha256=9a7a364ab9735585db83d5955f4bb46faf0776b050c3477e2e7e5cfca5b11b2d,19465
|
|
14
|
+
llama_deploy/cli/textual/deployment_help.py,sha256=7dae54ffbdaea201362928883cc206b496b1386023fb7f1c78d168132543e592,2339
|
|
15
|
+
llama_deploy/cli/textual/git_validation.py,sha256=44e359d16aa879f4566a0077d025fdd799f500862a8462b5ed3586e528f7a273,13300
|
|
16
|
+
llama_deploy/cli/textual/github_callback_server.py,sha256=031929592f448c5005e11cea19268fd696d60d92573c385a0397cfabacb06eb7,7444
|
|
17
|
+
llama_deploy/cli/textual/llama_loader.py,sha256=468213a504057f21838b01f48d51f52e60aa622d6f0fe5bb800d76ced846cea9,1245
|
|
18
|
+
llama_deploy/cli/textual/profile_form.py,sha256=6c2d55b7c0a1712796eebc8f05bb0597e955cf1dd6f96d37a6f0dce7865a2554,5984
|
|
19
|
+
llama_deploy/cli/textual/secrets_form.py,sha256=b46b0e5999cd7c92433b91dcfb560bb5f8de9e5c4e96abbad63ee68544c387be,7082
|
|
20
|
+
llama_deploy/cli/textual/styles.tcss,sha256=536cec7627d2a16dd03bf25bb9b6e4d53f1e0d18272b07ec0dc3bf76b0a7c2e0,3056
|
|
21
|
+
llamactl-0.3.0a6.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
|
|
22
|
+
llamactl-0.3.0a6.dist-info/entry_points.txt,sha256=b67e1eb64305058751a651a80f2d2268b5f7046732268421e796f64d4697f83c,52
|
|
23
|
+
llamactl-0.3.0a6.dist-info/METADATA,sha256=6bf285b99000994431ec30eb1d6a97881e6fbd2a85785ca1d36dcb25156a4abc,3166
|
|
24
|
+
llamactl-0.3.0a6.dist-info/RECORD,,
|
llama_deploy/cli/commands.py
DELETED
|
@@ -1,577 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
import click
|
|
5
|
-
from llama_deploy.appserver.app import start_server
|
|
6
|
-
from llama_deploy.core.config import DEFAULT_DEPLOYMENT_FILE_PATH
|
|
7
|
-
from llama_deploy.core.schema.deployments import DeploymentUpdate
|
|
8
|
-
from rich import print as rprint
|
|
9
|
-
from rich.console import Console
|
|
10
|
-
from rich.text import Text
|
|
11
|
-
from rich.table import Table
|
|
12
|
-
|
|
13
|
-
from .client import get_project_client, get_control_plane_client
|
|
14
|
-
from .config import config_manager
|
|
15
|
-
from .interactive_prompts.utils import (
|
|
16
|
-
confirm_action,
|
|
17
|
-
select_deployment,
|
|
18
|
-
select_profile,
|
|
19
|
-
)
|
|
20
|
-
from .options import global_options
|
|
21
|
-
from .textual.deployment_form import create_deployment_form, edit_deployment_form
|
|
22
|
-
from .textual.profile_form import create_profile_form, edit_profile_form
|
|
23
|
-
|
|
24
|
-
RETRY_WAIT_SECONDS = 1
|
|
25
|
-
console = Console(highlight=False)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Create sub-applications for organizing commands
|
|
29
|
-
@click.group(help="Manage profiles", no_args_is_help=True)
|
|
30
|
-
@global_options
|
|
31
|
-
def profile() -> None:
|
|
32
|
-
"""Manage profiles"""
|
|
33
|
-
pass
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@click.group(help="Manage projects", no_args_is_help=True)
|
|
37
|
-
@global_options
|
|
38
|
-
def projects() -> None:
|
|
39
|
-
"""Manage projects"""
|
|
40
|
-
pass
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@click.group(help="Manage deployments", no_args_is_help=True)
|
|
44
|
-
@global_options
|
|
45
|
-
def deployments() -> None:
|
|
46
|
-
"""Manage deployments"""
|
|
47
|
-
pass
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# Profile commands
|
|
51
|
-
@profile.command("create")
|
|
52
|
-
@global_options
|
|
53
|
-
@click.option("--name", help="Profile name")
|
|
54
|
-
@click.option("--api-url", help="API server URL")
|
|
55
|
-
@click.option("--project-id", help="Default project ID")
|
|
56
|
-
def create_profile(
|
|
57
|
-
name: Optional[str], api_url: Optional[str], project_id: Optional[str]
|
|
58
|
-
) -> None:
|
|
59
|
-
"""Create a new profile"""
|
|
60
|
-
try:
|
|
61
|
-
# If all required args are provided via CLI, skip interactive mode
|
|
62
|
-
if name and api_url:
|
|
63
|
-
# Use CLI args directly
|
|
64
|
-
profile = config_manager.create_profile(name, api_url, project_id)
|
|
65
|
-
rprint(f"[green]Created profile '{profile.name}'[/green]")
|
|
66
|
-
|
|
67
|
-
# Automatically switch to the new profile
|
|
68
|
-
config_manager.set_current_profile(name)
|
|
69
|
-
rprint(f"[green]Switched to profile '{name}'[/green]")
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
# Use interactive creation
|
|
73
|
-
profile = create_profile_form()
|
|
74
|
-
if profile is None:
|
|
75
|
-
rprint("[yellow]Cancelled[/yellow]")
|
|
76
|
-
return
|
|
77
|
-
|
|
78
|
-
try:
|
|
79
|
-
rprint(f"[green]Created profile '{profile.name}'[/green]")
|
|
80
|
-
|
|
81
|
-
# Automatically switch to the new profile
|
|
82
|
-
config_manager.set_current_profile(profile.name)
|
|
83
|
-
rprint(f"[green]Switched to profile '{profile.name}'[/green]")
|
|
84
|
-
except Exception as e:
|
|
85
|
-
rprint(f"[red]Error creating profile: {e}[/red]")
|
|
86
|
-
raise click.Abort()
|
|
87
|
-
|
|
88
|
-
except ValueError as e:
|
|
89
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
90
|
-
raise click.Abort()
|
|
91
|
-
except Exception as e:
|
|
92
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
93
|
-
raise click.Abort()
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@profile.command("list")
|
|
97
|
-
@global_options
|
|
98
|
-
def list_profiles() -> None:
|
|
99
|
-
"""List all profiles"""
|
|
100
|
-
try:
|
|
101
|
-
profiles = config_manager.list_profiles()
|
|
102
|
-
current_name = config_manager.get_current_profile_name()
|
|
103
|
-
|
|
104
|
-
if not profiles:
|
|
105
|
-
rprint("[yellow]No profiles found[/yellow]")
|
|
106
|
-
rprint("Create one with: [cyan]llamactl profile create[/cyan]")
|
|
107
|
-
return
|
|
108
|
-
|
|
109
|
-
table = Table(title="Profiles")
|
|
110
|
-
table.add_column("Name", style="cyan")
|
|
111
|
-
table.add_column("API URL", style="green")
|
|
112
|
-
table.add_column("Active Project", style="yellow")
|
|
113
|
-
table.add_column("Current", style="magenta")
|
|
114
|
-
|
|
115
|
-
for profile in profiles:
|
|
116
|
-
is_current = "✓" if profile.name == current_name else ""
|
|
117
|
-
active_project = profile.active_project_id or "-"
|
|
118
|
-
table.add_row(profile.name, profile.api_url, active_project, is_current)
|
|
119
|
-
|
|
120
|
-
console.print(table)
|
|
121
|
-
|
|
122
|
-
except Exception as e:
|
|
123
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
124
|
-
raise click.Abort()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
@profile.command("switch")
|
|
128
|
-
@global_options
|
|
129
|
-
@click.argument("name", required=False)
|
|
130
|
-
def switch_profile(name: Optional[str]) -> None:
|
|
131
|
-
"""Switch to a different profile"""
|
|
132
|
-
try:
|
|
133
|
-
name = select_profile(name)
|
|
134
|
-
if not name:
|
|
135
|
-
rprint("[yellow]No profile selected[/yellow]")
|
|
136
|
-
return
|
|
137
|
-
|
|
138
|
-
profile = config_manager.get_profile(name)
|
|
139
|
-
if not profile:
|
|
140
|
-
rprint(f"[red]Profile '{name}' not found[/red]")
|
|
141
|
-
raise click.Abort()
|
|
142
|
-
|
|
143
|
-
config_manager.set_current_profile(name)
|
|
144
|
-
rprint(f"[green]Switched to profile '{name}'[/green]")
|
|
145
|
-
|
|
146
|
-
except Exception as e:
|
|
147
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
148
|
-
raise click.Abort()
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
@profile.command("delete")
|
|
152
|
-
@global_options
|
|
153
|
-
@click.argument("name", required=False)
|
|
154
|
-
def delete_profile(name: Optional[str]) -> None:
|
|
155
|
-
"""Delete a profile"""
|
|
156
|
-
try:
|
|
157
|
-
name = select_profile(name)
|
|
158
|
-
if not name:
|
|
159
|
-
rprint("[yellow]No profile selected[/yellow]")
|
|
160
|
-
return
|
|
161
|
-
|
|
162
|
-
profile = config_manager.get_profile(name)
|
|
163
|
-
if not profile:
|
|
164
|
-
rprint(f"[red]Profile '{name}' not found[/red]")
|
|
165
|
-
raise click.Abort()
|
|
166
|
-
|
|
167
|
-
if config_manager.delete_profile(name):
|
|
168
|
-
rprint(f"[green]Deleted profile '{name}'[/green]")
|
|
169
|
-
else:
|
|
170
|
-
rprint(f"[red]Profile '{name}' not found[/red]")
|
|
171
|
-
|
|
172
|
-
except Exception as e:
|
|
173
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
174
|
-
raise click.Abort()
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
@profile.command("edit")
|
|
178
|
-
@global_options
|
|
179
|
-
@click.argument("name", required=False)
|
|
180
|
-
def edit_profile(name: Optional[str]) -> None:
|
|
181
|
-
"""Edit a profile"""
|
|
182
|
-
try:
|
|
183
|
-
name = select_profile(name)
|
|
184
|
-
if not name:
|
|
185
|
-
rprint("[yellow]No profile selected[/yellow]")
|
|
186
|
-
return
|
|
187
|
-
|
|
188
|
-
# Get current profile
|
|
189
|
-
maybe_profile = config_manager.get_profile(name)
|
|
190
|
-
if not maybe_profile:
|
|
191
|
-
rprint(f"[red]Profile '{name}' not found[/red]")
|
|
192
|
-
raise click.Abort()
|
|
193
|
-
profile = maybe_profile
|
|
194
|
-
|
|
195
|
-
# Use the interactive edit menu
|
|
196
|
-
updated = edit_profile_form(profile)
|
|
197
|
-
if updated is None:
|
|
198
|
-
rprint("[yellow]Cancelled[/yellow]")
|
|
199
|
-
return
|
|
200
|
-
|
|
201
|
-
try:
|
|
202
|
-
current_profile = config_manager.get_current_profile()
|
|
203
|
-
if not current_profile or current_profile.name != updated.name:
|
|
204
|
-
config_manager.set_current_profile(updated.name)
|
|
205
|
-
rprint(f"[green]Updated profile '{profile.name}'[/green]")
|
|
206
|
-
except Exception as e:
|
|
207
|
-
rprint(f"[red]Error updating profile: {e}[/red]")
|
|
208
|
-
raise click.Abort()
|
|
209
|
-
|
|
210
|
-
except Exception as e:
|
|
211
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
212
|
-
raise click.Abort()
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
# Projects commands
|
|
216
|
-
@projects.command("list")
|
|
217
|
-
@global_options
|
|
218
|
-
def list_projects() -> None:
|
|
219
|
-
"""List all projects with deployment counts"""
|
|
220
|
-
try:
|
|
221
|
-
client = get_control_plane_client()
|
|
222
|
-
projects = client.list_projects()
|
|
223
|
-
|
|
224
|
-
if not projects:
|
|
225
|
-
rprint("[yellow]No projects found[/yellow]")
|
|
226
|
-
return
|
|
227
|
-
|
|
228
|
-
table = Table(title="Projects")
|
|
229
|
-
table.add_column("Project ID", style="cyan")
|
|
230
|
-
table.add_column("Deployments", style="green")
|
|
231
|
-
|
|
232
|
-
for project in projects:
|
|
233
|
-
project_id = project.project_id
|
|
234
|
-
deployment_count = project.deployment_count
|
|
235
|
-
table.add_row(project_id, str(deployment_count))
|
|
236
|
-
|
|
237
|
-
console.print(table)
|
|
238
|
-
|
|
239
|
-
except Exception as e:
|
|
240
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
241
|
-
raise click.Abort()
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
# Health check command (at root level)
|
|
245
|
-
@click.command()
|
|
246
|
-
@global_options
|
|
247
|
-
def health_check() -> None:
|
|
248
|
-
"""Check if the API server is healthy"""
|
|
249
|
-
try:
|
|
250
|
-
client = get_control_plane_client()
|
|
251
|
-
health = client.health_check()
|
|
252
|
-
|
|
253
|
-
status = health.get("status", "unknown")
|
|
254
|
-
if status == "ok":
|
|
255
|
-
rprint("[green]API server is healthy[/green]")
|
|
256
|
-
else:
|
|
257
|
-
rprint(f"[yellow]API server status: {status}[/yellow]")
|
|
258
|
-
|
|
259
|
-
except Exception as e:
|
|
260
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
261
|
-
raise click.Abort()
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
# Deployments commands
|
|
265
|
-
@deployments.command("list")
|
|
266
|
-
@global_options
|
|
267
|
-
def list_deployments() -> None:
|
|
268
|
-
"""List deployments for the configured project"""
|
|
269
|
-
try:
|
|
270
|
-
client = get_project_client()
|
|
271
|
-
deployments = client.list_deployments()
|
|
272
|
-
|
|
273
|
-
if not deployments:
|
|
274
|
-
rprint(
|
|
275
|
-
f"[yellow]No deployments found for project {client.project_id}[/yellow]"
|
|
276
|
-
)
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
table = Table(title=f"Deployments for project {client.project_id}")
|
|
280
|
-
table.add_column("Name", style="cyan")
|
|
281
|
-
table.add_column("ID", style="yellow")
|
|
282
|
-
table.add_column("Status", style="green")
|
|
283
|
-
table.add_column("Repository", style="blue")
|
|
284
|
-
table.add_column("Deployment File", style="magenta")
|
|
285
|
-
table.add_column("Git Ref", style="white")
|
|
286
|
-
table.add_column("PAT", style="red")
|
|
287
|
-
table.add_column("Secrets", style="bright_green")
|
|
288
|
-
|
|
289
|
-
for deployment in deployments:
|
|
290
|
-
name = deployment.name
|
|
291
|
-
deployment_id = deployment.id
|
|
292
|
-
status = deployment.status
|
|
293
|
-
repo_url = deployment.repo_url
|
|
294
|
-
deployment_file_path = deployment.deployment_file_path
|
|
295
|
-
git_ref = deployment.git_ref
|
|
296
|
-
has_pat = "✓" if deployment.has_personal_access_token else "-"
|
|
297
|
-
secret_names = deployment.secret_names
|
|
298
|
-
secrets_display = str(len(secret_names)) if secret_names else "-"
|
|
299
|
-
|
|
300
|
-
table.add_row(
|
|
301
|
-
name,
|
|
302
|
-
deployment_id,
|
|
303
|
-
status,
|
|
304
|
-
repo_url,
|
|
305
|
-
deployment_file_path,
|
|
306
|
-
git_ref,
|
|
307
|
-
has_pat,
|
|
308
|
-
secrets_display,
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
console.print(table)
|
|
312
|
-
|
|
313
|
-
except Exception as e:
|
|
314
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
315
|
-
raise click.Abort()
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
@deployments.command("get")
|
|
319
|
-
@global_options
|
|
320
|
-
@click.argument("deployment_id", required=False)
|
|
321
|
-
def get_deployment(deployment_id: Optional[str]) -> None:
|
|
322
|
-
"""Get details of a specific deployment"""
|
|
323
|
-
try:
|
|
324
|
-
client = get_project_client()
|
|
325
|
-
|
|
326
|
-
deployment_id = select_deployment(deployment_id)
|
|
327
|
-
if not deployment_id:
|
|
328
|
-
rprint("[yellow]No deployment selected[/yellow]")
|
|
329
|
-
return
|
|
330
|
-
|
|
331
|
-
deployment = client.get_deployment(deployment_id)
|
|
332
|
-
|
|
333
|
-
table = Table(title=f"Deployment: {deployment.name}")
|
|
334
|
-
table.add_column("Property", style="cyan")
|
|
335
|
-
table.add_column("Value", style="green")
|
|
336
|
-
|
|
337
|
-
table.add_row("ID", deployment.id)
|
|
338
|
-
table.add_row("Project ID", deployment.project_id)
|
|
339
|
-
table.add_row("Status", deployment.status)
|
|
340
|
-
table.add_row("Repository", deployment.repo_url)
|
|
341
|
-
table.add_row("Deployment File", deployment.deployment_file_path)
|
|
342
|
-
table.add_row("Git Ref", deployment.git_ref)
|
|
343
|
-
table.add_row("Has PAT", str(deployment.has_personal_access_token))
|
|
344
|
-
|
|
345
|
-
apiserver_url = deployment.apiserver_url
|
|
346
|
-
if apiserver_url:
|
|
347
|
-
table.add_row("API Server URL", str(apiserver_url))
|
|
348
|
-
|
|
349
|
-
secret_names = deployment.secret_names
|
|
350
|
-
if secret_names:
|
|
351
|
-
table.add_row("Secrets", ", ".join(secret_names))
|
|
352
|
-
|
|
353
|
-
console.print(table)
|
|
354
|
-
|
|
355
|
-
except Exception as e:
|
|
356
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
357
|
-
raise click.Abort()
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
@deployments.command("create")
|
|
361
|
-
@global_options
|
|
362
|
-
@click.option("--repo-url", help="HTTP(S) Git Repository URL")
|
|
363
|
-
@click.option("--name", help="Deployment name")
|
|
364
|
-
@click.option("--deployment-file-path", help="Path to deployment file")
|
|
365
|
-
@click.option("--git-ref", help="Git reference (branch, tag, or commit)")
|
|
366
|
-
@click.option(
|
|
367
|
-
"--personal-access-token", help="Git Personal Access Token (HTTP Basic Auth)"
|
|
368
|
-
)
|
|
369
|
-
def create_deployment(
|
|
370
|
-
repo_url: Optional[str],
|
|
371
|
-
name: Optional[str],
|
|
372
|
-
deployment_file_path: Optional[str],
|
|
373
|
-
git_ref: Optional[str],
|
|
374
|
-
personal_access_token: Optional[str],
|
|
375
|
-
) -> None:
|
|
376
|
-
"""Create a new deployment"""
|
|
377
|
-
|
|
378
|
-
# Use interactive creation
|
|
379
|
-
deployment_form = create_deployment_form()
|
|
380
|
-
if deployment_form is None:
|
|
381
|
-
rprint("[yellow]Cancelled[/yellow]")
|
|
382
|
-
return
|
|
383
|
-
|
|
384
|
-
rprint(
|
|
385
|
-
f"[green]Created deployment: {deployment_form.name} (id: {deployment_form.id})[/green]"
|
|
386
|
-
)
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
@deployments.command("delete")
|
|
390
|
-
@global_options
|
|
391
|
-
@click.argument("deployment_id", required=False)
|
|
392
|
-
@click.option("--confirm", is_flag=True, help="Skip confirmation prompt")
|
|
393
|
-
def delete_deployment(deployment_id: Optional[str], confirm: bool) -> None:
|
|
394
|
-
"""Delete a deployment"""
|
|
395
|
-
try:
|
|
396
|
-
client = get_project_client()
|
|
397
|
-
|
|
398
|
-
deployment_id = select_deployment(deployment_id)
|
|
399
|
-
if not deployment_id:
|
|
400
|
-
rprint("[yellow]No deployment selected[/yellow]")
|
|
401
|
-
return
|
|
402
|
-
|
|
403
|
-
if not confirm:
|
|
404
|
-
if not confirm_action(f"Delete deployment '{deployment_id}'?"):
|
|
405
|
-
rprint("[yellow]Cancelled[/yellow]")
|
|
406
|
-
return
|
|
407
|
-
|
|
408
|
-
client.delete_deployment(deployment_id)
|
|
409
|
-
rprint(f"[green]Deleted deployment: {deployment_id}[/green]")
|
|
410
|
-
|
|
411
|
-
except Exception as e:
|
|
412
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
413
|
-
raise click.Abort()
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
@deployments.command("edit")
|
|
417
|
-
@global_options
|
|
418
|
-
@click.argument("deployment_id", required=False)
|
|
419
|
-
def edit_deployment(deployment_id: Optional[str]) -> None:
|
|
420
|
-
"""Interactively edit a deployment"""
|
|
421
|
-
try:
|
|
422
|
-
client = get_project_client()
|
|
423
|
-
|
|
424
|
-
deployment_id = select_deployment(deployment_id)
|
|
425
|
-
if not deployment_id:
|
|
426
|
-
rprint("[yellow]No deployment selected[/yellow]")
|
|
427
|
-
return
|
|
428
|
-
|
|
429
|
-
# Get current deployment details
|
|
430
|
-
current_deployment = client.get_deployment(deployment_id)
|
|
431
|
-
|
|
432
|
-
# Use the interactive edit form
|
|
433
|
-
updated_deployment = edit_deployment_form(current_deployment)
|
|
434
|
-
if updated_deployment is None:
|
|
435
|
-
rprint("[yellow]Cancelled[/yellow]")
|
|
436
|
-
return
|
|
437
|
-
|
|
438
|
-
rprint(
|
|
439
|
-
f"[green]Successfully updated deployment: {updated_deployment.name}[/green]"
|
|
440
|
-
)
|
|
441
|
-
|
|
442
|
-
except Exception as e:
|
|
443
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
444
|
-
raise click.Abort()
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
@deployments.command("refresh")
|
|
448
|
-
@global_options
|
|
449
|
-
@click.argument("deployment_id", required=False)
|
|
450
|
-
def refresh_deployment(deployment_id: Optional[str]) -> None:
|
|
451
|
-
"""Refresh a deployment with the latest code from its git reference"""
|
|
452
|
-
try:
|
|
453
|
-
client = get_project_client()
|
|
454
|
-
|
|
455
|
-
deployment_id = select_deployment(deployment_id)
|
|
456
|
-
if not deployment_id:
|
|
457
|
-
rprint("[yellow]No deployment selected[/yellow]")
|
|
458
|
-
return
|
|
459
|
-
|
|
460
|
-
# Get current deployment details to show what we're refreshing
|
|
461
|
-
current_deployment = client.get_deployment(deployment_id)
|
|
462
|
-
deployment_name = current_deployment.name
|
|
463
|
-
old_git_sha = current_deployment.git_sha or ""
|
|
464
|
-
|
|
465
|
-
# Create an empty update to force git SHA refresh with spinner
|
|
466
|
-
with console.status(f"Refreshing {deployment_name}..."):
|
|
467
|
-
deployment_update = DeploymentUpdate()
|
|
468
|
-
updated_deployment = client.update_deployment(
|
|
469
|
-
deployment_id, deployment_update, force_git_sha_update=True
|
|
470
|
-
)
|
|
471
|
-
|
|
472
|
-
# Show the git SHA change with short SHAs
|
|
473
|
-
new_git_sha = updated_deployment.git_sha or ""
|
|
474
|
-
old_short = old_git_sha[:7] if old_git_sha else "none"
|
|
475
|
-
new_short = new_git_sha[:7] if new_git_sha else "none"
|
|
476
|
-
|
|
477
|
-
if old_git_sha == new_git_sha:
|
|
478
|
-
rprint(f"No changes: already at {new_short}")
|
|
479
|
-
else:
|
|
480
|
-
rprint(f"Updated: {old_short} → {new_short}")
|
|
481
|
-
|
|
482
|
-
except Exception as e:
|
|
483
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
484
|
-
raise click.Abort()
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
@click.command("serve")
|
|
488
|
-
@click.argument(
|
|
489
|
-
"deployment_file",
|
|
490
|
-
required=False,
|
|
491
|
-
default=DEFAULT_DEPLOYMENT_FILE_PATH,
|
|
492
|
-
type=click.Path(dir_okay=False, resolve_path=True, path_type=Path), # type: ignore
|
|
493
|
-
)
|
|
494
|
-
@click.option(
|
|
495
|
-
"--no-install", is_flag=True, help="Skip installing python and js dependencies"
|
|
496
|
-
)
|
|
497
|
-
@click.option(
|
|
498
|
-
"--no-reload", is_flag=True, help="Skip reloading the API server on code changes"
|
|
499
|
-
)
|
|
500
|
-
@click.option("--no-open-browser", is_flag=True, help="Skip opening the browser")
|
|
501
|
-
@click.option(
|
|
502
|
-
"--preview",
|
|
503
|
-
is_flag=True,
|
|
504
|
-
help="Preview mode pre-builds the UI to static files, like a production build",
|
|
505
|
-
)
|
|
506
|
-
@global_options
|
|
507
|
-
def serve(
|
|
508
|
-
deployment_file: Path,
|
|
509
|
-
no_install: bool,
|
|
510
|
-
no_reload: bool,
|
|
511
|
-
no_open_browser: bool,
|
|
512
|
-
preview: bool,
|
|
513
|
-
) -> None:
|
|
514
|
-
"""Run llama_deploy API Server in the foreground. If no deployment_file is provided, will look for a llama_deploy.yaml in the current directory."""
|
|
515
|
-
if not deployment_file.exists():
|
|
516
|
-
rprint(f"[red]Deployment file '{deployment_file}' not found[/red]")
|
|
517
|
-
raise click.Abort()
|
|
518
|
-
|
|
519
|
-
try:
|
|
520
|
-
start_server(
|
|
521
|
-
cwd=deployment_file.parent,
|
|
522
|
-
deployment_file=deployment_file,
|
|
523
|
-
proxy_ui=not preview,
|
|
524
|
-
reload=not no_reload,
|
|
525
|
-
install=not no_install,
|
|
526
|
-
build=preview,
|
|
527
|
-
open_browser=not no_open_browser,
|
|
528
|
-
)
|
|
529
|
-
|
|
530
|
-
except KeyboardInterrupt:
|
|
531
|
-
print("Shutting down...")
|
|
532
|
-
|
|
533
|
-
except Exception as e:
|
|
534
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
535
|
-
raise click.Abort()
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
@click.command("version")
|
|
539
|
-
@global_options
|
|
540
|
-
def version() -> None:
|
|
541
|
-
"""Print the version of llama_deploy"""
|
|
542
|
-
try:
|
|
543
|
-
from importlib.metadata import PackageNotFoundError, version as pkg_version
|
|
544
|
-
|
|
545
|
-
ver = pkg_version("llamactl")
|
|
546
|
-
console.print(Text.assemble("client version: ", (ver, "green")))
|
|
547
|
-
|
|
548
|
-
# If there is an active profile, attempt to query server version
|
|
549
|
-
profile = config_manager.get_current_profile()
|
|
550
|
-
if profile and profile.api_url:
|
|
551
|
-
try:
|
|
552
|
-
cp_client = get_control_plane_client()
|
|
553
|
-
data = cp_client.server_version()
|
|
554
|
-
server_ver = data.get("version")
|
|
555
|
-
console.print(
|
|
556
|
-
Text.assemble(
|
|
557
|
-
"server version: ",
|
|
558
|
-
(
|
|
559
|
-
server_ver or "unknown",
|
|
560
|
-
"bright_yellow" if server_ver is None else "green",
|
|
561
|
-
),
|
|
562
|
-
)
|
|
563
|
-
)
|
|
564
|
-
except Exception as e:
|
|
565
|
-
console.print(
|
|
566
|
-
Text.assemble(
|
|
567
|
-
"server version: ",
|
|
568
|
-
("unavailable", "bright_yellow"),
|
|
569
|
-
(f" - {e}", "dim"),
|
|
570
|
-
)
|
|
571
|
-
)
|
|
572
|
-
except PackageNotFoundError:
|
|
573
|
-
rprint("[red]Package 'llamactl' not found[/red]")
|
|
574
|
-
raise click.Abort()
|
|
575
|
-
except Exception as e:
|
|
576
|
-
rprint(f"[red]Error: {e}[/red]")
|
|
577
|
-
raise click.Abort()
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
llama_deploy/cli/__init__.py,sha256=7f5381a1f1f3631a53e8d264830f591e36e9a509eae01b114fdfcd0213ff0c21,827
|
|
2
|
-
llama_deploy/cli/client.py,sha256=1e033b3f620439e67d5e5cceb3e5821039449431f2dbbc22bcff76416c638fb7,7103
|
|
3
|
-
llama_deploy/cli/commands.py,sha256=a5ec26923b80b87cbd7874b9dc36973c5f02310b5d09d140f331c87e486ec161,18619
|
|
4
|
-
llama_deploy/cli/config.py,sha256=b339d95fceb7a15a183663032396aaeb2afffe1ddf06494416a6a0183a6658ca,6275
|
|
5
|
-
llama_deploy/cli/debug.py,sha256=e85a72d473bbe1645eb31772f7349bde703d45704166f767385895c440afc762,496
|
|
6
|
-
llama_deploy/cli/env.py,sha256=bb1dcde428c779796ad2b39b58d84f08df75a15031afca577aca0db5ce9a9ea0,1015
|
|
7
|
-
llama_deploy/cli/interactive_prompts/utils.py,sha256=894d0cec574a5fa98de267cdc7a4f4f95fdbb4dbddf06635b2ec1d723db18940,2504
|
|
8
|
-
llama_deploy/cli/options.py,sha256=78b6e36e39fa88f0587146995e2cb66418b67d16f945f0b7570dab37cf5fc673,576
|
|
9
|
-
llama_deploy/cli/textual/deployment_form.py,sha256=261ce5102b84b71b1bf1e34518516aa4d3b45b3821ce874c93b19ebb80a957f5,15076
|
|
10
|
-
llama_deploy/cli/textual/git_validation.py,sha256=d83cb37aa452d9ebbe2cfec0d37580655c87a6a2352e66999586ecd7479f223f,13301
|
|
11
|
-
llama_deploy/cli/textual/github_callback_server.py,sha256=a74b1f5741bdaa682086771fd73a145e1e22359601f16f036f72a87e64b0a152,7444
|
|
12
|
-
llama_deploy/cli/textual/llama_loader.py,sha256=dfef7118eb42d0fec033731b3f3b16ed4dbf4c551f4059c36e290e73c9aa5d13,1244
|
|
13
|
-
llama_deploy/cli/textual/profile_form.py,sha256=2c6ca4690c22b499cc327b117c97e7914d4243b73faa92c0f5ac9cfdcf59b3d7,6015
|
|
14
|
-
llama_deploy/cli/textual/secrets_form.py,sha256=1fd47a5a5ee9dfa0fd2a86f5888894820897c55fbb0cd30e60d6bc08570288b5,6303
|
|
15
|
-
llama_deploy/cli/textual/styles.tcss,sha256=72338c5634bae0547384669382c4e06deec1380ef7bbc31099b1dca8ce49b2d0,2711
|
|
16
|
-
llamactl-0.3.0a4.dist-info/WHEEL,sha256=66530aef82d5020ef5af27ae0123c71abb9261377c5bc519376c671346b12918,79
|
|
17
|
-
llamactl-0.3.0a4.dist-info/entry_points.txt,sha256=b67e1eb64305058751a651a80f2d2268b5f7046732268421e796f64d4697f83c,52
|
|
18
|
-
llamactl-0.3.0a4.dist-info/METADATA,sha256=954ac8a1ced28d50d5f440a1fb27a022bc2bf1c09407461df37d2fbb3d1133a1,3166
|
|
19
|
-
llamactl-0.3.0a4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|