Skip to content

Commit 823af07

Browse files
author
Lasim
committed
feat(gateway): enhance login and logout commands with spinner feedback and improve console messages
1 parent eca1091 commit 823af07

File tree

4 files changed

+58
-48
lines changed

4 files changed

+58
-48
lines changed

services/gateway/src/commands/login.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ export function registerLoginCommand(program: Command) {
3939
}
4040

4141
// Start OAuth flow
42+
spinner = ora('Processing authorization code...').start();
4243
const authResult = await oauth.authenticate({
4344
openBrowser: options.browser !== false,
44-
timeout: 120000 // 2 minutes
45+
timeout: 120000, // 2 minutes
46+
spinner
4547
});
4648

47-
spinner = ora('Storing credentials securely...').start();
49+
spinner.text = 'Storing credentials securely...';
4850

4951
// Device registration now happens automatically during OAuth2 token exchange
5052
// Store credentials with device context if available from OAuth2 response
@@ -97,16 +99,16 @@ export function registerLoginCommand(program: Command) {
9799
});
98100

99101
if (startResult.success) {
100-
spinner.succeed('Authentication complete - Gateway server is now running');
101-
console.log(chalk.green(`🚀 Gateway server started successfully`));
102+
spinner.succeed('Authentication complete');
103+
console.log(chalk.green(`Gateway server started successfully`));
102104
console.log(chalk.blue(` • Server URL: http://localhost:9095`));
103105
console.log(chalk.blue(` • SSE Endpoint: http://localhost:9095/sse`));
104106
console.log(chalk.blue(` • PID: ${startResult.pid}`));
105107
if (startResult.mcpServersStarted && startResult.mcpServersStarted > 0) {
106108
console.log(chalk.blue(` • MCP Servers: ${startResult.mcpServersStarted} running`));
107109
}
108110
} else {
109-
spinner.succeed('Credentials stored, default team selected, and MCP config downloaded');
111+
spinner.succeed('Authentication complete');
110112
console.log(chalk.yellow('⚠️ Gateway server is already running - you can check status with "deploystack status"'));
111113
if (startResult.pid) {
112114
console.log(chalk.gray(` Running PID: ${startResult.pid}`));
@@ -137,18 +139,14 @@ export function registerLoginCommand(program: Command) {
137139
spinner = null;
138140

139141
console.log(chalk.green(`✅ Successfully authenticated as ${authResult.credentials.userEmail}`));
140-
console.log(chalk.green(`🎉 You can now use the DeployStack Gateway CLI`));
142+
console.log(chalk.green(`You can now use the DeployStack Gateway CLI`));
141143

142144
// Show available commands
143-
console.log(chalk.blue(`\n💡 Available commands:`));
145+
console.log(chalk.blue(`\nAvailable commands:`));
144146
console.log(chalk.gray(` deploystack whoami - Show your user information`));
145147
console.log(chalk.gray(` deploystack teams - List your teams`));
146148
console.log(chalk.gray(` deploystack mcp - Manage MCP server configurations`));
147149
console.log(chalk.gray(` deploystack start - Start the gateway server`));
148-
149-
if (options.url !== 'https://cloud-api.deploystack.io') {
150-
console.log(chalk.yellow(` ⚠️ For MCP changes, visit: ${options.url}`));
151-
}
152150

153151
// Exit successfully
154152
process.exit(0);

services/gateway/src/commands/logout.ts

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,42 +41,39 @@ export function registerLogoutCommand(program: Command) {
4141
spinner.succeed('All credentials and configurations cleared');
4242
console.log(chalk.green('✅ Successfully logged out all users'));
4343
} else {
44-
console.log(chalk.blue(`🔐 Logging out ${userEmail}...`));
45-
spinner = ora('Clearing credentials and MCP configurations...').start();
44+
spinner = ora(`Logging out ${userEmail}...`).start();
4645

4746
// Clear MCP configurations for selected team
4847
const mcpService = new MCPConfigService();
4948
await mcpService.clearMCPConfig();
5049

50+
spinner.text = 'Clearing credentials and configurations...';
5151
await storage.clearCredentials(userEmail);
5252

53-
spinner.succeed('Credentials and configurations cleared');
54-
console.log(chalk.green(`✅ Successfully logged out ${userEmail}`));
55-
}
56-
57-
// Stop the gateway server if it's running
58-
const stopService = new ServerStopService();
59-
if (stopService.isServerRunning()) {
60-
console.log(chalk.blue('🛑 Stopping gateway server...'));
61-
spinner = ora('Stopping gateway server and MCP processes...').start();
53+
spinner.text = 'Stopping gateway server...';
6254

63-
try {
64-
const stopResult = await stopService.stopGatewayServer({ timeout: 15 });
65-
if (stopResult.success && stopResult.wasRunning) {
66-
spinner.succeed('Gateway server stopped');
67-
console.log(chalk.gray('💡 All MCP servers have been stopped along with the gateway'));
68-
} else {
69-
spinner.succeed('Gateway server was not running');
55+
// Stop the gateway server if it's running
56+
const stopService = new ServerStopService();
57+
if (stopService.isServerRunning()) {
58+
try {
59+
const stopResult = await stopService.stopGatewayServer({ timeout: 15 });
60+
if (stopResult.success && stopResult.wasRunning) {
61+
spinner.stop();
62+
console.log('Gateway server stopped - you are successfully logged out');
63+
} else {
64+
spinner.stop();
65+
console.log('You are successfully logged out');
66+
}
67+
} catch (error) {
68+
spinner.warn('Failed to stop gateway server gracefully');
69+
console.log(chalk.yellow(`⚠️ Gateway server may still be running: ${error instanceof Error ? error.message : String(error)}`));
7070
}
71-
} catch (error) {
72-
spinner.warn('Failed to stop gateway server gracefully');
73-
console.log(chalk.yellow(`⚠️ Gateway server may still be running: ${error instanceof Error ? error.message : String(error)}`));
71+
} else {
72+
spinner.stop();
73+
console.log('You are successfully logged out');
7474
}
7575
}
7676

77-
console.log(chalk.gray(`💡 Use 'deploystack login' to authenticate again`));
78-
console.log(chalk.gray(`💡 Use 'deploystack start' to start the gateway server again`));
79-
8077
} catch (error) {
8178
if (spinner) {
8279
spinner.fail('Failed to clear credentials');

services/gateway/src/core/auth/oauth.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fetch from 'node-fetch';
22
import chalk from 'chalk';
3+
import ora from 'ora';
34
import { generateCodeVerifier, generateCodeChallenge, generateState } from '../../utils/pkce';
45
import { buildAuthConfig } from '../../utils/auth-config';
56
import { CallbackServer } from './callback-server';
@@ -32,10 +33,11 @@ export class OAuth2Client {
3233
* @param options Authentication options
3334
* @returns Authentication result with credentials and user info
3435
*/
35-
async authenticate(options: AuthenticationOptions = {}): Promise<AuthenticationResult> {
36+
async authenticate(options: AuthenticationOptions & { spinner?: ReturnType<typeof ora> } = {}): Promise<AuthenticationResult> {
3637
const {
3738
openBrowser = true,
38-
timeout = 120000
39+
timeout = 120000,
40+
spinner
3941
} = options;
4042

4143
// Generate PKCE parameters
@@ -89,22 +91,32 @@ export class OAuth2Client {
8991
);
9092
}
9193

92-
console.log(chalk.green('✅ Authorization code received'));
93-
console.log(chalk.gray('🔄 Exchanging code for tokens...'));
94+
if (spinner) {
95+
spinner.text = 'Processing authorization code...';
96+
} else {
97+
console.log(chalk.green('✅ Authorization code received'));
98+
console.log(chalk.gray('🔄 Exchanging code for tokens...'));
99+
}
94100

95101
// Exchange code for tokens
96102
const tokenResponse = await this.exchangeCodeForTokens({
97103
code: callbackResult.code,
98104
codeVerifier
99-
});
105+
}, spinner);
100106

101-
console.log(chalk.green('✅ Tokens received'));
102-
console.log(chalk.gray('👤 Fetching user information...'));
107+
if (spinner) {
108+
spinner.text = 'Fetching user information...';
109+
} else {
110+
console.log(chalk.green('✅ Tokens received'));
111+
console.log(chalk.gray('👤 Fetching user information...'));
112+
}
103113

104114
// Get user information
105115
const userInfo = await this.getUserInfo(tokenResponse.access_token);
106116

107-
console.log(chalk.green('✅ User information retrieved'));
117+
if (!spinner) {
118+
console.log(chalk.green('✅ User information retrieved'));
119+
}
108120

109121
// Build credentials object
110122
const credentials: StoredCredentials = {
@@ -152,12 +164,13 @@ export class OAuth2Client {
152164
/**
153165
* Exchange authorization code for access and refresh tokens
154166
* @param params Code exchange parameters
167+
* @param spinner Optional spinner for progress updates
155168
* @returns Token response
156169
*/
157170
private async exchangeCodeForTokens(params: {
158171
code: string;
159172
codeVerifier: string;
160-
}): Promise<TokenResponse> {
173+
}, spinner?: ReturnType<typeof ora>): Promise<TokenResponse> {
161174
try {
162175
// Detect device information for automatic registration
163176
const deviceInfo = await detectDeviceInfo();
@@ -199,7 +212,11 @@ export class OAuth2Client {
199212

200213
// Log device registration success if device info is included in response
201214
if (tokenResponse.device) {
202-
console.log(chalk.green(`📱 Device registered: ${tokenResponse.device.device_name}`));
215+
if (spinner) {
216+
spinner.text = 'Registering device...';
217+
} else {
218+
console.log(chalk.green(`📱 Device registered: ${tokenResponse.device.device_name}`));
219+
}
203220
}
204221

205222
return tokenResponse;

services/gateway/src/core/auth/storage.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { keyring } from '@zowe/secrets-for-zowe-sdk';
1+
import { keyring } from '@zowe/secrets-for-zowe-sdk';
22
import { writeFileSync, readFileSync, existsSync, unlinkSync } from 'fs';
33
import { join } from 'path';
44
import { homedir } from 'os';
@@ -34,7 +34,6 @@ export class CredentialStorage {
3434
// Also maintain a list of accounts for retrieval
3535
await this.addToAccountsList(credentials.userEmail);
3636

37-
console.log('✓ Credentials stored in OS keychain');
3837
return; // Success, no need for fallback
3938
} catch (error) {
4039
keychainError = error as Error;
@@ -365,7 +364,6 @@ export class CredentialStorage {
365364
JSON.stringify(config)
366365
);
367366

368-
console.log('✓ MCP config stored in OS keychain');
369367
return; // Success, no need for fallback
370368
} catch (error) {
371369
keychainError = error as Error;

0 commit comments

Comments
 (0)