refactor: flatten CLI directory structure - remove 'box in a box'

BEFORE:
/opt/aitbc/cli/
├── aitbc_cli/                    # Python package (box in a box)
│   ├── commands/
│   ├── main.py
│   └── ...
├── setup.py

AFTER:
/opt/aitbc/cli/                    # Flat structure
├── commands/                      # Direct access
├── main.py                        # Direct access
├── auth/
├── config/
├── core/
├── models/
├── utils/
├── plugins.py
└── setup.py

CHANGES MADE:
- Moved all files from aitbc_cli/ to cli/ root
- Fixed all relative imports (from . to absolute imports)
- Updated setup.py entry point: aitbc_cli.main → main
- Added CLI directory to Python path in entry script
- Simplified deployment.py to remove dependency on deleted core.deployment
- Fixed import paths in all command files
- Recreated virtual environment with new structure

BENEFITS:
- Eliminated 'box in a box' nesting
- Simpler directory structure
- Direct access to all modules
- Cleaner imports
- Easier maintenance and development
- CLI works with both 'python main.py' and 'aitbc' commands
This commit is contained in:
2026-03-26 09:12:02 +01:00
parent b3cf7384ce
commit c0952c2525
89 changed files with 265 additions and 4605 deletions

246
cli/commands/swarm.py Executable file
View File

@@ -0,0 +1,246 @@
"""Swarm intelligence commands for AITBC CLI"""
import click
import httpx
import json
from typing import Optional, Dict, Any, List
from utils import output, error, success, warning
@click.group()
def swarm():
"""Swarm intelligence and collective optimization"""
pass
@swarm.command()
@click.option("--role", required=True,
type=click.Choice(["load-balancer", "resource-optimizer", "task-coordinator", "monitor"]),
help="Swarm role")
@click.option("--capability", required=True, help="Agent capability")
@click.option("--region", help="Operating region")
@click.option("--priority", default="normal",
type=click.Choice(["low", "normal", "high"]),
help="Swarm priority")
@click.pass_context
def join(ctx, role: str, capability: str, region: Optional[str], priority: str):
"""Join agent swarm for collective optimization"""
config = ctx.obj['config']
swarm_data = {
"role": role,
"capability": capability,
"priority": priority
}
if region:
swarm_data["region"] = region
try:
with httpx.Client() as client:
response = client.post(
f"{config.coordinator_url}/swarm/join",
headers={"X-Api-Key": config.api_key or ""},
json=swarm_data
)
if response.status_code == 201:
result = response.json()
success(f"Joined swarm: {result['swarm_id']}")
output(result, ctx.obj['output_format'])
else:
error(f"Failed to join swarm: {response.status_code}")
if response.text:
error(response.text)
ctx.exit(1)
except Exception as e:
error(f"Network error: {e}")
ctx.exit(1)
@swarm.command()
@click.option("--task", required=True, help="Swarm task type")
@click.option("--collaborators", type=int, default=5, help="Number of collaborators")
@click.option("--strategy", default="consensus",
type=click.Choice(["consensus", "leader-election", "distributed"]),
help="Coordination strategy")
@click.option("--timeout", default=3600, help="Task timeout in seconds")
@click.pass_context
def coordinate(ctx, task: str, collaborators: int, strategy: str, timeout: int):
"""Coordinate swarm task execution"""
config = ctx.obj['config']
coordination_data = {
"task": task,
"collaborators": collaborators,
"strategy": strategy,
"timeout_seconds": timeout
}
try:
with httpx.Client() as client:
response = client.post(
f"{config.coordinator_url}/swarm/coordinate",
headers={"X-Api-Key": config.api_key or ""},
json=coordination_data
)
if response.status_code == 202:
result = response.json()
success(f"Swarm coordination started: {result['task_id']}")
output(result, ctx.obj['output_format'])
else:
error(f"Failed to start coordination: {response.status_code}")
if response.text:
error(response.text)
ctx.exit(1)
except Exception as e:
error(f"Network error: {e}")
ctx.exit(1)
@swarm.command()
@click.option("--swarm-id", help="Filter by swarm ID")
@click.option("--status", help="Filter by status")
@click.option("--limit", default=20, help="Number of swarms to list")
@click.pass_context
def list(ctx, swarm_id: Optional[str], status: Optional[str], limit: int):
"""List active swarms"""
config = ctx.obj['config']
params = {"limit": limit}
if swarm_id:
params["swarm_id"] = swarm_id
if status:
params["status"] = status
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url}/swarm/list",
headers={"X-Api-Key": config.api_key or ""},
params=params
)
if response.status_code == 200:
swarms = response.json()
output(swarms, ctx.obj['output_format'])
else:
error(f"Failed to list swarms: {response.status_code}")
ctx.exit(1)
except Exception as e:
error(f"Network error: {e}")
ctx.exit(1)
@swarm.command()
@click.argument("task_id")
@click.option("--real-time", is_flag=True, help="Show real-time progress")
@click.option("--interval", default=10, help="Update interval for real-time monitoring")
@click.pass_context
def status(ctx, task_id: str, real_time: bool, interval: int):
"""Get swarm task status"""
config = ctx.obj['config']
def get_status():
try:
with httpx.Client() as client:
response = client.get(
f"{config.coordinator_url}/swarm/tasks/{task_id}/status",
headers={"X-Api-Key": config.api_key or ""}
)
if response.status_code == 200:
return response.json()
else:
error(f"Failed to get task status: {response.status_code}")
return None
except Exception as e:
error(f"Network error: {e}")
return None
if real_time:
click.echo(f"Monitoring swarm task {task_id} (Ctrl+C to stop)...")
while True:
status_data = get_status()
if status_data:
click.clear()
click.echo(f"Task ID: {task_id}")
click.echo(f"Status: {status_data.get('status', 'Unknown')}")
click.echo(f"Progress: {status_data.get('progress', 0)}%")
click.echo(f"Collaborators: {status_data.get('active_collaborators', 0)}/{status_data.get('total_collaborators', 0)}")
if status_data.get('status') in ['completed', 'failed', 'cancelled']:
break
time.sleep(interval)
else:
status_data = get_status()
if status_data:
output(status_data, ctx.obj['output_format'])
@swarm.command()
@click.argument("swarm_id")
@click.pass_context
def leave(ctx, swarm_id: str):
"""Leave swarm"""
config = ctx.obj['config']
if not click.confirm(f"Leave swarm {swarm_id}?"):
click.echo("Operation cancelled")
return
try:
with httpx.Client() as client:
response = client.post(
f"{config.coordinator_url}/swarm/{swarm_id}/leave",
headers={"X-Api-Key": config.api_key or ""}
)
if response.status_code == 200:
result = response.json()
success(f"Left swarm {swarm_id}")
output(result, ctx.obj['output_format'])
else:
error(f"Failed to leave swarm: {response.status_code}")
if response.text:
error(response.text)
ctx.exit(1)
except Exception as e:
error(f"Network error: {e}")
ctx.exit(1)
@swarm.command()
@click.argument("task_id")
@click.option("--consensus-threshold", default=0.7, help="Consensus threshold (0.0-1.0)")
@click.pass_context
def consensus(ctx, task_id: str, consensus_threshold: float):
"""Achieve swarm consensus on task result"""
config = ctx.obj['config']
consensus_data = {
"consensus_threshold": consensus_threshold
}
try:
with httpx.Client() as client:
response = client.post(
f"{config.coordinator_url}/swarm/tasks/{task_id}/consensus",
headers={"X-Api-Key": config.api_key or ""},
json=consensus_data
)
if response.status_code == 200:
result = response.json()
success(f"Consensus achieved: {result.get('consensus_reached', False)}")
output(result, ctx.obj['output_format'])
else:
error(f"Failed to achieve consensus: {response.status_code}")
if response.text:
error(response.text)
ctx.exit(1)
except Exception as e:
error(f"Network error: {e}")
ctx.exit(1)