#!/usr/bin/env node /** * NeoHub CLI Entry Point */ import { Command } from 'commander'; import chalk from 'chalk'; import { ChatSession } from './chat'; import { initCommand } from './commands/init'; import { editCommand } from './commands/edit'; import { analyzeCommand } from './commands/analyze'; import { recommendCommand } from './commands/recommend'; import { completionCommand } from './commands/completion'; import { analyticsCommand } from './commands/analytics'; import { searchCommand } from './commands/search'; interface EditOptions { file: string; instruction: string; backup?: boolean; } interface AnalyzeOptions { path: string; type?: 'review' | 'explain' | 'security' | 'performance'; } const program = new Command(); program.name('neohub').description('AI-powered code assistant using Ollama').version('1.0.0'); // Init command program .command('init') .description('Initialize NeoHub configuration') .action(async () => { await initCommand(); }); // Chat command program .command('chat') .description('Start an interactive chat session') .action(async () => { const session = new ChatSession(); await session.start(); }); // Edit command program .command('edit') .description('Edit a file with AI assistance') .requiredOption('-f, --file ', 'File to edit') .requiredOption('-i, --instruction ', 'Edit instruction') .option('-b, --backup', 'Create backup before editing', false) .action(async (options: EditOptions) => { await editCommand(options); }); // Analyze command program .command('analyze') .description('Analyze code') .argument('', 'File or directory to analyze') .option('-t, --type ', 'Analysis type (review|explain|security|performance)', 'review') .action(async (pathArg: string, options: Omit) => { await analyzeCommand({ path: pathArg, ...options } as AnalyzeOptions); }); // Models command program .command('models') .description('List available Ollama models') .action(async () => { const { OllamaClient } = await import('@fsfalmansour/neohub-core'); const { ConfigManager } = await import('./config'); const ora = (await import('ora')).default; const config = new ConfigManager(); const ollama = new OllamaClient(config.getOllamaConfig()); const spinner = ora('Fetching models...').start(); try { const response = await ollama.listModels(); spinner.stop(); console.log(chalk.bold.cyan('\n📦 Available Models\n')); response.models.forEach(model => { const size = (model.size / 1024 / 1024 / 1024).toFixed(2); console.log(chalk.green('●') + ` ${model.name} ${chalk.gray(`(${size} GB)`)}`); }); console.log(''); } catch (error) { spinner.fail(chalk.red('Failed to fetch models: ' + (error as Error).message)); } }); // Recommend command program .command('recommend') .description('Get intelligent model recommendation for your task') .action(async () => { await recommendCommand(); }); // Config command program .command('config') .description('Show current configuration') .action(async () => { const { ConfigManager } = await import('./config'); const config = new ConfigManager(); console.log(chalk.bold.cyan('\n⚙️ NeoHub Configuration\n')); console.log(chalk.gray('Config file: ' + config.getConfigPath())); console.log(''); console.log(JSON.stringify(config.getConfig(), null, 2)); console.log(''); }); // Completion command program .command('completion') .description('Generate shell completion script') .option('--shell ', 'Shell type (bash|zsh|fish)') .action(async (options: { shell?: string }) => { await completionCommand(options); }); // Analytics command program .command('analytics') .description('View usage analytics and statistics') .option('--clear', 'Clear all analytics data') .option('--export', 'Export analytics data as JSON') .option('--disable', 'Disable analytics tracking') .option('--enable', 'Enable analytics tracking') .action(async (options: { clear?: boolean; export?: boolean; disable?: boolean; enable?: boolean }) => { await analyticsCommand(options); }); // Search command program .command('search') .description('Search for code patterns across your project') .argument('', 'Search pattern') .option('-i, --case-sensitive', 'Case sensitive search', false) .option('-w, --whole-word', 'Match whole words only', false) .option('-r, --regex', 'Use regex pattern', false) .option('-p, --path ', 'Directory to search in') .option('-m, --max-results ', 'Maximum number of results', '100') .option('-c, --context-lines ', 'Lines of context to show', '2') .action(async (pattern: string, options: any) => { await searchCommand(pattern, { ...options, maxResults: parseInt(options.maxResults), contextLines: parseInt(options.contextLines), }); }); // Error handling program.configureOutput({ outputError: (str, write) => write(chalk.red(str)), }); // Parse arguments program.parse(); // Show help if no command provided if (!process.argv.slice(2).length) { program.outputHelp(); }