UNPKG

veas

Version:

Veas CLI - Command-line interface for Veas platform

223 lines 8.14 kB
import { password, select, spinner, text } from '@clack/prompts'; import pc from 'picocolors'; import { AuthManager } from '../auth/auth-manager.js'; import { OAuthDeviceFlow } from '../auth/device-flow.js'; import { logger } from '../utils/logger.js'; export async function login(options) { logger.info(pc.cyan('Login to Veas')); const authManager = AuthManager.getInstance(); let method = options?.method; if (!method) { const selected = await select({ message: 'How would you like to authenticate?', options: [ { value: 'web', label: 'Web browser (recommended)', hint: 'Opens browser for secure authentication' }, { value: 'password', label: 'Email & password', hint: 'Traditional login' }, { value: 'token', label: 'Personal access token', hint: 'Use existing token' }, ], }); if (typeof selected === 'symbol') { logger.info(pc.red('Login cancelled')); process.exit(0); } method = selected; } try { switch (method) { case 'web': await loginWithWeb(authManager); break; case 'token': await loginWithToken(authManager); break; default: await loginWithPassword(authManager); break; } } catch (error) { logger.error(error.message); process.exit(1); } } async function loginWithWeb(authManager) { const deviceFlow = new OAuthDeviceFlow(); try { logger.debug('[Login] Starting web authentication flow...'); const tokenResponse = await deviceFlow.authenticate(); logger.debugSensitive('[Login] Token response received:', { has_access_token: !!tokenResponse.access_token, has_refresh_token: !!tokenResponse.refresh_token, token_type: tokenResponse.token_type, }); logger.debug('[Login] Calling loginWithDevice with token response...'); const { user } = await authManager.loginWithDeviceCode(tokenResponse); logger.debug('[Login] Login successful!'); const extendedUser = user; const displayName = extendedUser.first_name && extendedUser.last_name ? `${extendedUser.first_name} ${extendedUser.last_name}` : extendedUser.username || user.email || user.id; logger.info(`Logged in as ${pc.green(displayName)}`); logger.info(pc.dim('Authentication credentials saved securely')); const session = await authManager.getSession(); if (session?.patToken) { logger.info(''); logger.info(pc.cyan('✨ Personal Access Token created for MCP integration')); logger.info(pc.dim('Your CLI can now communicate with MCP-enabled tools')); } } catch (error) { logger.error('[Login] Web authentication error:', error); throw new Error(`Web authentication failed: ${error.message}`); } } async function loginWithToken(authManager) { const token = await text({ message: 'Personal Access Token:', validate: value => { if (!value || value.length < 10) { return 'Please enter a valid token'; } return; }, }); if (typeof token === 'symbol') { logger.info(pc.red('Login cancelled')); process.exit(0); } const s = spinner(); s.start('Validating token...'); try { const { user } = await authManager.loginWithToken(token); const extendedUser = user; const displayName = extendedUser.first_name && extendedUser.last_name ? `${extendedUser.first_name} ${extendedUser.last_name}` : extendedUser.username || user.email || user.id; s.stop(`Logged in as ${pc.green(displayName)}`); logger.info(pc.dim('Authentication credentials saved securely')); } catch (error) { s.stop(pc.red('Token validation failed')); throw error; } } async function loginWithPassword(authManager) { let email; let pass; if (process.env.CI && process.env.VEAS_EMAIL && process.env.VEAS_PASSWORD) { email = process.env.VEAS_EMAIL; pass = process.env.VEAS_PASSWORD; logger.debug('[Login] Using credentials from environment variables'); } else { const emailInput = await text({ message: 'Email:', validate: value => { if (!value || !value.includes('@')) { return 'Please enter a valid email'; } return; }, }); if (typeof emailInput === 'symbol') { logger.info(pc.red('Login cancelled')); process.exit(0); } email = emailInput; const passInput = await password({ message: 'Password:', validate: value => { if (!value || value.length < 6) { return 'Password must be at least 6 characters'; } return; }, }); if (typeof passInput === 'symbol') { logger.info(pc.red('Login cancelled')); process.exit(0); } pass = passInput; } const s = spinner(); s.start('Logging in...'); try { const { user } = await authManager.login(email, pass); const extendedUser = user; const displayName = extendedUser.first_name && extendedUser.last_name ? `${extendedUser.first_name} ${extendedUser.last_name}` : extendedUser.username || user.email || 'User'; s.stop(`Logged in as ${pc.green(displayName)}`); logger.info(pc.dim('Authentication credentials saved securely')); } catch (error) { s.stop(pc.red('Login failed')); throw error; } } export async function logout() { const s = spinner(); s.start('Logging out...'); try { const authManager = AuthManager.getInstance(); await authManager.logout(); s.stop('Logged out successfully'); } catch (error) { s.stop(pc.red('Logout failed')); logger.error(error.message); process.exit(1); } } export async function status() { try { const authManager = AuthManager.getInstance(); const session = await authManager.getSession(); if (!session) { logger.info(pc.yellow('Not logged in')); logger.info(pc.dim('Run "veas login" to authenticate')); return; } logger.info(pc.green('Logged in')); const user = session.user; const displayName = user?.first_name && user?.last_name ? `${user.first_name} ${user.last_name}` : user?.username ? user.username : 'User'; logger.info(pc.dim(`Name: ${displayName}`)); logger.info(pc.dim(`Email: ${user?.email || 'N/A'}`)); if (user?.username) { logger.info(pc.dim(`Username: ${user.username}`)); } if (user?.id) { logger.info(pc.dim(`User ID: ${user.id}`)); } logger.info(pc.dim(`Auth type: ${session?.type || 'standard'}`)); if (session?.patToken) { logger.info(pc.dim(`MCP Token: ${pc.green('✓')} Personal Access Token available`)); } else { logger.info(pc.dim(`MCP Token: ${pc.yellow('✗')} No PAT (run 'veas pat create' to add one)`)); } } catch (error) { logger.error('Error checking status:', error); process.exit(1); } } export async function refresh() { const authManager = AuthManager.getInstance(); const s = spinner(); s.start('Refreshing authentication token...'); try { await authManager.refreshToken(); s.stop(pc.green('Token refreshed successfully')); } catch (error) { s.stop(pc.red('Failed to refresh token')); logger.error(error.message); process.exit(1); } } //# sourceMappingURL=auth.js.map