crewai-ts
Version:
TypeScript port of crewAI for agent-based workflows
167 lines (166 loc) • 6.75 kB
JavaScript
export class CLI {
commands = new Map();
aliases = new Map();
/**
* Create a new CLI handler
*/
constructor() {
this.initializeCommands();
}
/**
* Register a command with the CLI
* @param command Command to register
* @param aliases Optional command aliases
*/
registerCommand(command, aliases = []) {
// Register the command by its name
this.commands.set(command.name, command);
// Register any aliases
for (const alias of aliases) {
this.aliases.set(alias, command.name);
}
}
/**
* Initialize built-in commands
*/
initializeCommands() {
// Import command classes dynamically to avoid circular dependencies
const loadCommands = async () => {
try {
// Flow commands
const { CreateFlowCommand } = await import('./commands/CreateFlowCommand.js');
const { PlotFlowCommand } = await import('./commands/PlotFlowCommand.js');
const { RunFlowCommand } = await import('./commands/RunFlowCommand.js');
// Crew commands
const { RunCrewCommand } = await import('./commands/RunCrewCommand.js');
const { TrainCrewCommand } = await import('./commands/TrainCrewCommand.js');
const { TestCrewCommand } = await import('./commands/TestCrewCommand.js');
// Task and memory commands
const { ReplayTaskCommand } = await import('./commands/ReplayTaskCommand.js');
const { LogTasksOutputsCommand } = await import('./commands/LogTasksOutputsCommand.js');
const { ResetMemoriesCommand } = await import('./commands/ResetMemoriesCommand.js');
// Interactive commands
const { ChatCommand } = await import('./commands/ChatCommand.js');
// Register commands with aliases for better UX
// Flow commands
this.registerCommand(new CreateFlowCommand(), ['new-flow']);
this.registerCommand(new PlotFlowCommand(), ['visualize-flow']);
this.registerCommand(new RunFlowCommand(), ['execute-flow']);
// Crew commands
this.registerCommand(new RunCrewCommand(), ['execute-crew']);
this.registerCommand(new TrainCrewCommand(), ['train']);
this.registerCommand(new TestCrewCommand(), ['test', 'evaluate']);
// Task and memory commands
this.registerCommand(new ReplayTaskCommand(), ['replay']);
this.registerCommand(new LogTasksOutputsCommand(), ['log-outputs']);
this.registerCommand(new ResetMemoriesCommand(), ['reset']);
// Interactive commands
this.registerCommand(new ChatCommand(), []);
}
catch (error) {
console.error('Error initializing commands:', error);
}
};
// Execute async loading
loadCommands();
}
/**
* Parse and execute a command from command line arguments
* @param args Command line arguments
*/
async parseAndExecute(args) {
// Remove the first two arguments (node and script name)
const cmdArgs = args.slice(2);
if (cmdArgs.length === 0 || cmdArgs[0] === 'help') {
this.showHelp();
return;
}
const commandName = cmdArgs[0];
const commandArgs = cmdArgs.slice(1);
// Check if the command exists directly or via an alias with optimized type handling
let resolvedCommandName = commandName;
if (commandName && this.aliases.has(commandName)) {
const aliasTarget = this.aliases.get(commandName);
if (aliasTarget) {
resolvedCommandName = aliasTarget;
}
}
if (resolvedCommandName && this.commands.has(resolvedCommandName)) {
try {
const command = this.commands.get(resolvedCommandName);
// Ensure command is defined
if (!command) {
console.error(`Command ${resolvedCommandName} not found`);
process.exit(1);
}
// Show command-specific help if requested
if (commandArgs.length > 0 && commandArgs[0] === '--help') {
command.showHelp();
return;
}
// Execute the command
await command.execute(commandArgs);
}
catch (error) {
console.error(`Error executing command ${resolvedCommandName}:`, error);
process.exit(1);
}
}
else {
console.error(`Unknown command: ${commandName}`);
this.showHelp();
process.exit(1);
}
}
/**
* Show the main CLI help
*/
showHelp() {
console.log('\nCrewAI Command Line Interface\n');
console.log('Available commands:');
// Group commands by category for better organization
const categories = new Map();
for (const command of this.commands.values()) {
const category = this.getCommandCategory(command);
if (!categories.has(category)) {
categories.set(category, []);
}
const commands = categories.get(category);
if (commands) {
commands.push(command);
}
}
// Sort categories and print commands
const sortedCategories = Array.from(categories.keys()).sort();
for (const category of sortedCategories) {
console.log(`\n${category}:`);
const commands = categories.get(category);
if (!commands)
continue;
for (const command of commands) {
console.log(` ${command.name.padEnd(15)} ${command.description}`);
}
}
console.log('\nFor command-specific help, use: <command> --help\n');
}
/**
* Get the category for a command (used for help organization)
* @param command Command to categorize
*/
getCommandCategory(command) {
// Derived from command name by convention
// e.g., create-flow -> Flow, run-crew -> Crew
if (command.name.startsWith('create-')) {
return 'Creation';
}
else if (command.name.startsWith('run-')) {
return 'Execution';
}
else if (command.name.startsWith('plot-')) {
return 'Visualization';
}
else {
return 'General';
}
}
}