ai-expert
Version:
AI Expert CLI - Advanced management system for specialized Claude assistants
217 lines ⢠9.03 kB
JavaScript
import { Command } from 'commander';
import { ExpertBuilder } from '../../services/expert-builder.js';
import inquirer from 'inquirer';
import chalk from 'chalk';
export function expertCommand(storage) {
const expert = new Command('expert');
const builder = new ExpertBuilder(storage);
expert
.description('Manage AI experts')
.alias('e');
expert
.command('create <name>')
.description('Create a new expert')
.option('-d, --description <desc>', 'Expert description')
.option('-c, --context <id>', 'Base context ID')
.option('-s, --system <id>', 'Base system ID (overrides context system)')
.option('--category <category>', 'Expert category')
.option('-t, --tags <tags...>', 'Expert tags')
.action(async (name, options) => {
try {
// Interactive mode if no options provided
if (!options.description || !options.context) {
const contexts = await storage.listContexts();
const systems = await storage.listSystems();
const config = await storage.getConfig();
const answers = await inquirer.prompt([
{
type: 'input',
name: 'description',
message: 'Expert description:',
default: options.description,
when: !options.description
},
{
type: 'list',
name: 'context',
message: 'Select base context:',
choices: [
{ name: 'None', value: null },
...contexts.map(c => ({ name: `${c.name} - ${c.description}`, value: c.id }))
],
when: !options.context
},
{
type: 'list',
name: 'system',
message: 'Select base system (optional):',
choices: [
{ name: 'Use context default', value: null },
...systems.map(s => ({ name: `${s.name} - ${s.description}`, value: s.id }))
],
when: !options.system
},
{
type: 'list',
name: 'category',
message: 'Select category:',
choices: config.categories.experts,
default: options.category || 'custom'
}
]);
Object.assign(options, answers);
}
const expert = await builder.createExpert(name, options.description, {
baseContextId: options.context,
baseSystemId: options.system,
category: options.category,
tags: options.tags
});
console.log(chalk.green('ā
Expert created successfully!'));
console.log(chalk.cyan(`ID: ${expert.id}`));
console.log(chalk.cyan(`Slug: ${expert.slug}`));
console.log(`\nUse: ${chalk.yellow(`ai ${expert.slug} "your question"`)}`);
}
catch (error) {
console.error(chalk.red('ā Error:'), error.message);
}
});
expert
.command('list')
.description('List all experts')
.option('-c, --category <category>', 'Filter by category')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
const experts = await storage.listExperts(options.category);
if (options.json) {
console.log(JSON.stringify(experts, null, 2));
return;
}
if (experts.length === 0) {
console.log(chalk.yellow('No experts found.'));
console.log(`Create one with: ${chalk.cyan('ai expert create <name>')}`);
return;
}
console.log(chalk.bold('\nš¤ Available Experts:\n'));
for (const expert of experts) {
console.log(chalk.cyan(`š ${expert.slug}`) + chalk.gray(` - ${expert.name}`));
console.log(` ${expert.description}`);
if (expert.category) {
console.log(chalk.gray(` Category: ${expert.category}`));
}
if (expert.tags?.length) {
console.log(chalk.gray(` Tags: ${expert.tags.join(', ')}`));
}
if (expert.usageCount > 0) {
console.log(chalk.gray(` Used: ${expert.usageCount} times`));
}
console.log();
}
}
catch (error) {
console.error(chalk.red('ā Error:'), error.message);
}
});
expert
.command('show <slug>')
.description('Show expert details')
.option('--json', 'Output as JSON')
.action(async (slug, options) => {
try {
const expert = await storage.getExpert(slug);
if (!expert) {
console.error(chalk.red(`ā Expert '${slug}' not found`));
return;
}
if (options.json) {
console.log(JSON.stringify(expert, null, 2));
return;
}
console.log(chalk.bold(`\nš¤ Expert: ${expert.name}\n`));
console.log(`Slug: ${chalk.cyan(expert.slug)}`);
console.log(`Description: ${expert.description}`);
console.log(`Category: ${expert.category}`);
if (expert.tags?.length) {
console.log(`Tags: ${expert.tags.join(', ')}`);
}
if (expert.baseContextId) {
const context = await storage.getContext(expert.baseContextId);
console.log(`Base Context: ${chalk.cyan(context?.name || expert.baseContextId)}`);
}
if (expert.baseSystemId) {
const system = await storage.getSystem(expert.baseSystemId);
console.log(`Base System: ${chalk.cyan(system?.name || expert.baseSystemId)}`);
}
console.log(`Created: ${new Date(expert.created).toLocaleString()}`);
if (expert.updated) {
console.log(`Updated: ${new Date(expert.updated).toLocaleString()}`);
}
console.log(`Usage: ${expert.usageCount} times`);
if (expert.additionalRules.length > 0) {
console.log(chalk.bold('\nAdditional Rules:'));
for (const rule of expert.additionalRules) {
console.log(`- ${rule.name}: ${rule.content}`);
}
}
}
catch (error) {
console.error(chalk.red('ā Error:'), error.message);
}
});
expert
.command('edit <slug>')
.description('Edit expert configuration')
.action(async (slug) => {
try {
const expert = await storage.getExpert(slug);
if (!expert) {
console.error(chalk.red(`ā Expert '${slug}' not found`));
return;
}
// Open editor
const { edit } = await import('../../utils/editor.js');
const updated = await edit(expert);
if (updated) {
updated.updated = new Date().toISOString();
await storage.saveExpert(updated);
console.log(chalk.green('ā
Expert updated successfully!'));
}
}
catch (error) {
console.error(chalk.red('ā Error:'), error.message);
}
});
expert
.command('delete <slug>')
.description('Delete an expert')
.option('-f, --force', 'Skip confirmation')
.action(async (slug, options) => {
try {
const expert = await storage.getExpert(slug);
if (!expert) {
console.error(chalk.red(`ā Expert '${slug}' not found`));
return;
}
if (!options.force) {
const { confirm } = await inquirer.prompt([{
type: 'confirm',
name: 'confirm',
message: `Are you sure you want to delete expert '${expert.name}'?`,
default: false
}]);
if (!confirm) {
console.log('Cancelled.');
return;
}
}
await storage.deleteExpert(slug);
console.log(chalk.green(`ā
Expert '${expert.name}' deleted successfully!`));
}
catch (error) {
console.error(chalk.red('ā Error:'), error.message);
}
});
return expert;
}
//# sourceMappingURL=expert.js.map