UNPKG

@vibe-dev-kit/cli

Version:

Advanced Command-line toolkit that analyzes your codebase and deploys project-aware rules, memories, commands and agents to any AI coding assistant - VDK is the world's first Vibe Development Kit

349 lines (313 loc) • 9.66 kB
/** * Category Selection Utility * Provides interactive category selection for command fetching */ import { intro, multiselect, outro, select } from '@clack/prompts'; import chalk from 'chalk'; /** * Available command categories with descriptions */ export const COMMAND_CATEGORIES = { development: { name: 'Development', description: 'Core development tasks: bug fixes, migrations, project setup', commands: [ 'bug-fix', 'dependencies', 'integrate', 'migrate', 'onboard', 'project-setup', 'prototype', ], essential: true, }, quality: { name: 'Quality & Testing', description: 'Code quality, debugging, refactoring, and testing', commands: [ 'benchmark', 'clean', 'debug', 'health-check', 'perf', 'refactor', 'review', 'standardize', 'tdd', 'technical-debt', 'validate', ], essential: true, }, workflow: { name: 'Workflow & CI/CD', description: 'Git workflows, deployment, monitoring, and coordination', commands: [ 'ci-gen', 'commit', 'coordinate', 'deploy', 'git-workflow', 'monitor', 'parallel', 'plan', 'pr', 'release', ], essential: false, }, meta: { name: 'Documentation & Analysis', description: 'Documentation, research, visualization, and API management', commands: [ 'api', 'changelog', 'diagram', 'document', 'explain', 'research', 'summary', 'visualize', ], essential: false, }, security: { name: 'Security', description: 'Security auditing and hardening', commands: ['audit', 'harden'], essential: false, }, }; /** * Predefined preset configurations */ export const PRESETS = { minimal: { name: 'Minimal', description: 'Essential commands for basic development', categories: ['development'], commands: ['bug-fix', 'integrate', 'project-setup', 'review', 'refactor'], }, development: { name: 'Development Focus', description: 'Core development and quality commands', categories: ['development', 'quality'], commands: null, // null means all commands from categories }, full: { name: 'Full Suite', description: 'All available commands', categories: ['development', 'quality', 'workflow', 'meta', 'security'], commands: null, }, production: { name: 'Production Ready', description: 'Commands for production environments', categories: ['development', 'quality', 'workflow', 'security'], commands: null, }, auto: { name: 'Auto (Smart Selection)', description: 'Automatically select based on project analysis', categories: [], // Will be determined dynamically commands: null, }, }; /** * Smart category selection based on project analysis */ export function getSmartCategories(projectContext) { const smartCategories = ['development']; // Always include development // Add quality if testing frameworks detected if (projectContext.techStack?.testingFrameworks?.length > 0) { smartCategories.push('quality'); } // Add workflow if CI/CD indicators found if ( projectContext.projectStructure?.hasCI || projectContext.techStack?.libraries?.some( (lib) => lib.includes('github-actions') || lib.includes('gitlab-ci') || lib.includes('jenkins') ) ) { smartCategories.push('workflow'); } // Add security for production projects if ( projectContext.techStack?.frameworks?.some( (fw) => fw.includes('next') || fw.includes('express') || fw.includes('fastapi') ) ) { smartCategories.push('security'); } // Add meta for documentation-heavy projects if (projectContext.projectStructure?.fileTypes?.md > 5) { smartCategories.push('meta'); } return smartCategories; } /** * Interactive category selection */ export async function selectCategoriesInteractively(projectContext) { intro(chalk.blue('šŸŽÆ VDK Command Category Selection')); // Check if this is a demo mode (when commands aren't actually available) const isDemoMode = !process.env.VDK_GITHUB_TOKEN || process.env.VDK_GITHUB_TOKEN.includes('expired'); if (isDemoMode) { console.log( chalk.yellow('šŸ“‹ Interactive Selection Demo (commands not available due to authentication)') ); console.log(chalk.dim('This shows what the selection process would look like:\n')); } try { // Show project context if (projectContext.techStack) { console.log(chalk.green('šŸ“Š Detected Project Context:')); console.log( ` Language: ${projectContext.techStack.primaryLanguages?.join(', ') || 'Unknown'}` ); console.log( ` Framework: ${projectContext.techStack.frameworks?.join(', ') || 'None detected'}` ); console.log( ` Testing: ${projectContext.techStack.testingFrameworks?.join(', ') || 'None detected'}` ); console.log(''); } // Ask for selection method const method = await select({ message: 'How would you like to select commands?', options: [ { value: 'preset', label: 'Use a preset configuration (recommended)' }, { value: 'categories', label: 'Select individual categories' }, { value: 'auto', label: 'Use smart auto-selection' }, ], }); let result; if (method === 'preset') { result = await selectPreset(); } else if (method === 'categories') { result = await selectIndividualCategories(); } else if (method === 'auto') { const smartCategories = getSmartCategories(projectContext); console.log(chalk.green(`šŸ¤– Smart selection chose: ${smartCategories.join(', ')}`)); result = { categories: smartCategories, preset: 'auto' }; } else { console.log(chalk.yellow('Invalid choice, using auto-selection')); result = { categories: getSmartCategories(projectContext), preset: 'auto' }; } outro(chalk.green('āœ… Category selection complete!')); if (isDemoMode) { console.log(chalk.yellow('\nšŸ“‹ Demo complete! To actually fetch commands:')); console.log(chalk.gray(' • Add a valid GitHub token to .env.local')); console.log(chalk.gray(' • Run vdk init --interactive again')); } return result; } catch (error) { if (error.message === 'User cancelled') { outro(chalk.yellow('Operation cancelled')); process.exit(0); } throw error; } } /** * Select a preset configuration */ async function selectPreset() { const presetOptions = Object.entries(PRESETS).map(([key, preset]) => ({ value: key, label: `${preset.name} - ${preset.description}`, hint: preset.categories.length > 0 ? `Categories: ${preset.categories.join(', ')}` : 'Smart selection', })); const selectedPreset = await select({ message: 'Choose a preset configuration:', options: presetOptions, }); const preset = PRESETS[selectedPreset]; console.log(chalk.green(`Selected preset: ${preset.name}`)); return { categories: preset.categories, preset: selectedPreset, specificCommands: preset.commands, }; } /** * Select individual categories */ async function selectIndividualCategories() { const categoryOptions = Object.entries(COMMAND_CATEGORIES).map(([key, category]) => ({ value: key, label: `${category.name}${category.essential ? ' ⭐' : ''}`, hint: `${category.description} (${category.commands.length} commands)`, })); const selectedCategories = await multiselect({ message: 'Select command categories:', options: categoryOptions, required: true, }); if (!selectedCategories || selectedCategories.length === 0) { console.log(chalk.yellow('No categories selected, using development')); return { categories: ['development'], preset: 'custom', }; } console.log(chalk.green(`Selected categories: ${selectedCategories.join(', ')}`)); return { categories: selectedCategories, preset: 'custom', }; } /** * Get category filter for repository fetching */ export function getCategoryFilter(options, _projectContext) { // If specific categories provided via CLI if (options.categories && options.categories.length > 0) { return { categories: options.categories, preset: 'custom', }; } // If preset specified if (options.preset && options.preset !== 'auto' && PRESETS[options.preset]) { const preset = PRESETS[options.preset]; return { categories: preset.categories, preset: options.preset, specificCommands: preset.commands, }; } // Auto selection if (!options.interactive) { const smartCategories = getSmartCategories(options.projectContext || {}); return { categories: smartCategories, preset: 'auto', }; } // This will be handled by interactive selection return null; } /** * Display selection summary */ export function displaySelectionSummary(selection, projectContext) { console.log(chalk.blue('\nšŸ“‹ Command Selection Summary:')); console.log(` Preset: ${selection.preset}`); console.log(` Categories: ${selection.categories.join(', ')}`); if (selection.specificCommands) { console.log(` Specific Commands: ${selection.specificCommands.join(', ')}`); } const totalCommands = selection.categories.reduce((total, cat) => { return total + (COMMAND_CATEGORIES[cat]?.commands.length || 0); }, 0); console.log(` Estimated Commands: ${selection.specificCommands?.length || totalCommands}`); console.log(''); }