bindai-cli 0.1.3__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.
- bindai_cli-0.1.3/PKG-INFO +9 -0
- bindai_cli-0.1.3/README.md +3 -0
- bindai_cli-0.1.3/pyproject.toml +29 -0
- bindai_cli-0.1.3/setup.cfg +4 -0
- bindai_cli-0.1.3/src/bindai_cli/__init__.py +1 -0
- bindai_cli-0.1.3/src/bindai_cli/__main__.py +9 -0
- bindai_cli-0.1.3/src/bindai_cli/app.py +49 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/__init__.py +1 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/add.py +23 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/doctor.py +122 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/inspect.py +42 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/new.py +84 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/run.py +67 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/template.py +222 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/version.py +13 -0
- bindai_cli-0.1.3/src/bindai_cli/commands/workflow.py +112 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/__init__.py +9 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/agent.py +8 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/directories.py +23 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/knowledge.py +0 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/memory.py +0 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/pyproject.py +23 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/tool.py +8 -0
- bindai_cli-0.1.3/src/bindai_cli/generators/workflow.py +31 -0
- bindai_cli-0.1.3/src/bindai_cli/inspectors/project.py +34 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/.env.example +5 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/.gitignore +30 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/LICENSE +0 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/README.md +32 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/agents/assistant.py +6 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/bindai.toml +16 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/knowledge/.gitkeep +0 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/main.py +23 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/memory/.gitkeep +0 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/requirements.txt +1 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/templates/.gitkeep +0 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/tests/.gitkeep +0 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/tools/.gitkeep +0 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/tools/echo.py +8 -0
- bindai_cli-0.1.3/src/bindai_cli/scaffolds/basic/workflows/.gitkeep +0 -0
- bindai_cli-0.1.3/src/bindai_cli/templates/installer.py +58 -0
- bindai_cli-0.1.3/src/bindai_cli/templates/models.py +24 -0
- bindai_cli-0.1.3/src/bindai_cli/templates/registry.py +50 -0
- bindai_cli-0.1.3/src/bindai_cli/templates/validator.py +56 -0
- bindai_cli-0.1.3/src/bindai_cli/templates/workflow-basic/template.json +14 -0
- bindai_cli-0.1.3/src/bindai_cli/utils/config.py +14 -0
- bindai_cli-0.1.3/src/bindai_cli/utils/providers.py +8 -0
- bindai_cli-0.1.3/src/bindai_cli/utils/scaffold.py +65 -0
- bindai_cli-0.1.3/src/bindai_cli/workflows/graph.py +34 -0
- bindai_cli-0.1.3/src/bindai_cli/workflows/validator.py +32 -0
- bindai_cli-0.1.3/src/bindai_cli.egg-info/PKG-INFO +9 -0
- bindai_cli-0.1.3/src/bindai_cli.egg-info/SOURCES.txt +54 -0
- bindai_cli-0.1.3/src/bindai_cli.egg-info/dependency_links.txt +1 -0
- bindai_cli-0.1.3/src/bindai_cli.egg-info/entry_points.txt +2 -0
- bindai_cli-0.1.3/src/bindai_cli.egg-info/requires.txt +4 -0
- bindai_cli-0.1.3/src/bindai_cli.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "bindai-cli"
|
|
3
|
+
version = "0.1.3"
|
|
4
|
+
description = "BindAI Command Line Interface"
|
|
5
|
+
requires-python = ">=3.11"
|
|
6
|
+
|
|
7
|
+
dependencies = [
|
|
8
|
+
"typer>=0.16",
|
|
9
|
+
"rich>=14.0",
|
|
10
|
+
"python-dotenv>=1.0",
|
|
11
|
+
"bindai-config",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
bindai = "bindai_cli.__main__:main"
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["setuptools>=69"]
|
|
19
|
+
build-backend = "setuptools.build_meta"
|
|
20
|
+
|
|
21
|
+
[tool.setuptools.packages.find]
|
|
22
|
+
where = ["src"]
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.package-data]
|
|
25
|
+
bindai_cli = [
|
|
26
|
+
"templates/*/template.json",
|
|
27
|
+
"scaffolds/**/*",
|
|
28
|
+
"scaffolds/**/.*",
|
|
29
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.2"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from bindai_cli.commands.doctor import app as doctor_app
|
|
4
|
+
from bindai_cli.commands.inspect import app as inspect_app
|
|
5
|
+
from bindai_cli.commands.new import app as new_app
|
|
6
|
+
from bindai_cli.commands.run import app as run_app
|
|
7
|
+
from bindai_cli.commands.template import app as template_app
|
|
8
|
+
from bindai_cli.commands.version import app as version_app
|
|
9
|
+
from bindai_cli.commands.workflow import app as workflow_app
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(
|
|
12
|
+
help="BindAI Command Line Interface",
|
|
13
|
+
no_args_is_help=True,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
app.add_typer(
|
|
17
|
+
version_app,
|
|
18
|
+
name="version",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
app.add_typer(
|
|
22
|
+
doctor_app,
|
|
23
|
+
name="doctor",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
app.add_typer(
|
|
27
|
+
new_app,
|
|
28
|
+
name="new",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
app.add_typer(
|
|
32
|
+
run_app,
|
|
33
|
+
name="run",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
app.add_typer(
|
|
37
|
+
template_app,
|
|
38
|
+
name="template",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
app.add_typer(
|
|
42
|
+
workflow_app,
|
|
43
|
+
name="workflow",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
app.add_typer(
|
|
47
|
+
inspect_app,
|
|
48
|
+
name="inspect",
|
|
49
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from . import version as version
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from ..app import app
|
|
4
|
+
from ..generators import (
|
|
5
|
+
generate_agent,
|
|
6
|
+
generate_tool,
|
|
7
|
+
generate_workflow,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command("agent")
|
|
12
|
+
def add_agent(name: str):
|
|
13
|
+
generate_agent(Path.cwd(), name)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command("tool")
|
|
17
|
+
def add_tool(name: str):
|
|
18
|
+
generate_tool(Path.cwd(), name)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@app.command("workflow")
|
|
22
|
+
def add_workflow(name: str):
|
|
23
|
+
generate_workflow(Path.cwd(), name)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from dotenv import load_dotenv
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
|
|
12
|
+
from bindai_cli.utils.config import load_config
|
|
13
|
+
from bindai_cli.utils.providers import installed_providers
|
|
14
|
+
|
|
15
|
+
load_dotenv()
|
|
16
|
+
|
|
17
|
+
app = typer.Typer(
|
|
18
|
+
invoke_without_command=True,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
console = Console()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@app.callback()
|
|
25
|
+
def doctor() -> None:
|
|
26
|
+
"""
|
|
27
|
+
Check BindAI installation and project configuration.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
table = Table(title="BindAI Doctor")
|
|
31
|
+
|
|
32
|
+
table.add_column("Check", style="cyan")
|
|
33
|
+
table.add_column("Status")
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# Python
|
|
37
|
+
#
|
|
38
|
+
|
|
39
|
+
table.add_row(
|
|
40
|
+
"Python",
|
|
41
|
+
f"✅ {platform.python_version()}",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
#
|
|
45
|
+
# Virtual Environment
|
|
46
|
+
#
|
|
47
|
+
|
|
48
|
+
venv = hasattr(sys, "real_prefix") or sys.prefix != sys.base_prefix
|
|
49
|
+
|
|
50
|
+
table.add_row(
|
|
51
|
+
"Virtual Environment",
|
|
52
|
+
"✅ Active" if venv else "❌ Not Active",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Configuration
|
|
57
|
+
#
|
|
58
|
+
|
|
59
|
+
config = load_config()
|
|
60
|
+
|
|
61
|
+
if config:
|
|
62
|
+
table.add_row("Project", config.name)
|
|
63
|
+
|
|
64
|
+
table.add_row("Default Provider", config.provider)
|
|
65
|
+
|
|
66
|
+
table.add_row("Default Model", config.model)
|
|
67
|
+
else:
|
|
68
|
+
table.add_row(
|
|
69
|
+
"Configuration",
|
|
70
|
+
"⚠ No bindai.toml",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# Templates
|
|
75
|
+
#
|
|
76
|
+
|
|
77
|
+
from bindai_cli.templates.registry import TemplateRegistry
|
|
78
|
+
|
|
79
|
+
registry = TemplateRegistry()
|
|
80
|
+
|
|
81
|
+
table.add_row(
|
|
82
|
+
"Templates",
|
|
83
|
+
f"✅ {len(registry.list())} available",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
#
|
|
87
|
+
# Installed Providers
|
|
88
|
+
#
|
|
89
|
+
|
|
90
|
+
providers = installed_providers()
|
|
91
|
+
|
|
92
|
+
if providers:
|
|
93
|
+
table.add_row(
|
|
94
|
+
"Providers",
|
|
95
|
+
", ".join(providers),
|
|
96
|
+
)
|
|
97
|
+
else:
|
|
98
|
+
table.add_row(
|
|
99
|
+
"Providers",
|
|
100
|
+
"⚠ None installed",
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
#
|
|
104
|
+
# Environment Variables
|
|
105
|
+
#
|
|
106
|
+
|
|
107
|
+
table.add_row(
|
|
108
|
+
"OPENAI_API_KEY",
|
|
109
|
+
"✅ Configured" if os.getenv("OPENAI_API_KEY") else "⚠ Missing",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
table.add_row(
|
|
113
|
+
"ANTHROPIC_API_KEY",
|
|
114
|
+
"✅ Configured" if os.getenv("ANTHROPIC_API_KEY") else "⚠ Missing",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
table.add_row(
|
|
118
|
+
"OLLAMA_HOST",
|
|
119
|
+
os.getenv("OLLAMA_HOST", "localhost"),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
console.print(table)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from bindai_cli.inspectors.project import ProjectInspector
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(
|
|
12
|
+
invoke_without_command=True,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.callback()
|
|
19
|
+
def inspect():
|
|
20
|
+
|
|
21
|
+
inspector = ProjectInspector(
|
|
22
|
+
Path.cwd(),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
data = inspector.inspect()
|
|
26
|
+
|
|
27
|
+
table = Table(
|
|
28
|
+
title="Project Inspection",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
table.add_column("Component")
|
|
32
|
+
table.add_column("Count")
|
|
33
|
+
table.add_column("Items")
|
|
34
|
+
|
|
35
|
+
for key, values in data.items():
|
|
36
|
+
table.add_row(
|
|
37
|
+
key.capitalize(),
|
|
38
|
+
str(len(values)),
|
|
39
|
+
", ".join(values) if values else "-",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
console.print(table)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
from bindai_cli.utils.scaffold import copy_scaffold
|
|
9
|
+
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(
|
|
13
|
+
invoke_without_command=True,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.callback()
|
|
18
|
+
def new(
|
|
19
|
+
name: str,
|
|
20
|
+
install: bool = typer.Option(
|
|
21
|
+
False,
|
|
22
|
+
"--install",
|
|
23
|
+
help="Install dependencies.",
|
|
24
|
+
),
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Create a new BindAI project.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
root = Path(name)
|
|
31
|
+
|
|
32
|
+
if root.exists():
|
|
33
|
+
console.print(
|
|
34
|
+
f"[red]Project '{name}' already exists.[/red]"
|
|
35
|
+
)
|
|
36
|
+
raise typer.Exit(1)
|
|
37
|
+
|
|
38
|
+
scaffold = Path(__file__).parent.parent / "scaffolds" / "basic"
|
|
39
|
+
|
|
40
|
+
copy_scaffold(
|
|
41
|
+
scaffold,
|
|
42
|
+
root,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
console.print("[cyan]Creating virtual environment...[/cyan]")
|
|
46
|
+
|
|
47
|
+
subprocess.run(
|
|
48
|
+
[
|
|
49
|
+
sys.executable,
|
|
50
|
+
"-m",
|
|
51
|
+
"venv",
|
|
52
|
+
str(root / ".venv"),
|
|
53
|
+
],
|
|
54
|
+
check=False,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
print()
|
|
58
|
+
|
|
59
|
+
console.print(
|
|
60
|
+
f"[green]✓ Project '{name}' created successfully.[/green]"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
console.print()
|
|
64
|
+
|
|
65
|
+
console.print("[bold]Next steps:[/bold]")
|
|
66
|
+
|
|
67
|
+
console.print(f" cd {name}")
|
|
68
|
+
console.print(" .venv\\Scripts\\activate")
|
|
69
|
+
console.print(" pip install -r requirements.txt")
|
|
70
|
+
console.print(" bindai doctor")
|
|
71
|
+
console.print(" python main.py")
|
|
72
|
+
|
|
73
|
+
if install:
|
|
74
|
+
subprocess.run(
|
|
75
|
+
[
|
|
76
|
+
str(root / ".venv" / "Scripts" / "python"),
|
|
77
|
+
"-m",
|
|
78
|
+
"pip",
|
|
79
|
+
"install",
|
|
80
|
+
"-r",
|
|
81
|
+
str(root / "requirements.txt"),
|
|
82
|
+
],
|
|
83
|
+
check=False,
|
|
84
|
+
)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich import print
|
|
9
|
+
|
|
10
|
+
app = typer.Typer(
|
|
11
|
+
invoke_without_command=True,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.callback()
|
|
16
|
+
def run():
|
|
17
|
+
"""
|
|
18
|
+
Run the current BindAI project.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
project = Path.cwd()
|
|
22
|
+
|
|
23
|
+
config = project / "bindai.toml"
|
|
24
|
+
|
|
25
|
+
main = project / "main.py"
|
|
26
|
+
|
|
27
|
+
workflow = project / "workflow.py"
|
|
28
|
+
|
|
29
|
+
# Full BindAI project
|
|
30
|
+
if config.exists():
|
|
31
|
+
if not main.exists():
|
|
32
|
+
print("[red]main.py not found.[/red]")
|
|
33
|
+
|
|
34
|
+
raise typer.Exit(1)
|
|
35
|
+
|
|
36
|
+
target = main
|
|
37
|
+
|
|
38
|
+
# Template / example / demo
|
|
39
|
+
elif main.exists():
|
|
40
|
+
target = main
|
|
41
|
+
|
|
42
|
+
# Future workflow entrypoint
|
|
43
|
+
elif workflow.exists():
|
|
44
|
+
target = workflow
|
|
45
|
+
|
|
46
|
+
else:
|
|
47
|
+
print("[red]Nothing to run.[/red]")
|
|
48
|
+
|
|
49
|
+
print()
|
|
50
|
+
|
|
51
|
+
print("Expected one of:")
|
|
52
|
+
|
|
53
|
+
print(" • bindai.toml")
|
|
54
|
+
|
|
55
|
+
print(" • main.py")
|
|
56
|
+
|
|
57
|
+
print(" • workflow.py")
|
|
58
|
+
|
|
59
|
+
raise typer.Exit(1)
|
|
60
|
+
|
|
61
|
+
subprocess.run(
|
|
62
|
+
[
|
|
63
|
+
sys.executable,
|
|
64
|
+
str(target),
|
|
65
|
+
],
|
|
66
|
+
check=True,
|
|
67
|
+
)
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from bindai_cli.templates.installer import TemplateInstaller
|
|
10
|
+
from bindai_cli.templates.registry import TemplateRegistry
|
|
11
|
+
from bindai_cli.templates.validator import TemplateValidator
|
|
12
|
+
|
|
13
|
+
app = typer.Typer()
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command("list")
|
|
19
|
+
def list_templates():
|
|
20
|
+
|
|
21
|
+
registry = TemplateRegistry()
|
|
22
|
+
|
|
23
|
+
table = Table(title="Available Templates")
|
|
24
|
+
|
|
25
|
+
table.add_column("Name")
|
|
26
|
+
table.add_column("Category")
|
|
27
|
+
table.add_column("Status")
|
|
28
|
+
table.add_column("Description")
|
|
29
|
+
|
|
30
|
+
for template in registry.list():
|
|
31
|
+
table.add_row(
|
|
32
|
+
template.name,
|
|
33
|
+
template.category,
|
|
34
|
+
template.status,
|
|
35
|
+
template.description,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
console.print(table)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@app.command("install")
|
|
42
|
+
def install_template(
|
|
43
|
+
name: str,
|
|
44
|
+
):
|
|
45
|
+
|
|
46
|
+
console.print("[cyan]Installing template...[/cyan]")
|
|
47
|
+
|
|
48
|
+
installer = TemplateInstaller()
|
|
49
|
+
|
|
50
|
+
console.print(" • Reading metadata")
|
|
51
|
+
|
|
52
|
+
console.print(" • Copying files")
|
|
53
|
+
|
|
54
|
+
destination = Path.cwd()
|
|
55
|
+
|
|
56
|
+
if any(destination.iterdir()):
|
|
57
|
+
console.print("[yellow]Current directory is not empty.[/yellow]")
|
|
58
|
+
raise typer.Exit(1)
|
|
59
|
+
|
|
60
|
+
installer.install(
|
|
61
|
+
name,
|
|
62
|
+
destination,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
console.print(" • Creating environment")
|
|
66
|
+
|
|
67
|
+
console.print()
|
|
68
|
+
|
|
69
|
+
console.print(f"[green]✓ Template '{name}' installed successfully.[/green]")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@app.command("create")
|
|
73
|
+
def create_template(
|
|
74
|
+
template: str,
|
|
75
|
+
project: str,
|
|
76
|
+
):
|
|
77
|
+
"""
|
|
78
|
+
Create a new project from a template.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
from bindai_cli.utils.scaffold import copy_scaffold
|
|
82
|
+
|
|
83
|
+
registry = TemplateRegistry()
|
|
84
|
+
|
|
85
|
+
template_obj = registry.get(template)
|
|
86
|
+
|
|
87
|
+
if template_obj is None:
|
|
88
|
+
console.print(f"[red]Unknown template:[/red] {template}")
|
|
89
|
+
|
|
90
|
+
raise typer.Exit(1)
|
|
91
|
+
|
|
92
|
+
destination = Path(project)
|
|
93
|
+
|
|
94
|
+
if destination.exists():
|
|
95
|
+
console.print(f"[red]Project '{project}' already exists.[/red]")
|
|
96
|
+
|
|
97
|
+
raise typer.Exit(1)
|
|
98
|
+
|
|
99
|
+
copy_scaffold(
|
|
100
|
+
Path(template_obj.path),
|
|
101
|
+
destination,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
console.print()
|
|
105
|
+
|
|
106
|
+
console.print(f"[green]✓ Created project '{project}' from template '{template}'.[/green]")
|
|
107
|
+
|
|
108
|
+
console.print()
|
|
109
|
+
|
|
110
|
+
console.print("[bold]Next steps:[/bold]")
|
|
111
|
+
|
|
112
|
+
console.print(f" cd {project}")
|
|
113
|
+
|
|
114
|
+
console.print(" .venv\\Scripts\\activate")
|
|
115
|
+
|
|
116
|
+
console.print(" pip install -r requirements.txt")
|
|
117
|
+
|
|
118
|
+
console.print(" python main.py")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@app.command("info")
|
|
122
|
+
def info_template(
|
|
123
|
+
name: str,
|
|
124
|
+
):
|
|
125
|
+
|
|
126
|
+
registry = TemplateRegistry()
|
|
127
|
+
|
|
128
|
+
template = registry.get(name)
|
|
129
|
+
|
|
130
|
+
if template is None:
|
|
131
|
+
console.print(f"[red]Unknown template:[/red] {name}")
|
|
132
|
+
raise typer.Exit(1)
|
|
133
|
+
|
|
134
|
+
table = Table(title=template.title)
|
|
135
|
+
|
|
136
|
+
table.add_column("Field")
|
|
137
|
+
table.add_column("Value")
|
|
138
|
+
|
|
139
|
+
table.add_row("Name", template.name)
|
|
140
|
+
table.add_row("Version", template.version)
|
|
141
|
+
table.add_row("Author", template.author)
|
|
142
|
+
table.add_row("Category", template.category)
|
|
143
|
+
table.add_row("Status", template.status)
|
|
144
|
+
table.add_row("Description", template.description)
|
|
145
|
+
table.add_row(
|
|
146
|
+
"Tags",
|
|
147
|
+
", ".join(template.tags),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
console.print(table)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@app.command("search")
|
|
154
|
+
def search_templates(
|
|
155
|
+
query: str,
|
|
156
|
+
):
|
|
157
|
+
|
|
158
|
+
registry = TemplateRegistry()
|
|
159
|
+
|
|
160
|
+
templates = registry.list()
|
|
161
|
+
|
|
162
|
+
query = query.lower()
|
|
163
|
+
|
|
164
|
+
matches = [
|
|
165
|
+
template
|
|
166
|
+
for template in templates
|
|
167
|
+
if (
|
|
168
|
+
query in template.name.lower()
|
|
169
|
+
or query in template.title.lower()
|
|
170
|
+
or query in template.description.lower()
|
|
171
|
+
or query in template.category.lower()
|
|
172
|
+
or any(query in tag.lower() for tag in template.tags)
|
|
173
|
+
)
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
if not matches:
|
|
177
|
+
console.print(f"[yellow]No templates found for '{query}'.[/yellow]")
|
|
178
|
+
raise typer.Exit()
|
|
179
|
+
|
|
180
|
+
table = Table(title=f"Search: {query}")
|
|
181
|
+
|
|
182
|
+
table.add_column("Name")
|
|
183
|
+
table.add_column("Category")
|
|
184
|
+
table.add_column("Status")
|
|
185
|
+
table.add_column("Description")
|
|
186
|
+
|
|
187
|
+
for template in matches:
|
|
188
|
+
table.add_row(
|
|
189
|
+
template.name,
|
|
190
|
+
template.category,
|
|
191
|
+
template.status,
|
|
192
|
+
template.description,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
console.print(table)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@app.command("validate")
|
|
199
|
+
def validate_template(
|
|
200
|
+
name: str,
|
|
201
|
+
):
|
|
202
|
+
|
|
203
|
+
registry = TemplateRegistry()
|
|
204
|
+
|
|
205
|
+
template = registry.get(name)
|
|
206
|
+
|
|
207
|
+
if template is None:
|
|
208
|
+
console.print("[red]Template not found.[/red]")
|
|
209
|
+
|
|
210
|
+
raise typer.Exit(1)
|
|
211
|
+
|
|
212
|
+
errors = TemplateValidator.validate(Path(template.path))
|
|
213
|
+
|
|
214
|
+
if not errors:
|
|
215
|
+
console.print("[green]✓ Template is valid.[/green]")
|
|
216
|
+
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
console.print("[red]Template has problems:[/red]")
|
|
220
|
+
|
|
221
|
+
for error in errors:
|
|
222
|
+
console.print(f" • {error}")
|