llamactl 0.3.13__tar.gz → 0.3.14__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.
Files changed (39) hide show
  1. {llamactl-0.3.13 → llamactl-0.3.14}/PKG-INFO +5 -5
  2. {llamactl-0.3.13 → llamactl-0.3.14}/pyproject.toml +5 -5
  3. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/commands/deployment.py +127 -4
  4. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/commands/init.py +24 -47
  5. {llamactl-0.3.13 → llamactl-0.3.14}/README.md +0 -0
  6. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/__init__.py +0 -0
  7. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/app.py +0 -0
  8. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/auth/client.py +0 -0
  9. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/client.py +0 -0
  10. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/commands/aliased_group.py +0 -0
  11. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/commands/auth.py +0 -0
  12. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/commands/env.py +0 -0
  13. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/commands/serve.py +0 -0
  14. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/_config.py +0 -0
  15. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/_migrations.py +0 -0
  16. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/auth_service.py +0 -0
  17. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/env_service.py +0 -0
  18. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/migrations/0001_init.sql +0 -0
  19. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/migrations/0002_add_auth_fields.sql +0 -0
  20. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/migrations/__init__.py +0 -0
  21. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/config/schema.py +0 -0
  22. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/debug.py +0 -0
  23. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/env.py +0 -0
  24. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/interactive_prompts/session_utils.py +0 -0
  25. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/interactive_prompts/utils.py +0 -0
  26. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/options.py +0 -0
  27. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/py.typed +0 -0
  28. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/styles.py +0 -0
  29. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/deployment_form.py +0 -0
  30. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/deployment_help.py +0 -0
  31. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/deployment_monitor.py +0 -0
  32. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/git_validation.py +0 -0
  33. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/github_callback_server.py +0 -0
  34. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/llama_loader.py +0 -0
  35. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/secrets_form.py +0 -0
  36. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/textual/styles.tcss +0 -0
  37. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/utils/env_inject.py +0 -0
  38. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/utils/redact.py +0 -0
  39. {llamactl-0.3.13 → llamactl-0.3.14}/src/llama_deploy/cli/utils/version.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: llamactl
3
- Version: 0.3.13
3
+ Version: 0.3.14
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[client]>=0.3.13,<0.4.0
9
- Requires-Dist: llama-deploy-appserver>=0.3.13,<0.4.0
10
- Requires-Dist: httpx>=0.24.0,<1.0.0
8
+ Requires-Dist: llama-deploy-core[client]>=0.3.14,<0.4.0
9
+ Requires-Dist: llama-deploy-appserver>=0.3.14,<0.4.0
10
+ Requires-Dist: vibe-llama-core>=0.1.0
11
11
  Requires-Dist: rich>=13.0.0
12
12
  Requires-Dist: questionary>=2.0.0
13
13
  Requires-Dist: click>=8.2.1
@@ -15,7 +15,7 @@ Requires-Dist: python-dotenv>=1.0.0
15
15
  Requires-Dist: tenacity>=9.1.2
16
16
  Requires-Dist: textual>=6.0.0
17
17
  Requires-Dist: aiohttp>=3.12.14
18
- Requires-Dist: copier>=9.9.0
18
+ Requires-Dist: copier>=9.10.2
19
19
  Requires-Dist: pyjwt[crypto]>=2.10.1
20
20
  Requires-Python: >=3.11, <4
21
21
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "llamactl"
3
- version = "0.3.13"
3
+ version = "0.3.14"
4
4
  description = "A command-line interface for managing LlamaDeploy projects and deployments"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -9,9 +9,9 @@ authors = [
9
9
  ]
10
10
  requires-python = ">=3.11, <4"
11
11
  dependencies = [
12
- "llama-deploy-core[client]>=0.3.13,<0.4.0",
13
- "llama-deploy-appserver>=0.3.13,<0.4.0",
14
- "httpx>=0.24.0,<1.0.0",
12
+ "llama-deploy-core[client]>=0.3.14,<0.4.0",
13
+ "llama-deploy-appserver>=0.3.14,<0.4.0",
14
+ "vibe-llama-core>=0.1.0",
15
15
  "rich>=13.0.0",
16
16
  "questionary>=2.0.0",
17
17
  "click>=8.2.1",
@@ -19,7 +19,7 @@ dependencies = [
19
19
  "tenacity>=9.1.2",
20
20
  "textual>=6.0.0",
21
21
  "aiohttp>=3.12.14",
22
- "copier>=9.9.0",
22
+ "copier>=9.10.2",
23
23
  "pyjwt[crypto]>=2.10.1",
24
24
  ]
25
25
 
@@ -12,13 +12,17 @@ import click
12
12
  import questionary
13
13
  from llama_deploy.cli.commands.auth import validate_authenticated_profile
14
14
  from llama_deploy.cli.styles import HEADER_COLOR, MUTED_COL, PRIMARY_COL, WARNING
15
- from llama_deploy.core.schema.deployments import DeploymentUpdate
15
+ from llama_deploy.core.schema.deployments import (
16
+ DeploymentHistoryResponse,
17
+ DeploymentResponse,
18
+ DeploymentUpdate,
19
+ )
16
20
  from rich import print as rprint
17
21
  from rich.table import Table
18
22
  from rich.text import Text
19
23
 
20
24
  from ..app import app, console
21
- from ..client import get_project_client
25
+ from ..client import get_project_client, project_client_context
22
26
  from ..interactive_prompts.session_utils import (
23
27
  is_interactive_session,
24
28
  )
@@ -221,8 +225,15 @@ def edit_deployment(deployment_id: str | None, interactive: bool) -> None:
221
225
  @deployments.command("update")
222
226
  @global_options
223
227
  @click.argument("deployment_id", required=False)
228
+ @click.option(
229
+ "--git-ref",
230
+ help="Reference branch or commit SHA for the deployment. If not provided, the current reference branch and latest commit on it will be used.",
231
+ default=None,
232
+ )
224
233
  @interactive_option
225
- def refresh_deployment(deployment_id: str | None, interactive: bool) -> None:
234
+ def refresh_deployment(
235
+ deployment_id: str | None, git_ref: str | None, interactive: bool
236
+ ) -> None:
226
237
  """Update the deployment, pulling the latest code from it's branch"""
227
238
  validate_authenticated_profile(interactive)
228
239
  try:
@@ -240,7 +251,9 @@ def refresh_deployment(deployment_id: str | None, interactive: bool) -> None:
240
251
 
241
252
  # Create an empty update to force git SHA refresh with spinner
242
253
  with console.status(f"Refreshing {deployment_name}..."):
243
- deployment_update = DeploymentUpdate()
254
+ deployment_update = DeploymentUpdate(
255
+ git_ref=git_ref,
256
+ )
244
257
  updated_deployment = asyncio.run(
245
258
  get_project_client().update_deployment(
246
259
  deployment_id,
@@ -263,6 +276,116 @@ def refresh_deployment(deployment_id: str | None, interactive: bool) -> None:
263
276
  raise click.Abort()
264
277
 
265
278
 
279
+ @deployments.command("history")
280
+ @global_options
281
+ @click.argument("deployment_id", required=False)
282
+ @interactive_option
283
+ def show_history(deployment_id: str | None, interactive: bool) -> None:
284
+ """Show release history for a deployment."""
285
+ validate_authenticated_profile(interactive)
286
+ try:
287
+ deployment_id = select_deployment(deployment_id, interactive=interactive)
288
+ if not deployment_id:
289
+ rprint(f"[{WARNING}]No deployment selected[/]")
290
+ return
291
+
292
+ async def _fetch_history() -> DeploymentHistoryResponse:
293
+ async with project_client_context() as client:
294
+ return await client.get_deployment_history(deployment_id)
295
+
296
+ history = asyncio.run(_fetch_history())
297
+ items = history.history
298
+ if not items:
299
+ rprint(f"No history recorded for {deployment_id}")
300
+ return
301
+
302
+ table = Table(show_edge=False, box=None, header_style=f"bold {HEADER_COLOR}")
303
+ table.add_column("Released At", style=MUTED_COL)
304
+ table.add_column("Git SHA", style=PRIMARY_COL)
305
+ # newest first
306
+ items_sorted = sorted(
307
+ items,
308
+ key=lambda it: it.released_at,
309
+ reverse=True,
310
+ )
311
+ for item in items_sorted:
312
+ ts = item.released_at.isoformat()
313
+ sha = item.git_sha
314
+ table.add_row(ts, sha)
315
+ console.print(table)
316
+ except Exception as e:
317
+ rprint(f"[red]Error: {e}[/red]")
318
+ raise click.Abort()
319
+
320
+
321
+ @deployments.command("rollback", hidden=True)
322
+ @global_options
323
+ @click.argument("deployment_id", required=False)
324
+ @click.option("--git-sha", required=False, help="Git SHA to roll back to")
325
+ @interactive_option
326
+ def rollback(deployment_id: str | None, git_sha: str | None, interactive: bool) -> None:
327
+ """Rollback a deployment to a previous git sha."""
328
+ validate_authenticated_profile(interactive)
329
+ try:
330
+ deployment_id = select_deployment(deployment_id, interactive=interactive)
331
+ if not deployment_id:
332
+ rprint(f"[{WARNING}]No deployment selected[/]")
333
+ return
334
+
335
+ if not git_sha:
336
+ # If not provided, prompt from history
337
+ async def _fetch_current_and_history() -> tuple[
338
+ DeploymentResponse, DeploymentHistoryResponse
339
+ ]:
340
+ async with project_client_context() as client:
341
+ current = await client.get_deployment(deployment_id)
342
+ hist = await client.get_deployment_history(deployment_id)
343
+ return current, hist
344
+
345
+ current_deployment, history = asyncio.run(_fetch_current_and_history())
346
+ current_sha = current_deployment.git_sha or ""
347
+
348
+ items = history.history or []
349
+ # Sort newest first
350
+ items_sorted = sorted(items, key=lambda it: it.released_at, reverse=True)
351
+ choices = []
352
+ for it in items_sorted:
353
+ short = it.git_sha[:7]
354
+ suffix = (
355
+ " [current]" if current_sha and it.git_sha == current_sha else ""
356
+ )
357
+ choices.append(
358
+ questionary.Choice(
359
+ title=f"{short}{suffix} ({it.released_at})", value=it.git_sha
360
+ )
361
+ )
362
+ if not choices:
363
+ rprint(f"[{WARNING}]No history available to rollback[/]")
364
+ return
365
+ git_sha = questionary.select("Select git sha:", choices=choices).ask()
366
+ if not git_sha:
367
+ rprint(f"[{WARNING}]Cancelled[/]")
368
+ return
369
+
370
+ if interactive and not confirm_action(
371
+ f"Rollback '{deployment_id}' to {git_sha[:7]}?"
372
+ ):
373
+ rprint(f"[{WARNING}]Cancelled[/]")
374
+ return
375
+
376
+ async def _do_rollback() -> DeploymentResponse:
377
+ async with project_client_context() as client:
378
+ return await client.rollback_deployment(deployment_id, git_sha)
379
+
380
+ updated = asyncio.run(_do_rollback())
381
+ rprint(
382
+ f"[green]Rollback initiated[/green]: {deployment_id} → {updated.git_sha[:7] if updated.git_sha else 'unknown'}"
383
+ )
384
+ except Exception as e:
385
+ rprint(f"[red]Error: {e}[/red]")
386
+ raise click.Abort()
387
+
388
+
266
389
  def select_deployment(
267
390
  deployment_id: str | None = None, interactive: bool = is_interactive_session()
268
391
  ) -> str | None:
@@ -9,7 +9,6 @@ from pathlib import Path
9
9
 
10
10
  import click
11
11
  import copier
12
- import httpx
13
12
  import questionary
14
13
  from click.exceptions import Exit
15
14
  from llama_deploy.cli.app import app
@@ -18,9 +17,9 @@ from llama_deploy.cli.options import (
18
17
  interactive_option,
19
18
  )
20
19
  from llama_deploy.cli.styles import HEADER_COLOR_HEX
21
- from llama_deploy.core.client.ssl_util import get_httpx_verify_param
22
20
  from rich import print as rprint
23
21
  from rich.text import Text
22
+ from vibe_llama_core.docs import get_agent_rules
24
23
 
25
24
 
26
25
  @app.command()
@@ -295,14 +294,16 @@ def _create(
295
294
  # Extract a short error message if present
296
295
  err_msg = ""
297
296
  if isinstance(e, subprocess.CalledProcessError):
298
- stderr = getattr(e, "stderr", b"")
299
- if isinstance(stderr, (bytes, bytearray)):
297
+ stderr_bytes = e.stderr or b""
298
+ if isinstance(stderr_bytes, (bytes, bytearray)):
300
299
  try:
301
- stderr = stderr.decode("utf-8", "ignore")
300
+ stderr_text = stderr_bytes.decode("utf-8", "ignore")
302
301
  except Exception:
303
- stderr = ""
304
- if isinstance(stderr, str) and stderr.strip():
305
- err_msg = stderr.strip().split("\n")[-1]
302
+ stderr_text = ""
303
+ else:
304
+ stderr_text = str(stderr_bytes)
305
+ if stderr_text.strip():
306
+ err_msg = stderr_text.strip().split("\n")[-1]
306
307
  elif isinstance(e, FileNotFoundError):
307
308
  err_msg = "git executable not found"
308
309
 
@@ -406,14 +407,6 @@ async def _download_and_write_agents_md(include_llama_cloud: bool) -> bool:
406
407
 
407
408
  Returns True if any documentation was fetched, False otherwise.
408
409
  """
409
- BASE_URL = "https://raw.githubusercontent.com/run-llama/vibe-llama/main"
410
-
411
- services: dict[str, str] = {
412
- "LlamaIndex": f"{BASE_URL}/documentation/llamaindex.md",
413
- "LlamaCloud Services": f"{BASE_URL}/documentation/llamacloud.md",
414
- "llama-index-workflows": f"{BASE_URL}/documentation/llama-index-workflows.md",
415
- "LlamaDeploy": f"{BASE_URL}/documentation/llamadeploy.md",
416
- }
417
410
 
418
411
  selected_services: list[str] = [
419
412
  "LlamaDeploy",
@@ -423,35 +416,19 @@ async def _download_and_write_agents_md(include_llama_cloud: bool) -> bool:
423
416
  if include_llama_cloud:
424
417
  selected_services.append("LlamaCloud Services")
425
418
 
426
- urls: list[str] = [(s, u) for s in selected_services if (u := services.get(s))]
427
-
428
- contents: list[str] = []
429
- timeout = httpx.Timeout(5.0)
430
- async with httpx.AsyncClient(
431
- timeout=timeout, verify=get_httpx_verify_param()
432
- ) as client:
433
-
434
- async def get_docs(service: str, url: str) -> str | None:
435
- try:
436
- resp = await client.get(url)
437
- resp.raise_for_status()
438
- text = resp.text.strip()
439
- if text:
440
- return text
441
- except Exception:
442
- # best-effort: skip failures
443
- rprint(
444
- f"[yellow]Failed to fetch documentation for {service}, skipping[/]"
445
- )
446
- return None
447
-
448
- results = await asyncio.gather(
449
- *[get_docs(service, url) for service, url in urls]
450
- )
451
- contents = [r for r in results if r is not None]
452
-
453
- if contents:
454
- agents_md = "\n\n---\n\n".join(contents) + "\n"
455
- Path("AGENTS.md").write_text(agents_md, encoding="utf-8")
419
+ downloads = 0
420
+
421
+ for service in selected_services:
422
+ try:
423
+ await get_agent_rules(
424
+ agent="OpenAI Codex CLI",
425
+ service=service,
426
+ overwrite_files=False,
427
+ verbose=False,
428
+ ) # type: ignore
429
+ except Exception:
430
+ rprint(f"[yellow]Failed to fetch documentation for {service}, skipping[/]")
431
+ else:
432
+ downloads += 1
456
433
 
457
- return bool(contents)
434
+ return downloads > 0
File without changes