diff --git a/src/commands/prompt.py b/src/commands/prompt.py new file mode 100644 index 0000000..00d720b --- /dev/null +++ b/src/commands/prompt.py @@ -0,0 +1,152 @@ +"""Prompt management CLI commands.""" + +from datetime import datetime +from typing import Optional + +import click + +from ..models import Prompt +from ..storage import PromptStorage + + +@click.group() +def prompt_cmd(): + """Manage prompts.""" + pass + + +@prompt_cmd.command("create") +@click.argument("name") +@click.option("--template", "-t", required=True, help="Prompt template string") +@click.option("--description", "-d", default="", help="Prompt description") +@click.option("--tag", multiple=True, help="Tags to add to the prompt") +@click.option("--variable", "-v", multiple=True, help="Variables as name:description:required") +@click.option("--provider", default="", help="LLM provider (ollama, lmstudio)") +@click.option("--model", default="", help="Model name") +@click.option("--dir", "prompt_dir", default=None, help="Prompt directory") +def create_prompt( + name: str, + template: str, + description: str, + tag: tuple, + variable: tuple, + provider: str, + model: str, + prompt_dir: Optional[str] +): + """Create a new prompt.""" + storage = PromptStorage(prompt_dir) + + if storage.prompt_exists(name): + click.echo(f"Error: Prompt '{name}' already exists", err=True) + return + + variables = [] + for v in variable: + if ":" in v: + parts = v.split(":", 2) + var_dict = { + "name": parts[0].strip(), + "description": parts[1].strip() if len(parts) > 1 else "", + "required": len(parts) < 3 or parts[2].strip().lower() != "false" + } + variables.append(var_dict) + + prompt = Prompt( + name=name, + template=template, + description=description, + tags=list(tag), + variables=variables, + provider=provider, + model=model, + created_at=datetime.now().isoformat(), + updated_at=datetime.now().isoformat(), + ) + + storage.save_prompt(prompt) + + for t in tag: + storage.add_tag_to_prompt(name, t) + + click.echo(f"Created prompt: {name}") + + +@prompt_cmd.command("list") +@click.option("--tag", "-t", default=None, help="Filter by tag") +@click.option("--dir", "prompt_dir", default=None, help="Prompt directory") +def list_prompts(tag: Optional[str], prompt_dir: Optional[str]): + """List all prompts.""" + from rich.console import Console + from rich.table import Table + + storage = PromptStorage(prompt_dir) + + if tag: + prompts = storage.get_prompts_by_tag(tag) + else: + prompt_names = storage.list_prompts() + prompts = [storage.get_prompt(n) for n in prompt_names] + + table = Table(title="Prompts") + table.add_column("Name", style="cyan") + table.add_column("Tags", style="magenta") + table.add_column("Description", style="green") + + for prompt in prompts: + tags_str = ", ".join(prompt.tags) if prompt.tags else "-" + desc = prompt.description[:50] + "..." if len(prompt.description) > 50 else prompt.description + table.add_row(prompt.name, tags_str, desc) + + console = Console() + console.print(table) + + +@prompt_cmd.command("show") +@click.argument("name") +@click.option("--dir", "prompt_dir", default=None, help="Prompt directory") +def show_prompt(name: str, prompt_dir: Optional[str]): + """Show prompt details.""" + from rich.console import Console + from rich.panel import Panel + + storage = PromptStorage(prompt_dir) + prompt = storage.get_prompt(name) + + if not prompt: + click.echo(f"Error: Prompt '{name}' not found", err=True) + return + + content = f"""Name: {prompt.name} + Description: {prompt.description} + Tags: {', '.join(prompt.tags) if prompt.tags else 'None'} + Variables: {', '.join(prompt.get_required_variables()) if prompt.get_required_variables() else 'None'} + Provider: {prompt.provider or 'Default'} + Model: {prompt.model or 'Default'} + + Template: +{prompt.template} + """ + + console = Console() + console.print(Panel(content, title=f"Prompt: {name}")) + + +@prompt_cmd.command("delete") +@click.argument("name") +@click.option("--force", "-f", is_flag=True, help="Skip confirmation") +@click.option("--dir", "prompt_dir", default=None, help="Prompt directory") +def delete_prompt(name: str, force: bool, prompt_dir: Optional[str]): + """Delete a prompt.""" + storage = PromptStorage(prompt_dir) + + if not storage.prompt_exists(name): + click.echo(f"Error: Prompt '{name}' not found", err=True) + return + + if not force: + if not click.confirm(f"Delete prompt '{name}'?"): + return + + storage.delete_prompt(name) + click.echo(f"Deleted prompt: {name}")