From ba73ac2861543a7dd07c903215295ca30d2b9a68 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Wed, 4 Feb 2026 12:30:06 +0000 Subject: [PATCH] Add CLI commands (init, run, test, prompt) --- src/promptforge/cli/commands/prompt.py | 139 +++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/promptforge/cli/commands/prompt.py diff --git a/src/promptforge/cli/commands/prompt.py b/src/promptforge/cli/commands/prompt.py new file mode 100644 index 0000000..778f1e2 --- /dev/null +++ b/src/promptforge/cli/commands/prompt.py @@ -0,0 +1,139 @@ +import sys +import click +from pathlib import Path +from datetime import datetime +from promptforge.core.prompt import Prompt, PromptVariable, VariableType +from promptforge.core.template import TemplateEngine +from promptforge.core.git_manager import GitManager + + +@click.group() +def prompt(): + """Manage prompts.""" + pass + + +@prompt.command("create") +@click.argument("name") +@click.option("--content", "-c", help="Prompt content") +@click.option("--description", "-d", help="Prompt description") +@click.option("--provider", "-p", help="Default provider") +@click.option("--tag", "-t", multiple=True, help="Tags for the prompt") +@click.pass_obj +def create(ctx, name: str, content: str, description: str, provider: str, tag: tuple): + """Create a new prompt.""" + prompts_dir = ctx["prompts_dir"] + + if not content: + click.echo("Enter prompt content (end with Ctrl+D on new line):") + content = click.get_text_stream("stdin").read() + + variables = [] + if "{" in content and "}" in content: + template_engine = TemplateEngine() + var_names = template_engine.get_variables(content) + for var_name in var_names: + var_type = click.prompt( + f"Variable '{var_name}' type", + type=click.Choice(["string", "integer", "float", "boolean", "choice"]), + default="string", + ) + is_required = click.confirm(f"Is '{var_name}' required?", default=True) + default_val = None + if not is_required: + default_val = click.prompt(f"Default value for '{var_name}'", default="") + variables.append(PromptVariable( + name=var_name, + type=VariableType(var_type), + required=is_required, + default=default_val, + )) + + prompt = Prompt( + name=name, + description=description, + content=content, + provider=provider, + tags=list(tag), + variables=variables, + ) + + filepath = prompt.save(prompts_dir) + click.echo(f"Created prompt: {filepath}") + + git_manager = GitManager(prompts_dir) + if (prompts_dir / ".git").exists(): + try: + git_manager.commit(f"Add prompt: {name}") + click.echo("Committed to git") + except Exception: + pass + + +@prompt.command("list") +@click.pass_obj +def list_prompts(ctx): + """List all prompts.""" + prompts_dir = ctx["prompts_dir"] + prompts = Prompt.list(prompts_dir) + + if not prompts: + click.echo("No prompts found. Create one with 'pf prompt create'") + return + + for prompt in prompts: + status = "✓" if prompt.provider else "○" + click.echo(f"{status} {prompt.name} (v{prompt.version})") + if prompt.description: + click.echo(f" {prompt.description}") + + +@prompt.command("show") +@click.argument("name") +@click.pass_obj +def show(ctx, name: str): + """Show prompt details.""" + prompts_dir = ctx["prompts_dir"] + prompts = Prompt.list(prompts_dir) + + prompt = next((p for p in prompts if p.name == name), None) + if not prompt: + click.echo(f"Prompt '{name}' not found", err=True) + raise click.Abort() + + click.echo(f"Name: {prompt.name}") + click.echo(f"Version: {prompt.version}") + if prompt.description: + click.echo(f"Description: {prompt.description}") + if prompt.provider: + click.echo(f"Provider: {prompt.provider}") + if prompt.tags: + click.echo(f"Tags: {', '.join(prompt.tags)}") + click.echo(f"\n--- Content ---") + click.echo(prompt.content) + + +@prompt.command("delete") +@click.argument("name") +@click.option("--yes", "-y", is_flag=True, help="Skip confirmation") +@click.pass_obj +def delete(ctx, name: str, yes: bool): + """Delete a prompt.""" + prompts_dir = ctx["prompts_dir"] + prompts = Prompt.list(prompts_dir) + + prompt = next((p for p in prompts if p.name == name), None) + if not prompt: + click.echo(f"Prompt '{name}' not found", err=True) + raise click.Abort() + + if not yes and not click.confirm(f"Delete prompt '{name}'?"): + raise click.Abort() + + filepath = prompts_dir / f"{name.lower().replace(' ', '_').replace('/', '_')}.yaml" + if filepath.exists(): + filepath.unlink() + click.echo(f"Deleted prompt: {name}") + else: + click.echo(f"Prompt file not found", err=True) + raise click.Abort() \ No newline at end of file