@ace-sdk/cli
Version:
ACE CLI - Command-line tool for intelligent pattern learning and playbook management
275 lines • 9.59 kB
JavaScript
/**
* Usage Display Utilities for ACE CLI
*
* Functions for formatting and displaying subscription usage information.
*
* @package @ace-sdk/cli
* @since v2.8.0
*/
import chalk from 'chalk';
// =============================================================================
// Progress Bar Formatting
// =============================================================================
/**
* Format a usage metric as a progress bar
*
* @param used - Current usage
* @param limit - Maximum limit
* @param width - Bar width in characters (default: 20)
* @returns Formatted progress bar string
*
* @example
* ```typescript
* formatUsageBar(80, 100);
* // Returns: "████████████████░░░░ 80 / 100 (80%)"
* ```
*/
export function formatUsageBar(used, limit, width = 20) {
// Handle unlimited (limit = -1 or 0)
if (limit <= 0) {
return `${chalk.dim('unlimited')} ${formatNumber(used)} used`;
}
const percentage = Math.min(100, Math.round((used / limit) * 100));
const filled = Math.round((percentage / 100) * width);
const empty = width - filled;
// Color based on usage level
let barColor = chalk.green;
let warningIcon = '';
if (percentage >= 90) {
barColor = chalk.red;
warningIcon = ' 🔴';
}
else if (percentage >= 80) {
barColor = chalk.yellow;
warningIcon = ' ⚠️';
}
const bar = barColor('█'.repeat(filled)) + chalk.dim('░'.repeat(empty));
const numbers = `${formatNumber(used)} / ${formatNumber(limit)} (${percentage}%)`;
return `${bar} ${numbers}${warningIcon}`;
}
/**
* Format a number with thousands separators
*/
export function formatNumber(num) {
return num.toLocaleString('en-US');
}
// =============================================================================
// Plan Name Formatting
// =============================================================================
/**
* Format plan name for display
*
* @param type - Subscription type (individual/team)
* @param tier - Plan tier (free/basic/pro)
* @returns Formatted plan name
*
* @example
* ```typescript
* formatPlanName('individual', 'pro');
* // Returns: "Individual PRO"
* ```
*/
export function formatPlanName(type, tier) {
const typeDisplay = type.charAt(0).toUpperCase() + type.slice(1);
const tierDisplay = tier.toUpperCase();
return `${typeDisplay} ${tierDisplay}`;
}
/**
* Get colored plan badge
*/
export function getPlanBadge(type, tier) {
const name = formatPlanName(type, tier);
switch (tier) {
case 'pro':
return chalk.bgMagenta.white.bold(` ${name} `);
case 'basic':
return chalk.bgBlue.white.bold(` ${name} `);
default:
return chalk.bgGray.white(` ${name} `);
}
}
// =============================================================================
// Status Formatting
// =============================================================================
/**
* Format subscription status for display
*/
export function formatStatus(status) {
switch (status) {
case 'active':
return chalk.green('Active');
case 'trialing':
return chalk.cyan('Trial');
case 'read_only':
return chalk.yellow('Read-Only');
case 'blocked':
return chalk.red('Blocked');
default:
return status;
}
}
/**
* Get status icon
*/
export function getStatusIcon(status) {
switch (status) {
case 'active':
return '✅';
case 'trialing':
return '🧪';
case 'read_only':
return '⚠️';
case 'blocked':
return '🚫';
default:
return '❓';
}
}
// =============================================================================
// Features Formatting
// =============================================================================
/**
* Format feature availability
*/
export function formatFeatures(features) {
const items = [];
if (features.teams) {
items.push(chalk.green('✅ Teams'));
}
if (features.sharing) {
items.push(chalk.green('✅ Sharing'));
}
if (features.apiAccess) {
items.push(chalk.green('✅ API Access'));
}
if (features.prioritySupport) {
items.push(chalk.green('✅ Priority Support'));
}
if (items.length === 0) {
return chalk.dim('No premium features');
}
return items.join(' ');
}
// =============================================================================
// Full Status Display
// =============================================================================
/**
* Display complete usage status
*
* @param usage - Usage information
*/
export function displayUsageStatus(usage) {
const statusIcon = getStatusIcon(usage.status);
const planBadge = getPlanBadge(usage.subscriptionType, usage.planTier);
console.log();
console.log(chalk.bold(`Subscription: ${planBadge} ${statusIcon} ${formatStatus(usage.status)}`));
console.log();
// Usage metrics
console.log(chalk.bold('Usage:'));
console.log(` ${chalk.cyan('Patterns:'.padEnd(18))}${formatUsageBar(usage.patterns.used, usage.patterns.limit)}`);
console.log(` ${chalk.cyan('Total Patterns:'.padEnd(18))}${formatUsageBar(usage.patternsTotal.used, usage.patternsTotal.limit)}`);
console.log(` ${chalk.cyan('Projects:'.padEnd(18))}${formatUsageBar(usage.projects.used, usage.projects.limit)}`);
console.log(` ${chalk.cyan('Domains:'.padEnd(18))}${formatUsageBar(usage.domains.used, usage.domains.limit)}`);
console.log(` ${chalk.cyan('Templates:'.padEnd(18))}${formatUsageBar(usage.templates.used, usage.templates.limit)}`);
console.log(` ${chalk.cyan('API Calls:'.padEnd(18))}${formatUsageBar(usage.apiCalls.used, usage.apiCalls.limit)}`);
console.log(` ${chalk.cyan('Traces Today:'.padEnd(18))}${formatUsageBar(usage.tracesToday.used, usage.tracesToday.limit)}`);
console.log();
// Reset info
console.log(chalk.dim(' ℹ️ API Calls reset on billing cycle. Traces reset daily at midnight UTC.'));
console.log();
// Features
console.log(chalk.bold('Features:'), formatFeatures(usage.features));
console.log();
// Team info (if applicable)
if (usage.team) {
console.log(chalk.bold('Team:'));
console.log(` ${chalk.cyan('Organization:')} ${usage.team.orgName}`);
console.log(` ${chalk.cyan('Seats:'.padEnd(18))}${formatUsageBar(usage.team.seatsUsed, usage.team.seatsLimit)}`);
console.log();
}
// Warnings
displayWarnings(usage);
}
/**
* Display warnings based on usage status
*/
export function displayWarnings(usage) {
// Read-only mode warning
if (usage.status === 'read_only') {
console.log(chalk.yellow.bold('⚠️ Account is in READ-ONLY mode due to payment failure.'));
console.log(chalk.yellow(' Update payment: https://ace-ai.app/settings/billing'));
console.log();
}
// Blocked account warning
if (usage.status === 'blocked') {
console.log(chalk.red.bold('🚫 Account is BLOCKED.'));
console.log(chalk.red(' Resolve at: https://ace-ai.app/settings/billing'));
console.log();
}
// Trial ending warning (if trialing and would show usage)
if (usage.status === 'trialing') {
console.log(chalk.cyan('🧪 You are on a trial period.'));
console.log(chalk.cyan(' Upgrade: https://ace-ai.app/pricing'));
console.log();
}
// Near-limit warnings
const nearLimitResources = [];
if (isNearLimit(usage.patterns)) {
nearLimitResources.push('Patterns (per-project)');
}
if (isNearLimit(usage.patternsTotal)) {
nearLimitResources.push('Patterns (total)');
}
if (isNearLimit(usage.projects)) {
nearLimitResources.push('Projects');
}
if (isNearLimit(usage.apiCalls)) {
nearLimitResources.push('API Calls');
}
if (isNearLimit(usage.tracesToday)) {
nearLimitResources.push('Daily Traces');
}
if (nearLimitResources.length > 0) {
console.log(chalk.yellow.bold('⚠️ Approaching limits:'));
nearLimitResources.forEach(resource => {
console.log(chalk.yellow(` • ${resource}`));
});
console.log(chalk.yellow(' Upgrade: https://ace-ai.app/pricing'));
console.log();
}
}
/**
* Check if a metric is near its limit (>80%)
*/
function isNearLimit(metric, threshold = 80) {
if (metric.limit <= 0)
return false;
return (metric.used / metric.limit) * 100 >= threshold;
}
// =============================================================================
// JSON Output
// =============================================================================
/**
* Format usage info for JSON output
*/
export function formatUsageJson(usage) {
return {
plan: usage.plan,
subscription_type: usage.subscriptionType,
plan_tier: usage.planTier,
status: usage.status,
usage: {
patterns: usage.patterns,
patterns_total: usage.patternsTotal,
projects: usage.projects,
domains: usage.domains,
templates: usage.templates,
api_calls: usage.apiCalls,
traces_today: usage.tracesToday
},
features: usage.features,
team: usage.team || null,
upgrade_url: 'https://ace-ai.app/pricing'
};
}
//# sourceMappingURL=usage-display.js.map