proxima-cli 1.0.0__py3-none-any.whl
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.
- prox/__init__.py +3 -0
- prox/api.py +107 -0
- prox/auth.py +157 -0
- prox/cli.py +121 -0
- prox/commands/__init__.py +0 -0
- prox/commands/agent.py +345 -0
- prox/commands/catalog.py +242 -0
- prox/commands/governance.py +63 -0
- prox/commands/knowledge.py +141 -0
- prox/commands/model.py +69 -0
- prox/commands/ontology.py +209 -0
- prox/commands/platform.py +50 -0
- prox/commands/routine.py +84 -0
- prox/commands/secret.py +59 -0
- prox/commands/team.py +82 -0
- prox/commands/toolbox.py +136 -0
- prox/commands/workflow.py +129 -0
- prox/config.py +98 -0
- proxima_cli-1.0.0.dist-info/METADATA +115 -0
- proxima_cli-1.0.0.dist-info/RECORD +22 -0
- proxima_cli-1.0.0.dist-info/WHEEL +4 -0
- proxima_cli-1.0.0.dist-info/entry_points.txt +2 -0
prox/commands/team.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""prox team — manage agent hierarchy and relationships."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
import typer
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
from ..api import gateway_get, gateway_post, gateway_delete, APIError
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Manage agent teams and relationships.")
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@app.command("show")
|
|
14
|
+
def show_team():
|
|
15
|
+
"""Show agent hierarchy and relationships."""
|
|
16
|
+
try:
|
|
17
|
+
data = gateway_get("/team")
|
|
18
|
+
except APIError as e:
|
|
19
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
20
|
+
raise typer.Exit(1)
|
|
21
|
+
|
|
22
|
+
agents = data.get("agents", [])
|
|
23
|
+
relationships = data.get("relationships", [])
|
|
24
|
+
teams = data.get("teams", [])
|
|
25
|
+
|
|
26
|
+
if not agents:
|
|
27
|
+
console.print("[dim]No agents deployed.[/dim]")
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
# Show agents by domain
|
|
31
|
+
domains: dict[str, list] = {}
|
|
32
|
+
for a in agents:
|
|
33
|
+
d = a.get("domain", "unknown")
|
|
34
|
+
domains.setdefault(d, []).append(a)
|
|
35
|
+
|
|
36
|
+
console.print(f"\n[bold]AI Workforce[/bold] — {len(agents)} agents, {len(relationships)} relationships\n")
|
|
37
|
+
for domain, domain_agents in sorted(domains.items()):
|
|
38
|
+
console.print(f" [bold]{domain}[/bold]")
|
|
39
|
+
for a in domain_agents:
|
|
40
|
+
role = a.get("role", "agent")
|
|
41
|
+
status = a.get("status", "planned")
|
|
42
|
+
st_style = "green" if status == "active" else "dim"
|
|
43
|
+
prefix = " ★" if role == "orchestrator" else " "
|
|
44
|
+
console.print(f" {prefix} {a.get('codename', '')} ({a.get('name', a['id'])}) [{st_style}]{status}[/{st_style}]")
|
|
45
|
+
console.print()
|
|
46
|
+
|
|
47
|
+
if relationships:
|
|
48
|
+
console.print(f" [bold]Relationships:[/bold]")
|
|
49
|
+
for r in relationships[:15]:
|
|
50
|
+
console.print(f" {r.get('from', '?')} → {r.get('to', '?')}: {r.get('description', '')}")
|
|
51
|
+
if len(relationships) > 15:
|
|
52
|
+
console.print(f" ... +{len(relationships) - 15} more")
|
|
53
|
+
console.print()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@app.command("add")
|
|
57
|
+
def add_relationship(
|
|
58
|
+
from_agent: str = typer.Option(..., "--from", help="Source agent ID"),
|
|
59
|
+
to_agent: str = typer.Option(..., "--to", help="Target agent ID"),
|
|
60
|
+
description: str = typer.Option(..., "--desc", help="Relationship description"),
|
|
61
|
+
):
|
|
62
|
+
"""Add a relationship between two agents."""
|
|
63
|
+
try:
|
|
64
|
+
gateway_post("/team/relationships", {"from": from_agent, "to": to_agent, "description": description})
|
|
65
|
+
console.print(f"[green]✓[/green] Relationship added: {from_agent} → {to_agent}")
|
|
66
|
+
except APIError as e:
|
|
67
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
68
|
+
raise typer.Exit(1)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@app.command("remove")
|
|
72
|
+
def remove_relationship(
|
|
73
|
+
from_agent: str = typer.Option(..., "--from", help="Source agent ID"),
|
|
74
|
+
to_agent: str = typer.Option(..., "--to", help="Target agent ID"),
|
|
75
|
+
):
|
|
76
|
+
"""Remove a relationship between two agents."""
|
|
77
|
+
try:
|
|
78
|
+
gateway_delete("/team/relationships") # This needs body — use post with delete semantic
|
|
79
|
+
console.print(f"[green]✓[/green] Relationship removed: {from_agent} → {to_agent}")
|
|
80
|
+
except APIError as e:
|
|
81
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
82
|
+
raise typer.Exit(1)
|
prox/commands/toolbox.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""prox toolbox — manage toolboxes (tool containers)."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
from ..api import gateway_get, gateway_post, gateway_delete, APIError
|
|
12
|
+
from ..config import get_value
|
|
13
|
+
|
|
14
|
+
app = typer.Typer(help="Manage toolboxes.")
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command("list")
|
|
19
|
+
def list_toolboxes():
|
|
20
|
+
"""List registered toolboxes."""
|
|
21
|
+
try:
|
|
22
|
+
data = gateway_get("/build/toolboxes")
|
|
23
|
+
except APIError as e:
|
|
24
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
25
|
+
raise typer.Exit(1)
|
|
26
|
+
|
|
27
|
+
toolboxes = data.get("toolboxes", [])
|
|
28
|
+
if not toolboxes:
|
|
29
|
+
console.print("[dim]No toolboxes registered.[/dim]")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
table = Table(title=f"Toolboxes ({len(toolboxes)})")
|
|
33
|
+
table.add_column("ID", style="bold")
|
|
34
|
+
table.add_column("Name")
|
|
35
|
+
table.add_column("Tools", justify="right")
|
|
36
|
+
table.add_column("Endpoint", style="dim")
|
|
37
|
+
|
|
38
|
+
for t in toolboxes:
|
|
39
|
+
table.add_row(t.get("id"), t.get("name", ""), str(len(t.get("tools", []))), t.get("endpoint", ""))
|
|
40
|
+
|
|
41
|
+
console.print(table)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@app.command("register")
|
|
45
|
+
def register_toolbox(
|
|
46
|
+
id: str = typer.Option(..., "--id", help="Toolbox ID"),
|
|
47
|
+
endpoint: str = typer.Option(..., "--endpoint", help="Toolbox HTTP endpoint"),
|
|
48
|
+
name: Optional[str] = typer.Option(None, "--name", help="Display name"),
|
|
49
|
+
discover: bool = typer.Option(False, "--discover", help="Auto-discover tools from OpenAPI"),
|
|
50
|
+
):
|
|
51
|
+
"""Register an existing toolbox endpoint."""
|
|
52
|
+
try:
|
|
53
|
+
gateway_post("/build/toolboxes", {
|
|
54
|
+
"id": id,
|
|
55
|
+
"name": name or id,
|
|
56
|
+
"endpoint": endpoint,
|
|
57
|
+
"type": "openapi",
|
|
58
|
+
})
|
|
59
|
+
if discover:
|
|
60
|
+
gateway_post("/build/toolboxes/discover", {"toolbox_id": id})
|
|
61
|
+
console.print(f"[green]✓[/green] Registered + discovered tools: {id}")
|
|
62
|
+
else:
|
|
63
|
+
console.print(f"[green]✓[/green] Registered: {id}")
|
|
64
|
+
except APIError as e:
|
|
65
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
66
|
+
raise typer.Exit(1)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@app.command("discover")
|
|
70
|
+
def discover_tools(
|
|
71
|
+
endpoint: str = typer.Option(None, "--endpoint", help="Discover from URL"),
|
|
72
|
+
toolbox_id: str = typer.Option(None, "--id", help="Re-discover existing toolbox"),
|
|
73
|
+
):
|
|
74
|
+
"""Discover tools from an OpenAPI endpoint."""
|
|
75
|
+
try:
|
|
76
|
+
payload = {}
|
|
77
|
+
if toolbox_id:
|
|
78
|
+
payload["toolbox_id"] = toolbox_id
|
|
79
|
+
if endpoint:
|
|
80
|
+
payload["endpoint"] = endpoint
|
|
81
|
+
data = gateway_post("/build/toolboxes/discover", payload)
|
|
82
|
+
tools = data.get("tools", [])
|
|
83
|
+
console.print(f"[green]✓[/green] Discovered {len(tools)} tools")
|
|
84
|
+
for t in tools:
|
|
85
|
+
console.print(f" • {t.get('name', t)}")
|
|
86
|
+
except APIError as e:
|
|
87
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
88
|
+
raise typer.Exit(1)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@app.command("deploy")
|
|
92
|
+
def deploy_toolbox(
|
|
93
|
+
from_path: Path = typer.Option(..., "--from", help="Path to toolbox directory"),
|
|
94
|
+
name: str = typer.Option(..., "--name", help="Toolbox name/ID"),
|
|
95
|
+
):
|
|
96
|
+
"""Build, push, and register a toolbox from source."""
|
|
97
|
+
registry = get_value("registry")
|
|
98
|
+
if not registry:
|
|
99
|
+
console.print("[red]Error:[/red] No registry configured. Run: prox config set registry <acr>")
|
|
100
|
+
raise typer.Exit(1)
|
|
101
|
+
|
|
102
|
+
if not (from_path / "Dockerfile").exists():
|
|
103
|
+
console.print(f"[red]Error:[/red] No Dockerfile in {from_path}")
|
|
104
|
+
raise typer.Exit(1)
|
|
105
|
+
|
|
106
|
+
image = f"{registry}/{name}:latest"
|
|
107
|
+
console.print(f"Building {image}...")
|
|
108
|
+
|
|
109
|
+
r = subprocess.run(["docker", "build", "--platform", "linux/amd64", "-t", image, "."], cwd=from_path, capture_output=True, text=True)
|
|
110
|
+
if r.returncode != 0:
|
|
111
|
+
console.print(f"[red]Build failed:[/red]\n{r.stderr[:500]}")
|
|
112
|
+
raise typer.Exit(1)
|
|
113
|
+
|
|
114
|
+
console.print("Pushing...")
|
|
115
|
+
r = subprocess.run(["docker", "push", image], capture_output=True, text=True)
|
|
116
|
+
if r.returncode != 0:
|
|
117
|
+
console.print(f"[red]Push failed:[/red]\n{r.stderr[:500]}")
|
|
118
|
+
raise typer.Exit(1)
|
|
119
|
+
|
|
120
|
+
console.print(f"[green]✓[/green] Deployed: {image}")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@app.command("delete")
|
|
124
|
+
def delete_toolbox(
|
|
125
|
+
toolbox_id: str = typer.Argument(help="Toolbox ID"),
|
|
126
|
+
confirm: bool = typer.Option(False, "--yes", "-y"),
|
|
127
|
+
):
|
|
128
|
+
"""Delete a toolbox."""
|
|
129
|
+
if not confirm:
|
|
130
|
+
typer.confirm(f"Delete toolbox '{toolbox_id}'?", abort=True)
|
|
131
|
+
try:
|
|
132
|
+
gateway_delete(f"/build/toolboxes/{toolbox_id}")
|
|
133
|
+
console.print(f"[green]✓[/green] Deleted: {toolbox_id}")
|
|
134
|
+
except APIError as e:
|
|
135
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
136
|
+
raise typer.Exit(1)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""prox workflow — manage multi-agent workflows."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
import typer
|
|
6
|
+
import yaml
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
from ..api import gateway_get, gateway_post, gateway_put, gateway_delete, APIError
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(help="Manage workflows.")
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.command("list")
|
|
16
|
+
def list_workflows():
|
|
17
|
+
"""List workflows."""
|
|
18
|
+
try:
|
|
19
|
+
data = gateway_get("/build/workflows")
|
|
20
|
+
workflows = data.get("workflows", [])
|
|
21
|
+
if not workflows:
|
|
22
|
+
console.print("[dim]No workflows.[/dim]")
|
|
23
|
+
return
|
|
24
|
+
table = Table(title="Workflows")
|
|
25
|
+
table.add_column("ID", style="bold")
|
|
26
|
+
table.add_column("Name")
|
|
27
|
+
table.add_column("Nodes", justify="right")
|
|
28
|
+
table.add_column("Status")
|
|
29
|
+
table.add_column("Version", justify="right")
|
|
30
|
+
for w in workflows:
|
|
31
|
+
st = w.get("status", "draft")
|
|
32
|
+
st_style = "green" if st == "published" else "yellow"
|
|
33
|
+
table.add_row(w.get("id"), w.get("name", ""), str(len(w.get("nodes", []))), f"[{st_style}]{st}[/{st_style}]", str(w.get("version", 1)))
|
|
34
|
+
console.print(table)
|
|
35
|
+
except APIError as e:
|
|
36
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
37
|
+
raise typer.Exit(1)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@app.command("create")
|
|
41
|
+
def create_workflow(
|
|
42
|
+
from_file: Path = typer.Option(..., "--from", help="YAML workflow definition"),
|
|
43
|
+
):
|
|
44
|
+
"""Create a workflow from YAML file."""
|
|
45
|
+
if not from_file.exists():
|
|
46
|
+
console.print(f"[red]Error:[/red] File not found: {from_file}")
|
|
47
|
+
raise typer.Exit(1)
|
|
48
|
+
wf = yaml.safe_load(from_file.read_text())
|
|
49
|
+
try:
|
|
50
|
+
gateway_post("/build/workflows", wf)
|
|
51
|
+
console.print(f"[green]✓[/green] Workflow created: {wf.get('id', '?')}")
|
|
52
|
+
except APIError as e:
|
|
53
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
54
|
+
raise typer.Exit(1)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@app.command("publish")
|
|
58
|
+
def publish_workflow(workflow_id: str = typer.Argument(help="Workflow ID")):
|
|
59
|
+
"""Publish a workflow."""
|
|
60
|
+
try:
|
|
61
|
+
gateway_post(f"/build/workflows/{workflow_id}/publish")
|
|
62
|
+
console.print(f"[green]✓[/green] Published: {workflow_id}")
|
|
63
|
+
except APIError as e:
|
|
64
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
65
|
+
raise typer.Exit(1)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@app.command("trigger")
|
|
69
|
+
def trigger_workflow(
|
|
70
|
+
workflow_id: str = typer.Argument(help="Workflow ID"),
|
|
71
|
+
input: Optional[str] = typer.Option(None, "--input", "-i", help="Input message"),
|
|
72
|
+
):
|
|
73
|
+
"""Trigger a workflow execution."""
|
|
74
|
+
payload = {"input": {"message": input}} if input else {"input": {}}
|
|
75
|
+
try:
|
|
76
|
+
data = gateway_post(f"/workflows/{workflow_id}/trigger", payload)
|
|
77
|
+
console.print(f"[green]✓[/green] Triggered: {workflow_id}")
|
|
78
|
+
if data.get("run_id"):
|
|
79
|
+
console.print(f" Run ID: {data['run_id']}")
|
|
80
|
+
except APIError as e:
|
|
81
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
82
|
+
raise typer.Exit(1)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@app.command("runs")
|
|
86
|
+
def list_runs(
|
|
87
|
+
workflow_id: Optional[str] = typer.Option(None, "--workflow", "-w"),
|
|
88
|
+
status: Optional[str] = typer.Option(None, "--status", "-s"),
|
|
89
|
+
):
|
|
90
|
+
"""List workflow runs."""
|
|
91
|
+
try:
|
|
92
|
+
params = {}
|
|
93
|
+
if workflow_id:
|
|
94
|
+
params["workflow_id"] = workflow_id
|
|
95
|
+
if status:
|
|
96
|
+
params["status"] = status
|
|
97
|
+
data = gateway_get("/workflows/runs", params=params)
|
|
98
|
+
runs = data.get("runs", [])
|
|
99
|
+
if not runs:
|
|
100
|
+
console.print("[dim]No runs.[/dim]")
|
|
101
|
+
return
|
|
102
|
+
table = Table(title="Workflow Runs")
|
|
103
|
+
table.add_column("Run ID", style="bold")
|
|
104
|
+
table.add_column("Workflow")
|
|
105
|
+
table.add_column("Status")
|
|
106
|
+
table.add_column("Trigger")
|
|
107
|
+
for r in runs:
|
|
108
|
+
st = r.get("status", "?")
|
|
109
|
+
st_style = "green" if st == "completed" else "yellow" if "waiting" in st else "red" if st == "failed" else "dim"
|
|
110
|
+
trigger = r.get("trigger", {})
|
|
111
|
+
tby = trigger.get("triggered_by", "?") if isinstance(trigger, dict) else "?"
|
|
112
|
+
table.add_row(r.get("id", ""), r.get("workflow_id", ""), f"[{st_style}]{st}[/{st_style}]", tby)
|
|
113
|
+
console.print(table)
|
|
114
|
+
except APIError as e:
|
|
115
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
116
|
+
raise typer.Exit(1)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@app.command("delete")
|
|
120
|
+
def delete_workflow(workflow_id: str = typer.Argument(), confirm: bool = typer.Option(False, "--yes", "-y")):
|
|
121
|
+
"""Delete a workflow."""
|
|
122
|
+
if not confirm:
|
|
123
|
+
typer.confirm(f"Delete workflow '{workflow_id}'?", abort=True)
|
|
124
|
+
try:
|
|
125
|
+
gateway_delete(f"/build/workflows/{workflow_id}")
|
|
126
|
+
console.print(f"[green]✓[/green] Deleted: {workflow_id}")
|
|
127
|
+
except APIError as e:
|
|
128
|
+
console.print(f"[red]Error:[/red] {e.detail}")
|
|
129
|
+
raise typer.Exit(1)
|
prox/config.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Configuration management — ~/.prox/ directory."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
PROX_DIR = Path.home() / ".prox"
|
|
8
|
+
CONFIG_FILE = PROX_DIR / "config.json"
|
|
9
|
+
CREDENTIALS_FILE = PROX_DIR / "credentials.json"
|
|
10
|
+
PACKAGES_DIR = PROX_DIR / "packages"
|
|
11
|
+
|
|
12
|
+
DEFAULT_CONFIG = {
|
|
13
|
+
"environment": "local",
|
|
14
|
+
"environments": {
|
|
15
|
+
"local": {
|
|
16
|
+
"gateway": "http://localhost:9000",
|
|
17
|
+
"catalog": "https://catalog.proximaintel.com",
|
|
18
|
+
"registry": "",
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def ensure_dirs():
|
|
25
|
+
PROX_DIR.mkdir(exist_ok=True)
|
|
26
|
+
PACKAGES_DIR.mkdir(exist_ok=True)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def load_config() -> dict:
|
|
30
|
+
ensure_dirs()
|
|
31
|
+
if not CONFIG_FILE.exists():
|
|
32
|
+
save_config(DEFAULT_CONFIG)
|
|
33
|
+
return DEFAULT_CONFIG
|
|
34
|
+
return json.loads(CONFIG_FILE.read_text())
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def save_config(config: dict):
|
|
38
|
+
ensure_dirs()
|
|
39
|
+
CONFIG_FILE.write_text(json.dumps(config, indent=2))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_env_config() -> dict:
|
|
43
|
+
"""Get the active environment's config."""
|
|
44
|
+
config = load_config()
|
|
45
|
+
env = config.get("environment", "local")
|
|
46
|
+
return config.get("environments", {}).get(env, {})
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_value(key: str) -> Optional[str]:
|
|
50
|
+
return get_env_config().get(key)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def set_value(key: str, value: str):
|
|
54
|
+
config = load_config()
|
|
55
|
+
env = config.get("environment", "local")
|
|
56
|
+
if env not in config.get("environments", {}):
|
|
57
|
+
config.setdefault("environments", {})[env] = {}
|
|
58
|
+
config["environments"][env][key] = value
|
|
59
|
+
save_config(config)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def use_environment(name: str):
|
|
63
|
+
config = load_config()
|
|
64
|
+
if name not in config.get("environments", {}):
|
|
65
|
+
config.setdefault("environments", {})[name] = {}
|
|
66
|
+
config["environment"] = name
|
|
67
|
+
save_config(config)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def current_environment() -> str:
|
|
71
|
+
return load_config().get("environment", "local")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# --- Credentials ---
|
|
75
|
+
|
|
76
|
+
def load_credentials() -> dict:
|
|
77
|
+
ensure_dirs()
|
|
78
|
+
if not CREDENTIALS_FILE.exists():
|
|
79
|
+
return {}
|
|
80
|
+
return json.loads(CREDENTIALS_FILE.read_text())
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def save_credentials(creds: dict):
|
|
84
|
+
ensure_dirs()
|
|
85
|
+
CREDENTIALS_FILE.write_text(json.dumps(creds, indent=2))
|
|
86
|
+
CREDENTIALS_FILE.chmod(0o600)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_token() -> Optional[str]:
|
|
90
|
+
return load_credentials().get("token")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_license_key() -> Optional[str]:
|
|
94
|
+
return load_credentials().get("license_key")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_master_key() -> Optional[str]:
|
|
98
|
+
return load_credentials().get("master_key")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: proxima-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Proxima AIP CLI — manage your Proxima Intelligence platform
|
|
5
|
+
Project-URL: Homepage, https://proximaintel.com/aip
|
|
6
|
+
Project-URL: Documentation, https://docs.proximaintel.com/cli
|
|
7
|
+
Project-URL: Repository, https://github.com/proximaintel/proxima-cli
|
|
8
|
+
Author-email: Proxima Intelligence <hello@proximaintel.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: agents,ai,cli,platform,proxima
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Requires-Dist: httpx>=0.27
|
|
18
|
+
Requires-Dist: pyyaml>=6
|
|
19
|
+
Requires-Dist: rich>=13
|
|
20
|
+
Requires-Dist: typer[all]>=0.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Proxima CLI
|
|
24
|
+
|
|
25
|
+
The official command-line interface for **Proxima AIP** — manage your AI agent platform from the terminal.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pipx install proxima-cli
|
|
31
|
+
# or
|
|
32
|
+
pip install proxima-cli
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Login (opens browser for SSO)
|
|
39
|
+
prox login
|
|
40
|
+
|
|
41
|
+
# Check connection
|
|
42
|
+
prox whoami
|
|
43
|
+
|
|
44
|
+
# List agents
|
|
45
|
+
prox agent list
|
|
46
|
+
|
|
47
|
+
# Create a domain
|
|
48
|
+
prox domain create --id finance --name "Finance"
|
|
49
|
+
|
|
50
|
+
# Deploy an agent from a package
|
|
51
|
+
prox agent deploy --from ./my-agent/
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Set your platform gateway URL
|
|
58
|
+
prox config set gateway https://gateway.your-platform.com
|
|
59
|
+
|
|
60
|
+
# Set catalog (for pulling pre-built agents)
|
|
61
|
+
prox config set catalog https://catalog.proximaintel.com
|
|
62
|
+
|
|
63
|
+
# View config
|
|
64
|
+
prox config list
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Commands
|
|
68
|
+
|
|
69
|
+
| Command Group | Description |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `prox login / logout / whoami` | Authentication |
|
|
72
|
+
| `prox config` | Environment configuration |
|
|
73
|
+
| `prox catalog` | Browse and pull agents from Proxima Catalog |
|
|
74
|
+
| `prox agent` | Create, configure, deploy, publish agents |
|
|
75
|
+
| `prox toolbox` | Build and register toolboxes |
|
|
76
|
+
| `prox knowledge` | Manage data sources and knowledge bases |
|
|
77
|
+
| `prox secret` | Manage credentials |
|
|
78
|
+
| `prox model` | Register LLM providers |
|
|
79
|
+
| `prox ontology` | Manage entity models |
|
|
80
|
+
| `prox routine` | Schedule autonomous agent execution |
|
|
81
|
+
| `prox workflow` | Multi-agent orchestration pipelines |
|
|
82
|
+
| `prox governance` | Audit logs and usage stats |
|
|
83
|
+
| `prox platform` | Health checks and service management |
|
|
84
|
+
|
|
85
|
+
## Agent Deployment
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
prox agent deploy --from ./my-agent/
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Expects:
|
|
92
|
+
```
|
|
93
|
+
my-agent/
|
|
94
|
+
├── agent.yaml # Agent config
|
|
95
|
+
├── toolbox/ # Optional: custom tools
|
|
96
|
+
│ ├── tools.py
|
|
97
|
+
│ ├── Dockerfile
|
|
98
|
+
│ └── requirements.txt
|
|
99
|
+
├── knowledge.yaml # Data source requirements
|
|
100
|
+
└── workspace.json # Dashboard layout
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
One command. Full agent. Production-ready.
|
|
104
|
+
|
|
105
|
+
## CI/CD
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
prox login --api-key $PLATFORM_API_KEY
|
|
109
|
+
prox config set gateway $GATEWAY_URL
|
|
110
|
+
prox agent deploy --from ./agents/my-agent/
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Documentation
|
|
114
|
+
|
|
115
|
+
Full docs at [docs.proximaintel.com/cli](https://docs.proximaintel.com/cli)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
prox/__init__.py,sha256=Bcs1sfs1zo9IQ6jNNme0kaP0eD9Q26nSV70ynUkA73Y,64
|
|
2
|
+
prox/api.py,sha256=m5cHzpWrgaI8ZPuSbwBbmHjhxaKTppyNNV288BGRWqc,3312
|
|
3
|
+
prox/auth.py,sha256=5KzkDpbNsUiFDa24iGvtVLugBZsGnqcapFeVtVGQUq8,5327
|
|
4
|
+
prox/cli.py,sha256=fhIUosETDi8ieDnsf0gY0ggA47yEgQkAx6TipJcJn4s,4231
|
|
5
|
+
prox/config.py,sha256=q-UlgSQtFHQbKhhxJJJJfnegV8QzMium61ssCXQ7SeM,2397
|
|
6
|
+
prox/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
prox/commands/agent.py,sha256=kdmPXzR9VAOrLWJ1pI21MBM5E1Ne3E4uTYHP8sNn774,13081
|
|
8
|
+
prox/commands/catalog.py,sha256=ytcZTwL5wkykhM3QLVtHs1G0xIGKNZ23BCNZxjPlPnw,8936
|
|
9
|
+
prox/commands/governance.py,sha256=PBdM30r3aEJ89jOUxWdFfkmkVLeYcJLEOghGkP0DQq4,2330
|
|
10
|
+
prox/commands/knowledge.py,sha256=1bzUHa_HjR9a0wvPOzif-LcSdQRzAwRHKGOlILqKNFc,5000
|
|
11
|
+
prox/commands/model.py,sha256=YVvaMni-PZ4JE40mZPQRM2ZVZmipK9iRDNtmKiMbzZk,2495
|
|
12
|
+
prox/commands/ontology.py,sha256=1DLis-226EW1f03Gy09W4wr4hWUQuYcw8ZllfmdFNo0,7282
|
|
13
|
+
prox/commands/platform.py,sha256=tOhZxlf_Mx8B75U_qTalLS1_fvAH9ny_bf7mchtwFHk,1601
|
|
14
|
+
prox/commands/routine.py,sha256=yKv2gIPphFmuMP2MJQzINKDi3C6B0ZTAMef7MhYjkJE,3087
|
|
15
|
+
prox/commands/secret.py,sha256=ZP5mYaG_vP388EpCRaZ9OP56aR-pgb8trlyWQJMEv20,1994
|
|
16
|
+
prox/commands/team.py,sha256=mklup9FuvdFus11H5hOB0uxrQdX5mj9hk-Hu7EX11QE,3127
|
|
17
|
+
prox/commands/toolbox.py,sha256=UanlA-Km6OsyUl4MCPPh2E9OJwPdg66akQ9dbI3Z1Qw,4671
|
|
18
|
+
prox/commands/workflow.py,sha256=fRx3vkZR8kC7TWpx2vbQXhdnYY04AXrlxhaa5s6Ou_Y,4758
|
|
19
|
+
proxima_cli-1.0.0.dist-info/METADATA,sha256=cRjRiqg0iub90yzIisvop7b6Lk1dyLQwAZ_Cq9f3y-w,2995
|
|
20
|
+
proxima_cli-1.0.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
21
|
+
proxima_cli-1.0.0.dist-info/entry_points.txt,sha256=kDTz7VO9X7wf_4P-fBjPa5MPVT9L3KygYS7p15dqfJI,38
|
|
22
|
+
proxima_cli-1.0.0.dist-info/RECORD,,
|