bindai-cli 0.1.8__tar.gz → 0.2.1__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.8 → bindai_cli-0.2.1}/PKG-INFO +4 -11
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/README.md +1 -9
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/pyproject.toml +4 -3
- bindai_cli-0.2.1/src/bindai_cli/__init__.py +1 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/app.py +15 -4
- bindai_cli-0.2.1/src/bindai_cli/commands/config.py +204 -0
- bindai_cli-0.2.1/src/bindai_cli/commands/connections.py +144 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/doctor.py +53 -0
- bindai_cli-0.2.1/src/bindai_cli/commands/new.py +116 -0
- bindai_cli-0.2.1/src/bindai_cli/scaffolds/basic/requirements.txt +1 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli.egg-info/PKG-INFO +4 -11
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli.egg-info/SOURCES.txt +4 -0
- bindai_cli-0.2.1/src/bindai_cli.egg-info/requires.txt +5 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/tests/test_app.py +7 -0
- bindai_cli-0.2.1/tests/test_config.py +461 -0
- bindai_cli-0.2.1/tests/test_connections.py +416 -0
- bindai_cli-0.2.1/tests/test_doctor.py +170 -0
- bindai_cli-0.2.1/tests/test_new.py +208 -0
- bindai_cli-0.1.8/src/bindai_cli/__init__.py +0 -1
- bindai_cli-0.1.8/src/bindai_cli/commands/new.py +0 -80
- bindai_cli-0.1.8/src/bindai_cli/scaffolds/basic/requirements.txt +0 -1
- bindai_cli-0.1.8/src/bindai_cli.egg-info/requires.txt +0 -4
- bindai_cli-0.1.8/tests/test_doctor.py +0 -60
- bindai_cli-0.1.8/tests/test_new.py +0 -64
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/setup.cfg +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/__main__.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/__init__.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/add.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/inspect.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/run.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/template.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/version.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/commands/workflow.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/__init__.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/agent.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/directories.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/knowledge.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/memory.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/pyproject.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/tool.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/generators/workflow.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/inspectors/project.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/.env.example +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/.gitignore +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/LICENSE +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/README.md +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/__pycache__/main.cpython-314.pyc +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/agents/__pycache__/assistant.cpython-314.pyc +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/agents/assistant.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/bindai.toml +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/knowledge/.gitkeep +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/main.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/memory/.gitkeep +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/templates/.gitkeep +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/tests/.gitkeep +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/tools/.gitkeep +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/tools/__pycache__/echo.cpython-314.pyc +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/tools/echo.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/scaffolds/basic/workflows/.gitkeep +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/templates/installer.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/templates/models.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/templates/registry.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/templates/validator.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/templates/workflow-basic/template.json +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/utils/config.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/utils/providers.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/utils/scaffold.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/workflows/graph.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli/workflows/validator.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli.egg-info/dependency_links.txt +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli.egg-info/entry_points.txt +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/src/bindai_cli.egg-info/top_level.txt +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/tests/test_run.py +0 -0
- {bindai_cli-0.1.8 → bindai_cli-0.2.1}/tests/test_templates.py +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bindai-cli
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: BindAI Command Line Interface
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
7
|
Requires-Dist: typer>=0.16
|
|
8
8
|
Requires-Dist: rich>=14.0
|
|
9
9
|
Requires-Dist: python-dotenv>=1.0
|
|
10
|
-
Requires-Dist: bindai-config>=0.
|
|
10
|
+
Requires-Dist: bindai-config>=0.2.0
|
|
11
|
+
Requires-Dist: bindai-connections[credentials]>=0.2.0
|
|
11
12
|
|
|
12
13
|
# BindAI CLI
|
|
13
14
|
|
|
@@ -19,7 +20,7 @@ The CLI is designed to provide a convenient developer workflow around the BindAI
|
|
|
19
20
|
|
|
20
21
|
The BindAI CLI provides commands for common development tasks, including:
|
|
21
22
|
|
|
22
|
-
* Project
|
|
23
|
+
* Project creation
|
|
23
24
|
* Project scaffolding
|
|
24
25
|
* BindAI environment inspection
|
|
25
26
|
* Framework diagnostics
|
|
@@ -63,14 +64,6 @@ Inspect the current BindAI environment or project:
|
|
|
63
64
|
bindai inspect
|
|
64
65
|
```
|
|
65
66
|
|
|
66
|
-
### Initialize
|
|
67
|
-
|
|
68
|
-
Initialize a BindAI project:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
bindai init
|
|
72
|
-
```
|
|
73
|
-
|
|
74
67
|
### Create a Project
|
|
75
68
|
|
|
76
69
|
Create a new BindAI project:
|
|
@@ -8,7 +8,7 @@ The CLI is designed to provide a convenient developer workflow around the BindAI
|
|
|
8
8
|
|
|
9
9
|
The BindAI CLI provides commands for common development tasks, including:
|
|
10
10
|
|
|
11
|
-
* Project
|
|
11
|
+
* Project creation
|
|
12
12
|
* Project scaffolding
|
|
13
13
|
* BindAI environment inspection
|
|
14
14
|
* Framework diagnostics
|
|
@@ -52,14 +52,6 @@ Inspect the current BindAI environment or project:
|
|
|
52
52
|
bindai inspect
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
### Initialize
|
|
56
|
-
|
|
57
|
-
Initialize a BindAI project:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
bindai init
|
|
61
|
-
```
|
|
62
|
-
|
|
63
55
|
### Create a Project
|
|
64
56
|
|
|
65
57
|
Create a new BindAI project:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bindai-cli"
|
|
3
|
-
version = "0.1
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "BindAI Command Line Interface"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -9,7 +9,8 @@ dependencies = [
|
|
|
9
9
|
"typer>=0.16",
|
|
10
10
|
"rich>=14.0",
|
|
11
11
|
"python-dotenv>=1.0",
|
|
12
|
-
"bindai-config>=0.
|
|
12
|
+
"bindai-config>=0.2.0",
|
|
13
|
+
"bindai-connections[credentials]>=0.2.0",
|
|
13
14
|
]
|
|
14
15
|
|
|
15
16
|
[project.scripts]
|
|
@@ -27,4 +28,4 @@ bindai_cli = [
|
|
|
27
28
|
"templates/*/template.json",
|
|
28
29
|
"scaffolds/**/*",
|
|
29
30
|
"scaffolds/**/.*",
|
|
30
|
-
]
|
|
31
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.1"
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import typer
|
|
2
2
|
|
|
3
|
+
from bindai_cli.commands.config import app as config_app
|
|
4
|
+
from bindai_cli.commands.connections import app as connections_app
|
|
3
5
|
from bindai_cli.commands.doctor import app as doctor_app
|
|
4
6
|
from bindai_cli.commands.inspect import app as inspect_app
|
|
5
|
-
from bindai_cli.commands.new import
|
|
7
|
+
from bindai_cli.commands.new import new
|
|
6
8
|
from bindai_cli.commands.run import app as run_app
|
|
7
9
|
from bindai_cli.commands.template import app as template_app
|
|
8
10
|
from bindai_cli.commands.version import app as version_app
|
|
@@ -23,10 +25,9 @@ app.add_typer(
|
|
|
23
25
|
name="doctor",
|
|
24
26
|
)
|
|
25
27
|
|
|
26
|
-
app.
|
|
27
|
-
new_app,
|
|
28
|
+
app.command(
|
|
28
29
|
name="new",
|
|
29
|
-
)
|
|
30
|
+
)(new)
|
|
30
31
|
|
|
31
32
|
app.add_typer(
|
|
32
33
|
run_app,
|
|
@@ -47,3 +48,13 @@ app.add_typer(
|
|
|
47
48
|
inspect_app,
|
|
48
49
|
name="inspect",
|
|
49
50
|
)
|
|
51
|
+
|
|
52
|
+
app.add_typer(
|
|
53
|
+
config_app,
|
|
54
|
+
name="config",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
app.add_typer(
|
|
58
|
+
connections_app,
|
|
59
|
+
name="connections",
|
|
60
|
+
)
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import fields
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, get_args, get_type_hints
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from bindai_config import ProjectConfig, ProjectRuntime, TomlWriter
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(
|
|
13
|
+
help="Inspect and modify BindAI project configuration.",
|
|
14
|
+
no_args_is_help=True,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
console = Console()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@app.command(name="list")
|
|
21
|
+
def list_config() -> None:
|
|
22
|
+
"""
|
|
23
|
+
List effective project configuration and its source.
|
|
24
|
+
"""
|
|
25
|
+
runtime = ProjectRuntime(Path.cwd())
|
|
26
|
+
values = runtime.resolver.all()
|
|
27
|
+
|
|
28
|
+
table = Table(title="Configuration")
|
|
29
|
+
table.add_column("Name", style="cyan")
|
|
30
|
+
table.add_column("Value")
|
|
31
|
+
table.add_column("Source")
|
|
32
|
+
|
|
33
|
+
for name, config_value in values.items():
|
|
34
|
+
table.add_row(
|
|
35
|
+
name,
|
|
36
|
+
str(config_value.value),
|
|
37
|
+
config_value.source,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
console.print(table)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@app.command(name="get")
|
|
44
|
+
def get_config(
|
|
45
|
+
name: str = typer.Argument(
|
|
46
|
+
...,
|
|
47
|
+
help="Configuration field to inspect.",
|
|
48
|
+
),
|
|
49
|
+
) -> None:
|
|
50
|
+
"""
|
|
51
|
+
Show one effective configuration value and its source.
|
|
52
|
+
"""
|
|
53
|
+
runtime = ProjectRuntime(Path.cwd())
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
config_value = runtime.resolver.resolve(name)
|
|
57
|
+
except KeyError as exc:
|
|
58
|
+
raise typer.BadParameter(
|
|
59
|
+
f'Unknown configuration field "{name}".',
|
|
60
|
+
) from exc
|
|
61
|
+
|
|
62
|
+
console.print(f"{name} = {config_value.value}")
|
|
63
|
+
console.print(f"source = {config_value.source}")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@app.command(name="set")
|
|
67
|
+
def set_config(
|
|
68
|
+
name: str = typer.Argument(
|
|
69
|
+
...,
|
|
70
|
+
help="Configuration field to update.",
|
|
71
|
+
),
|
|
72
|
+
value: str = typer.Argument(
|
|
73
|
+
...,
|
|
74
|
+
help="Value to persist in bindai.toml.",
|
|
75
|
+
),
|
|
76
|
+
) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Set one project configuration value in bindai.toml.
|
|
79
|
+
"""
|
|
80
|
+
config_path = Path.cwd() / "bindai.toml"
|
|
81
|
+
|
|
82
|
+
if not config_path.exists():
|
|
83
|
+
raise typer.BadParameter(
|
|
84
|
+
f'No bindai.toml found in "{Path.cwd()}".',
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
expected_type = _field_type(name)
|
|
89
|
+
converted_value = _convert_value(
|
|
90
|
+
name,
|
|
91
|
+
value,
|
|
92
|
+
expected_type,
|
|
93
|
+
)
|
|
94
|
+
except KeyError as exc:
|
|
95
|
+
raise typer.BadParameter(str(exc).strip("'")) from exc
|
|
96
|
+
except ValueError as exc:
|
|
97
|
+
raise typer.BadParameter(str(exc)) from exc
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
TomlWriter().set(
|
|
101
|
+
config_path,
|
|
102
|
+
name,
|
|
103
|
+
converted_value,
|
|
104
|
+
)
|
|
105
|
+
except (TypeError, ValueError) as exc:
|
|
106
|
+
raise typer.BadParameter(str(exc)) from exc
|
|
107
|
+
|
|
108
|
+
console.print(
|
|
109
|
+
f'Set {name} = {converted_value!r} in {config_path.name}.',
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@app.command(name="path")
|
|
114
|
+
def config_path() -> None:
|
|
115
|
+
"""
|
|
116
|
+
Show the path to the active bindai.toml file.
|
|
117
|
+
"""
|
|
118
|
+
config_path = Path.cwd() / "bindai.toml"
|
|
119
|
+
|
|
120
|
+
if not config_path.exists():
|
|
121
|
+
raise typer.BadParameter(
|
|
122
|
+
f'No bindai.toml found in "{Path.cwd()}".',
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
console.print(config_path.resolve())
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _field_type(name: str) -> Any:
|
|
129
|
+
config_fields = {
|
|
130
|
+
field.name: field
|
|
131
|
+
for field in fields(ProjectConfig)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if name not in config_fields:
|
|
135
|
+
raise KeyError(
|
|
136
|
+
f'Unknown configuration field "{name}".'
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return get_type_hints(ProjectConfig)[name]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _convert_value(
|
|
143
|
+
name: str,
|
|
144
|
+
value: str,
|
|
145
|
+
expected_type: Any,
|
|
146
|
+
) -> Any:
|
|
147
|
+
expected_types = get_args(expected_type)
|
|
148
|
+
|
|
149
|
+
if expected_types:
|
|
150
|
+
non_none_types = tuple(
|
|
151
|
+
item
|
|
152
|
+
for item in expected_types
|
|
153
|
+
if item is not type(None)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
if len(non_none_types) == 1:
|
|
157
|
+
return _convert_value(
|
|
158
|
+
name,
|
|
159
|
+
value,
|
|
160
|
+
non_none_types[0],
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
raise ValueError(
|
|
164
|
+
f'Unsupported configuration type for "{name}".',
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if expected_type is str:
|
|
168
|
+
return value
|
|
169
|
+
|
|
170
|
+
if expected_type is int:
|
|
171
|
+
try:
|
|
172
|
+
return int(value)
|
|
173
|
+
except ValueError as exc:
|
|
174
|
+
raise ValueError(
|
|
175
|
+
f'Invalid value for "{name}": '
|
|
176
|
+
f'expected an integer, got "{value}".',
|
|
177
|
+
) from exc
|
|
178
|
+
|
|
179
|
+
if expected_type is float:
|
|
180
|
+
try:
|
|
181
|
+
return float(value)
|
|
182
|
+
except ValueError as exc:
|
|
183
|
+
raise ValueError(
|
|
184
|
+
f'Invalid value for "{name}": '
|
|
185
|
+
f'expected a number, got "{value}".',
|
|
186
|
+
) from exc
|
|
187
|
+
|
|
188
|
+
if expected_type is bool:
|
|
189
|
+
normalized = value.strip().lower()
|
|
190
|
+
|
|
191
|
+
if normalized in {"1", "true", "yes", "on"}:
|
|
192
|
+
return True
|
|
193
|
+
|
|
194
|
+
if normalized in {"0", "false", "no", "off"}:
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
raise ValueError(
|
|
198
|
+
f'Invalid value for "{name}": '
|
|
199
|
+
f'expected a boolean, got "{value}".',
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
raise ValueError(
|
|
203
|
+
f'Unsupported configuration type for "{name}".',
|
|
204
|
+
)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from bindai_config import get_provider_connection
|
|
7
|
+
from bindai_connections import (
|
|
8
|
+
ConnectionManifest,
|
|
9
|
+
KeyringProviderCredentialStore,
|
|
10
|
+
)
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
|
|
14
|
+
app = typer.Typer(
|
|
15
|
+
help="Manage provider connections.",
|
|
16
|
+
no_args_is_help=True,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
console = Console()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.command(name="add")
|
|
23
|
+
def add_connection(
|
|
24
|
+
provider: str = typer.Argument(
|
|
25
|
+
...,
|
|
26
|
+
help="Provider to connect.",
|
|
27
|
+
),
|
|
28
|
+
name: str | None = typer.Option(
|
|
29
|
+
None,
|
|
30
|
+
"--name",
|
|
31
|
+
help="Connection name. Defaults to the provider name.",
|
|
32
|
+
),
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Store a connection credential and register its non-secret metadata.
|
|
36
|
+
"""
|
|
37
|
+
provider_name = provider.strip().lower()
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
get_provider_connection(provider_name)
|
|
41
|
+
except KeyError as exc:
|
|
42
|
+
raise typer.BadParameter(
|
|
43
|
+
str(exc).strip("'"),
|
|
44
|
+
) from exc
|
|
45
|
+
|
|
46
|
+
connection_name = (
|
|
47
|
+
name.strip().lower()
|
|
48
|
+
if name is not None
|
|
49
|
+
else provider_name
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if not connection_name:
|
|
53
|
+
raise typer.BadParameter(
|
|
54
|
+
"Connection name cannot be empty.",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
credential = typer.prompt(
|
|
58
|
+
"Credential",
|
|
59
|
+
hide_input=True,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
store = KeyringProviderCredentialStore()
|
|
63
|
+
manifest = ConnectionManifest(
|
|
64
|
+
Path.cwd() / ".bindai" / "connections.toml",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
store.set(
|
|
68
|
+
connection_name,
|
|
69
|
+
credential,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
manifest.add(
|
|
73
|
+
connection_name,
|
|
74
|
+
provider_name,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
console.print(
|
|
78
|
+
f'Connection "{connection_name}" added for provider '
|
|
79
|
+
f'"{provider_name}".',
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@app.command(name="list")
|
|
84
|
+
def list_connections() -> None:
|
|
85
|
+
"""
|
|
86
|
+
List configured provider connections and credential status.
|
|
87
|
+
"""
|
|
88
|
+
manifest = ConnectionManifest(
|
|
89
|
+
Path.cwd() / ".bindai" / "connections.toml",
|
|
90
|
+
)
|
|
91
|
+
store = KeyringProviderCredentialStore()
|
|
92
|
+
|
|
93
|
+
connections = manifest.list()
|
|
94
|
+
|
|
95
|
+
table = Table(title="BindAI Connections")
|
|
96
|
+
|
|
97
|
+
table.add_column("Name", style="cyan")
|
|
98
|
+
table.add_column("Provider")
|
|
99
|
+
table.add_column("Credential")
|
|
100
|
+
|
|
101
|
+
for connection in connections:
|
|
102
|
+
credential_status = (
|
|
103
|
+
"Configured"
|
|
104
|
+
if store.exists(connection.name)
|
|
105
|
+
else "Missing"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
table.add_row(
|
|
109
|
+
connection.name,
|
|
110
|
+
connection.provider,
|
|
111
|
+
credential_status,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
console.print(table)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@app.command(name="remove")
|
|
118
|
+
def remove_connection(
|
|
119
|
+
name: str = typer.Argument(
|
|
120
|
+
...,
|
|
121
|
+
help="Connection name to remove.",
|
|
122
|
+
),
|
|
123
|
+
) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Remove a named provider connection and its stored credential.
|
|
126
|
+
"""
|
|
127
|
+
manifest = ConnectionManifest(
|
|
128
|
+
Path.cwd() / ".bindai" / "connections.toml",
|
|
129
|
+
)
|
|
130
|
+
store = KeyringProviderCredentialStore()
|
|
131
|
+
|
|
132
|
+
connection = manifest.get(name)
|
|
133
|
+
|
|
134
|
+
if connection is None:
|
|
135
|
+
raise typer.BadParameter(
|
|
136
|
+
f'Connection "{name}" not found.',
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
store.delete(connection.name)
|
|
140
|
+
manifest.remove(connection.name)
|
|
141
|
+
|
|
142
|
+
console.print(
|
|
143
|
+
f'Connection "{connection.name}" removed.',
|
|
144
|
+
)
|
|
@@ -3,8 +3,13 @@ from __future__ import annotations
|
|
|
3
3
|
import os
|
|
4
4
|
import platform
|
|
5
5
|
import sys
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import typer
|
|
9
|
+
from bindai_connections import (
|
|
10
|
+
ConnectionManifest,
|
|
11
|
+
KeyringProviderCredentialStore,
|
|
12
|
+
)
|
|
8
13
|
from dotenv import load_dotenv
|
|
9
14
|
from rich.console import Console
|
|
10
15
|
from rich.table import Table
|
|
@@ -64,6 +69,11 @@ def doctor() -> None:
|
|
|
64
69
|
table.add_row("Default Provider", config.provider)
|
|
65
70
|
|
|
66
71
|
table.add_row("Default Model", config.model)
|
|
72
|
+
|
|
73
|
+
_add_connection_checks(
|
|
74
|
+
table,
|
|
75
|
+
config.connection,
|
|
76
|
+
)
|
|
67
77
|
else:
|
|
68
78
|
table.add_row(
|
|
69
79
|
"Configuration",
|
|
@@ -120,3 +130,46 @@ def doctor() -> None:
|
|
|
120
130
|
)
|
|
121
131
|
|
|
122
132
|
console.print(table)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _add_connection_checks(
|
|
136
|
+
table: Table,
|
|
137
|
+
connection_name: str | None,
|
|
138
|
+
) -> None:
|
|
139
|
+
if connection_name is None:
|
|
140
|
+
table.add_row(
|
|
141
|
+
"Connection",
|
|
142
|
+
"Not configured",
|
|
143
|
+
)
|
|
144
|
+
return
|
|
145
|
+
|
|
146
|
+
table.add_row(
|
|
147
|
+
"Connection",
|
|
148
|
+
connection_name,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
manifest = ConnectionManifest(
|
|
152
|
+
Path.cwd() / ".bindai" / "connections.toml",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
connection = manifest.get(connection_name)
|
|
156
|
+
|
|
157
|
+
if connection is None:
|
|
158
|
+
table.add_row(
|
|
159
|
+
"Connection Credential",
|
|
160
|
+
"Connection not configured",
|
|
161
|
+
)
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
store = KeyringProviderCredentialStore()
|
|
165
|
+
|
|
166
|
+
if store.exists(connection.name):
|
|
167
|
+
table.add_row(
|
|
168
|
+
"Connection Credential",
|
|
169
|
+
"Configured",
|
|
170
|
+
)
|
|
171
|
+
else:
|
|
172
|
+
table.add_row(
|
|
173
|
+
"Connection Credential",
|
|
174
|
+
"Missing",
|
|
175
|
+
)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
|
|
9
|
+
from bindai_cli.utils.scaffold import copy_scaffold
|
|
10
|
+
|
|
11
|
+
console = Console()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _venv_python(root: Path) -> Path:
|
|
15
|
+
bin_dir = "Scripts" if os.name == "nt" else "bin"
|
|
16
|
+
return root / ".venv" / bin_dir / "python"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _activation_command() -> str:
|
|
20
|
+
if os.name == "nt":
|
|
21
|
+
return ".venv\\Scripts\\activate"
|
|
22
|
+
return "source .venv/bin/activate"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def new(
|
|
26
|
+
name: str,
|
|
27
|
+
install: bool = typer.Option(
|
|
28
|
+
False,
|
|
29
|
+
"--install",
|
|
30
|
+
help="Install dependencies.",
|
|
31
|
+
),
|
|
32
|
+
) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Create a new BindAI project.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
root = Path(name)
|
|
38
|
+
|
|
39
|
+
if root.exists():
|
|
40
|
+
console.print(f"[red]Project '{name}' already exists.[/red]")
|
|
41
|
+
raise typer.Exit(1)
|
|
42
|
+
|
|
43
|
+
scaffold = Path(__file__).parent.parent / "scaffolds" / "basic"
|
|
44
|
+
|
|
45
|
+
copy_scaffold(
|
|
46
|
+
scaffold,
|
|
47
|
+
root,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
console.print("[cyan]Creating virtual environment...[/cyan]")
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
subprocess.run(
|
|
54
|
+
[
|
|
55
|
+
sys.executable,
|
|
56
|
+
"-m",
|
|
57
|
+
"venv",
|
|
58
|
+
str(root / ".venv"),
|
|
59
|
+
],
|
|
60
|
+
check=True,
|
|
61
|
+
)
|
|
62
|
+
except subprocess.CalledProcessError as exc:
|
|
63
|
+
console.print(
|
|
64
|
+
"[red]Failed to create the virtual environment.[/red]"
|
|
65
|
+
)
|
|
66
|
+
console.print(
|
|
67
|
+
f"Project '{name}' was created, but setup is incomplete."
|
|
68
|
+
)
|
|
69
|
+
console.print(f"Command exited with status {exc.returncode}.")
|
|
70
|
+
raise typer.Exit(1) from exc
|
|
71
|
+
|
|
72
|
+
print()
|
|
73
|
+
|
|
74
|
+
if install:
|
|
75
|
+
console.print("[cyan]Installing dependencies...[/cyan]")
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
subprocess.run(
|
|
79
|
+
[
|
|
80
|
+
str(_venv_python(root)),
|
|
81
|
+
"-m",
|
|
82
|
+
"pip",
|
|
83
|
+
"install",
|
|
84
|
+
"-r",
|
|
85
|
+
str(root / "requirements.txt"),
|
|
86
|
+
],
|
|
87
|
+
check=True,
|
|
88
|
+
)
|
|
89
|
+
except subprocess.CalledProcessError as exc:
|
|
90
|
+
console.print(
|
|
91
|
+
"[red]Failed to install project dependencies.[/red]"
|
|
92
|
+
)
|
|
93
|
+
console.print(
|
|
94
|
+
f"Project '{name}' was created, but setup is incomplete."
|
|
95
|
+
)
|
|
96
|
+
console.print(f"Command exited with status {exc.returncode}.")
|
|
97
|
+
raise typer.Exit(1) from exc
|
|
98
|
+
|
|
99
|
+
print()
|
|
100
|
+
|
|
101
|
+
console.print(
|
|
102
|
+
f"[green]✓ Project '{name}' created successfully.[/green]"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
print()
|
|
106
|
+
|
|
107
|
+
console.print("[bold]Next steps:[/bold]")
|
|
108
|
+
|
|
109
|
+
console.print(f" cd {name}")
|
|
110
|
+
console.print(f" {_activation_command()}")
|
|
111
|
+
|
|
112
|
+
if not install:
|
|
113
|
+
console.print(" pip install -r requirements.txt")
|
|
114
|
+
|
|
115
|
+
console.print(" bindai doctor")
|
|
116
|
+
console.print(" python main.py")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bindai[openai]>=0.1.6
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bindai-cli
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: BindAI Command Line Interface
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
7
|
Requires-Dist: typer>=0.16
|
|
8
8
|
Requires-Dist: rich>=14.0
|
|
9
9
|
Requires-Dist: python-dotenv>=1.0
|
|
10
|
-
Requires-Dist: bindai-config>=0.
|
|
10
|
+
Requires-Dist: bindai-config>=0.2.0
|
|
11
|
+
Requires-Dist: bindai-connections[credentials]>=0.2.0
|
|
11
12
|
|
|
12
13
|
# BindAI CLI
|
|
13
14
|
|
|
@@ -19,7 +20,7 @@ The CLI is designed to provide a convenient developer workflow around the BindAI
|
|
|
19
20
|
|
|
20
21
|
The BindAI CLI provides commands for common development tasks, including:
|
|
21
22
|
|
|
22
|
-
* Project
|
|
23
|
+
* Project creation
|
|
23
24
|
* Project scaffolding
|
|
24
25
|
* BindAI environment inspection
|
|
25
26
|
* Framework diagnostics
|
|
@@ -63,14 +64,6 @@ Inspect the current BindAI environment or project:
|
|
|
63
64
|
bindai inspect
|
|
64
65
|
```
|
|
65
66
|
|
|
66
|
-
### Initialize
|
|
67
|
-
|
|
68
|
-
Initialize a BindAI project:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
bindai init
|
|
72
|
-
```
|
|
73
|
-
|
|
74
67
|
### Create a Project
|
|
75
68
|
|
|
76
69
|
Create a new BindAI project:
|