Source code for neurocore.cli.new_cmd

"""neurocore new — scaffold a project from a template.

Usage:
    neurocore new --list
    neurocore new ollama-agent my-agent
    neurocore new research-agent ac1-researcher --dir ~/projects
"""
from __future__ import annotations

from pathlib import Path
from typing import Optional

import typer
from rich.console import Console
from rich.table import Table

from neurocore.scaffold.registry import TEMPLATES, get_template, list_templates
from neurocore.scaffold.render import TEMPLATES_DIR, render_tree

console = Console()


def _print_templates() -> None:
    table = Table(title="Available templates")
    table.add_column("Template", style="cyan")
    table.add_column("Description")
    table.add_column("Suggested skills", style="dim")
    for spec in list_templates():
        table.add_row(spec.name, spec.description, ", ".join(spec.suggested_skills))
    console.print(table)


[docs] def new_project( template: Optional[str] = typer.Argument( None, help="Template name (run 'neurocore new --list' to see options)." ), name: Optional[str] = typer.Argument(None, help="Project name."), directory: Path = typer.Option( Path("."), "--dir", "-d", help="Parent directory to create the project in." ), list_flag: bool = typer.Option( False, "--list", "-l", help="List available templates and exit." ), ) -> None: """Scaffold a new NeuroCore project from a template.""" if list_flag or template is None: _print_templates() if list_flag: return console.print("\n[dim]Usage:[/dim] neurocore new <template> <name>") raise typer.Exit(code=0 if list_flag else 1) spec = get_template(template) if spec is None: console.print(f"[red]Unknown template:[/red] '{template}'\n") _print_templates() raise typer.Exit(code=1) if not name: console.print("[red]Error:[/red] a project name is required.") raise typer.Exit(code=1) project_dir = directory.resolve() / name if project_dir.exists(): console.print(f"[red]Error:[/red] Directory '{project_dir}' already exists.") raise typer.Exit(code=1) src = TEMPLATES_DIR / spec.dir_name if not src.is_dir(): console.print(f"[red]Error:[/red] template files missing for '{template}'.") raise typer.Exit(code=1) try: render_tree(src, project_dir, {"project_name": name}) # Ensure conventional working directories exist. for sub in ("data", "logs", "skills"): (project_dir / sub).mkdir(parents=True, exist_ok=True) except OSError as e: console.print(f"[red]Error:[/red] Failed to create project: {e}") raise typer.Exit(code=1) from None console.print(f"\n[green]Created[/green] {name} [dim](template: {template})[/dim]") console.print(f" {project_dir}\n") console.print("[dim]Next steps:[/dim]") console.print(f" cd {name}") extras = "".join(f"[{x}]" for x in spec.requires_extras) console.print(f' pip install "neurocore-ai{extras}"') for skill in spec.suggested_skills: console.print(f" pip install {skill}") console.print(" cp .env.example .env # then add your keys") console.print(" neurocore run blueprints/*.flow.yaml")
# Make TEMPLATES importable for tests without circular import concerns. __all__ = ["new_project", "TEMPLATES"]