@ace-sdk/cli
Version:
ACE CLI - Command-line tool for intelligent pattern learning and playbook management
163 lines • 5.71 kB
JavaScript
/**
* Device Management Commands
*
* Commands for managing authorized devices.
*
* @package @ace-sdk/cli
* @since 3.6.0
*/
import chalk from 'chalk';
import * as readline from 'readline/promises';
import { stdin, stdout } from 'process';
import { globalOptions } from '../cli.js';
import { Logger } from '../services/logger.js';
import { listDevices, renameDevice, removeDevice, getDeviceLimit, getOrCreateDeviceId } from '@ace-sdk/core';
/**
* Format relative time from ISO date string
*/
function formatRelativeTime(isoDate) {
const date = new Date(isoDate);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffMins = Math.floor(diffMs / 60000);
const diffHours = Math.floor(diffMins / 60);
const diffDays = Math.floor(diffHours / 24);
if (diffMins < 1)
return 'just now';
if (diffMins === 1)
return '1 minute ago';
if (diffMins < 60)
return `${diffMins} minutes ago`;
if (diffHours === 1)
return '1 hour ago';
if (diffHours < 24)
return `${diffHours} hours ago`;
if (diffDays === 1)
return '1 day ago';
return `${diffDays} days ago`;
}
/**
* Handle error with proper formatting
*/
function handleError(logger, error, message) {
if (logger.isJson()) {
logger.output({ error: error instanceof Error ? error.message : String(error) });
}
else {
logger.error(message, error instanceof Error ? error : String(error));
}
process.exit(1);
}
/**
* ace-cli devices list
* List all authorized devices for the current user
*/
export async function devicesListCommand() {
const logger = new Logger(globalOptions);
const spinner = logger.spinner('Fetching devices...');
try {
const devices = await listDevices();
const currentDeviceId = getOrCreateDeviceId();
spinner?.succeed();
if (logger.isJson()) {
logger.output({ devices, current_device_id: currentDeviceId });
return;
}
if (devices.length === 0) {
logger.info(chalk.dim('No devices found.'));
return;
}
logger.info(chalk.bold(`\nYour Devices (${devices.length}):\n`));
for (const device of devices) {
const isCurrent = device.device_id === currentDeviceId;
const icon = isCurrent ? '📍' : '💻';
const name = device.device_name || chalk.dim('Unnamed device');
const currentBadge = isCurrent ? chalk.cyan(' ← this device') : '';
logger.info(` ${icon} ${chalk.bold(name)}${currentBadge}`);
logger.info(` ID: ${chalk.dim(device.device_id)}`);
logger.info(` Last active: ${formatRelativeTime(device.last_seen_at)}`);
logger.info(` Clients: ${device.clients.length > 0 ? device.clients.join(', ') : chalk.dim('none')}`);
logger.info('');
}
}
catch (error) {
spinner?.fail();
handleError(logger, error, 'Failed to list devices');
}
}
/**
* ace-cli devices rename <id> <name>
* Rename a device for easier identification
*/
export async function devicesRenameCommand(deviceId, newName) {
const logger = new Logger(globalOptions);
const spinner = logger.spinner(`Renaming device to "${newName}"...`);
try {
const device = await renameDevice(deviceId, newName);
spinner?.succeed();
if (logger.isJson()) {
logger.output({ success: true, device });
return;
}
logger.success(`Device renamed to "${newName}"`);
}
catch (error) {
spinner?.fail();
handleError(logger, error, 'Failed to rename device');
}
}
/**
* ace-cli devices remove <id>
* Remove a device and revoke all its sessions
*/
export async function devicesRemoveCommand(deviceId, options) {
const logger = new Logger(globalOptions);
try {
// Confirmation unless --yes
if (!options.yes && !logger.isJson()) {
const rl = readline.createInterface({ input: stdin, output: stdout });
const answer = await rl.question(chalk.yellow('⚠️ This will revoke all sessions on this device. Continue? (y/N): '));
rl.close();
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
logger.info(chalk.dim('Cancelled'));
return;
}
}
const spinner = logger.spinner('Removing device...');
const result = await removeDevice(deviceId);
spinner?.succeed();
if (logger.isJson()) {
logger.output({ success: true, revoked_count: result.revoked_count });
return;
}
logger.success(`Device removed. ${result.revoked_count} session(s) revoked.`);
}
catch (error) {
handleError(logger, error, 'Failed to remove device');
}
}
/**
* ace-cli devices limit
* Show device limit information
*/
export async function devicesLimitCommand() {
const logger = new Logger(globalOptions);
const spinner = logger.spinner('Fetching device limit...');
try {
const limit = await getDeviceLimit();
spinner?.succeed();
if (logger.isJson()) {
logger.output(limit);
return;
}
logger.info(chalk.bold('\nDevice Limit:'));
logger.info(` Used: ${limit.current_devices} of ${limit.max_devices}`);
logger.info(` Custom limit: ${limit.is_custom ? 'Yes' : 'No (default)'}`);
logger.info('');
}
catch (error) {
spinner?.fail();
handleError(logger, error, 'Failed to get device limit');
}
}
//# sourceMappingURL=devices.js.map