UNPKG

keyvault-cli

Version:

Secure API key management CLI tool

2,205 lines 92.5 kB
#!/usr/bin/env node
import { Command } from 'commander';
import chalk from 'chalk';
import inquirer from 'inquirer';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { CodeScanner } from './scanner.js';
import { CLIAuth } from './auth.js';
// Get package version dynamically
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packageJsonPath = path.join(__dirname, '..', 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const program = new Command();
// ASCII Logo
const logo = `
╦╔═╔═╗╦ ╦╦  ╦╔═╗╦ ╦╦ ╔╦╗
╠╩╗║╣ ╚╦╝╚╗╔╝╠═╣║ ║║  ║ 
╩ ╩╚═╝ ╩  ╚╝ ╩ ╩╚═╝╩═╝╩ 
`;
program
    .name('keyvault')
    .description(`${chalk.cyan(logo)}\nKeyVault CLI - Secure API key management for developers`)
    .version(packageJson.version);
// Scan command
program
    .command('scan')
    .description('Scan codebase for exposed API keys and secrets')
    .option('-d, --directory <path>', 'Directory to scan', process.cwd())
    .option('-o, --output <file>', 'Output file for results')
    .option('-f, --format <format>', 'Output format (json|text)', 'text')
    .action(async (options) => {
    console.log(chalk.blue('🔍 Scanning for API keys and secrets...'));
    const scanner = new CodeScanner();
    const results = await scanner.scanDirectory(options.directory);
    if (options.format === 'json') {
        const output = JSON.stringify(results, null, 2);
        if (options.output) {
            await fs.promises.writeFile(options.output, output);
            console.log(chalk.green(`Results saved to ${options.output}`));
        }
        else {
            console.log(output);
        }
    }
    else {
        const report = scanner.generateReport(results);
        if (options.output) {
            await fs.promises.writeFile(options.output, report);
            console.log(chalk.green(`Report saved to ${options.output}`));
        }
        else {
            console.log(report);
        }
    }
    if (results.length > 0) {
        console.log(chalk.yellow('\n⚠️  Security issues found! Please review and secure your API keys.'));
        process.exit(1);
    }
    else {
        console.log(chalk.green('\n✅ No exposed API keys found in your codebase.'));
    }
});
// Helper functions for init
async function initPersonalKeys() {
    console.log(chalk.blue('🔐 Personal KeyVault Setup'));
    console.log(chalk.gray('This will generate your personal encryption keys from a master passphrase.'));
    console.log(chalk.gray('Your passphrase is the ONLY way to access your encrypted keys.'));
    console.log(chalk.yellow('⚠️  Keep your passphrase safe - it cannot be recovered if lost!'));
    const { KeyVaultCrypto } = await import('./crypto.js');
    const { passphrase, confirmPassphrase } = await inquirer.prompt([
        {
            type: 'password',
            name: 'passphrase',
            message: 'Enter your master passphrase:',
            mask: '*',
            validate: (input) => {
                const validation = KeyVaultCrypto.validatePassphrase(input);
                return validation.valid || validation.message || 'Invalid passphrase';
            }
        },
        {
            type: 'password',
            name: 'confirmPassphrase',
            message: 'Confirm your master passphrase:',
            mask: '*',
            validate: (input, answers) => input === answers.passphrase || 'Passphrases do not match'
        }
    ]);
    console.log(chalk.blue('\n🔑 Generating your personal encryption keys...'));
    try {
        // Generate deterministic key pair
        const keyPair = KeyVaultCrypto.generateKeyPair(passphrase);
        console.log(chalk.green('✅ Personal keys generated successfully!'));
        console.log(chalk.gray(`Address: ${keyPair.address}`));
        console.log(chalk.gray(`Public Key: ${KeyVaultCrypto.maskKey(keyPair.publicKey)}`));
        // Save personal keys to ~/.keyvault/config.json
        const personalKeys = {
            address: keyPair.address,
            publicKey: keyPair.publicKey,
            privateKey: keyPair.privateKey,
            createdAt: new Date().toISOString()
        };
        await CLIAuth.savePersonalKeys(personalKeys);
        console.log(chalk.green(`🔐 Personal keys saved to ~/.keyvault/config.json`));
        console.log(chalk.gray('Keys are stored in your home directory for global access'));
        console.log(chalk.gray('\nYour private key is stored locally and will never be sent to the server.'));
        console.log(chalk.gray('Keep this file safe - it contains your encryption keys.'));
        // Keys are stored locally only, no server upload needed
        console.log(chalk.blue('\n✅ Personal setup complete! Your keys are stored locally.'));
        console.log(chalk.gray('Your private key never leaves this device for maximum security.'));
    }
    catch (error) {
        console.log(chalk.red('❌ Personal key generation failed:'), error instanceof Error ? error.message : 'Unknown error');
    }
}
async function createTeamAndInitKeys(teamName) {
    try {
        // First create the team on the server
        const config = await CLIAuth.getConfig();
        if (!config?.token) {
            console.log(chalk.red('❌ Not logged in. Please login first.'));
            return;
        }
        console.log(chalk.blue(`🏢 Creating team "${teamName}" on server...`));
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/teams`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.token}`
            },
            body: JSON.stringify({ name: teamName })
        });
        if (!response.ok) {
            const errorData = await response.json();
            console.log(chalk.red(`❌ Failed to create team: ${errorData.message}`));
            return;
        }
        console.log(chalk.green(`✅ Team "${teamName}" created successfully!`));
        // Now init the encryption keys
        await initTeamKeys(teamName);
    }
    catch (error) {
        console.error(chalk.red('❌ Error creating team:'), error);
    }
}
async function initTeamKeys(teamName) {
    console.log(chalk.blue(`🏢 Team KeyVault Setup: ${teamName}`));
    console.log(chalk.gray('This will generate team-specific encryption keys from a team passphrase.'));
    console.log(chalk.gray('Team members with the same passphrase will generate identical keys.'));
    console.log(chalk.yellow('⚠️  Keep the team passphrase safe and share it securely with team members!'));
    const { KeyVaultCrypto } = await import('./crypto.js');
    const { passphrase, confirmPassphrase } = await inquirer.prompt([
        {
            type: 'password',
            name: 'passphrase',
            message: `Enter team passphrase for "${teamName}":`,
            mask: '*',
            validate: (input) => {
                const validation = KeyVaultCrypto.validatePassphrase(input);
                return validation.valid || validation.message || 'Invalid passphrase';
            }
        },
        {
            type: 'password',
            name: 'confirmPassphrase',
            message: 'Confirm team passphrase:',
            mask: '*',
            validate: (input, answers) => input === answers.passphrase || 'Passphrases do not match'
        }
    ]);
    console.log(chalk.blue(`\n🔑 Generating team encryption keys for "${teamName}"...`));
    try {
        // Generate deterministic team key pair using team name + passphrase
        const teamSeed = `team:${teamName}:${passphrase}`;
        const keyPair = KeyVaultCrypto.generateKeyPair(teamSeed);
        console.log(chalk.green(`✅ Team keys for "${teamName}" generated successfully!`));
        console.log(chalk.gray(`Team Address: ${keyPair.address}`));
        console.log(chalk.gray(`Team Public Key: ${KeyVaultCrypto.maskKey(keyPair.publicKey)}`));
        // Save team keys to ~/.keyvault/config.json
        const teamKeys = {
            address: keyPair.address,
            publicKey: keyPair.publicKey,
            privateKey: keyPair.privateKey,
            createdAt: new Date().toISOString()
        };
        await CLIAuth.saveTeamKeys(teamName, teamKeys);
        console.log(chalk.green(`🔐 Team keys saved to ~/.keyvault/config.json`));
        console.log(chalk.gray('Keys are stored in your home directory for global access'));
        console.log(chalk.gray(`\nTeam "${teamName}" private key is stored locally.`));
        console.log(chalk.gray('Share the team passphrase securely with team members.'));
        console.log(chalk.blue(`\n✅ Team "${teamName}" setup complete!`));
        console.log(chalk.gray('All team members with the same passphrase will generate identical keys.'));
    }
    catch (error) {
        console.log(chalk.red(`❌ Team key generation failed for "${teamName}":`, error instanceof Error ? error.message : 'Unknown error'));
    }
}
// Init commands
const initCommand = program
    .command('init')
    .description('Initialize KeyVault encryption keys');
// Main init command - ask user to choose type
initCommand
    .action(async () => {
    console.log(chalk.blue('🔐 KeyVault Initialization'));
    console.log(chalk.gray('Choose the type of encryption keys to generate:'));
    const { keyType } = await inquirer.prompt([
        {
            type: 'list',
            name: 'keyType',
            message: 'What type of keys do you want to generate?',
            choices: [
                {
                    name: '👤 Personal Keys - For your individual API keys',
                    value: 'personal'
                },
                {
                    name: '🏢 Team Keys - For shared team API keys',
                    value: 'team'
                }
            ]
        }
    ]);
    if (keyType === 'personal') {
        // Call personal init directly
        await initPersonalKeys();
    }
    else {
        // Team init - first check if user is logged in and has teams
        const config = await CLIAuth.getConfig();
        if (!config?.token) {
            console.log(chalk.yellow('💡 To see your teams, please login first: keyvault login'));
            console.log(chalk.gray('You can still create team keys manually by entering a team name.'));
            const { teamName } = await inquirer.prompt([
                {
                    type: 'input',
                    name: 'teamName',
                    message: 'Enter team name:',
                    validate: (input) => {
                        if (!input || typeof input !== 'string') {
                            return 'Team name is required';
                        }
                        const teamNameRegex = /^[a-zA-Z0-9._-]+$/;
                        if (!teamNameRegex.test(input)) {
                            return 'Team names can only contain letters, numbers, hyphens, underscores, and dots';
                        }
                        if (input.length < 2 || input.length > 50) {
                            return 'Team name must be between 2 and 50 characters';
                        }
                        return true;
                    }
                }
            ]);
            await initTeamKeys(teamName);
            return;
        }
        // User is logged in, fetch their teams
        try {
            const fetch = (await import('node-fetch')).default;
            const response = await fetch(`${config.apiUrl}/api/teams`, {
                headers: {
                    'Authorization': `Bearer ${config.token}`
                }
            });
            if (response.ok) {
                const data = await response.json();
                const teams = data.teams || data;
                if (teams.length === 0) {
                    console.log(chalk.yellow('📝 You have no teams yet. Let\'s create a new team and generate encryption keys for it.'));
                    const { teamName } = await inquirer.prompt([
                        {
                            type: 'input',
                            name: 'teamName',
                            message: 'Enter team name:',
                            validate: (input) => {
                                if (!input || typeof input !== 'string') {
                                    return 'Team name is required';
                                }
                                const teamNameRegex = /^[a-zA-Z0-9._-]+$/;
                                if (!teamNameRegex.test(input)) {
                                    return 'Team names can only contain letters, numbers, hyphens, underscores, and dots';
                                }
                                if (input.length < 2 || input.length > 50) {
                                    return 'Team name must be between 2 and 50 characters';
                                }
                                return true;
                            }
                        }
                    ]);
                    // Create the team first, then init keys
                    await createTeamAndInitKeys(teamName);
                }
                else {
                    // User has teams, let them choose
                    const choices = teams.map((team, index) => ({
                        name: `${team.name} (ID: ${team.id})`,
                        value: team.name
                    }));
                    choices.push({
                        name: '➕ Create keys for a different team',
                        value: 'NEW_TEAM'
                    });
                    const { selectedTeam } = await inquirer.prompt([
                        {
                            type: 'list',
                            name: 'selectedTeam',
                            message: 'Select a team to generate encryption keys for:',
                            choices: choices
                        }
                    ]);
                    if (selectedTeam === 'NEW_TEAM') {
                        const { teamName } = await inquirer.prompt([
                            {
                                type: 'input',
                                name: 'teamName',
                                message: 'Enter team name:',
                                validate: (input) => {
                                    if (!input || typeof input !== 'string') {
                                        return 'Team name is required';
                                    }
                                    const teamNameRegex = /^[a-zA-Z0-9._-]+$/;
                                    if (!teamNameRegex.test(input)) {
                                        return 'Team names can only contain letters, numbers, hyphens, underscores, and dots';
                                    }
                                    if (input.length < 2 || input.length > 50) {
                                        return 'Team name must be between 2 and 50 characters';
                                    }
                                    return true;
                                }
                            }
                        ]);
                        // Create the team first, then init keys
                        await createTeamAndInitKeys(teamName);
                    }
                    else {
                        await initTeamKeys(selectedTeam);
                    }
                }
            }
            else {
                // API call failed, fallback to manual input
                console.log(chalk.yellow('⚠️  Unable to fetch your teams. You can still create team keys manually.'));
                const { teamName } = await inquirer.prompt([
                    {
                        type: 'input',
                        name: 'teamName',
                        message: 'Enter team name:',
                        validate: (input) => {
                            if (!input || typeof input !== 'string') {
                                return 'Team name is required';
                            }
                            const teamNameRegex = /^[a-zA-Z0-9._-]+$/;
                            if (!teamNameRegex.test(input)) {
                                return 'Team names can only contain letters, numbers, hyphens, underscores, and dots';
                            }
                            if (input.length < 2 || input.length > 50) {
                                return 'Team name must be between 2 and 50 characters';
                            }
                            return true;
                        }
                    }
                ]);
                await initTeamKeys(teamName);
            }
        }
        catch (error) {
            console.log(chalk.yellow('⚠️  Unable to fetch your teams. You can still create team keys manually.'));
            const { teamName } = await inquirer.prompt([
                {
                    type: 'input',
                    name: 'teamName',
                    message: 'Enter team name:',
                    validate: (input) => {
                        if (!input || typeof input !== 'string') {
                            return 'Team name is required';
                        }
                        const teamNameRegex = /^[a-zA-Z0-9._-]+$/;
                        if (!teamNameRegex.test(input)) {
                            return 'Team names can only contain letters, numbers, hyphens, underscores, and dots';
                        }
                        if (input.length < 2 || input.length > 50) {
                            return 'Team name must be between 2 and 50 characters';
                        }
                        return true;
                    }
                }
            ]);
            await initTeamKeys(teamName);
        }
    }
});
initCommand
    .command('personal')
    .alias('user')
    .description('Initialize personal encryption keys')
    .action(async () => {
    await initPersonalKeys();
});
initCommand
    .command('team <teamName>')
    .description('Initialize team-specific encryption keys (team name must be URL-safe)')
    .action(async (teamName) => {
    // Validate team name
    if (!teamName || typeof teamName !== 'string') {
        console.log(chalk.red('❌ Team name is required'));
        return;
    }
    // Team name validation: only alphanumeric, hyphens, underscores, dots
    const teamNameRegex = /^[a-zA-Z0-9._-]+$/;
    if (!teamNameRegex.test(teamName)) {
        console.log(chalk.red('❌ Invalid team name format'));
        console.log(chalk.gray('Team names can only contain:'));
        console.log(chalk.gray('  • Letters (a-z, A-Z)'));
        console.log(chalk.gray('  • Numbers (0-9)'));
        console.log(chalk.gray('  • Hyphens (-)'));
        console.log(chalk.gray('  • Underscores (_)'));
        console.log(chalk.gray('  • Dots (.)'));
        console.log(chalk.gray('Examples: frontend-team, backend_api, team.mobile'));
        return;
    }
    // Check length
    if (teamName.length < 2 || teamName.length > 50) {
        console.log(chalk.red('❌ Team name must be between 2 and 50 characters'));
        return;
    }
    await initTeamKeys(teamName);
});
// Backward compatibility: keep the old 'init' command working
program
    .command('init-legacy')
    .description('Initialize KeyVault with your master passphrase (legacy)')
    .option('--generate-keys', 'Generate new key pair from passphrase')
    .action(async (options) => {
    console.log(chalk.yellow('⚠️  This is the legacy init command. Consider using "keyvault init personal" instead.'));
    console.log(chalk.blue('🔐 KeyVault Setup'));
    console.log(chalk.gray('This will generate your personal encryption keys from a master passphrase.'));
    console.log(chalk.gray('Your passphrase is the ONLY way to access your encrypted keys.'));
    console.log(chalk.yellow('⚠️  Keep your passphrase safe - it cannot be recovered if lost!'));
    const { KeyVaultCrypto } = await import('./crypto.js');
    const { passphrase, confirmPassphrase } = await inquirer.prompt([
        {
            type: 'password',
            name: 'passphrase',
            message: 'Enter your master passphrase:',
            mask: '*',
            validate: (input) => {
                const validation = KeyVaultCrypto.validatePassphrase(input);
                return validation.valid || validation.message || 'Invalid passphrase';
            }
        },
        {
            type: 'password',
            name: 'confirmPassphrase',
            message: 'Confirm your master passphrase:',
            mask: '*',
            validate: (input, answers) => input === answers.passphrase || 'Passphrases do not match'
        }
    ]);
    console.log(chalk.blue('\n🔑 Generating your encryption keys...'));
    try {
        // Generate deterministic key pair
        const keyPair = KeyVaultCrypto.generateKeyPair(passphrase);
        console.log(chalk.green('✅ Keys generated successfully!'));
        console.log(chalk.gray(`Address: ${keyPair.address}`));
        console.log(chalk.gray(`Public Key: ${KeyVaultCrypto.maskKey(keyPair.publicKey)}`));
        // Save keys to ~/.keyvault/config.json (legacy support)
        const personalKeys = {
            address: keyPair.address,
            publicKey: keyPair.publicKey,
            privateKey: keyPair.privateKey,
            createdAt: new Date().toISOString()
        };
        await CLIAuth.savePersonalKeys(personalKeys);
        console.log(chalk.green(`🔐 Key information saved to ~/.keyvault/config.json`));
        console.log(chalk.gray('Keys are stored in your home directory for global access'));
        console.log(chalk.gray('\nYour private key is stored locally and will never be sent to the server.'));
        console.log(chalk.gray('Keep this file safe - it contains your encryption keys.'));
        // Keys are stored locally only, no server upload needed
        console.log(chalk.blue('\n✅ Setup complete! Your keys are stored locally.'));
        console.log(chalk.gray('Your private key never leaves this device for maximum security.'));
    }
    catch (error) {
        console.log(chalk.red('❌ Key generation failed:'), error instanceof Error ? error.message : 'Unknown error');
    }
});
// Check command
program
    .command('check')
    .description('Check if current directory contains any exposed secrets')
    .action(async () => {
    const scanner = new CodeScanner();
    const results = await scanner.scanDirectory(process.cwd());
    if (results.length > 0) {
        console.log(chalk.red(`❌ Found ${results.length} exposed secrets!`));
        const highSeverity = results.filter((r) => r.severity === 'high');
        if (highSeverity.length > 0) {
            console.log(chalk.red(`🔴 ${highSeverity.length} high-severity issues require immediate attention`));
        }
        process.exit(1);
    }
    else {
        console.log(chalk.green('✅ No exposed secrets found'));
    }
});
// Auth commands
program
    .command('login')
    .description('Login to KeyVault')
    .action(async () => {
    await CLIAuth.login();
});
program
    .command('register')
    .alias('signup')
    .description('Create a new KeyVault account')
    .action(async () => {
    console.log(chalk.blue('🚀 KeyVault Registration'));
    const apiUrl = 'https://1pass.vercel.app';
    const { email, password, confirmPassword } = await inquirer.prompt([
        {
            type: 'input',
            name: 'email',
            message: 'Email:',
            validate: (input) => input.includes('@') || 'Please enter a valid email'
        },
        {
            type: 'password',
            name: 'password',
            message: 'Password:',
            mask: '*',
            validate: (input) => input.length >= 6 || 'Password must be at least 6 characters'
        },
        {
            type: 'password',
            name: 'confirmPassword',
            message: 'Confirm Password:',
            mask: '*',
            validate: (input, answers) => input === answers.password || 'Passwords do not match'
        }
    ]);
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${apiUrl}/api/auth/register`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email, password })
        });
        if (!response.ok) {
            const error = await response.json();
            throw new Error(error.error || 'Registration failed');
        }
        const data = await response.json();
        await CLIAuth.saveConfig({
            apiUrl,
            token: data.token,
            email
        });
        console.log(chalk.green('✅ Registration successful!'));
        console.log(chalk.gray(`Logged in as: ${email}`));
    }
    catch (error) {
        console.log(chalk.red('❌ Registration failed:'), error instanceof Error ? error.message : 'Unknown error');
        process.exit(1);
    }
});
program
    .command('logout')
    .description('Logout from KeyVault')
    .action(async () => {
    await CLIAuth.logout();
});
program
    .command('whoami')
    .description('Show current user info')
    .action(async () => {
    await CLIAuth.whoami();
});
program
    .command('forgot-password')
    .description('Reset your password')
    .action(async () => {
    await CLIAuth.forgotPassword();
});
program
    .command('reset-password')
    .description('Reset password with token')
    .option('-t, --token <token>', 'Reset token from email')
    .action(async (options) => {
    const apiUrl = 'https://1pass.vercel.app';
    await CLIAuth.resetPassword(apiUrl, options.token);
});
// Team management commands
const teamCommand = program
    .command('team')
    .description('Team management commands');
teamCommand
    .command('create <name>')
    .description('Create a new team (name must be URL-safe)')
    .action(async (name) => {
    // Validate team name
    if (!name || typeof name !== 'string') {
        console.log(chalk.red('❌ Team name is required'));
        return;
    }
    // Team name validation: only alphanumeric, hyphens, underscores, dots
    const teamNameRegex = /^[a-zA-Z0-9._-]+$/;
    if (!teamNameRegex.test(name)) {
        console.log(chalk.red('❌ Invalid team name format'));
        console.log(chalk.gray('Team names can only contain:'));
        console.log(chalk.gray('  • Letters (a-z, A-Z)'));
        console.log(chalk.gray('  • Numbers (0-9)'));
        console.log(chalk.gray('  • Hyphens (-)'));
        console.log(chalk.gray('  • Underscores (_)'));
        console.log(chalk.gray('  • Dots (.)'));
        console.log(chalk.gray('Examples: frontend-team, backend_api, team.mobile'));
        return;
    }
    // Check length
    if (name.length < 2 || name.length > 50) {
        console.log(chalk.red('❌ Team name must be between 2 and 50 characters'));
        return;
    }
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/teams`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.token}`
            },
            body: JSON.stringify({ name })
        });
        if (response.ok) {
            const data = await response.json();
            console.log(chalk.green(`✅ Team "${name}" created successfully`));
            console.log(chalk.gray(`Team ID: ${data.team.id}`));
            console.log(chalk.blue(`💡 Generate team encryption keys with: keyvault init team ${name}`));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to create team: ${error}`));
    }
});
teamCommand
    .command('list')
    .alias('ls')
    .description('List your teams')
    .action(async () => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/teams`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            const data = await response.json();
            const teams = data.teams || data;
            if (teams.length === 0) {
                console.log(chalk.yellow('📝 No teams found. Create one with: keyvault team create <name>'));
            }
            else {
                console.log(chalk.blue('👥 Your Teams:'));
                console.log('');
                teams.forEach((team, index) => {
                    const isActive = config.activeTeamId === team.id;
                    const activeIndicator = isActive ? chalk.green('●') : chalk.gray('○');
                    console.log(`${activeIndicator} ${chalk.white(`${index + 1}. ${team.name}`)}`);
                    console.log(chalk.gray(`   ID: ${team.id}`));
                    console.log(chalk.gray(`   Created: ${new Date(team.createdAt).toLocaleDateString()}`));
                    if (isActive) {
                        console.log(chalk.green('   ✅ Currently active'));
                    }
                    console.log('');
                });
                console.log(chalk.gray('💡 Switch to a team: keyvault team switch <number|id>'));
                console.log(chalk.gray('   Example: keyvault team switch 1'));
                if (teams[0]?.id) {
                    console.log(chalk.gray('   Example: keyvault team switch ' + teams[0].id));
                }
            }
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to fetch teams: ${error}`));
    }
});
teamCommand
    .command('invite [email]')
    .description('Invite a user to your active team')
    .option('-e, --email <email>', 'User email to invite')
    .option('-r, --role <role>', 'User role (admin|developer|read-only)', 'developer')
    .action(async (emailParam, options) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    // Check if user has switched to a team
    if (!config.activeTeamId) {
        console.log(chalk.red('❌ No active team selected. Please switch to a team first:'));
        console.log(chalk.gray('   1. List your teams: keyvault team list'));
        console.log(chalk.gray('   2. Switch to a team: keyvault team switch <team-id>'));
        return;
    }
    let email = emailParam || options.email;
    let role = options.role;
    // Interactive prompts for missing options
    if (!email) {
        const answers = await inquirer.prompt([
            {
                type: 'input',
                name: 'email',
                message: 'Email address to invite:',
                validate: (input) => input.includes('@') || 'Please enter a valid email'
            },
            {
                type: 'list',
                name: 'role',
                message: 'User role:',
                choices: [
                    { name: 'Developer - Can view and manage keys', value: 'developer' },
                    { name: 'Admin - Full team management access', value: 'admin' },
                    { name: 'Read-only - View access only', value: 'read-only' }
                ],
                default: 'developer'
            }
        ]);
        email = answers.email;
        role = answers.role;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        // First get team name for confirmation
        const teamResponse = await fetch(`${config.apiUrl}/api/teams/${config.activeTeamId}`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (!teamResponse.ok) {
            console.log(chalk.red('❌ Active team not found. Please switch to a valid team.'));
            return;
        }
        const teamData = await teamResponse.json();
        const team = teamData.team || teamData;
        const response = await fetch(`${config.apiUrl}/api/teams/${config.activeTeamId}/invite`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.token}`
            },
            body: JSON.stringify({ email, role })
        });
        if (response.ok) {
            console.log(chalk.green(`✅ Invitation sent to ${email}`));
            console.log(chalk.gray(`Team: ${team.name}`));
            console.log(chalk.gray(`Role: ${role}`));
            console.log(chalk.gray('They will receive an email with instructions to join the team.'));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to send invitation: ${error}`));
    }
});
teamCommand
    .command('switch <teamIdentifier>')
    .description('Switch to a different team context (by number or ID)')
    .action(async (teamIdentifier) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        // First get all teams
        const teamsResponse = await fetch(`${config.apiUrl}/api/teams`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (!teamsResponse.ok) {
            console.log(chalk.red('❌ Failed to fetch teams'));
            return;
        }
        const teamsData = await teamsResponse.json();
        const teams = teamsData.teams || teamsData;
        if (teams.length === 0) {
            console.log(chalk.yellow('📝 No teams found. Create one with: keyvault team create <name>'));
            return;
        }
        let targetTeam;
        // Check if it's a number (index)
        const teamIndex = parseInt(teamIdentifier);
        if (!isNaN(teamIndex) && teamIndex >= 1 && teamIndex <= teams.length) {
            targetTeam = teams[teamIndex - 1];
        }
        else {
            // Try to find by ID
            targetTeam = teams.find((team) => team.id === teamIdentifier);
        }
        if (!targetTeam) {
            console.log(chalk.red(`❌ Team "${teamIdentifier}" not found`));
            console.log(chalk.gray('Available teams:'));
            teams.forEach((team, index) => {
                console.log(chalk.gray(`  ${index + 1}. ${team.name} (${team.id})`));
            });
            return;
        }
        // Verify team access
        const response = await fetch(`${config.apiUrl}/api/teams/${targetTeam.id}`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            // Update config with active team
            const updatedConfig = {
                ...config,
                activeTeamId: targetTeam.id
            };
            await CLIAuth.saveConfig(updatedConfig);
            console.log(chalk.green(`✅ Switched to team: ${targetTeam.name}`));
            console.log(chalk.gray(`Team ID: ${targetTeam.id}`));
            console.log(chalk.gray('All subsequent operations will use this team context.'));
            console.log(chalk.gray('Now you can use: keyvault team invite -e user@example.com'));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error || 'Team not found or access denied'}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to switch team: ${error}`));
    }
});
teamCommand
    .command('deactivate')
    .alias('exit')
    .description('Exit team context and return to personal mode')
    .action(async () => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    if (!config.activeTeamId) {
        console.log(chalk.yellow('ℹ️  No active team to deactivate. Already in personal mode.'));
        return;
    }
    try {
        // Get team name before removing it
        const fetch = (await import('node-fetch')).default;
        const teamResponse = await fetch(`${config.apiUrl}/api/teams/${config.activeTeamId}`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        let teamName = 'Unknown Team';
        if (teamResponse.ok) {
            const teamData = await teamResponse.json();
            const team = teamData.team || teamData;
            teamName = team.name;
        }
        // Remove active team from config
        const updatedConfig = {
            ...config,
            activeTeamId: undefined
        };
        await CLIAuth.saveConfig(updatedConfig);
        console.log(chalk.green(`✅ Exited team context: ${teamName}`));
        console.log(chalk.gray('Now in personal mode. All operations will affect your personal keys.'));
        console.log(chalk.gray('To switch back to a team: keyvault team switch <team-id>'));
    }
    catch (error) {
        // Even if API call fails, still remove from config
        const updatedConfig = {
            ...config,
            activeTeamId: undefined
        };
        await CLIAuth.saveConfig(updatedConfig);
        console.log(chalk.green('✅ Exited team context'));
        console.log(chalk.gray('Now in personal mode.'));
    }
});
teamCommand
    .command('members <teamId>')
    .description('List team members')
    .action(async (teamId) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/teams/${teamId}/members`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            const data = await response.json();
            const members = data.members || [];
            if (members.length === 0) {
                console.log(chalk.yellow('👥 No team members found.'));
            }
            else {
                console.log(chalk.blue(`👥 Team Members (${members.length}):`));
                members.forEach((member, index) => {
                    console.log(chalk.white(`${index + 1}. ${member.email || member.userId}`));
                    console.log(chalk.gray(`   Role: ${member.role}`));
                    console.log(chalk.gray(`   Joined: ${new Date(member.joinedAt).toLocaleDateString()}`));
                    if (member.isOwner) {
                        console.log(chalk.yellow(`   👑 Team Owner`));
                    }
                    console.log('');
                });
            }
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to fetch team members: ${error}`));
    }
});
teamCommand
    .command('invitations')
    .alias('invites')
    .description('List your pending team invitations')
    .action(async () => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/user/invitations`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            const data = await response.json();
            const invitations = data.invitations || [];
            if (invitations.length === 0) {
                console.log(chalk.gray('📬 No pending invitations found.'));
            }
            else {
                console.log(chalk.blue(`📬 Your Team Invitations (${invitations.length}):`));
                console.log('');
                invitations.forEach((invitation, index) => {
                    const status = invitation.status || 'pending';
                    const statusIcon = status === 'pending' ? '⏳' : status === 'accepted' ? '✅' : '❌';
                    const expiresAt = invitation.expiresAt ? new Date(invitation.expiresAt) : null;
                    const isExpired = expiresAt ? expiresAt < new Date() : false;
                    console.log(`${index + 1}. ${statusIcon} ${chalk.white(invitation.teamName)}`);
                    console.log(`   ${chalk.gray('From:')} ${invitation.inviterEmail}`);
                    console.log(`   ${chalk.gray('Role:')} ${invitation.role}`);
                    console.log(`   ${chalk.gray('Status:')} ${status}`);
                    if (invitation.message) {
                        console.log(`   ${chalk.gray('Message:')} ${invitation.message}`);
                    }
                    if (expiresAt) {
                        if (isExpired) {
                            console.log(`   ${chalk.red('⚠️  Expired:')} ${expiresAt.toLocaleDateString()}`);
                        }
                        else {
                            console.log(`   ${chalk.gray('Expires:')} ${expiresAt.toLocaleDateString()}`);
                        }
                    }
                    else {
                        console.log(`   ${chalk.gray('Expires:')} Not set`);
                    }
                    if (status === 'pending' && !isExpired) {
                        console.log(`   ${chalk.green('💡 Accept:')} keyvault team accept ${invitation.id}`);
                    }
                    console.log('');
                });
            }
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to fetch invitations: ${error}`));
    }
});
teamCommand
    .command('accept <invitationId>')
    .description('Accept a team invitation')
    .action(async (invitationId) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        // First get invitation details
        const inviteResponse = await fetch(`${config.apiUrl}/api/user/invitations`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (!inviteResponse.ok) {
            console.log(chalk.red('❌ Failed to fetch invitations'));
            return;
        }
        const inviteData = await inviteResponse.json();
        const invitations = inviteData.invitations || [];
        const invitation = invitations.find((inv) => inv.id === invitationId);
        if (!invitation) {
            console.log(chalk.red(`❌ Invitation ${invitationId} not found`));
            console.log(chalk.gray('Use "keyvault team invitations" to see pending invitations'));
            return;
        }
        if (invitation.status !== 'pending') {
            console.log(chalk.yellow(`⚠️  Invitation already ${invitation.status}`));
            return;
        }
        const expiresAt = new Date(invitation.expiresAt);
        if (expiresAt < new Date()) {
            console.log(chalk.red('❌ This invitation has expired'));
            return;
        }
        // Show invitation details and confirm
        console.log(chalk.blue('📋 Team Invitation Details:'));
        console.log(`   ${chalk.white('Team:')} ${invitation.teamName}`);
        console.log(`   ${chalk.white('From:')} ${invitation.inviterEmail}`);
        console.log(`   ${chalk.white('Role:')} ${invitation.role}`);
        if (invitation.message) {
            console.log(`   ${chalk.white('Message:')} ${invitation.message}`);
        }
        console.log('');
        const { confirm } = await inquirer.prompt([
            {
                type: 'confirm',
                name: 'confirm',
                message: `Accept invitation to join "${invitation.teamName}"?`,
                default: true
            }
        ]);
        if (!confirm) {
            console.log(chalk.gray('Invitation not accepted.'));
            return;
        }
        // Accept the invitation
        const response = await fetch(`${config.apiUrl}/api/team-invitations/${invitationId}/accept`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            console.log(chalk.green(`✅ Successfully joined team: ${invitation.teamName}`));
            console.log(chalk.gray(`Your role: ${invitation.role}`));
            console.log(chalk.gray('You can now switch to this team: keyvault team switch <team-name>'));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to accept invitation: ${error}`));
    }
});
teamCommand
    .command('decline <invitationId>')
    .description('Decline a team invitation')
    .action(async (invitationId) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        // First get invitation details
        const inviteResponse = await fetch(`${config.apiUrl}/api/user/invitations`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (!inviteResponse.ok) {
            console.log(chalk.red('❌ Failed to fetch invitations'));
            return;
        }
        const inviteData = await inviteResponse.json();
        const invitations = inviteData.invitations || [];
        const invitation = invitations.find((inv) => inv.id === invitationId);
        if (!invitation) {
            console.log(chalk.red(`❌ Invitation ${invitationId} not found`));
            console.log(chalk.gray('Use "keyvault team invitations" to see pending invitations'));
            return;
        }
        if (invitation.status !== 'pending') {
            console.log(chalk.yellow(`⚠️  Invitation already ${invitation.status}`));
            return;
        }
        // Show invitation details and confirm
        console.log(chalk.blue('📋 Team Invitation Details:'));
        console.log(`   ${chalk.white('Team:')} ${invitation.teamName}`);
        console.log(`   ${chalk.white('From:')} ${invitation.inviterEmail}`);
        console.log('');
        const { confirm } = await inquirer.prompt([
            {
                type: 'confirm',
                name: 'confirm',
                message: `Decline invitation to join "${invitation.teamName}"?`,
                default: false
            }
        ]);
        if (!confirm) {
            console.log(chalk.gray('Invitation not declined.'));
            return;
        }
        // Decline the invitation
        const response = await fetch(`${config.apiUrl}/api/team-invitations/${invitationId}/decline`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            console.log(chalk.yellow(`📋 Declined invitation to: ${invitation.teamName}`));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to decline invitation: ${error}`));
    }
});
// Key management commands
const keyCommand = program
    .command('key')
    .description('API key management commands');
keyCommand
    .command('add')
    .description('Add a new API key (uses active team if available)')
    .option('-n, --name <name>', 'Key name')
    .option('-s, --service <service>', 'Service name')
    .option('-v, --value <value>', 'Key value')
    .option('-t, --team <teamId>', 'Team ID (optional)')
    .action(async (options) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    let keyData = {};
    // Determine team context - use provided team, or ask user to choose
    let targetTeamId;
    if (options.team !== undefined) {
        // Team explicitly specified (including empty string for personal)
        targetTeamId = options.team || undefined;
    }
    else {
        // No team specified - check if user has encryption keys to determine options
        const personalKeys = await CLIAuth.getPersonalKeys();
        const teamKeysAll = await CLIAuth.getTeamKeys();
        const teamNames = teamKeysAll ? Object.keys(teamKeysAll) : [];
        if (!personalKeys && teamNames.length === 0) {
            console.log(chalk.red('❌ No encryption keys found. Run "keyvault init personal" or "keyvault init team <n>" first.'));
            return;
        }
        let choices = [];
        // Add personal option if available
        if (personalKeys) {
            choices.push({
                name: '👤 Personal Key - Just for you',
                value: 'personal'
            });
        }
        // Add team options if available
        if (teamNames.length > 0) {
            for (const teamName of teamNames) {
                choices.push({
                    name: `🏢 Team: ${teamName} - Shared with team members`,
                    value: teamName
                });
            }
        }
        if (choices.length === 1) {
            // Only one option available
            const choice = choices[0];
            if (choice.value === 'personal') {
                targetTeamId = undefined;
                console.log(chalk.cyan('🔐 Using personal encryption (only option available)'));
            }
            else {
                targetTeamId = choice.value; // This is the team name
                console.log(chalk.cyan(`🔐 Using team encryption for "${choice.value}" (only option available)`));
            }
        }
        else {
            // Multiple options - let user choose
            const { keyType } = await inquirer.prompt([
                {
                    type: 'list',
                    name: 'keyType',
                    message: 'Where do you want to store this API key?',
                    choices: choices
                }
            ]);
            if (keyType === 'personal') {
                targetTeamId = undefined;
            }
            else {
                targetTeamId = keyType; // This is the team name
            }
        }
    }
    // Show context info
    if (targetTeamId) {
        if (options.team) {
            console.log(chalk.cyan(`🔗 Creating team key for: ${targetTeamId}`));
        }
        else {
            console.log(chalk.cyan(`🔗 Creating team key for: ${targetTeamId}`));
        }
    }
    else if (options.team === "") {
        console.log(chalk.cyan('👤 Creating personal key (team context overridden)'));
    }
    else {
        console.log(chalk.cyan('👤 Creating personal key'));
    }
    // Interactive prompts for missing options
    if (!options.name || !options.service || !options.value) {
        const answers = await inquirer.prompt([
            {
                type: 'input',
                name: 'name',
                message: 'Key name:',
                default: options.name,
                when: !options.name,
                validate: (input) => {
                    if (!input || input.trim().length === 0) {
                        return 'Key name is required';
                    }
                    if (input.includes(' ')) {
                        return 'Key name cannot contain spaces. Use hyphens or underscores instead.';
                    }
                    if (input.length > 50) {
                        return 'Key name must be 50 characters or less';
                    }
                    return true;
                }
            },
            {
                type: 'input',
                name: 'service',
                message: 'Service name:',
                default: options.service,
                when: !options.service,
                validate: (input) => input.trim().length > 0 || 'Service name is required'
            },
            {
                type: 'password',
                name: 'value',
                message: 'Key value:',
                default: options.value,
                when: !options.value,
                mask: '*',
                validate: (input) => input.trim().length > 0 || 'Key value is required'
            }
        ]);
        keyData = {
            name: options.name || answers.name,
            service: options.service || answers.service,
            value: options.value || answers.value,
            teamId: targetTeamId
        };
    }
    else {
        keyData = {
            name: options.name,
            service: options.service,
            value: options.value,
            teamId: targetTeamId
        };
    }
    try {
        // Encrypt the key value on client side before sending
        const personalKeys = await CLIAuth.getPersonalKeys();
        const teamKeysAll = await CLIAuth.getTeamKeys();
        if (!personalKeys && !teamKeysAll) {
            console.log(chalk.red('❌ No encryption keys found. Run "keyvault init personal" or "keyvault init team <n>" first.'));
            return;
        }
        const { KeyVaultCrypto } = await import('./crypto.js');
        let encryptionKey;
        let encryptionType;
        let actualTeamId; // For server storage
        if (targetTeamId) {
            // Team key - targetTeamId is the team name
            const teamName = targetTeamId;
            // Check if team keys exist
            const teamKeys = await CLIAuth.getTeamKeys(teamName);
            if (teamKeys) {
                encryptionKey = teamKeys.publicKey;
                encryptionType = `team "${teamName}"`;
                console.log(chalk.blue(`🔐 Using team encryption key for "${teamName}"`));
                // Get actual team ID from server for storage
                try {
                    const fetch = (await import('node-fetch')).default;
                    const teamsResponse = await fetch(`${config.apiUrl}/api/teams`, {
                        headers: {
                            'Authorization': `Bearer ${config.token}`
                        }
                    });
                    if (teamsResponse.ok) {
                        const teamsData = await teamsResponse.json();
                        const teams = teamsData.teams || teamsData;
                        const team = teams.find((t) => t.name === teamName);
                        if (team) {
                            actualTeamId = team.id;
                        }
                        else {
                            console.log(chalk.red(`❌ Team "${teamName}" not found on server. Please ensure you're a member of this team.`));
                            return;
                        }
                    }
                    else {
                        console.log(chalk.red('❌ Failed to fetch team information from server.'));
                        return;
                    }
                }
                catch (teamError) {
                    console.log(chalk.red('❌ Failed to fetch team information from server.'));
                    return;
                }
            }
            else {
                console.log(chalk.red(`❌ No team encryption keys found for "${teamName}". Run "keyvault init team ${teamName}" first.`));
                return;
            }
        }
        else {
            // Personal key
            if (personalKeys) {
                encryptionKey = personalKeys.publicKey;
                encryptionType = 'personal';
                console.log(chalk.blue('🔐 Using personal encryption key'));
                actualTeamId = undefined;
            }
            else {
                console.log(chalk.red('❌ No personal encryption keys found. Run "keyvault init personal" first.'));
                return;
            }
        }
        // Encrypt the key value with appropriate encryption key
        const encryptedValue = KeyVaultCrypto.encrypt(keyData.value, encryptionKey);
        // Send encrypted data to server
        const encryptedKeyData = {
            name: keyData.name,
            service: keyData.service,
            encryptedValue: encryptedValue, // Send encrypted value instead of plain text
            teamId: actualTeamId // Use actual team ID from server, not team name
        };
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/keys`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.token}`
            },
            body: JSON.stringify(encryptedKeyData)
        });
        if (response.ok) {
            const data = await response.json();
            console.log(chalk.green(`✅ API key "${keyData.name}" added successfully`));
            console.log(chalk.gray(`Key ID: ${data.key.id}`));
            console.log(chalk.gray(`Service: ${keyData.service}`));
            if (actualTeamId) {
                console.log(chalk.gray(`Team: ${targetTeamId} (ID: ${actualTeamId})`));
            }
            else {
                console.log(chalk.gray('Type: Personal'));
            }
            console.log(chalk.green(`🔒 Key encrypted with ${encryptionType} key and stored securely`));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to add key: ${error}`));
    }
});
keyCommand
    .command('list')
    .alias('ls')
    .description('List your personal API keys')
    .action(async () => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/keys`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            const data = await response.json();
            const allKeys = data.keys || data;
            // Filter to only personal keys (exclude team keys)
            const keys = allKeys.filter((key) => !key.teamId);
            if (keys.length === 0) {
                console.log(chalk.yellow('🔑 No personal API keys found. Add one with: keyvault key add'));
            }
            else {
                console.log(chalk.blue('🔑 Your Personal API Keys:'));
                keys.forEach((key, index) => {
                    console.log(chalk.white(`${index + 1}. ${key.name}`));
                    console.log(chalk.gray(`   Service: ${key.service}`));
                    console.log(chalk.gray(`   ID: ${key.id}`));
                    console.log(chalk.gray(`   Created: ${new Date(key.createdAt).toLocaleDateString()}`));
                    if (key.lastUsed) {
                        console.log(chalk.gray(`   Last Used: ${new Date(key.lastUsed).toLocaleDateString()}`));
                    }
                    console.log('');
                });
            }
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to fetch keys: ${error}`));
    }
});
keyCommand
    .command('list-team [teamId]')
    .alias('lst')
    .description('List team API keys (uses active team if no ID provided)')
    .action(async (teamId) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    // Use provided teamId or fall back to active team
    const targetTeamId = teamId || config.activeTeamId;
    if (!targetTeamId) {
        console.log(chalk.red('❌ No team specified and no active team selected.'));
        console.log(chalk.gray('Options:'));
        console.log(chalk.gray('   1. Specify team ID: keyvault key list-team <team-id>'));
        console.log(chalk.gray('   2. Switch to a team: keyvault team switch <team-id>'));
        console.log(chalk.gray('   3. List your teams: keyvault team list'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        // Get team name for display
        const teamResponse = await fetch(`${config.apiUrl}/api/teams/${targetTeamId}`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        let teamName = 'Unknown Team';
        if (teamResponse.ok) {
            const teamData = await teamResponse.json();
            const team = teamData.team || teamData;
            teamName = team.name;
        }
        const response = await fetch(`${config.apiUrl}/api/teams/${targetTeamId}/keys`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            const data = await response.json();
            const keys = data.keys || data;
            if (keys.length === 0) {
                console.log(chalk.yellow(`🔑 No team API keys found for "${teamName}"`));
                console.log(chalk.gray('Add team keys through the web interface or create keys with teamId'));
            }
            else {
                console.log(chalk.blue(`🔑 Team "${teamName}" API Keys:`));
                keys.forEach((key, index) => {
                    console.log(chalk.white(`${index + 1}. ${key.name}`));
                    console.log(chalk.gray(`   Service: ${key.service}`));
                    console.log(chalk.gray(`   ID: ${key.id}`));
                    console.log(chalk.gray(`   Created: ${new Date(key.createdAt).toLocaleDateString()}`));
                    if (key.lastUsed) {
                        console.log(chalk.gray(`   Last Used: ${new Date(key.lastUsed).toLocaleDateString()}`));
                    }
                    console.log('');
                });
            }
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to fetch team keys: ${error}`));
    }
});
keyCommand
    .command('list-all')
    .alias('la')
    .description('List both personal and team keys')
    .action(async () => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        console.log(chalk.blue('🔑 All Your API Keys:'));
        console.log('');
        // Personal keys
        const personalResponse = await fetch(`${config.apiUrl}/api/keys`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (personalResponse.ok) {
            const personalData = await personalResponse.json();
            const allPersonalKeys = personalData.keys || personalData;
            // Filter to only personal keys (exclude team keys)
            const personalKeys = allPersonalKeys.filter((key) => !key.teamId);
            console.log(chalk.cyan('📝 Personal Keys:'));
            if (personalKeys.length === 0) {
                console.log(chalk.gray('   No personal keys found'));
            }
            else {
                personalKeys.forEach((key, index) => {
                    console.log(chalk.white(`   ${index + 1}. ${key.name}`));
                    console.log(chalk.gray(`      Service: ${key.service}`));
                    console.log(chalk.gray(`      ID: ${key.id}`));
                    console.log('');
                });
            }
        }
        // Team keys (get all teams first)
        const teamsResponse = await fetch(`${config.apiUrl}/api/teams`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (teamsResponse.ok) {
            const teamsData = await teamsResponse.json();
            const teams = teamsData.teams || teamsData;
            for (const team of teams) {
                const teamKeysResponse = await fetch(`${config.apiUrl}/api/teams/${team.id}/keys`, {
                    headers: {
                        'Authorization': `Bearer ${config.token}`
                    }
                });
                if (teamKeysResponse.ok) {
                    const teamKeysData = await teamKeysResponse.json();
                    const teamKeys = teamKeysData.keys || teamKeysData;
                    console.log(chalk.cyan(`👥 Team "${team.name}" Keys:`));
                    if (teamKeys.length === 0) {
                        console.log(chalk.gray('   No team keys found'));
                    }
                    else {
                        teamKeys.forEach((key, index) => {
                            console.log(chalk.white(`   ${index + 1}. ${key.name}`));
                            console.log(chalk.gray(`      Service: ${key.service}`));
                            console.log(chalk.gray(`      ID: ${key.id}`));
                            console.log('');
                        });
                    }
                }
            }
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to fetch keys: ${error}`));
    }
});
keyCommand
    .command('get [keyIdentifier]')
    .description('Get API key value (by ID or name)')
    .option('-n, --name <name>', 'Key name to get')
    .option('-t, --team', 'Get from team keys')
    .option('-p, --personal', 'Get from personal keys')
    .action(async (keyIdentifier, options) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        let keyName = keyIdentifier || options.name;
        // Check conflicting flags
        if (options.team && options.personal) {
            console.log(chalk.red('❌ Cannot use both --team and --personal flags together'));
            return;
        }
        let targetKey;
        if (!keyName) {
            // Get personal keys
            const personalResponse = await fetch(`${config.apiUrl}/api/keys`, {
                headers: {
                    'Authorization': `Bearer ${config.token}`
                }
            });
            let personalKeys = [];
            if (personalResponse.ok) {
                const personalData = await personalResponse.json();
                const allKeys = personalData.keys || personalData;
                // Filter to only personal keys (exclude team keys)
                personalKeys = allKeys.filter((key) => !key.teamId);
            }
            // Get team keys
            let teamKeys = [];
            const teamsResponse = await fetch(`${config.apiUrl}/api/teams`, {
                headers: {
                    'Authorization': `Bearer ${config.token}`
                }
            });
            if (teamsResponse.ok) {
                const teamsData = await teamsResponse.json();
                const teams = teamsData.teams || teamsData;
                for (const team of teams) {
                    const teamKeysResponse = await fetch(`${config.apiUrl}/api/teams/${team.id}/keys`, {
                        headers: {
                            'Authorization': `Bearer ${config.token}`
                        }
                    });
                    if (teamKeysResponse.ok) {
                        const teamKeysData = await teamKeysResponse.json();
                        const keys = teamKeysData.keys || teamKeysData;
                        keys.forEach((key) => {
                            teamKeys.push({
                                ...key,
                                teamName: team.name,
                                teamId: team.id
                            });
                        });
                    }
                }
            }
            // Filter based on flags
            let availableKeys = [];
            if (options.personal) {
                availableKeys = personalKeys.map((key) => ({
                    ...key,
                    displayName: `👤 ${key.name} (${key.service})`,
                    type: 'personal'
                }));
            }
            else if (options.team) {
                availableKeys = teamKeys.map((key) => ({
                    ...key,
                    displayName: `🏢 [${key.teamName}] ${key.name} (${key.service})`,
                    type: 'team'
                }));
            }
            else {
                // Show both with clear separation
                availableKeys = [
                    ...personalKeys.map((key) => ({
                        ...key,
                        displayName: `👤 ${key.name} (${key.service})`,
                        type: 'personal'
                    })),
                    ...teamKeys.map((key) => ({
                        ...key,
                        displayName: `🏢 [${key.teamName}] ${key.name} (${key.service})`,
                        type: 'team'
                    }))
                ];
            }
            if (availableKeys.length === 0) {
                console.log(chalk.yellow('🔑 No keys found'));
                return;
            }
            const { selectedKey } = await inquirer.prompt([
                {
                    type: 'list',
                    name: 'selectedKey',
                    message: 'Select a key to retrieve:',
                    choices: availableKeys.map((key) => ({
                        name: key.displayName,
                        value: key
                    }))
                }
            ]);
            // Use the selected key directly instead of searching again
            targetKey = selectedKey;
        }
        else {
            // User provided key name, need to search for it
            // Find the key from all available keys
            const personalResponse = await fetch(`${config.apiUrl}/api/keys`, {
                headers: {
                    'Authorization': `Bearer ${config.token}`
                }
            });
            let allKeys = [];
            if (personalResponse.ok) {
                const personalData = await personalResponse.json();
                const personalKeys = personalData.keys || personalData;
                allKeys = personalKeys.filter((key) => !key.teamId); // Personal keys only
            }
            // Get team keys as well
            const teamsResponse = await fetch(`${config.apiUrl}/api/teams`, {
                headers: {
                    'Authorization': `Bearer ${config.token}`
                }
            });
            if (teamsResponse.ok) {
                const teamsData = await teamsResponse.json();
                const teams = teamsData.teams || teamsData;
                for (const team of teams) {
                    const teamKeysResponse = await fetch(`${config.apiUrl}/api/teams/${team.id}/keys`, {
                        headers: {
                            'Authorization': `Bearer ${config.token}`
                        }
                    });
                    if (teamKeysResponse.ok) {
                        const teamKeysData = await teamKeysResponse.json();
                        const keys = teamKeysData.keys || teamKeysData;
                        keys.forEach((key) => {
                            allKeys.push({
                                ...key,
                                teamName: team.name,
                                teamId: team.id
                            });
                        });
                    }
                }
            }
            targetKey = allKeys.find((key) => key.name === keyName || key.id === keyName);
        }
        if (!targetKey) {
            console.log(chalk.red(`❌ Key "${keyName}" not found`));
            return;
        }
        // Check flag constraints
        if (options.personal && targetKey.teamId) {
            console.log(chalk.red(`❌ Key "${keyName}" is a team key, not personal. Use --team flag or remove --personal flag.`));
            return;
        }
        if (options.team && !targetKey.teamId) {
            console.log(chalk.red(`❌ Key "${keyName}" is a personal key, not team. Use --personal flag or remove --team flag.`));
            return;
        }
        // Get the key details
        const response = await fetch(`${config.apiUrl}/api/keys/${targetKey.id}`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            const data = await response.json();
            console.log(chalk.blue(`🔑 Key: ${data.name}`));
            console.log(chalk.gray(`Service: ${data.service}`));
            // Check if we have client-side encryption data or old system
            if (data.encryptedValue) {
                // New system: Decrypt on client-side
                try {
                    // Load keys for decryption from ~/.keyvault/config.json
                    const personalKeys = await CLIAuth.getPersonalKeys();
                    const teamKeysAll = await CLIAuth.getTeamKeys();
                    if (!personalKeys && !teamKeysAll) {
                        console.log(chalk.red('❌ No encryption keys found. Run "keyvault init personal" or "keyvault init team <n>" first.'));
                        return;
                    }
                    const { KeyVaultCrypto } = await import('./crypto.js');
                    let decryptionKey;
                    let decryptionType = 'unknown';
                    // Determine if this is a team key or personal key
                    // Use targetKey.teamId (from selection) instead of data.teamId (from API response)
                    if (targetKey.teamId) {
                        // This is a team key - find the team name first
                        const teamName = targetKey.teamName;
                        const teamKeys = await CLIAuth.getTeamKeys(teamName);
                        if (teamKeys) {
                            decryptionKey = teamKeys.privateKey;
                            decryptionType = `team "${teamName}"`;
                            console.log(chalk.blue(`🔓 Decrypting with team key for "${teamName}"`));
                        }
                        else {
                            console.log(chalk.red(`❌ No team decryption keys found for "${teamName}". Run "keyvault init team ${teamName}" first.`));
                            console.log(chalk.gray('Note: You need the team passphrase to decrypt team keys.'));
                            return;
                        }
                    }
                    else {
                        // This is a personal key
                        if (personalKeys) {
                            decryptionKey = personalKeys.privateKey;
                            decryptionType = 'personal';
                            console.log(chalk.blue('🔓 Decrypting with personal key'));
                        }
                        else {
                            console.log(chalk.red('❌ No personal decryption keys found. Run "keyvault init personal" first.'));
                            console.log(chalk.gray('Note: Legacy key format detected. Please regenerate with "keyvault init personal"'));
                            return;
                        }
                    }
                    // Decrypt using appropriate private key
                    const decryptedValue = KeyVaultCrypto.decrypt(data.encryptedValue, decryptionKey);
                    console.log(chalk.yellow(`Value: ${decryptedValue}`));
                    console.log(chalk.gray(`Decrypted with: ${decryptionType} key`));
                }
                catch (decryptError) {
                    console.log(chalk.red('❌ Failed to decrypt key. Wrong private key or corrupted data.'));
                    console.log(chalk.gray('Make sure you have the correct encryption keys for this key type.'));
                }
            }
            else if (data.value) {
                // Old system: Already decrypted by server
                console.log(chalk.yellow(`Value: ${data.value}`));
                console.log(chalk.gray('Decrypted with: server-side (legacy)'));
            }
            else {
                console.log(chalk.red('❌ No value data received from server.'));
            }
            console.log(chalk.gray(`ID: ${data.id}`));
            console.log(chalk.gray(`Created: ${new Date(data.createdAt).toLocaleDateString()}`));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to get key: ${error}`));
    }
});
keyCommand
    .command('delete <keyIdentifier>')
    .description('Delete an API key (by ID or name)')
    .action(async (keyIdentifier) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        // First, get all keys to find by name if needed
        const listResponse = await fetch(`${config.apiUrl}/api/keys`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (!listResponse.ok) {
            console.log(chalk.red('❌ Failed to fetch keys'));
            return;
        }
        const listData = await listResponse.json();
        const keys = listData.keys || listData;
        // Try to find key by name first, then by ID
        let targetKey = keys.find((key) => key.name === keyIdentifier);
        if (!targetKey) {
            targetKey = keys.find((key) => key.id === keyIdentifier);
        }
        if (!targetKey) {
            console.log(chalk.red(`❌ Key "${keyIdentifier}" not found`));
            console.log(chalk.gray('Available keys:'));
            keys.forEach((key, index) => {
                console.log(chalk.gray(`  ${index + 1}. ${key.name} (${key.id})`));
            });
            return;
        }
        // Show key info and confirm deletion
        console.log(chalk.yellow(`About to delete key: ${targetKey.name} (${targetKey.service})`));
        const { confirm } = await inquirer.prompt([
            {
                type: 'confirm',
                name: 'confirm',
                message: 'Are you sure you want to delete this API key?',
                default: false
            }
        ]);
        if (!confirm) {
            console.log(chalk.gray('Deletion cancelled.'));
            return;
        }
        const response = await fetch(`${config.apiUrl}/api/keys/${targetKey.id}`, {
            method: 'DELETE',
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            console.log(chalk.green(`✅ API key "${targetKey.name}" deleted successfully`));
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to delete key: ${error}`));
    }
});
// Endpoint management commands
const endpointCommand = program
    .command('endpoint')
    .description('API endpoint management commands');
endpointCommand
    .command('add')
    .description('Add a new API endpoint')
    .option('-n, --name <name>', 'Endpoint name')
    .option('-u, --url <url>', 'Endpoint URL')
    .option('-m, --method <method>', 'HTTP method', 'GET')
    .option('-d, --description <description>', 'Endpoint description')
    .option('-t, --team <teamId>', 'Team ID (optional)')
    .action(async (options) => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    let endpointData = {};
    // Interactive prompts for missing options
    if (!options.name || !options.url) {
        const answers = await inquirer.prompt([
            {
                type: 'input',
                name: 'name',
                message: 'Endpoint name:',
                default: options.name,
                when: !options.name,
                validate: (input) => input.trim().length > 0 || 'Endpoint name is required'
            },
            {
                type: 'input',
                name: 'url',
                message: 'Endpoint URL:',
                default: options.url,
                when: !options.url,
                validate: (input) => input.trim().length > 0 || 'Endpoint URL is required'
            },
            {
                type: 'list',
                name: 'method',
                message: 'HTTP method:',
                choices: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
                default: options.method || 'GET',
                when: !options.method
            },
            {
                type: 'input',
                name: 'description',
                message: 'Description (optional):',
                default: options.description || '',
                when: !options.description
            },
            {
                type: 'input',
                name: 'team',
                message: 'Team ID (optional, press enter to skip):',
                default: options.team || '',
                when: !options.team
            }
        ]);
        endpointData = {
            name: options.name || answers.name,
            url: options.url || answers.url,
            method: options.method || answers.method,
            description: options.description || answers.description || undefined,
            teamId: options.team || answers.team || undefined
        };
    }
    else {
        endpointData = {
            name: options.name,
            url: options.url,
            method: options.method || 'GET',
            description: options.description || undefined,
            teamId: options.team || undefined
        };
    }
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/endpoints`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.token}`
            },
            body: JSON.stringify(endpointData)
        });
        if (response.ok) {
            const data = await response.json();
            console.log(chalk.green(`✅ Endpoint "${endpointData.name}" added successfully`));
            console.log(chalk.gray(`Endpoint ID: ${data.id}`));
            console.log(chalk.gray(`URL: ${data.url}`));
            console.log(chalk.gray(`Method: ${data.method}`));
            if (data.teamId) {
                console.log(chalk.gray(`Team: ${data.teamId}`));
            }
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to add endpoint: ${error}`));
    }
});
endpointCommand
    .command('list')
    .alias('ls')
    .description('List your API endpoints')
    .action(async () => {
    const config = await CLIAuth.getConfig();
    if (!config?.token) {
        console.log(chalk.red('❌ Please login first: keyvault login'));
        return;
    }
    try {
        const fetch = (await import('node-fetch')).default;
        const response = await fetch(`${config.apiUrl}/api/endpoints`, {
            headers: {
                'Authorization': `Bearer ${config.token}`
            }
        });
        if (response.ok) {
            const data = await response.json();
            const endpoints = data.endpoints || data;
            if (endpoints.length === 0) {
                console.log(chalk.yellow('🌐 No endpoints found. Add one with: keyvault endpoint add'));
            }
            else {
                console.log(chalk.blue('🌐 Your API Endpoints:'));
                endpoints.forEach((endpoint, index) => {
                    console.log(chalk.white(`${index + 1}. ${endpoint.name}`));
                    console.log(chalk.gray(`   URL: ${endpoint.url}`));
                    console.log(chalk.gray(`   Method: ${endpoint.method}`));
                    console.log(chalk.gray(`   ID: ${endpoint.id}`));
                    if (endpoint.description) {
                        console.log(chalk.gray(`   Description: ${endpoint.description}`));
                    }
                    console.log(chalk.gray(`   Created: ${new Date(endpoint.createdAt).toLocaleDateString()}`));
                    console.log('');
                });
            }
        }
        else {
            const error = await response.json();
            console.log(chalk.red(`❌ Error: ${error.error}`));
        }
    }
    catch (error) {
        console.log(chalk.red(`❌ Failed to fetch endpoints: ${error}`));
    }
});
// Upgrade command
program
    .command('upgrade')
    .description('Check for and install latest version of KeyVault CLI')
    .option('--check-only', 'Only check for updates without installing')
    .action(async (options) => {
    console.log(chalk.blue('🔄 Checking for KeyVault CLI updates...'));
    try {
        const fetch = (await import('node-fetch')).default;
        const { spawn } = await import('child_process');
        // Get current version from package.json
        const __filename = fileURLToPath(import.meta.url);
        const __dirname = path.dirname(__filename);
        const packageJsonPath = path.join(__dirname, '..', 'package.json');
        const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf8'));
        const currentVersion = packageJson.version;
        // Check NPM registry for latest version
        const response = await fetch('https://registry.npmjs.org/keyvault-cli/latest');
        if (!response.ok) {
            console.log(chalk.red('❌ Failed to check for updates. Please try again later.'));
            return;
        }
        const packageInfo = await response.json();
        const latestVersion = packageInfo.version;
        console.log(chalk.gray(`Current version: ${currentVersion}`));
        console.log(chalk.gray(`Latest version: ${latestVersion}`));
        // Simple version comparison (assuming semantic versioning)
        const parseVersion = (version) => {
            return version.split('.').map(Number);
        };
        const currentParts = parseVersion(currentVersion);
        const latestParts = parseVersion(latestVersion);
        let isNewer = false;
        for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
            const current = currentParts[i] || 0;
            const latest = latestParts[i] || 0;
            if (latest > current) {
                isNewer = true;
                break;
            }
            else if (latest < current) {
                break;
            }
        }
        if (!isNewer) {
            console.log(chalk.green('✅ You are already using the latest version!'));
            return;
        }
        console.log(chalk.yellow(`📦 New version available: ${latestVersion}`));
        if (options.checkOnly) {
            console.log(chalk.gray('Run "keyvault upgrade" to install the latest version.'));
            return;
        }
        // Ask user for confirmation
        const { confirm } = await inquirer.prompt([
            {
                type: 'confirm',
                name: 'confirm',
                message: `Do you want to upgrade to version ${latestVersion}?`,
                default: true
            }
        ]);
        if (!confirm) {
            console.log(chalk.gray('Upgrade cancelled.'));
            return;
        }
        console.log(chalk.blue('📦 Installing latest version...'));
        console.log(chalk.gray('This may take a moment...'));
        // Install latest version
        const installProcess = spawn('npm', ['install', '-g', 'keyvault-cli@latest'], {
            stdio: 'inherit',
            shell: true
        });
        installProcess.on('close', (code) => {
            if (code === 0) {
                console.log(chalk.green(`✅ Successfully upgraded to version ${latestVersion}!`));
                console.log(chalk.gray('You may need to restart your terminal for changes to take effect.'));
            }
            else {
                console.log(chalk.red('❌ Upgrade failed. Please try running the command manually:'));
                console.log(chalk.gray('npm install -g keyvault-cli@latest'));
            }
        });
        installProcess.on('error', (error) => {
            console.log(chalk.red('❌ Upgrade failed:'), error.message);
            console.log(chalk.gray('Please try running the command manually:'));
            console.log(chalk.gray('npm install -g keyvault-cli@latest'));
        });
    }
    catch (error) {
        console.log(chalk.red('❌ Failed to check for updates:'), error instanceof Error ? error.message : 'Unknown error');
        console.log(chalk.gray('You can manually update with: npm install -g keyvault-cli@latest'));
    }
});
// Help command enhancement
program.configureHelp({
    sortSubcommands: true,
    subcommandTerm: (cmd) => cmd.name() + ' ' + cmd.usage()
});
// Show help if no command provided
if (!process.argv.slice(2).length) {
    program.outputHelp();
    process.exit(0);
}
// Parse arguments
program.parse();