UNPKG

@ace-sdk/cli

Version:

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

307 lines • 10.8 kB
/** * Session recording commands */ import { getRecorder } from '../services/recorder.js'; import { globalOptions } from '../cli.js'; import { Logger } from '../services/logger.js'; import chalk from 'chalk'; import { createContext } from '../types/config.js'; /** * Start recording a session */ export async function recordStartCommand(options) { const logger = new Logger(globalOptions); try { const recorder = getRecorder(); // Get project ID from config if available let projectId; try { const context = await createContext({ org: globalOptions.org, project: globalOptions.project }); projectId = context.projectId; } catch { // Config not available, continue without project ID } // Build command description const command = options.session || 'ce-ace session'; const result = recorder.start(command, projectId); if (logger.isJson()) { logger.output({ success: true, sessionId: result.sessionId, message: result.message }); } else { logger.success(`šŸ”“ ${result.message}`); logger.info(chalk.dim(` Run 'ce-ace record stop' to end recording`)); } } catch (error) { if (logger.isJson()) { logger.output({ success: false, error: error instanceof Error ? error.message : String(error) }); } else { logger.error('Failed to start recording', error instanceof Error ? error : String(error)); } process.exit(1); } } /** * Stop recording the current session */ export async function recordStopCommand() { const logger = new Logger(globalOptions); try { const recorder = getRecorder(); const result = recorder.stop(); const durationSeconds = (result.duration / 1000).toFixed(1); if (logger.isJson()) { logger.output({ success: true, sessionId: result.sessionId, events: result.events, duration_ms: result.duration }); } else { logger.success(`ā¹ļø Recording stopped`); logger.info(chalk.dim(` Session: ${result.sessionId}`)); logger.info(chalk.dim(` Events: ${result.events}`)); logger.info(chalk.dim(` Duration: ${durationSeconds}s`)); logger.info(''); logger.info(chalk.dim(` Run 'ce-ace record list' to see all sessions`)); logger.info(chalk.dim(` Run 'ce-ace summarize ${result.sessionId}' to analyze this session`)); } } catch (error) { if (logger.isJson()) { logger.output({ success: false, error: error instanceof Error ? error.message : String(error) }); } else { logger.error('Failed to stop recording', error instanceof Error ? error : String(error)); } process.exit(1); } } /** * List all recorded sessions */ export async function recordListCommand() { const logger = new Logger(globalOptions); try { const recorder = getRecorder(); const sessions = recorder.listSessions(); if (logger.isJson()) { logger.output({ sessions: sessions.map(s => ({ id: s.id, startTime: s.startTime, endTime: s.endTime, command: s.command, events: s.events, projectId: s.projectId })) }); } else { if (sessions.length === 0) { logger.info('No recorded sessions found'); logger.info(chalk.dim(`Run 'ce-ace record start' to begin recording`)); return; } logger.info(chalk.bold(`\nšŸ“¼ Recorded Sessions (${sessions.length})\n`)); for (const session of sessions) { const status = session.endTime ? chalk.green('āœ“') : chalk.yellow('āŗ'); const duration = session.endTime ? chalk.dim(formatDuration(session.startTime, session.endTime)) : chalk.yellow('(in progress)'); logger.info(`${status} ${chalk.cyan(session.id)}`); logger.info(chalk.dim(` Started: ${formatTimestamp(session.startTime)}`)); if (session.endTime) { logger.info(chalk.dim(` Ended: ${formatTimestamp(session.endTime)}`)); } logger.info(chalk.dim(` Duration: ${duration}`)); logger.info(chalk.dim(` Events: ${session.events}`)); logger.info(chalk.dim(` Command: ${session.command}`)); if (session.projectId) { logger.info(chalk.dim(` Project: ${session.projectId}`)); } logger.info(''); } logger.info(chalk.dim('Run \'ce-ace record export <sessionId> <output>\' to export a session')); logger.info(chalk.dim('Run \'ce-ace summarize <sessionId>\' to analyze a session\n')); } } catch (error) { if (logger.isJson()) { logger.output({ success: false, error: error instanceof Error ? error.message : String(error) }); } else { logger.error('Failed to list sessions', error instanceof Error ? error : String(error)); } process.exit(1); } } /** * Export a session to a file */ export async function recordExportCommand(sessionId, outputPath) { const logger = new Logger(globalOptions); try { const recorder = getRecorder(); recorder.exportSession(sessionId, outputPath); if (logger.isJson()) { logger.output({ success: true, sessionId, output: outputPath }); } else { logger.success(`šŸ“„ Session exported to ${outputPath}`); } } catch (error) { if (logger.isJson()) { logger.output({ success: false, error: error instanceof Error ? error.message : String(error) }); } else { logger.error('Failed to export session', error instanceof Error ? error : String(error)); } process.exit(1); } } /** * Delete a session recording */ export async function recordDeleteCommand(sessionId, options) { const logger = new Logger(globalOptions); try { const recorder = getRecorder(); // Verify session exists recorder.getSession(sessionId); // Confirm deletion if --yes not provided if (!options.yes && !logger.isJson()) { const readline = await import('readline/promises'); const { stdin, stdout } = await import('process'); const rl = readline.createInterface({ input: stdin, output: stdout }); const answer = await rl.question(chalk.yellow(`āš ļø Delete session ${sessionId}? (y/N): `)); rl.close(); if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') { logger.info(chalk.dim('Cancelled')); return; } } recorder.deleteSession(sessionId); if (logger.isJson()) { logger.output({ success: true, sessionId }); } else { logger.success(`šŸ—‘ļø Session ${sessionId} deleted`); } } catch (error) { if (logger.isJson()) { logger.output({ success: false, error: error instanceof Error ? error.message : String(error) }); } else { logger.error('Failed to delete session', error instanceof Error ? error : String(error)); } process.exit(1); } } /** * Get current recording status */ export async function recordStatusCommand() { const logger = new Logger(globalOptions); try { const recorder = getRecorder(); const state = recorder.getState(); if (logger.isJson()) { logger.output({ active: state.active, sessionId: state.sessionId, startTime: state.startTime?.toISOString(), eventCount: state.eventCount }); } else { if (state.active) { const duration = state.startTime ? formatDuration(state.startTime.toISOString(), new Date().toISOString()) : 'unknown'; logger.info(chalk.bold('\nšŸ”“ Recording Active\n')); logger.info(chalk.dim(` Session: ${state.sessionId}`)); logger.info(chalk.dim(` Started: ${formatTimestamp(state.startTime.toISOString())}`)); logger.info(chalk.dim(` Duration: ${duration}`)); logger.info(chalk.dim(` Events: ${state.eventCount}`)); logger.info(''); logger.info(chalk.dim(`Run 'ce-ace record stop' to end recording\n`)); } else { logger.info(chalk.dim('No active recording')); logger.info(chalk.dim(`Run 'ce-ace record start' to begin recording\n`)); } } } catch (error) { if (logger.isJson()) { logger.output({ success: false, error: error instanceof Error ? error.message : String(error) }); } else { logger.error('Failed to get status', error instanceof Error ? error : String(error)); } process.exit(1); } } /** * Format timestamp for display */ function formatTimestamp(timestamp) { const date = new Date(timestamp); return date.toLocaleString(); } /** * Format duration between two timestamps */ function formatDuration(start, end) { const startTime = new Date(start).getTime(); const endTime = new Date(end).getTime(); const durationMs = endTime - startTime; const seconds = Math.floor(durationMs / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); if (hours > 0) { return `${hours}h ${minutes % 60}m`; } else if (minutes > 0) { return `${minutes}m ${seconds % 60}s`; } else { return `${seconds}s`; } } //# sourceMappingURL=record.js.map