diff --git a/docs/source/distributions/building_distro.md b/docs/source/distributions/building_distro.md index 56b8d30a8..e039453bf 100644 --- a/docs/source/distributions/building_distro.md +++ b/docs/source/distributions/building_distro.md @@ -339,6 +339,48 @@ INFO: Application startup complete. INFO: Uvicorn running on http://['::', '0.0.0.0']:8321 (Press CTRL+C to quit) INFO: 2401:db00:35c:2d2b:face:0:c9:0:54678 - "GET /models/list HTTP/1.1" 200 OK ``` +### Listing Distributions +Using the list command, you can view all existing Llama Stack distributions, including stacks built from templates, from scratch, or using custom configuration files. + +``` +llama stack list -h +usage: llama stack list [-h] + +list the build stacks + +options: + -h, --help show this help message and exit +``` + +Example Usage + +``` +llama stack list +``` + +### Removing a Distribution +Use the remove command to delete a distribution you've previously built. + +``` +llama stack rm -h +usage: llama stack rm [-h] [--all] [name] + +Remove the build stack + +positional arguments: + name Name of the stack to delete (default: None) + +options: + -h, --help show this help message and exit + --all, -a Delete all stacks (use with caution) (default: False) +``` + +Example +``` +llama stack rm llamastack-test +``` + +To keep your environment organized and avoid clutter, consider using `llama stack list` to review old or unused distributions and `llama stack rm ` to delete them when they’re no longer needed. ### Troubleshooting diff --git a/llama_stack/cli/stack/list_stacks.py b/llama_stack/cli/stack/list_stacks.py index 64c29383a..2ea0fdeea 100644 --- a/llama_stack/cli/stack/list_stacks.py +++ b/llama_stack/cli/stack/list_stacks.py @@ -6,15 +6,15 @@ import argparse from pathlib import Path -from typing import Dict + from llama_stack.cli.subcommand import Subcommand from llama_stack.cli.table import print_table class StackListBuilds(Subcommand): - """List built stacks in .llama/distributions directory""" + """List built stacks in .llama/distributions directory""" - def __init__(self, subparsers: argparse._SubParsersAction): + def __init__(self, subparsers: argparse._SubParsersAction): super().__init__() self.parser = subparsers.add_parser( "list", @@ -24,47 +24,33 @@ class StackListBuilds(Subcommand): ) self._add_arguments() self.parser.set_defaults(func=self._list_stack_command) - - def _add_arguments(self): - self.parser.add_argument( - "--verbose", - "-v", - action="store_true", - help="Show additional details about each stack", - ) - def _get_distribution_dirs(self) -> Dict[str, Path]: + def _get_distribution_dirs(self) -> dict[str, Path]: """Return a dictionary of distribution names and their paths""" distributions = {} dist_dir = Path.home() / ".llama" / "distributions" - + if dist_dir.exists(): for stack_dir in dist_dir.iterdir(): if stack_dir.is_dir(): distributions[stack_dir.name] = stack_dir return distributions - def _list_stack_command(self, args: argparse.Namespace) -> None: + def _list_stack_command(self, args: argparse.Namespace) -> None: distributions = self._get_distribution_dirs() - + if not distributions: print("No stacks found in ~/.llama/distributions") return headers = ["Stack Name", "Path"] - if args.verbose: - headers.extend(["Build Config", "Run Config"]) - + headers.extend(["Build Config", "Run Config"]) rows = [] for name, path in distributions.items(): row = [name, str(path)] - - if args.verbose: - # Check for build and run config files - build_config = "Yes" if (path / f"{name}-build.yaml").exists() else "No" - run_config = "Yes" if (path / f"{name}-run.yaml").exists() else "No" - row.extend([build_config, run_config]) - + # Check for build and run config files + build_config = "Yes" if (path / f"{name}-build.yaml").exists() else "No" + run_config = "Yes" if (path / f"{name}-run.yaml").exists() else "No" + row.extend([build_config, run_config]) rows.append(row) - - print_table(rows, headers, separate_rows=True) \ No newline at end of file + print_table(rows, headers, separate_rows=True) diff --git a/llama_stack/cli/stack/remove.py b/llama_stack/cli/stack/remove.py index 57e756ab2..be7c49a5d 100644 --- a/llama_stack/cli/stack/remove.py +++ b/llama_stack/cli/stack/remove.py @@ -5,18 +5,20 @@ # the root directory of this source tree. import argparse -from pathlib import Path import shutil -from typing import Dict +import sys +from pathlib import Path + +from termcolor import cprint from llama_stack.cli.subcommand import Subcommand from llama_stack.cli.table import print_table class StackRemove(Subcommand): - """Remove the build stack""" + """Remove the build stack""" - def __init__(self, subparsers: argparse._SubParsersAction): + def __init__(self, subparsers: argparse._SubParsersAction): super().__init__() self.parser = subparsers.add_parser( "rm", @@ -27,25 +29,13 @@ class StackRemove(Subcommand): self._add_arguments() self.parser.set_defaults(func=self._remove_stack_build_command) - def _add_arguments(self) -> None: + def _add_arguments(self) -> None: self.parser.add_argument( "name", type=str, nargs="?", help="Name of the stack to delete", ) - self.parser.add_argument( - "--list", - "-l", - action="store_true", - help="List available stacks before deletion", - ) - self.parser.add_argument( - "--force", - "-f", - action="store_true", - help="Force deletion without confirmation", - ) self.parser.add_argument( "--all", "-a", @@ -53,18 +43,18 @@ class StackRemove(Subcommand): help="Delete all stacks (use with caution)", ) - def _get_distribution_dirs(self) -> Dict[str, Path]: + def _get_distribution_dirs(self) -> dict[str, Path]: """Return a dictionary of distribution names and their paths""" distributions = {} dist_dir = Path.home() / ".llama" / "distributions" - + if dist_dir.exists(): for stack_dir in dist_dir.iterdir(): if stack_dir.is_dir(): distributions[stack_dir.name] = stack_dir return distributions - def _list_stacks(self) -> None: + def _list_stacks(self) -> None: """Display available stacks in a table""" distributions = self._get_distribution_dirs() if not distributions: @@ -75,44 +65,52 @@ class StackRemove(Subcommand): rows = [[name, str(path)] for name, path in distributions.items()] print_table(rows, headers, separate_rows=True) - def _remove_stack_build_command(self, args: argparse.Namespace) -> None: + def _remove_stack_build_command(self, args: argparse.Namespace) -> None: distributions = self._get_distribution_dirs() - + if args.all: - if not args.force: - confirm = input("Are you sure you want to delete ALL stacks? [y/N] ").lower() - if confirm != 'y': - print("Deletion cancelled.") - return - + confirm = input("Are you sure you want to delete ALL stacks? [yes-i-really-want/N] ").lower() + if confirm != "yes-i-really-want": + print("Deletion cancelled.") + return + for name, path in distributions.items(): try: shutil.rmtree(path) print(f"Deleted stack: {name}") except Exception as e: - print(f"Failed to delete stack {name}: {e}") - return + cprint( + f"Failed to delete stack {name}: {e}", + color="red", + ) + sys.exit(2) - if args.list or not args.name: + if not args.name: self._list_stacks() if not args.name: return if args.name not in distributions: self._list_stacks() - print(f"Stack not found: {args.name}") + cprint( + f"Stack not found: {args.name}", + color="red", + ) return stack_path = distributions[args.name] - - if not args.force: - confirm = input(f"Are you sure you want to delete stack '{args.name}'? [y/N] ").lower() - if confirm != 'y': - print("Deletion cancelled.") - return + + confirm = input(f"Are you sure you want to delete stack '{args.name}'? [y/N] ").lower() + if confirm != "y": + print("Deletion cancelled.") + return try: shutil.rmtree(stack_path) print(f"Successfully deleted stack: {args.name}") except Exception as e: - print(f"Failed to delete stack {args.name}: {e}") \ No newline at end of file + cprint( + f"Failed to delete stack {args.name}: {e}", + color="red", + ) + sys.exit(2) diff --git a/llama_stack/cli/stack/stack.py b/llama_stack/cli/stack/stack.py index 9a0a491f2..3aff78e23 100644 --- a/llama_stack/cli/stack/stack.py +++ b/llama_stack/cli/stack/stack.py @@ -14,8 +14,8 @@ from llama_stack.cli.subcommand import Subcommand from .build import StackBuild from .list_apis import StackListApis from .list_providers import StackListProviders -from .run import StackRun from .remove import StackRemove +from .run import StackRun class StackParser(Subcommand):