@ace-sdk/cli
Version:
ACE CLI - Command-line tool for intelligent pattern learning and playbook management
307 lines ⢠10.8 kB
JavaScript
/**
* 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