UNPKG

@ace-sdk/cli

Version:

ACE CLI - Command-line tool for intelligent pattern learning and playbook management

146 lines • 6.38 kB
/** * Usage history command - time-windowed API usage analytics * * @package @ace-sdk/cli * @since v2.10.0 */ import { globalOptions } from '../cli.js'; import { createContext } from '../types/config.js'; import { ACEServerClient } from '../services/server-client.js'; import { Logger } from '../services/logger.js'; import chalk from 'chalk'; import { isSubscriptionError, QuotaExceededError, PaymentRequiredError, AccountBlockedError, TokenExpiredError } from '@ace-sdk/core'; import { formatNumber } from '../utils/usage-display.js'; const VALID_WINDOWS = ['1h', '6h', '12h', '1d', '7d', '14d', '30d']; /** * Show usage history with time-windowed buckets */ export async function usageCommand(options) { const logger = new Logger(globalOptions); // Validate window parameter const window = (options.window || '1d'); if (!VALID_WINDOWS.includes(window)) { logger.error(chalk.red(`Invalid window: ${options.window}. Valid: ${VALID_WINDOWS.join(', ')}`)); process.exit(1); } let spinner = logger.spinner(`Fetching usage history (${window})...`); try { const context = await createContext({ org: globalOptions.org, project: globalOptions.project }); const client = new ACEServerClient(context, logger); const result = await client.getUsageHistory({ window, projectId: options.project || undefined }); spinner?.succeed('Usage history retrieved'); if (logger.isJson()) { logger.output(result); } else { logger.info(chalk.bold(`\nUsage History (${result.window}, ${result.granularity})\n`)); if (result.project_id) { logger.info(` ${chalk.cyan('Project:')} ${result.project_id}`); } logger.info(` ${chalk.cyan('Org:')} ${result.org_id}\n`); if (result.buckets.length === 0) { logger.info(chalk.dim(' No activity in this time window.\n')); } else { // Table header const isHourly = result.granularity === 'hourly'; logger.info(chalk.bold(` ${'Period'.padEnd(isHourly ? 18 : 14)} ` + `${'API'.padStart(6)} ` + `${'Patterns'.padStart(10)} ` + `${'Traces'.padStart(8)} ` + `${'Bootstrap'.padStart(10)}`)); logger.info(chalk.dim(' ' + '-'.repeat(isHourly ? 56 : 52))); for (const bucket of result.buckets) { const period = formatPeriod(bucket.period, isHourly); logger.info(` ${chalk.cyan(period.padEnd(isHourly ? 18 : 14))} ` + `${formatNumber(bucket.api_calls_total).padStart(6)} ` + `${formatPatternSummary(bucket).padStart(10)} ` + `${formatNumber(bucket.traces_submitted).padStart(8)} ` + `${formatNumber(bucket.bootstrap_runs).padStart(10)}`); } // Totals logger.info(chalk.dim(' ' + '-'.repeat(isHourly ? 56 : 52))); logger.info(chalk.bold(` ${'Totals'.padEnd(isHourly ? 18 : 14)} ` + `${formatNumber(result.totals.api_calls_total).padStart(6)} ` + `${formatNumber(result.totals.patterns_created).padStart(10)} ` + `${formatNumber(result.totals.traces_submitted).padStart(8)}`)); } logger.info(''); } } catch (error) { spinner?.fail('Failed to fetch usage history'); // Handle token expiry errors (v2.11.0+) if (error instanceof TokenExpiredError) { if (logger.isJson()) { logger.error(JSON.stringify({ error: 'token_expired', message: error.message })); } else { logger.error(chalk.red('\nšŸ”‘ Session expired (7-day hard cap reached)')); logger.error(chalk.dim(' Your session has reached its maximum lifetime.')); logger.error(chalk.cyan(' Run: ace-cli login\n')); } process.exit(1); } if (isSubscriptionError(error)) { if (logger.isJson()) { logger.error(JSON.stringify({ error: error.name, message: error.message, upgrade_url: 'upgradeUrl' in error ? error.upgradeUrl : 'https://ace-ai.app/pricing' })); } else { if (error instanceof QuotaExceededError) { logger.error(chalk.yellow(`\n Quota exceeded: ${error.message}`)); } else if (error instanceof PaymentRequiredError) { logger.error(chalk.yellow(`\n Account is in read-only mode: ${error.message}`)); } else if (error instanceof AccountBlockedError) { logger.error(chalk.red(`\n Account is blocked: ${error.message}`)); } else { logger.error(chalk.red(`\n ${error.message}`)); } } process.exit(1); } if (logger.isJson()) { logger.error(JSON.stringify({ error: error instanceof Error ? error.message : String(error) })); } else { logger.error(chalk.red(`\n Error: ${error instanceof Error ? error.message : String(error)}\n`)); } process.exit(1); } } function formatPeriod(period, isHourly) { const date = new Date(period); if (isHourly) { return date.toLocaleString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }); } return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); } function formatPatternSummary(bucket) { const created = bucket.patterns_created; const updated = bucket.patterns_updated; const deleted = bucket.patterns_deleted; const parts = []; if (created > 0) parts.push(`+${created}`); if (updated > 0) parts.push(`~${updated}`); if (deleted > 0) parts.push(`-${deleted}`); return parts.length > 0 ? parts.join('/') : '0'; } //# sourceMappingURL=usage.js.map