veas
Version:
Veas CLI - Command-line interface for Veas platform
223 lines • 8.14 kB
JavaScript
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