Files
aitbc/cli/aitbc_cli/commands/plugin_marketplace.py
AITBC System b033923756 chore: normalize file permissions across repository
- Remove executable permissions from configuration files (.editorconfig, .env.example, .gitignore)
- Remove executable permissions from documentation files (README.md, LICENSE, SECURITY.md)
- Remove executable permissions from web assets (HTML, CSS, JS files)
- Remove executable permissions from data files (JSON, SQL, YAML, requirements.txt)
- Remove executable permissions from source code files across all apps
- Add executable permissions to Python
2026-03-08 11:26:18 +01:00

580 lines
25 KiB
Python
Executable File

"""
Plugin Marketplace CLI Commands for AITBC
Commands for browsing, purchasing, and managing plugins from the marketplace
"""
import click
import json
import requests
from datetime import datetime
from typing import Dict, Any, List, Optional
@click.group()
def plugin_marketplace():
"""Plugin marketplace commands"""
pass
@plugin_marketplace.command()
@click.option('--category', help='Filter by category')
@click.option('--price-min', type=float, help='Minimum price filter')
@click.option('--price-max', type=float, help='Maximum price filter')
@click.option('--rating-min', type=float, help='Minimum rating filter')
@click.option('--sort', default='popularity', help='Sort by (popularity, rating, price, newest)')
@click.option('--limit', type=int, default=20, help='Number of results')
@click.option('--test-mode', is_flag=True, help='Run in test mode')
def browse(category, price_min, price_max, rating_min, sort, limit, test_mode):
"""Browse plugins in the marketplace"""
try:
params = {
"limit": limit,
"sort": sort
}
if category:
params["category"] = category
if price_min is not None:
params["price_min"] = price_min
if price_max is not None:
params["price_max"] = price_max
if rating_min is not None:
params["rating_min"] = rating_min
if test_mode:
# Mock marketplace data
mock_plugins = [
{
"plugin_id": "trading-bot",
"name": "Advanced Trading Bot",
"version": "1.0.0",
"description": "Automated trading bot with advanced algorithms",
"author": "AITBC Team",
"category": "trading",
"price": 99.99,
"rating": 4.5,
"reviews_count": 42,
"downloads": 1250,
"featured": True,
"tags": ["trading", "automation", "bot"],
"preview_image": "https://marketplace.aitbc.dev/plugins/trading-bot/preview.png"
},
{
"plugin_id": "oracle-feed",
"name": "Oracle Price Feed",
"version": "2.1.0",
"description": "Real-time price oracle integration",
"author": "Oracle Developer",
"category": "oracle",
"price": 49.99,
"rating": 4.8,
"reviews_count": 28,
"downloads": 890,
"featured": True,
"tags": ["oracle", "price", "feed"],
"preview_image": "https://marketplace.aitbc.dev/plugins/oracle-feed/preview.png"
},
{
"plugin_id": "security-scanner",
"name": "Security Scanner Pro",
"version": "3.0.0",
"description": "Advanced security scanning and vulnerability detection",
"author": "Security Labs",
"category": "security",
"price": 199.99,
"rating": 4.7,
"reviews_count": 15,
"downloads": 567,
"featured": False,
"tags": ["security", "scanning", "vulnerability"],
"preview_image": "https://marketplace.aitbc.dev/plugins/security-scanner/preview.png"
}
]
click.echo("🛒 Plugin Marketplace:")
click.echo("=" * 60)
for plugin in mock_plugins[:limit]:
featured_badge = "" if plugin.get('featured') else ""
click.echo(f"{featured_badge} {plugin['name']} (v{plugin['version']})")
click.echo(f" 💰 Price: ${plugin['price']}")
click.echo(f" ⭐ Rating: {plugin['rating']}/5.0 ({plugin['reviews_count']} reviews)")
click.echo(f" 📥 Downloads: {plugin['downloads']}")
click.echo(f" 📂 Category: {plugin['category']}")
click.echo(f" 👤 Author: {plugin['author']}")
click.echo(f" 📝 {plugin['description'][:60]}...")
click.echo("")
return
# Fetch from marketplace service
config = get_config()
response = requests.get(
f"{config.coordinator_url}/api/v1/marketplace/browse",
params=params,
headers={"Authorization": f"Bearer {config.api_key}"},
timeout=30
)
if response.status_code == 200:
result = response.json()
plugins = result.get("plugins", [])
click.echo("🛒 Plugin Marketplace:")
click.echo("=" * 60)
for plugin in plugins:
featured_badge = "" if plugin.get('featured') else ""
click.echo(f"{featured_badge} {plugin['name']} (v{plugin['version']})")
click.echo(f" 💰 Price: ${plugin.get('price', 0.0)}")
click.echo(f" ⭐ Rating: {plugin.get('rating', 0)}/5.0 ({plugin.get('reviews_count', 0)} reviews)")
click.echo(f" 📥 Downloads: {plugin.get('downloads', 0)}")
click.echo(f" 📂 Category: {plugin.get('category', 'N/A')}")
click.echo(f" 👤 Author: {plugin.get('author', 'N/A')}")
click.echo(f" 📝 {plugin['description'][:60]}...")
click.echo("")
else:
click.echo(f"❌ Failed to browse marketplace: {response.text}", err=True)
except Exception as e:
click.echo(f"❌ Error browsing marketplace: {str(e)}", err=True)
@plugin_marketplace.command()
@click.argument('plugin_id')
@click.option('--test-mode', is_flag=True, help='Run in test mode')
def details(plugin_id, test_mode):
"""Get detailed information about a marketplace plugin"""
try:
if test_mode:
# Mock plugin details
mock_plugin = {
"plugin_id": plugin_id,
"name": "Advanced Trading Bot",
"version": "1.0.0",
"description": "Automated trading bot with advanced algorithms and machine learning capabilities. Features include real-time market analysis, automated trading strategies, risk management, and portfolio optimization.",
"author": "AITBC Team",
"category": "trading",
"price": 99.99,
"rating": 4.5,
"reviews_count": 42,
"downloads": 1250,
"featured": True,
"tags": ["trading", "automation", "bot", "ml", "risk-management"],
"repository": "https://github.com/aitbc/trading-bot",
"homepage": "https://aitbc.dev/plugins/trading-bot",
"license": "MIT",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-03-01T14:20:00Z",
"preview_image": "https://marketplace.aitbc.dev/plugins/trading-bot/preview.png",
"screenshots": [
"https://marketplace.aitbc.dev/plugins/trading-bot/screenshot1.png",
"https://marketplace.aitbc.dev/plugins/trading-bot/screenshot2.png"
],
"documentation": "https://docs.aitbc.dev/plugins/trading-bot",
"support": "support@aitbc.dev",
"compatibility": {
"aitbc_version": ">=1.0.0",
"python_version": ">=3.8",
"dependencies": ["exchange-integration", "oracle-feed"]
},
"pricing": {
"type": "one-time",
"amount": 99.99,
"currency": "USD",
"includes_support": True,
"includes_updates": True
},
"reviews": [
{
"id": 1,
"user": "trader123",
"rating": 5,
"title": "Excellent trading bot!",
"comment": "This bot has significantly improved my trading performance. Highly recommended!",
"date": "2024-02-15T10:30:00Z"
},
{
"id": 2,
"user": "alice_trader",
"rating": 4,
"title": "Good but needs improvements",
"comment": "Great features but the UI could be more intuitive.",
"date": "2024-02-10T14:20:00Z"
}
]
}
click.echo(f"🛒 Plugin Details: {mock_plugin['name']}")
click.echo("=" * 60)
click.echo(f"📦 Version: {mock_plugin['version']}")
click.echo(f"👤 Author: {mock_plugin['author']}")
click.echo(f"📂 Category: {mock_plugin['category']}")
click.echo(f"💰 Price: ${mock_plugin['price']} {mock_plugin['pricing']['currency']}")
click.echo(f"⭐ Rating: {mock_plugin['rating']}/5.0 ({mock_plugin['reviews_count']} reviews)")
click.echo(f"📥 Downloads: {mock_plugin['downloads']}")
click.echo(f"🏷️ Tags: {', '.join(mock_plugin['tags'])}")
click.echo(f"📄 License: {mock_plugin['license']}")
click.echo(f"📅 Created: {mock_plugin['created_at']}")
click.echo(f"🔄 Updated: {mock_plugin['updated_at']}")
click.echo("")
click.echo("📝 Description:")
click.echo(f" {mock_plugin['description']}")
click.echo("")
click.echo("💰 Pricing:")
click.echo(f" Type: {mock_plugin['pricing']['type']}")
click.echo(f" Amount: ${mock_plugin['pricing']['amount']} {mock_plugin['pricing']['currency']}")
click.echo(f" Includes Support: {'Yes' if mock_plugin['pricing']['includes_support'] else 'No'}")
click.echo(f" Includes Updates: {'Yes' if mock_plugin['pricing']['includes_updates'] else 'No'}")
click.echo("")
click.echo("🔗 Links:")
click.echo(f" 📦 Repository: {mock_plugin['repository']}")
click.echo(f" 🌐 Homepage: {mock_plugin['homepage']}")
click.echo(f" 📚 Documentation: {mock_plugin['documentation']}")
click.echo(f" 📧 Support: {mock_plugin['support']}")
click.echo("")
click.echo("🔧 Compatibility:")
click.echo(f" AITBC Version: {mock_plugin['compatibility']['aitbc_version']}")
click.echo(f" Python Version: {mock_plugin['compatibility']['python_version']}")
click.echo(f" Dependencies: {', '.join(mock_plugin['compatibility']['dependencies'])}")
click.echo("")
click.echo("⭐ Recent Reviews:")
for review in mock_plugin['reviews'][:3]:
stars = "" * review['rating']
click.echo(f" {stars} {review['title']}")
click.echo(f" 👤 {review['user']} - {review['date']}")
click.echo(f" 📝 {review['comment']}")
click.echo("")
return
# Fetch from marketplace service
config = get_config()
response = requests.get(
f"{config.coordinator_url}/api/v1/marketplace/plugins/{plugin_id}",
headers={"Authorization": f"Bearer {config.api_key}"},
timeout=30
)
if response.status_code == 200:
plugin = response.json()
click.echo(f"🛒 Plugin Details: {plugin['name']}")
click.echo("=" * 60)
click.echo(f"📦 Version: {plugin['version']}")
click.echo(f"👤 Author: {plugin['author']}")
click.echo(f"📂 Category: {plugin['category']}")
click.echo(f"💰 Price: ${plugin.get('price', 0.0)}")
click.echo(f"⭐ Rating: {plugin.get('rating', 0)}/5.0 ({plugin.get('reviews_count', 0)} reviews)")
click.echo(f"📥 Downloads: {plugin.get('downloads', 0)}")
click.echo(f"🏷️ Tags: {', '.join(plugin.get('tags', []))}")
click.echo(f"📄 License: {plugin.get('license', 'N/A')}")
click.echo(f"📅 Created: {plugin['created_at']}")
click.echo(f"🔄 Updated: {plugin['updated_at']}")
click.echo("")
click.echo("📝 Description:")
click.echo(f" {plugin['description']}")
else:
click.echo(f"❌ Plugin not found: {response.text}", err=True)
except Exception as e:
click.echo(f"❌ Error getting plugin details: {str(e)}", err=True)
@plugin_marketplace.command()
@click.argument('plugin_id')
@click.option('--test-mode', is_flag=True, help='Run in test mode')
def purchase(plugin_id, test_mode):
"""Purchase a plugin from the marketplace"""
try:
if test_mode:
click.echo(f"💰 Purchase initiated (test mode)")
click.echo(f"📦 Plugin ID: {plugin_id}")
click.echo(f"💳 Payment method: Test Card")
click.echo(f"💰 Amount: $99.99")
click.echo(f"✅ Purchase completed successfully")
click.echo(f"📧 License key: TEST-KEY-{plugin_id.upper()}")
click.echo(f"📥 Download link: https://marketplace.aitbc.dev/download/{plugin_id}")
return
# Get plugin details first
config = get_config()
response = requests.get(
f"{config.coordinator_url}/api/v1/marketplace/plugins/{plugin_id}",
headers={"Authorization": f"Bearer {config.api_key}"},
timeout=30
)
if response.status_code != 200:
click.echo(f"❌ Plugin not found: {response.text}", err=True)
return
plugin = response.json()
# Create purchase order
purchase_data = {
"plugin_id": plugin_id,
"price": plugin.get('price', 0.0),
"currency": plugin.get('pricing', {}).get('currency', 'USD'),
"payment_method": "credit_card",
"purchased_at": datetime.utcnow().isoformat()
}
response = requests.post(
f"{config.coordinator_url}/api/v1/marketplace/purchase",
json=purchase_data,
headers={"Authorization": f"Bearer {config.api_key}"},
timeout=30
)
if response.status_code == 201:
result = response.json()
click.echo(f"💰 Purchase completed successfully!")
click.echo(f"📦 Plugin: {result['plugin_name']}")
click.echo(f"💳 Amount: ${result['amount']} {result['currency']}")
click.echo(f"📧 License Key: {result['license_key']}")
click.echo(f"📥 Download: {result['download_url']}")
click.echo(f"📧 Support: {result['support_email']}")
else:
click.echo(f"❌ Purchase failed: {response.text}", err=True)
except Exception as e:
click.echo(f"❌ Error purchasing plugin: {str(e)}", err=True)
@plugin_marketplace.command()
@click.option('--category', help='Filter by category')
@click.option('--price-min', type=float, help='Minimum price filter')
@click.option('--price-max', type=float, help='Maximum price filter')
@click.option('--rating-min', type=float, help='Minimum rating filter')
@click.option('--limit', type=int, default=10, help='Number of results')
@click.option('--test-mode', is_flag=True, help='Run in test mode')
def featured(category, price_min, price_max, rating_min, limit, test_mode):
"""Browse featured plugins"""
try:
params = {
"featured": True,
"limit": limit
}
if category:
params["category"] = category
if price_min is not None:
params["price_min"] = price_min
if price_max is not None:
params["price_max"] = price_max
if rating_min is not None:
params["rating_min"] = rating_min
if test_mode:
# Mock featured plugins
mock_featured = [
{
"plugin_id": "trading-bot",
"name": "Advanced Trading Bot",
"version": "1.0.0",
"description": "Automated trading bot with advanced algorithms",
"author": "AITBC Team",
"category": "trading",
"price": 99.99,
"rating": 4.5,
"downloads": 1250,
"featured": True,
"featured_reason": "Top-rated trading automation tool"
},
{
"plugin_id": "oracle-feed",
"name": "Oracle Price Feed",
"version": "2.1.0",
"description": "Real-time price oracle integration",
"author": "Oracle Developer",
"category": "oracle",
"price": 49.99,
"rating": 4.8,
"downloads": 890,
"featured": True,
"featured_reason": "Most reliable oracle integration"
}
]
click.echo("⭐ Featured Plugins:")
click.echo("=" * 60)
for plugin in mock_featured[:limit]:
click.echo(f"{plugin['name']} (v{plugin['version']})")
click.echo(f" 💰 Price: ${plugin['price']}")
click.echo(f" ⭐ Rating: {plugin['rating']}/5.0")
click.echo(f" 📥 Downloads: {plugin['downloads']}")
click.echo(f" 📂 Category: {plugin['category']}")
click.echo(f" 👤 Author: {plugin['author']}")
click.echo(f" 🏆 {plugin['featured_reason']}")
click.echo("")
return
# Fetch from marketplace service
config = get_config()
response = requests.get(
f"{config.coordinator_url}/api/v1/marketplace/featured",
params=params,
headers={"Authorization": f"Bearer {config.api_key}"},
timeout=30
)
if response.status_code == 200:
result = response.json()
plugins = result.get("plugins", [])
click.echo("⭐ Featured Plugins:")
click.echo("=" * 60)
for plugin in plugins:
click.echo(f"{plugin['name']} (v{plugin['version']})")
click.echo(f" 💰 Price: ${plugin.get('price', 0.0)}")
click.echo(f" ⭐ Rating: {plugin.get('rating', 0)}/5.0")
click.echo(f" 📥 Downloads: {plugin.get('downloads', 0)}")
click.echo(f" 📂 Category: {plugin.get('category', 'N/A')}")
click.echo(f" 👤 Author: {plugin.get('author', 'N/A')}")
click.echo(f" 🏆 {plugin.get('featured_reason', 'Featured plugin')}")
click.echo("")
else:
click.echo(f"❌ Failed to get featured plugins: {response.text}", err=True)
except Exception as e:
click.echo(f"❌ Error getting featured plugins: {str(e)}", err=True)
@plugin_marketplace.command()
@click.option('--test-mode', is_flag=True, help='Run in test mode')
def my_purchases(test_mode):
"""View your purchased plugins"""
try:
if test_mode:
# Mock purchase history
mock_purchases = [
{
"plugin_id": "trading-bot",
"name": "Advanced Trading Bot",
"version": "1.0.0",
"purchase_date": "2024-02-15T10:30:00Z",
"price": 99.99,
"license_key": "TEST-KEY-TRADING-BOT",
"status": "active",
"download_count": 5
},
{
"plugin_id": "oracle-feed",
"name": "Oracle Price Feed",
"version": "2.1.0",
"purchase_date": "2024-02-10T14:20:00Z",
"price": 49.99,
"license_key": "TEST-KEY-ORACLE-FEED",
"status": "active",
"download_count": 3
}
]
click.echo("📋 Your Purchased Plugins:")
click.echo("=" * 60)
for purchase in mock_purchases:
status_icon = "" if purchase['status'] == 'active' else ""
click.echo(f"{status_icon} {purchase['name']} (v{purchase['version']})")
click.echo(f" 📅 Purchased: {purchase['purchase_date']}")
click.echo(f" 💰 Price: ${purchase['price']}")
click.echo(f" 📧 License Key: {purchase['license_key']}")
click.echo(f" 📥 Downloads: {purchase['download_count']}")
click.echo("")
return
# Get user's purchases
config = get_config()
response = requests.get(
f"{config.coordinator_url}/api/v1/marketplace/purchases",
headers={"Authorization": f"Bearer {config.api_key}"},
timeout=30
)
if response.status_code == 200:
result = response.json()
purchases = result.get("purchases", [])
click.echo("📋 Your Purchased Plugins:")
click.echo("=" * 60)
for purchase in purchases:
status_icon = "" if purchase['status'] == 'active' else ""
click.echo(f"{status_icon} {purchase['plugin_name']} (v{purchase['version']})")
click.echo(f" 📅 Purchased: {purchase['purchase_date']}")
click.echo(f" 💰 Price: ${purchase['price']} {purchase['currency']}")
click.echo(f" 📧 License Key: {purchase['license_key']}")
click.echo(f" 📥 Downloads: {purchase.get('download_count', 0)}")
click.echo("")
else:
click.echo(f"❌ Failed to get purchases: {response.text}", err=True)
except Exception as e:
click.echo(f"❌ Error getting purchases: {str(e)}", err=True)
@plugin_marketplace.command()
@click.argument('plugin_id')
@click.option('--license-key', help='License key for the plugin')
@click.option('--test-mode', is_flag=True, help='Run in test mode')
def download(plugin_id, license_key, test_mode):
"""Download a purchased plugin"""
try:
if test_mode:
click.echo(f"📥 Download started (test mode)")
click.echo(f"📦 Plugin ID: {plugin_id}")
click.echo(f"📧 License Key: {license_key or 'TEST-KEY'}")
click.echo(f"✅ Download completed successfully")
click.echo(f"📁 Download location: /tmp/{plugin_id}.zip")
return
# Validate license key
config = get_config()
response = requests.post(
f"{config.coordinator_url}/api/v1/marketplace/download/{plugin_id}",
json={"license_key": license_key},
headers={"Authorization": f"Bearer {config.api_key}"},
timeout=30
)
if response.status_code == 200:
result = response.json()
click.echo(f"📥 Download started!")
click.echo(f"📦 Plugin: {result['plugin_name']}")
click.echo(f"📁 Download URL: {result['download_url']}")
click.echo(f"📦 File Size: {result['file_size_mb']} MB")
click.echo(f"🔑 Checksum: {result['checksum']}")
# Download the file
download_response = requests.get(result['download_url'], timeout=60)
if download_response.status_code == 200:
filename = f"{plugin_id}.zip"
with open(filename, 'wb') as f:
f.write(download_response.content)
click.echo(f"✅ Download completed!")
click.echo(f"📁 Saved as: {filename}")
click.echo(f"📁 Size: {len(download_response.content) / 1024 / 1024:.1f} MB")
else:
click.echo(f"❌ Download failed: {download_response.text}", err=True)
else:
click.echo(f"❌ Download failed: {response.text}", err=True)
except Exception as e:
click.echo(f"❌ Error downloading plugin: {str(e)}", err=True)
# Helper function to get config
def get_config():
"""Get CLI configuration"""
try:
from .config import get_config
return get_config()
except ImportError:
# Fallback for testing
from types import SimpleNamespace
return SimpleNamespace(
coordinator_url="http://localhost:8014",
api_key="test-api-key"
)
if __name__ == "__main__":
plugin_marketplace()