Files
aitbc/cli/aitbc_cli/main.py
oib c8ee2a3e6e feat: implement role-based configuration system for CLI with automatic API key management
- Add role detection to command groups (admin, client, miner, blockchain)
- Load role-specific config files (~/.aitbc/{role}-config.yaml)
- Add role field to Config class with environment variable support
- Implement automatic role detection from invoked subcommand
- Add development mode API key bypass for testing (APP_ENV=dev)
- Update CLI checklist with role-based configuration documentation
- Add configuration override priority and
2026-03-05 14:02:51 +01:00

229 lines
6.2 KiB
Python

#!/usr/bin/env python3
"""
AITBC CLI - Main entry point for the AITBC Command Line Interface
"""
import click
import sys
from typing import Optional
from . import __version__
from .config import get_config
def with_role(role: str):
"""Decorator to set role for command groups"""
def decorator(func):
@click.pass_context
def wrapper(ctx, *args, **kwargs):
ctx.parent.detected_role = role
return func(ctx, *args, **kwargs)
return wrapper
return decorator
from .utils import output, setup_logging
from .commands.client import client
from .commands.miner import miner
from .commands.wallet import wallet
from .commands.auth import auth
from .commands.blockchain import blockchain
from .commands.marketplace import marketplace
from .commands.simulate import simulate
from .commands.admin import admin
from .commands.config import config
from .commands.monitor import monitor
from .commands.governance import governance
from .commands.exchange import exchange
from .commands.agent import agent
from .commands.multimodal import multimodal
from .commands.optimize import optimize
# from .commands.openclaw import openclaw # Temporarily disabled due to naming conflict
from .commands.marketplace_advanced import advanced # Re-enabled after fixing registration issues
from .commands.swarm import swarm
from .commands.chain import chain
from .commands.genesis import genesis
from .commands.test_cli import test
from .commands.node import node
from .commands.analytics import analytics
from .commands.agent_comm import agent_comm
from .commands.deployment import deploy
from .plugins import plugin, load_plugins
@click.group()
@click.option(
"--url",
default=None,
help="Coordinator API URL (overrides config)"
)
@click.option(
"--api-key",
default=None,
help="API key (overrides config)"
)
@click.option(
"--output",
type=click.Choice(["table", "json", "yaml"]),
default="table",
help="Output format"
)
@click.option(
"--verbose", "-v",
count=True,
help="Increase verbosity (use -v, -vv, -vvv)"
)
@click.option(
"--debug",
is_flag=True,
help="Enable debug mode"
)
@click.option(
"--config-file",
default=None,
help="Path to config file"
)
@click.option(
"--test-mode",
is_flag=True,
help="Enable test mode (uses mock data and test endpoints)"
)
@click.option(
"--dry-run",
is_flag=True,
help="Dry run mode (show what would be done without executing)"
)
@click.option(
"--timeout",
type=int,
default=30,
help="Request timeout in seconds (useful for testing)"
)
@click.option(
"--no-verify",
is_flag=True,
help="Skip SSL certificate verification (testing only)"
)
@click.version_option(version=__version__, prog_name="aitbc")
@click.pass_context
def cli(ctx, url: Optional[str], api_key: Optional[str], output: str,
verbose: int, debug: bool, config_file: Optional[str], test_mode: bool,
dry_run: bool, timeout: int, no_verify: bool):
"""
AITBC CLI - Command Line Interface for AITBC Network
Manage jobs, mining, wallets, and blockchain operations from the command line.
"""
# Ensure context object exists
ctx.ensure_object(dict)
# Setup logging based on verbosity
log_level = setup_logging(verbose, debug)
# Detect role from command name (before config is loaded)
role = None
# Check invoked_subcommand first
if ctx.invoked_subcommand:
if ctx.invoked_subcommand == 'client':
role = 'client'
elif ctx.invoked_subcommand == 'miner':
role = 'miner'
elif ctx.invoked_subcommand == 'blockchain':
role = 'blockchain'
elif ctx.invoked_subcommand == 'admin':
role = 'admin'
# Also check if role was already set by command group
if not role:
role = getattr(ctx, 'detected_role', None)
# Load configuration with role
config = get_config(config_file, role=role)
# Override config with command line options
if url:
config.coordinator_url = url
if api_key:
config.api_key = api_key
# Store in context for subcommands
ctx.obj['config'] = config
ctx.obj['output_format'] = output
ctx.obj['log_level'] = log_level
ctx.obj['test_mode'] = test_mode
ctx.obj['dry_run'] = dry_run
ctx.obj['timeout'] = timeout
ctx.obj['no_verify'] = no_verify
# Apply test mode settings
if test_mode:
config.coordinator_url = config.coordinator_url or "http://localhost:8000"
config.api_key = config.api_key or "test-api-key"
# Add command groups
cli.add_command(client)
cli.add_command(miner)
cli.add_command(wallet)
cli.add_command(plugin)
# cli.add_command(openclaw) # Temporarily disabled due to naming conflict
cli.add_command(advanced) # Re-enabled after fixing registration issues
cli.add_command(auth)
cli.add_command(blockchain)
cli.add_command(marketplace)
cli.add_command(simulate)
cli.add_command(admin)
cli.add_command(config)
cli.add_command(monitor)
cli.add_command(governance)
cli.add_command(exchange)
cli.add_command(agent)
cli.add_command(multimodal)
cli.add_command(optimize)
# cli.add_command(openclaw) # Temporarily disabled
cli.add_command(swarm)
cli.add_command(chain)
cli.add_command(genesis)
cli.add_command(test)
cli.add_command(node)
cli.add_command(analytics)
cli.add_command(agent_comm)
cli.add_command(deploy)
cli.add_command(plugin)
load_plugins(cli)
@cli.command()
@click.pass_context
def version(ctx):
"""Show version information"""
output(f"AITBC CLI version {__version__}", ctx.obj['output_format'])
@cli.command()
@click.pass_context
def config_show(ctx):
"""Show current configuration"""
config = ctx.obj['config']
output({
"coordinator_url": config.coordinator_url,
"api_key": "***REDACTED***" if config.api_key else None,
"output_format": ctx.obj['output_format'],
"config_file": config.config_file
}, ctx.obj['output_format'])
def main():
"""Main entry point"""
try:
cli()
except KeyboardInterrupt:
click.echo("\nAborted by user", err=True)
sys.exit(1)
except Exception as e:
click.echo(f"Error: {e}", err=True)
sys.exit(1)
if __name__ == "__main__":
main()