@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.61 kB
JavaScript
/**
* 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 > 0 || totalCommands}`)
console.log('')
}