import * as plugins from './moxytool.plugins.ts'; import * as paths from './moxytool.paths.ts'; import { logger } from './moxytool.logging.ts'; import { ScriptIndex } from './moxytool.classes.scriptindex.ts'; import { ScriptRunner } from './moxytool.classes.scriptrunner.ts'; export const runCli = async () => { const smartshellInstance = new plugins.smartshell.Smartshell({ executor: 'bash', }); const smartcliInstance = new plugins.smartcli.Smartcli(); // Initialize script index and check if refresh is needed const scriptIndex = new ScriptIndex(); // Silently check and refresh index in the background if needed (async () => { try { await scriptIndex.loadCache(); if (await scriptIndex.needsRefresh()) { // Don't block CLI startup, refresh in background scriptIndex.fetchIndex().catch(() => { // Silently fail, will use cached data }); } } catch { // Silently fail on index errors } })(); // Standard command (no arguments) smartcliInstance.standardCommand().subscribe(async () => { logger.log('info', 'MOXYTOOL - Proxmox Administration Tool'); logger.log('info', ''); logger.log('info', 'Available commands:'); logger.log('info', '* vgpu-setup - Install and configure Proxmox vGPU support'); logger.log('info', '* scripts - Manage Proxmox community scripts'); logger.log('info', ''); logger.log('info', 'Usage: moxytool [options]'); }); // vGPU setup command smartcliInstance.addCommand('vgpu-setup').subscribe(async (argvArg) => { logger.log('ok', 'Starting Proxmox vGPU setup process'); logger.log('info', 'This will install vGPU support for NVIDIA GPUs on Proxmox'); logger.log('info', ''); // Check for arguments const step = argvArg.step; const url = argvArg.url; const file = argvArg.file; const debug = argvArg.debug; // Check if running on Proxmox try { const result = await smartshellInstance.exec('which pveversion'); if (result.exitCode !== 0) { logger.log('error', 'This system does not appear to be running Proxmox'); logger.log('error', 'Please run this command on a Proxmox host'); Deno.exit(1); } } catch (e) { logger.log('error', 'Failed to verify Proxmox installation'); logger.log('error', 'Please ensure you are running this on a Proxmox host'); Deno.exit(1); } // Create temporary directory const tmpDir = '/tmp/moxytool-vgpu-setup'; await smartshellInstance.exec(`mkdir -p ${tmpDir}`); try { // Step 1: Clone and run the installer script logger.log('info', 'Step 1: Downloading Proxmox vGPU installer (supports v9)...'); const cloneResult = await smartshellInstance.exec( `cd ${tmpDir} && git clone https://github.com/anomixer/proxmox-vgpu-installer.git`, ); if (cloneResult.exitCode !== 0) { logger.log('error', 'Failed to clone the installer repository'); logger.log('error', cloneResult.stderr || 'Unknown error'); Deno.exit(1); } logger.log('ok', 'Installer downloaded successfully'); logger.log('info', ''); // Build command with arguments let command = 'bash proxmox-installer.sh'; if (step) { command += ` --step ${step}`; } if (url) { command += ` --url ${url}`; } if (file) { command += ` --file ${file}`; } if (debug) { command += ' --debug'; } logger.log('info', 'Running installer script...'); logger.log('info', 'Please follow the interactive prompts'); logger.log('info', ''); // Run the installer script interactively const installResult = await smartshellInstance.exec( `cd ${tmpDir}/proxmox-vgpu-installer && ${command}`, ); if (installResult.exitCode !== 0) { logger.log('error', 'Installer script failed'); logger.log('error', installResult.stderr || 'Unknown error'); Deno.exit(1); } logger.log('ok', 'vGPU setup process completed'); logger.log('info', ''); logger.log('info', 'Next steps:'); logger.log('info', '1. If prompted, reboot your system'); logger.log('info', '2. After reboot, run this command again to continue setup'); logger.log('info', '3. Verify installation with: mdevctl types'); logger.log('info', '4. Configure your VMs with vGPU in the Proxmox web UI'); } catch (error) { logger.log('error', `Setup failed: ${error instanceof Error ? error.message : String(error)}`); Deno.exit(1); } }); // Scripts management commands smartcliInstance.addCommand('scripts').subscribe(async (argvArg) => { const subcommand = argvArg._[0]; if (!subcommand) { logger.log('info', 'MOXYTOOL Scripts - Proxmox Community Scripts Management'); logger.log('info', ''); logger.log('info', 'Available subcommands:'); logger.log('info', '* list - List all available scripts'); logger.log('info', '* search - Search for scripts by name or description'); logger.log('info', '* info - Show detailed information about a script'); logger.log('info', '* run - Execute a script'); logger.log('info', '* refresh - Force refresh the script index'); logger.log('info', ''); logger.log('info', 'Usage: moxytool scripts [options]'); return; } // Ensure index is loaded await scriptIndex.loadCache(); switch (subcommand) { case 'list': { const scripts = scriptIndex.getAll(); if (scripts.length === 0) { logger.log('warn', 'No scripts found. Run "moxytool scripts refresh" to fetch the index.'); return; } const stats = scriptIndex.getStats(); logger.log('info', `Available Scripts (${stats.count} total, indexed ${stats.age})`); logger.log('info', ''); // Group by type const containers = scripts.filter(s => s.type === 'ct'); const vms = scripts.filter(s => s.type === 'vm'); if (containers.length > 0) { logger.log('info', 'Containers (LXC):'); containers.forEach(script => { logger.log('info', ` • ${script.slug.padEnd(25)} - ${script.name}`); }); logger.log('info', ''); } if (vms.length > 0) { logger.log('info', 'Virtual Machines:'); vms.forEach(script => { logger.log('info', ` • ${script.slug.padEnd(25)} - ${script.name}`); }); } logger.log('info', ''); logger.log('info', 'Use "moxytool scripts info " for more details'); logger.log('info', 'Use "moxytool scripts run " to install'); break; } case 'search': { const query = argvArg._[1]; if (!query) { logger.log('error', 'Please provide a search query'); logger.log('info', 'Usage: moxytool scripts search '); return; } const results = scriptIndex.search(query as string); if (results.length === 0) { logger.log('warn', `No scripts found matching "${query}"`); return; } logger.log('info', `Found ${results.length} script(s) matching "${query}":`); logger.log('info', ''); results.forEach(script => { logger.log('info', `${script.slug} (${script.type})`); logger.log('info', ` ${script.name}`); logger.log('info', ` ${script.description.substring(0, 80)}...`); logger.log('info', ''); }); logger.log('info', 'Use "moxytool scripts info " for more details'); break; } case 'info': { const slug = argvArg._[1]; if (!slug) { logger.log('error', 'Please provide a script slug'); logger.log('info', 'Usage: moxytool scripts info '); return; } const script = scriptIndex.getBySlug(slug as string); if (!script) { logger.log('error', `Script "${slug}" not found`); logger.log('info', 'Use "moxytool scripts search " to find scripts'); return; } logger.log('info', '═'.repeat(60)); logger.log('info', `${script.name}`); logger.log('info', '═'.repeat(60)); logger.log('info', ''); logger.log('info', `Slug: ${script.slug}`); logger.log('info', `Type: ${script.type === 'ct' ? 'Container (LXC)' : 'Virtual Machine'}`); logger.log('info', ''); logger.log('info', 'Description:'); logger.log('info', script.description); logger.log('info', ''); if (script.install_methods && script.install_methods[0]?.resources) { const res = script.install_methods[0].resources; logger.log('info', 'Resource Requirements:'); if (res.cpu) logger.log('info', ` CPU: ${res.cpu} cores`); if (res.ram) logger.log('info', ` RAM: ${res.ram} MB`); if (res.hdd) logger.log('info', ` Disk: ${res.hdd} GB`); if (res.os) logger.log('info', ` OS: ${res.os} ${res.version || ''}`); logger.log('info', ''); } if (script.interface_port) { logger.log('info', `Web Interface: http://:${script.interface_port}`); logger.log('info', ''); } if (script.default_credentials) { logger.log('info', 'Default Credentials:'); if (script.default_credentials.username) { logger.log('info', ` Username: ${script.default_credentials.username}`); } if (script.default_credentials.password) { logger.log('info', ` Password: ${script.default_credentials.password}`); } logger.log('info', ''); } if (script.notes && script.notes.length > 0) { logger.log('info', 'Important Notes:'); script.notes.forEach(note => { const prefix = note.type === 'warning' ? '⚠️ ' : 'ℹ️ '; logger.log('warn', `${prefix}${note.content}`); }); logger.log('info', ''); } if (script.documentation) { logger.log('info', `Documentation: ${script.documentation}`); } if (script.website) { logger.log('info', `Website: ${script.website}`); } logger.log('info', ''); logger.log('info', `To install: sudo moxytool scripts run ${script.slug}`); logger.log('info', '═'.repeat(60)); break; } case 'run': { const slug = argvArg._[1]; if (!slug) { logger.log('error', 'Please provide a script slug'); logger.log('info', 'Usage: sudo moxytool scripts run '); return; } const script = scriptIndex.getBySlug(slug as string); if (!script) { logger.log('error', `Script "${slug}" not found`); logger.log('info', 'Use "moxytool scripts search " to find scripts'); return; } // Validate Proxmox host const runner = new ScriptRunner(); const isProxmox = await runner.validateProxmoxHost(); if (!isProxmox) { logger.log('error', 'This system does not appear to be running Proxmox'); logger.log('error', 'Community scripts can only be run on Proxmox hosts'); Deno.exit(1); } // Execute the script const exitCode = await runner.execute(script); Deno.exit(exitCode); } case 'refresh': { logger.log('info', 'Refreshing script index...'); try { await scriptIndex.fetchIndex(); const stats = scriptIndex.getStats(); logger.log('success', `Index refreshed: ${stats.count} scripts cached`); } catch (error) { logger.log('error', `Failed to refresh index: ${error}`); Deno.exit(1); } break; } default: logger.log('error', `Unknown subcommand: ${subcommand}`); logger.log('info', 'Run "moxytool scripts" to see available subcommands'); } }); smartcliInstance.startParse(); };