CmdForge/src/cmdforge/cli/config_commands.py

186 lines
6.0 KiB
Python

"""Configuration commands."""
import socket
import sys
import time
from ..config import load_config, save_config, set_registry_token, get_registry_url
def cmd_config(args):
"""Manage CmdForge configuration."""
if args.config_cmd == "show":
return _cmd_config_show(args)
elif args.config_cmd == "set-token":
return _cmd_config_set_token(args)
elif args.config_cmd == "set":
return _cmd_config_set(args)
elif args.config_cmd == "connect":
return _cmd_config_connect(args)
elif args.config_cmd == "disconnect":
return _cmd_config_disconnect(args)
else:
print("Config commands:")
print(" show Show current configuration")
print(" connect <username> Connect this app to your CmdForge account")
print(" disconnect Disconnect from registry (clear token)")
print(" set-token <token> Set registry authentication token")
print(" set <key> <value> Set a configuration value")
return 0
def _cmd_config_show(args):
"""Show current configuration."""
config = load_config()
print("CmdForge Configuration:")
print(f" Registry URL: {config.registry.url}")
print(f" Token: {'***' if config.registry.token else '(not set)'}")
print(f" Client ID: {config.client_id}")
print(f" Auto-fetch: {config.auto_fetch_from_registry}")
if config.default_provider:
print(f" Default provider: {config.default_provider}")
return 0
def _cmd_config_set_token(args):
"""Set registry authentication token."""
token = args.token
set_registry_token(token)
print("Registry token saved.")
return 0
def _cmd_config_set(args):
"""Set a configuration value."""
config = load_config()
key = args.key
value = args.value
if key == "auto_fetch":
config.auto_fetch_from_registry = value.lower() in ("true", "1", "yes")
elif key == "default_provider":
config.default_provider = value if value else None
elif key == "registry_url":
config.registry.url = value
else:
print(f"Unknown config key: {key}")
print("Available keys: auto_fetch, default_provider, registry_url")
return 1
save_config(config)
print(f"Set {key} = {value}")
return 0
def _cmd_config_connect(args):
"""Connect this app to a CmdForge account via web pairing."""
try:
import requests
except ImportError:
print("Error: requests library required. Install with: pip install requests")
return 1
username = args.username
hostname = socket.gethostname()
registry_url = get_registry_url()
# Remove trailing /api/v1 if present to get base URL
base_url = registry_url.rstrip("/")
if base_url.endswith("/api/v1"):
base_url = base_url[:-7]
pairing_url = f"{base_url}/api/v1/pairing/check/{username}"
print(f"Connecting to CmdForge as @{username}...")
print(f"Device: {hostname}")
print()
print("Waiting for approval from the web interface...")
print("Go to https://cmdforge.brrd.tech/dashboard/connected-apps")
print("and click 'Connect New App', then 'I've Run the Command'")
print()
print("Press Ctrl+C to cancel")
print()
# Poll for pairing status
max_attempts = 150 # 5 minutes at 2-second intervals
attempt = 0
try:
while attempt < max_attempts:
attempt += 1
try:
response = requests.get(
pairing_url,
params={"hostname": hostname},
timeout=10
)
if response.status_code == 200:
data = response.json()
status = data.get("data", {}).get("status")
if status == "connected":
token = data.get("data", {}).get("token")
if token:
set_registry_token(token)
print("\nConnected successfully!")
print(f"Your device '{hostname}' is now linked to @{username}")
print("\nYou can now publish tools with: cmdforge registry publish")
return 0
else:
print("\nError: Pairing completed but no token received")
return 1
elif status == "pending":
# Still waiting, continue polling
pass
elif status == "expired":
print("\nPairing request expired. Please try again.")
return 1
elif status == "not_found":
# No pending pairing yet, continue waiting
pass
else:
# Unknown status, keep waiting
pass
elif response.status_code == 404:
# No pairing found yet, keep waiting
pass
else:
# Server error, but keep trying
pass
except requests.exceptions.RequestException:
# Network error, keep trying
pass
# Show progress indicator
dots = "." * ((attempt % 3) + 1)
sys.stdout.write(f"\rWaiting{dots} ")
sys.stdout.flush()
time.sleep(2)
print("\n\nTimed out waiting for approval.")
print("Please initiate the connection from the web interface first.")
return 1
except KeyboardInterrupt:
print("\n\nConnection cancelled.")
return 1
def _cmd_config_disconnect(args):
"""Disconnect from registry by clearing the token."""
config = load_config()
if not config.registry.token:
print("Not connected to registry (no token set).")
return 0
# Clear the token
set_registry_token(None)
print("Disconnected from registry.")
print("Token has been cleared from local configuration.")
return 0