|
| 1 | +import chalk from 'chalk'; |
| 2 | +import ora from 'ora'; |
| 3 | +import { CredentialStorage } from '../core/auth/storage'; |
| 4 | +import { DeployStackAPI } from '../core/auth/api-client'; |
| 5 | +import { MCPConfigService } from '../core/mcp'; |
| 6 | +import { AuthenticationError } from '../types/auth'; |
| 7 | + |
| 8 | +export interface RefreshOptions { |
| 9 | + url?: string; |
| 10 | +} |
| 11 | + |
| 12 | +export class RefreshService { |
| 13 | + private storage: CredentialStorage; |
| 14 | + private mcpService: MCPConfigService; |
| 15 | + |
| 16 | + constructor() { |
| 17 | + this.storage = new CredentialStorage(); |
| 18 | + this.mcpService = new MCPConfigService(); |
| 19 | + } |
| 20 | + |
| 21 | + /** |
| 22 | + * Refresh MCP server configurations from the cloud control plane |
| 23 | + * @param options Refresh options including optional backend URL override |
| 24 | + */ |
| 25 | + async refreshMCPConfiguration(options: RefreshOptions = {}): Promise<void> { |
| 26 | + let spinner: ReturnType<typeof ora> | null = null; |
| 27 | + |
| 28 | + try { |
| 29 | + // Check authentication |
| 30 | + if (!await this.storage.isAuthenticated()) { |
| 31 | + console.log(chalk.red('❌ Not authenticated')); |
| 32 | + console.log(chalk.gray(`💡 Run 'deploystack login' to authenticate`)); |
| 33 | + process.exit(1); |
| 34 | + } |
| 35 | + |
| 36 | + const credentials = await this.storage.getCredentials(); |
| 37 | + if (!credentials) { |
| 38 | + console.log(chalk.red('❌ No stored credentials found')); |
| 39 | + console.log(chalk.gray(`💡 Run 'deploystack login' to authenticate`)); |
| 40 | + process.exit(1); |
| 41 | + } |
| 42 | + |
| 43 | + // Check if team is selected |
| 44 | + if (!credentials.selectedTeam) { |
| 45 | + console.log(chalk.red('❌ No team selected')); |
| 46 | + console.log(chalk.gray(`💡 Run 'deploystack teams --switch <team-number>' to select a team`)); |
| 47 | + process.exit(1); |
| 48 | + } |
| 49 | + |
| 50 | + const backendUrl = options.url || credentials.baseUrl || 'https://cloud.deploystack.io'; |
| 51 | + const api = new DeployStackAPI(credentials, backendUrl); |
| 52 | + |
| 53 | + console.log(chalk.blue(`🔄 Refreshing MCP configuration for team: ${chalk.cyan(credentials.selectedTeam.name)}`)); |
| 54 | + spinner = ora('Downloading latest MCP configuration...').start(); |
| 55 | + |
| 56 | + try { |
| 57 | + const config = await this.mcpService.downloadAndStoreMCPConfig( |
| 58 | + credentials.selectedTeam.id, |
| 59 | + credentials.selectedTeam.name, |
| 60 | + api, |
| 61 | + false |
| 62 | + ); |
| 63 | + |
| 64 | + spinner.succeed(`MCP configuration refreshed (${config.servers.length} server${config.servers.length === 1 ? '' : 's'})`); |
| 65 | + console.log(chalk.green('✅ MCP configuration has been refreshed')); |
| 66 | + |
| 67 | + // Show summary |
| 68 | + console.log(chalk.gray(`\n📊 Configuration Summary:`)); |
| 69 | + console.log(chalk.gray(` Team: ${config.team_name}`)); |
| 70 | + console.log(chalk.gray(` Installations: ${config.installations.length}`)); |
| 71 | + console.log(chalk.gray(` Servers: ${config.servers.length}`)); |
| 72 | + console.log(chalk.gray(` Last Updated: ${new Date(config.last_updated).toLocaleString()}`)); |
| 73 | + |
| 74 | + } catch (error) { |
| 75 | + spinner.fail('Failed to refresh MCP configuration'); |
| 76 | + throw error; |
| 77 | + } |
| 78 | + |
| 79 | + } catch (error) { |
| 80 | + if (spinner) { |
| 81 | + spinner.fail('MCP refresh operation failed'); |
| 82 | + } |
| 83 | + |
| 84 | + if (error instanceof AuthenticationError) { |
| 85 | + console.log(chalk.red(`❌ Failed to refresh MCP configuration: ${error.message}`)); |
| 86 | + |
| 87 | + if (error.code === 'TOKEN_EXPIRED') { |
| 88 | + console.log(chalk.gray(`💡 Run 'deploystack login' to refresh your authentication`)); |
| 89 | + } else if (error.code === 'NETWORK_ERROR') { |
| 90 | + console.log(chalk.gray('💡 Check your internet connection and try again')); |
| 91 | + } |
| 92 | + } else { |
| 93 | + console.log(chalk.red(`❌ Unexpected error: ${error instanceof Error ? error.message : String(error)}`)); |
| 94 | + } |
| 95 | + |
| 96 | + process.exit(1); |
| 97 | + } |
| 98 | + } |
| 99 | +} |
0 commit comments