@ace-sdk/cli
Version:
ACE CLI - Command-line tool for intelligent pattern learning and playbook management
124 lines • 5.1 kB
JavaScript
/**
* Login Command - Device code authentication
* @package @ace-sdk/cli
*
* v2.9.0: Enhanced to validate token with server before claiming "already logged in"
*/
import ora from 'ora';
import chalk from 'chalk';
import { login, getTokenStatus, isAuthenticatedAsync } from '@ace-sdk/core';
import { globalOptions } from '../cli.js';
export async function loginCommand(options) {
const spinner = ora({ isSilent: globalOptions.quiet || globalOptions.json });
// Check token status locally first
const tokenStatus = getTokenStatus();
if (tokenStatus.hasToken && !tokenStatus.needsReLogin) {
// Token exists and appears valid locally - verify with server
spinner.start('Checking authentication status...');
const authResult = await isAuthenticatedAsync();
spinner.stop();
if (authResult.authenticated && authResult.user) {
if (globalOptions.json) {
console.log(JSON.stringify({
warning: 'Already logged in',
user: {
email: authResult.user.email,
user_id: authResult.user.user_id,
organizations: authResult.user.organizations?.length ?? 0
}
}));
}
else {
console.log(chalk.yellow('Already logged in as:'), chalk.cyan(authResult.user.email));
console.log(chalk.gray('Use'), chalk.white('ce-ace logout'), chalk.gray('to switch accounts'));
}
return;
}
// Token exists but server rejected it - inform and proceed with login
if (!globalOptions.json) {
if (authResult.reason === 'session_expired') {
console.log(chalk.yellow('Previous session expired. Starting new login...'));
}
else if (authResult.reason === 'server_error') {
console.log(chalk.yellow('Could not verify session. Starting new login...'));
}
}
}
else if (tokenStatus.hasToken && tokenStatus.needsReLogin) {
// Token is locally expired
if (!globalOptions.json) {
if (tokenStatus.isHardCapExpired) {
console.log(chalk.yellow('Session hard cap expired (7-day limit). Please re-authenticate.'));
}
else if (tokenStatus.isRefreshExpired) {
console.log(chalk.yellow('Session expired. Please re-authenticate.'));
}
}
}
try {
await login({
clientType: 'cli',
noBrowser: options.noBrowser,
onUserCode: (code, url) => {
if (globalOptions.json) {
console.log(JSON.stringify({
event: 'device_code',
user_code: code,
verification_url: url
}));
}
else {
console.log();
console.log(chalk.cyan(' Open this URL to authenticate:'));
console.log(chalk.white(` ${url}`));
console.log();
console.log(chalk.gray(' Or enter this code manually:'), chalk.yellow.bold(code));
console.log();
spinner.start('Waiting for authentication...');
}
},
onProgress: (message) => {
if (!globalOptions.json) {
spinner.text = message;
}
},
onSuccess: (user) => {
spinner.succeed('Authentication successful!');
if (globalOptions.json) {
console.log(JSON.stringify({
success: true,
user: {
user_id: user.user_id,
email: user.email,
name: user.name,
organizations: user.organizations
}
}));
}
else {
console.log();
console.log(chalk.green('Logged in as:'), chalk.cyan(user.email));
if (user.organizations.length > 0) {
console.log(chalk.gray('Organizations:'), user.organizations.map(o => o.name).join(', '));
}
console.log();
console.log(chalk.gray('Run'), chalk.white('ce-ace whoami'), chalk.gray('to see your account info'));
}
}
});
}
catch (error) {
spinner.fail('Authentication failed');
if (globalOptions.json) {
console.error(JSON.stringify({
error: true,
message: error instanceof Error ? error.message : String(error)
}));
}
else {
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
}
process.exit(1);
}
}
//# sourceMappingURL=login.js.map