@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
1,486 lines (1,280 loc) • 102 kB
JavaScript
import chalk from 'chalk';
import fs from 'fs-extra';
import os from 'os';
import path from 'path';
import { validateCommand } from '../../utils/schema-validator.js';
import { RuleAdapter } from './RuleAdapter.js';
/**
* Enhanced Claude Code Adapter
*
* Leverages Claude Code's advanced features including:
* - Hierarchical memory management with import system
* - Sophisticated slash command generation
* - MCP server integration patterns
* - Team memory synchronization
* - Native Claude Code file structure
*/
export class ClaudeCodeAdapter extends RuleAdapter {
constructor(options = {}) {
super(options);
this.claudeConfigPath = path.join(this.projectPath, '.claude');
this.claudeUserPath = path.join(os.homedir(), '.claude');
this.ruleGenerator = options.ruleGenerator; // Reference to parent RuleGenerator for centralized fetching
}
/**
* Enhanced Claude Code adaptation with memory hierarchy
*/
async adaptForClaude(rules, projectContext, categoryFilter = null) {
console.log('🧠 Generating enhanced Claude Code memory hierarchy...');
const adapted = {
files: [],
directories: [this.claudeConfigPath],
memoryHierarchy: await this.generateMemoryHierarchy(rules, projectContext, categoryFilter),
slashCommands: await this.generateSlashCommands(rules, projectContext, categoryFilter),
mcpIntegrations: await this.generateMcpIntegrations(rules, projectContext),
settings: await this.generateClaudeSettings(rules, projectContext),
};
// Ensure .claude directory exists
await fs.ensureDir(this.claudeConfigPath);
await fs.ensureDir(path.join(this.claudeConfigPath, 'commands'));
// Generate memory files
for (const memory of adapted.memoryHierarchy) {
await fs.writeFile(memory.path, memory.content);
adapted.files.push(memory.path);
}
// Generate slash commands
for (const command of adapted.slashCommands) {
const commandPath = path.join(this.claudeConfigPath, 'commands', `${command.name}.md`);
await fs.writeFile(commandPath, command.content);
adapted.files.push(commandPath);
}
// Generate settings
if (adapted.settings) {
const settingsPath = path.join(this.claudeConfigPath, 'settings.json');
await fs.writeFile(settingsPath, JSON.stringify(adapted.settings, null, 2));
adapted.files.push(settingsPath);
}
console.log(`✅ Generated ${adapted.files.length} Claude Code files`);
return adapted;
}
/**
* Generate hierarchical memory structure using CORRECT Claude Code format
*/
async generateMemoryHierarchy(rules, projectContext, categoryFilter = null) {
const memories = [];
const projectName = projectContext.name || path.basename(this.projectPath);
// Fetch technology-specific rules from remote repository
let technologyRules = [];
if (this.ruleGenerator && this.ruleGenerator.fetchFromRepository) {
try {
console.log('🔍 Fetching technology-specific rules for Claude Code...');
// Use the full projectContext as analysisData since it contains technologyData
technologyRules = await this.ruleGenerator.fetchFromRepository(
projectContext,
'rules',
null, // No specific platform filter for rules
categoryFilter
);
console.log(`📚 Fetched ${technologyRules.length} technology-specific rules`);
if (technologyRules.length > 0) {
console.log(`📋 Rule names: ${technologyRules.map((r) => r.name).join(', ')}`);
}
} catch (error) {
console.warn(`⚠️ Failed to fetch technology rules: ${error.message}`);
}
}
// Main project memory with CORRECT Claude Code structure and technology rules
const mainMemory = await this.generateCorrectClaudeMainMemory(
rules,
projectContext,
technologyRules
);
memories.push({
path: path.join(this.projectPath, 'CLAUDE.md'),
content: mainMemory,
type: 'project',
priority: 'high',
});
return memories;
}
/**
* Generate CORRECT Claude Code memory structure as per report findings
*/
async generateCorrectClaudeMainMemory(rules, projectContext, technologyRules = []) {
const projectName = projectContext.name || path.basename(this.projectPath);
// Handle both techStack and technologyData structure
const techData = projectContext.techStack || projectContext.technologyData || {};
const frameworks = techData.frameworks || [];
const languages = techData.primaryLanguages || [];
const libraries = techData.libraries || [];
const packageManager = await this.detectPackageManager(projectContext);
const buildTool = await this.detectBuildTool(projectContext);
const testFramework = techData.testFramework || 'jest';
// Extract technology-specific guidelines from remote rules
const technologyGuidelines = await this.extractTechnologyGuidelines(
technologyRules,
projectContext
);
return `# ${projectName} - Claude Code Memory
## Project Overview
This is a **${this.determineProjectType(frameworks, languages)}** project.
### Key Information
- **Project Type**: ${this.determineProjectType(frameworks, languages)}
- **Primary Language**: ${languages.join(', ') || 'Not detected'}
- **Frameworks**: ${frameworks.join(', ') || 'Not detected'}
- **Libraries**: ${libraries.slice(0, 3).join(', ') || 'Standard libraries'}
## Coding Preferences
### Code Style
- Use ${this.detectIndentation(projectContext)} indentation
- Prefer ${languages.includes('TypeScript') ? 'TypeScript strict mode' : 'modern JavaScript'}
- ${this.generateStyleGuidelines(projectContext)}
### Project Structure
- Follow ${this.detectProjectStructure(projectContext)} structure
- ${this.generateStructureGuidelines(projectContext)}
### Testing
- Use ${testFramework} for testing
- ${this.generateTestingGuidelines(projectContext)}
## Development Environment
### Tools & Setup
- Package manager: ${packageManager}
- Build tool: ${buildTool}
- Primary IDE: ${await this.detectPrimaryIDE(projectContext)}
- AI Assistant: Claude Code
### Development Commands
- \`${await this.detectDevCommand(projectContext)}\` - Start development server
- \`${await this.detectTestCommand(projectContext)}\` - Run tests
- \`${await this.detectBuildCommand(projectContext)}\` - Build for production
## Technology-Specific Guidelines
${technologyGuidelines}
## Workflow Preferences
### Development Workflow
- Start with failing tests when appropriate
- Run tests before committing
- Use feature flags for incomplete features
- Plan for rollback strategies
### Communication
- Over-communicate in remote environments
- Document decisions and reasoning
- Share knowledge through code comments and docs
- Ask for clarification when requirements are unclear
---
*Generated by VDK CLI - Enhanced for Claude Code*
*Technology rules: ${technologyRules.length} rules integrated*`;
}
/**
* Determine project type based on frameworks and languages
*/
determineProjectType(frameworks, languages) {
// Prioritize Astro detection first since it's more specific
if (frameworks.includes('Astro') && frameworks.includes('Starlight')) {
return 'Astro Starlight Documentation Site';
}
if (frameworks.includes('Astro')) {
return 'Astro Application';
}
if (frameworks.includes('Next.js') && frameworks.includes('Supabase')) {
return 'Next.js + Supabase Full-Stack Application';
}
if (frameworks.includes('Next.js')) {
return 'Next.js Application';
}
if (frameworks.includes('React')) {
return 'React Application';
}
if (frameworks.includes('Vue.js')) {
return 'Vue.js Application';
}
if (languages.includes('typescript')) {
return 'TypeScript Application';
}
if (languages.includes('javascript')) {
return 'JavaScript Application';
}
return 'Web Application';
}
/**
* Extract technology-specific guidelines from remote rules
*/
async extractTechnologyGuidelines(technologyRules, projectContext) {
if (!technologyRules || technologyRules.length === 0) {
return `### General Guidelines
- Follow established patterns in the codebase
- Maintain consistency with existing code
- Use project-specific conventions`;
}
console.log(
`🔍 Processing ${technologyRules.length} technology rules for guidelines extraction`
);
if (this.verbose) {
technologyRules.forEach((rule) => {
console.log(` 📄 Rule: ${rule.name}, Content length: ${rule.content?.length || 0}`);
});
}
const guidelines = [];
// Handle both techStack and technologyData structure
const techData = projectContext.techStack || projectContext.technologyData || {};
const frameworks = techData.frameworks || [];
const languages = techData.primaryLanguages || [];
// Group rules by category for better organization
const rulesByCategory = this.groupRulesByCategory(technologyRules);
// Extract framework-specific guidelines
for (const framework of frameworks) {
// Enhanced framework matching with aliases
const frameworkLower = framework.toLowerCase();
const frameworkAliases = {
'tailwind css': ['tailwind', 'tailwindcss'],
'next.js': ['nextjs'],
supabase: ['supabase'],
react: ['react'],
typescript: ['typescript', 'ts'],
'shadcn/ui': ['shadcn', 'shadcnui'],
};
const searchTerms = [frameworkLower];
if (frameworkAliases[frameworkLower]) {
searchTerms.push(...frameworkAliases[frameworkLower]);
}
const frameworkRules = technologyRules.filter((rule) =>
searchTerms.some(
(term) =>
rule.name.toLowerCase().includes(term) || rule.path?.toLowerCase().includes(term)
)
);
if (frameworkRules.length > 0) {
guidelines.push(`### ${framework} Guidelines`);
for (const rule of frameworkRules.slice(0, 3)) {
// Limit to 3 most relevant
const extractedContent = this.extractRuleContent(rule.content, projectContext);
if (extractedContent) {
guidelines.push(extractedContent);
}
}
guidelines.push(''); // Add spacing
}
}
// Extract language-specific guidelines
for (const language of languages) {
const languageRules = technologyRules.filter(
(rule) =>
rule.name.toLowerCase().includes(language.toLowerCase()) ||
rule.path?.toLowerCase().includes(language.toLowerCase())
);
if (languageRules.length > 0) {
guidelines.push(`### ${language} Guidelines`);
for (const rule of languageRules.slice(0, 2)) {
// Limit to 2 most relevant
const extractedContent = this.extractRuleContent(rule.content, projectContext);
if (extractedContent) {
guidelines.push(extractedContent);
}
}
guidelines.push(''); // Add spacing
}
}
// Extract library-specific guidelines (important for shadcn/ui, etc.)
const libraries = techData.libraries || [];
for (const library of libraries) {
const libraryLower = library.toLowerCase();
const libraryAliases = {
'shadcn/ui': ['shadcn', 'shadcnui'],
'tailwind css': ['tailwind', 'tailwindcss'],
'radix ui': ['radix'],
'framer motion': ['framer'],
};
const searchTerms = [libraryLower];
if (libraryAliases[libraryLower]) {
searchTerms.push(...libraryAliases[libraryLower]);
}
const libraryRules = technologyRules.filter((rule) =>
searchTerms.some(
(term) =>
rule.name.toLowerCase().includes(term) || rule.path?.toLowerCase().includes(term)
)
);
if (libraryRules.length > 0) {
guidelines.push(`### ${library} Guidelines`);
for (const rule of libraryRules.slice(0, 2)) {
// Limit to 2 most relevant
const extractedContent = this.extractRuleContent(rule.content, projectContext);
if (extractedContent) {
guidelines.push(extractedContent);
}
}
guidelines.push(''); // Add spacing
}
}
// Add core/general rules
const coreRules = technologyRules.filter(
(rule) =>
rule.path?.includes('core/') || rule.name.includes('core') || rule.name.includes('general')
);
if (coreRules.length > 0) {
guidelines.push(`### Core Development Practices`);
for (const rule of coreRules.slice(0, 2)) {
const extractedContent = this.extractRuleContent(rule.content);
if (extractedContent) {
guidelines.push(extractedContent);
}
}
}
return guidelines.length > 0
? guidelines.join('\n')
: `### Project-Specific Guidelines
- Follow patterns established in this ${frameworks.join('/')} codebase
- Maintain consistency with existing ${languages.join('/')} code
- Reference remote rules: ${technologyRules.length} rules available`;
}
/**
* Extract relevant content from a rule's markdown content
*/
extractRuleContent(content, projectContext = null) {
if (!content) return null;
try {
// Remove frontmatter (YAML between ---)
const withoutFrontmatter = this.stripFrontmatter(content);
// Split into lines and process
const lines = withoutFrontmatter.split('\n');
const relevantLines = [];
let currentSection = null;
let captureContent = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const trimmed = line.trim();
if (!trimmed) continue;
// Check for section headers that indicate useful content
if (
trimmed.match(
/^#+\s*(core principles|best practices|guidelines|rules|conventions|patterns|key concepts|important|essential|recommendations|development practices|coding standards)/i
)
) {
currentSection = trimmed.replace(/^#+\s*/, '');
captureContent = true;
continue;
}
// Check for technology-specific sections
if (
trimmed.match(
/^#+\s*(typescript|nextjs|supabase|react|development|code)\s+(guidelines|best practices|rules|patterns|conventions)/i
)
) {
currentSection = trimmed.replace(/^#+\s*/, '');
captureContent = true;
continue;
}
// Stop capturing if we hit unrelated sections or tech stacks (which are just lists)
if (
trimmed.match(
/^#+\s+(meta|compatibility|examples|implementation|setup|overview|tech stack|technology stack|recommended|stack)/i
)
) {
captureContent = false;
continue;
}
// Capture content if we're in a relevant section
if (captureContent) {
// CRITICAL: Filter out mobile/native patterns for web projects
const isMobilePattern = this.isMobilePattern(trimmed);
const isWebProject = this.isWebProject(projectContext);
if (isWebProject && isMobilePattern) {
continue; // Skip mobile patterns for web projects
}
// Skip technology lists that start with **Technology** (like **Next.js 15+**)
if (trimmed.match(/^-\s*\*\*[A-Z][^*]+\*\*\s*(with|for|v?\d)/i)) {
continue; // Skip technology stack items
}
// Capture bullet points that are actual guidelines (contain action words)
if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
if (this.isActionableGuideline(trimmed)) {
relevantLines.push(trimmed);
}
}
// Capture numbered lists that are guidelines
else if (trimmed.match(/^\d+\.\s/)) {
const content = trimmed.replace(/^\d+\.\s/, '');
if (this.isActionableGuideline(content)) {
relevantLines.push(`- ${content}`);
}
}
// Capture important standalone statements
else if (
trimmed.length > 25 &&
!trimmed.startsWith('#') &&
(trimmed.includes('should') ||
trimmed.includes('must') ||
trimmed.includes('prefer') ||
trimmed.includes('avoid') ||
trimmed.includes('use') ||
trimmed.includes('always') ||
trimmed.includes('never') ||
trimmed.includes('implement'))
) {
relevantLines.push(`- ${trimmed}`);
}
}
// Limit content extraction
if (relevantLines.length >= 10) break;
}
// If no structured content found, extract first few bullet points from anywhere
if (relevantLines.length === 0) {
const bullets = lines
.filter((line) => {
const trimmed = line.trim();
return (trimmed.startsWith('- ') || trimmed.startsWith('* ')) && trimmed.length > 15;
})
.slice(0, 5);
return bullets.length > 0 ? bullets.join('\n') : null;
}
return relevantLines.slice(0, 8).join('\n'); // Limit to 8 most relevant points
} catch (error) {
console.warn(`Failed to extract content from rule: ${error.message}`);
return null;
}
}
/**
* Strip YAML frontmatter from content (reusing RuleAdapter pattern)
*/
stripFrontmatter(content) {
if (content.startsWith('---')) {
const parts = content.split('---');
return parts.slice(2).join('---').trim();
}
return content;
}
/**
* Check if a line contains mobile/native patterns that shouldn't be in web projects
*/
isMobilePattern(line) {
const mobilePatternsLower = line.toLowerCase();
return (
mobilePatternsLower.includes('expo-font') ||
mobilePatternsLower.includes('react-native') ||
(mobilePatternsLower.includes('usecolorscheme') &&
mobilePatternsLower.includes('react-native')) ||
mobilePatternsLower.includes('expo router') ||
mobilePatternsLower.includes('@expo/') ||
(mobilePatternsLower.includes('error boundaries') &&
mobilePatternsLower.includes('navigation tree')) ||
(mobilePatternsLower.includes('ios') && mobilePatternsLower.includes('android')) ||
(mobilePatternsLower.includes('mobile') &&
(mobilePatternsLower.includes('app') || mobilePatternsLower.includes('device'))) ||
(mobilePatternsLower.includes('native') && !mobilePatternsLower.includes('native web')) ||
mobilePatternsLower.includes('capacitor') ||
mobilePatternsLower.includes('cordova') ||
(mobilePatternsLower.includes('ionic') && !mobilePatternsLower.includes('ionic')) // Keep general ionic references
);
}
/**
* Check if the project is a web project (Next.js, React web, etc.)
*/
isWebProject(projectContext) {
const techData = projectContext.techStack || projectContext.technologyData || {};
const frameworks = techData.frameworks || [];
return frameworks.some((framework) => {
const fw = framework.toLowerCase();
return (
fw.includes('next.js') ||
fw.includes('nextjs') ||
(fw.includes('react') && !fw.includes('react native')) ||
fw.includes('vue.js') ||
fw.includes('angular') ||
fw.includes('nuxt') ||
fw.includes('remix') ||
fw.includes('gatsby') ||
(fw.includes('supabase') && !fw.includes('mobile'))
);
});
}
/**
* Check if a line contains actionable guidelines rather than just technology lists
*/
isActionableGuideline(line) {
const lineLower = line.toLowerCase();
// Skip technology stack items that just list versions/tools
const techStackPatterns = [
/\*\*[^*]+\*\*\s*(with|for|v?\d+)/i, // **Next.js 15+** with App Router
/\*\*[^*]+\*\*\s*for\s+/i, // **Supabase** for backend services
/\*\*[^*]+\d+\.\d+\*\*/i, // **TypeScript 5.4+**
/^-?\s*\*\*[A-Z]/, // **React 19+**
];
if (techStackPatterns.some((pattern) => pattern.test(line))) {
return false;
}
// Look for actionable language that indicates actual guidelines
const actionableWords = [
'use',
'avoid',
'prefer',
'should',
'must',
'always',
'never',
'implement',
'ensure',
'configure',
'setup',
'create',
'define',
'follow',
'apply',
'enable',
'disable',
'keep',
'make',
'write',
'structure',
'organize',
'split',
'extract',
'handle',
'manage',
'validate',
'sanitize',
'optimize',
'test',
'document',
'review',
];
return actionableWords.some((word) => lineLower.includes(word)) && line.length > 20;
}
/**
* Group rules by category for better organization
*/
groupRulesByCategory(rules) {
const categories = {
frameworks: [],
languages: [],
stacks: [],
technologies: [],
core: [],
other: [],
};
for (const rule of rules) {
const path = rule.path?.toLowerCase() || '';
const name = rule.name?.toLowerCase() || '';
if (path.includes('frameworks/') || name.includes('framework')) {
categories.frameworks.push(rule);
} else if (path.includes('languages/') || name.includes('language')) {
categories.languages.push(rule);
} else if (path.includes('stacks/') || name.includes('stack')) {
categories.stacks.push(rule);
} else if (path.includes('technologies/') || name.includes('tech')) {
categories.technologies.push(rule);
} else if (path.includes('core/') || name.includes('core')) {
categories.core.push(rule);
} else {
categories.other.push(rule);
}
}
return categories;
}
/**
* Generate CORRECT Claude Code settings.json with permissions system
*/
async generateClaudeSettings(rules, projectContext) {
const packageManager = projectContext.techStack?.packageManager || 'npm';
const frameworks = projectContext.techStack?.frameworks || [];
const settings = {
allowedTools: [
'Read(src/**)',
'Edit(src/**)',
`Bash(${packageManager} run:*)`,
'Bash(git status)',
'Bash(git add:*)',
'Bash(git commit:*)',
'Bash(git diff:*)',
'Bash(git log:*)',
'Glob(**/*.js)',
'Glob(**/*.ts)',
'Glob(**/*.tsx)',
'Grep(*)',
],
deniedTools: [
'Bash(rm -rf:*)',
'Bash(sudo:*)',
'Edit(.env*)',
'Write(node_modules/**/*)',
'Write(.git/**/*)',
],
env: {
BASH_DEFAULT_TIMEOUT_MS: this.getOptimalTimeout(projectContext),
PROJECT_NAME: projectContext.name || path.basename(this.projectPath),
},
};
// Add framework-specific permissions
for (const framework of frameworks) {
const frameworkPermissions = this.getFrameworkPermissions(framework);
settings.allowedTools.push(...frameworkPermissions);
}
// Add project-specific environment variables
if (projectContext.techStack?.buildTools?.includes('vite')) {
settings.env.VITE_DEV_MODE = 'true';
}
if (projectContext.techStack?.testingFrameworks?.includes('jest')) {
settings.allowedTools.push('Bash(npm run test:*)', 'Bash(jest:*)');
}
return settings;
}
// Helper methods for Claude Code structure
detectIndentation(projectContext) {
if (projectContext.techStack?.languages?.includes('Python')) return '4-space';
if (projectContext.techStack?.languages?.includes('Go')) return '4-space';
return '2-space';
}
generateStyleGuidelines(projectContext) {
const guidelines = [];
if (projectContext.techStack?.frameworks?.includes('React')) {
guidelines.push('Use functional components with hooks');
}
if (projectContext.techStack?.languages?.includes('TypeScript')) {
guidelines.push('Always use TypeScript strict mode');
}
return guidelines.join('\n- ') || 'Follow project conventions';
}
detectProjectStructure(projectContext) {
if (projectContext.techStack?.frameworks?.includes('Next.js')) return 'Next.js App Router';
if (projectContext.techStack?.frameworks?.includes('React')) return 'React component-based';
return 'standard module';
}
generateStructureGuidelines(projectContext) {
if (projectContext.techStack?.frameworks?.includes('React')) {
return 'Keep components in src/components/, hooks in src/hooks/';
}
return 'Follow conventional directory structures';
}
generateTestingGuidelines(projectContext) {
return 'Write tests for all business logic, use descriptive test names';
}
async detectPrimaryIDE(projectContext) {
try {
const projectPath = projectContext.projectPath || this.projectPath;
// Check for IDE-specific files and folders
const ideIndicators = {
'VS Code': ['.vscode/', '.vscode/settings.json', '.vscode/launch.json'],
Cursor: ['.cursor/', 'cursor.json', '.cursorrules'],
Windsurf: ['.windsurf/', '.windsurfrules.md', '.codeium/'],
JetBrains: ['.idea/', '*.iml'],
Zed: ['.zed/', 'zed.json'],
};
for (const [ide, indicators] of Object.entries(ideIndicators)) {
for (const indicator of indicators) {
if (await this.fileExists(path.join(projectPath, indicator))) {
return ide;
}
}
}
// Additional detection methods for VS Code without .vscode folder:
// 1. Check for VS Code specific extensions in package.json
const packageJsonPath = path.join(projectPath, 'package.json');
if (await this.fileExists(packageJsonPath)) {
const packageContent = await fs.readFile(packageJsonPath, 'utf8');
const packageData = JSON.parse(packageContent);
// Check for VS Code extension development
if (
packageData.contributes ||
packageData.engines?.vscode ||
packageData.categories?.includes('Extension Packs') ||
packageData.main?.includes('extension.js')
) {
return 'VS Code';
}
// Check for common VS Code specific dev dependencies
const vscodeDevDeps = ['@types/vscode', 'vscode-test', '@vscode/test-electron'];
const allDeps = { ...packageData.dependencies, ...packageData.devDependencies };
if (vscodeDevDeps.some((dep) => allDeps[dep])) {
return 'VS Code';
}
}
// 2. Check for common workspace files that suggest VS Code
const vscodeWorkspaceFiles = ['*.code-workspace', 'workspace.json'];
for (const pattern of vscodeWorkspaceFiles) {
// This is a simplified check - in practice you'd use glob matching
if (await this.fileExists(path.join(projectPath, pattern.replace('*', 'project')))) {
return 'VS Code';
}
}
return 'Not specified';
} catch (error) {
return 'Not specified';
}
}
/**
* Detects package manager by checking lock files
*/
async detectPackageManager(projectContext) {
try {
const projectPath = projectContext.projectPath || this.projectPath;
// Check for lock files in order of preference
if (await this.fileExists(path.join(projectPath, 'pnpm-lock.yaml'))) {
return 'pnpm';
}
if (await this.fileExists(path.join(projectPath, 'yarn.lock'))) {
return 'yarn';
}
if (await this.fileExists(path.join(projectPath, 'bun.lockb'))) {
return 'bun';
}
if (await this.fileExists(path.join(projectPath, 'package-lock.json'))) {
return 'npm';
}
// Default fallback
return 'npm';
} catch (error) {
return 'npm';
}
}
/**
* Helper to check if file exists
*/
async fileExists(filePath) {
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}
/**
* Extract actual scripts from package.json
*/
async extractPackageScripts(projectContext) {
try {
const projectPath = projectContext.projectPath || this.projectPath;
const packageJsonPath = path.join(projectPath, 'package.json');
if (await this.fileExists(packageJsonPath)) {
const packageJsonContent = await fs.readFile(packageJsonPath, 'utf8');
const packageData = JSON.parse(packageJsonContent);
return packageData.scripts || {};
}
} catch (error) {
// Silently fail and return empty object
}
return {};
}
async detectDevCommand(projectContext) {
const pm = await this.detectPackageManager(projectContext);
const scripts = await this.extractPackageScripts(projectContext);
// Check for common dev script variations
if (scripts.dev) return `${pm} run dev`;
if (scripts.start) return `${pm} run start`;
if (scripts.serve) return `${pm} run serve`;
return `${pm} run dev`;
}
async detectTestCommand(projectContext) {
const pm = await this.detectPackageManager(projectContext);
const scripts = await this.extractPackageScripts(projectContext);
if (scripts.test) return `${pm} run test`;
if (scripts['test:unit']) return `${pm} run test:unit`;
return `${pm} run test`;
}
async detectBuildCommand(projectContext) {
const pm = await this.detectPackageManager(projectContext);
const scripts = await this.extractPackageScripts(projectContext);
if (scripts.build) return `${pm} run build`;
if (scripts['build:prod']) return `${pm} run build:prod`;
return `${pm} run build`;
}
async detectBuildTool(projectContext) {
const techData = projectContext.techStack || projectContext.technologyData || {};
const frameworks = techData.frameworks || [];
// Check for turbopack in Next.js projects
if (
frameworks.some(
(fw) => fw.toLowerCase().includes('next.js') || fw.toLowerCase().includes('nextjs')
)
) {
const scripts = await this.extractPackageScripts(projectContext);
// Check if dev script uses --turbo flag
if (scripts.dev && scripts.dev.includes('--turbo')) {
return 'Turbopack (Next.js)';
}
return 'Next.js';
}
if (frameworks.some((fw) => fw.toLowerCase().includes('nuxt'))) {
return 'Nuxt.js';
}
if (frameworks.some((fw) => fw.toLowerCase().includes('gatsby'))) {
return 'Gatsby';
}
if (frameworks.some((fw) => fw.toLowerCase().includes('astro'))) {
return 'Astro';
}
// Check for build tools in libraries/buildTools
const buildTools = techData.buildTools || [];
if (buildTools.includes('Vite')) return 'Vite';
if (buildTools.includes('Webpack')) return 'Webpack';
if (buildTools.includes('esbuild')) return 'esbuild';
if (buildTools.includes('Rollup')) return 'Rollup';
if (buildTools.includes('Parcel')) return 'Parcel';
// Default fallback
return 'npm scripts';
}
generateWorkflowPreferences(rules, projectContext) {
return `### Development Workflow
- Start with failing tests when appropriate
- Run tests before committing
- Use feature flags for incomplete features
- Plan for rollback strategies
### Framework-Specific Guidelines
${this.generateFrameworkSpecificGuidelines(projectContext)}`;
}
generateFrameworkSpecificGuidelines(projectContext) {
const frameworks = projectContext.techStack?.frameworks || [];
const guidelines = [];
if (frameworks.includes('React')) {
guidelines.push('- Use React hooks over class components');
guidelines.push('- Implement proper state management patterns');
}
if (frameworks.includes('Next.js')) {
guidelines.push('- Use App Router for new routes');
guidelines.push('- Leverage server components when possible');
}
return guidelines.join('\n') || '- Follow established patterns in the codebase';
}
getOptimalTimeout(projectContext) {
// Longer timeout for complex builds
if (projectContext.techStack?.frameworks?.includes('Next.js')) return '180000';
return '120000';
}
/**
* Generate main CLAUDE.md with import-based structure
*/
async generateMainMemory(rules, projectContext) {
const projectName = path.basename(this.projectPath);
const primaryLanguages = projectContext.techStack?.primaryLanguages || ['JavaScript'];
const frameworks = projectContext.techStack?.frameworks || [];
return `# ${projectName} - Claude Code Memory
## Project Overview
${projectContext.description || `${projectName} is a ${frameworks.join(', ') || primaryLanguages.join(', ')} project.`}
## Import Hierarchy
@CLAUDE-patterns.md
@CLAUDE-integrations.md
## Quick Commands
${await this.generateQuickCommandsSection(rules, projectContext)}
## Development Context
### Technology Stack
- **Languages**: ${primaryLanguages.join(', ')}
${frameworks.length > 0 ? `- **Frameworks**: ${frameworks.join(', ')}` : ''}
${projectContext.techStack?.libraries?.length > 0 ? `- **Libraries**: ${projectContext.techStack.libraries.slice(0, 5).join(', ')}` : ''}
### Project Structure
\`\`\`
${await this.generateProjectStructureSummary(projectContext)}
\`\`\`
## Development Commands
${await this.generateDevelopmentCommands(projectContext)}
## Coding Standards
${await this.generateCodingStandards(rules, projectContext)}
## Team Collaboration
- **Memory Management**: Use import-based structure for personal preferences
- **Slash Commands**: Available in \`.claude/commands/\` directory
- **Settings**: Configured in \`.claude/settings.json\`
## Personal Preferences Import
@~/.claude/my-project-preferences.md
---
*Generated by VDK CLI - Enhanced Claude Code Integration*
*Last updated: ${new Date().toISOString().split('T')[0]}*`;
}
/**
* Generate CLAUDE-patterns.md for code patterns and conventions
*/
async generatePatternsMemory(rules, projectContext) {
const patterns = projectContext.patterns || {};
const namingConventions = patterns.namingConventions || {};
return `# Code Patterns and Conventions
## Naming Conventions
${await this.generateNamingConventions(namingConventions)}
## Architectural Patterns
${await this.generateArchitecturalPatterns(patterns.architecturalPatterns || [])}
## Code Organization
${await this.generateCodeOrganization(projectContext)}
## Framework-Specific Patterns
${await this.generateFrameworkPatterns(rules, projectContext)}
## Testing Patterns
${await this.generateTestingPatterns(rules, projectContext)}
## Error Handling Patterns
${await this.generateErrorHandlingPatterns(rules, projectContext)}
## Performance Patterns
${await this.generatePerformancePatterns(rules, projectContext)}
---
*This file contains project-specific patterns discovered through codebase analysis*`;
}
/**
* Generate CLAUDE-integrations.md for MCP and tool integrations
*/
async generateIntegrationsMemory(rules, projectContext) {
return `# Claude Code Integrations
## MCP Server Configuration
${await this.generateMcpServerConfig(rules, projectContext)}
## Available Tools
${await this.generateAvailableTools(rules, projectContext)}
## Permission Configuration
${await this.generatePermissionConfig(rules, projectContext)}
## Hook System Integration
${await this.generateHookIntegration(rules, projectContext)}
## IDE Integration
- **Primary IDE**: ${this.detectPrimaryIDE(projectContext)}
- **Extensions**: Auto-detection enabled
- **Diff Viewer**: Configured for IDE integration
## External Services
${await this.generateExternalServices(rules, projectContext)}
---
*This file manages Claude Code's integration with external tools and services*`;
}
/**
* Generate sophisticated slash commands by fetching from remote repository
*/
async generateSlashCommands(rules, projectContext, categoryFilter = null) {
try {
// Use the centralized repository fetch method from RuleGenerator
if (this.ruleGenerator && this.ruleGenerator.fetchFromRepository) {
const remoteCommands = await this.ruleGenerator.fetchFromRepository(
projectContext,
'commands',
'claude-code',
categoryFilter
);
if (remoteCommands.length > 0) {
console.log(`✅ Fetched ${remoteCommands.length} commands from repository`);
// Transform the templates into command format
return this.transformTemplatesIntoCommands(remoteCommands, projectContext);
}
}
console.log('⚠️ No remote commands found, generating fallback commands');
console.log(chalk.yellow('💡 To get more commands when available:'));
console.log(chalk.gray(' • Check your GitHub token: VDK_GITHUB_TOKEN in .env.local'));
console.log(chalk.gray(' • Get a token from: https://github.com/settings/tokens'));
// Generate fallback commands based on detected technologies
return this.generateFallbackCommands(rules, projectContext, categoryFilter);
} catch (error) {
console.log(`⚠️ Failed to fetch remote commands: ${error.message}`);
if (error.message.includes('401')) {
console.log(chalk.yellow('💡 GitHub authentication failed. To enable command fetching:'));
console.log(chalk.gray(' • Add VDK_GITHUB_TOKEN=your_token to .env.local'));
console.log(chalk.gray(' • Get a token from: https://github.com/settings/tokens'));
console.log(chalk.gray(' • Token needs "public_repo" access for public repositories'));
}
// Generate fallback commands even when remote fetch fails
return this.generateFallbackCommands(rules, projectContext, categoryFilter);
}
}
/**
* Generate fallback commands when remote fetch fails
* @param {Array} rules - Available rules
* @param {Object} projectContext - Project context
* @param {Object} categoryFilter - Category filter
* @returns {Array} Fallback commands
*/
generateFallbackCommands(rules, projectContext, categoryFilter = null) {
const commands = [];
const frameworks = projectContext.techStack?.frameworks || [];
const languages = projectContext.techStack?.primaryLanguages || [];
const isAstroProject = frameworks.some((fw) => fw.toLowerCase().includes('astro'));
const isNextJSProject = frameworks.some((fw) => fw.toLowerCase().includes('next'));
const isContentProject = frameworks.some(
(fw) => fw.toLowerCase().includes('starlight') || fw.toLowerCase().includes('content')
);
// Core development commands (always included)
commands.push({
name: 'review-code',
description: 'Comprehensive code review and analysis',
content: `Perform a thorough code review focusing on:
- Code quality and best practices
- Performance optimizations
- Security considerations
- Architecture and design patterns
- Testing coverage
Provide specific, actionable feedback with examples.`,
});
commands.push({
name: 'debug-issue',
description: 'Debug and troubleshoot issues',
content: `Help debug the current issue by:
- Analyzing error messages and stack traces
- Identifying potential root causes
- Suggesting debugging strategies
- Providing step-by-step troubleshooting
Ask for relevant code, logs, or error details if needed.`,
});
commands.push({
name: 'optimize-performance',
description: 'Analyze and optimize performance',
content: `Analyze performance bottlenecks and provide optimization recommendations:
- Code performance analysis
- Bundle size optimization
- Runtime performance improvements
- Best practices for ${frameworks[0] || 'the current stack'}
Focus on measurable improvements with implementation examples.`,
});
// Astro-specific commands
if (isAstroProject) {
commands.push({
name: 'create-astro-component',
description: 'Create new Astro component following project patterns',
content: `Create a new Astro component with:
- Proper TypeScript typing
- Scoped CSS styling
- Props validation
- SEO optimization if needed
- Component documentation
Follow established project patterns for consistency.
## Arguments
- Component name (required): $ARGUMENTS
- Component type: page|layout|ui (default: ui)`,
});
if (isContentProject) {
commands.push({
name: 'create-content-page',
description: 'Create new content page with proper frontmatter',
content: `Create a new content page with:
- Proper frontmatter structure
- SEO metadata
- Navigation integration
- Content structure following site patterns
## Arguments
- Page title (required): $ARGUMENTS
- Content category: guide|reference|tutorial (default: guide)`,
});
commands.push({
name: 'update-navigation',
description: 'Update site navigation and content structure',
content: `Update the site navigation to include new content:
- Add to sidebar configuration
- Update content collections
- Ensure proper ordering
- Maintain consistent navigation patterns
Review current navigation structure and suggest improvements.`,
});
}
}
// Next.js specific commands
if (isNextJSProject) {
commands.push({
name: 'create-nextjs-page',
description: 'Create new Next.js page with App Router',
content: `Create a new Next.js page using App Router:
- Server Component by default
- Proper TypeScript typing
- SEO metadata
- Error boundaries
- Loading states
## Arguments
- Page path (required): $ARGUMENTS
- Page type: static|dynamic|api (default: static)`,
});
commands.push({
name: 'create-api-route',
description: 'Create new API route with validation',
content: `Create a new API route with:
- Request/response typing
- Input validation
- Error handling
- Rate limiting considerations
- Proper HTTP status codes
## Arguments
- Route path (required): $ARGUMENTS
- HTTP method: GET|POST|PUT|DELETE (default: GET)`,
});
}
// TypeScript specific commands
if (languages.includes('typescript') || languages.includes('TypeScript')) {
commands.push({
name: 'improve-types',
description: 'Improve TypeScript types and interfaces',
content: `Analyze and improve TypeScript usage:
- Add missing type annotations
- Improve type safety
- Reduce any usage
- Create utility types where beneficial
- Improve interface design
Focus on making types more precise and maintainable.`,
});
}
// Filter by categories if specified
if (categoryFilter?.categories) {
const allowedCategories = categoryFilter.categories;
return commands.filter((cmd) => {
// Map commands to categories (simplified)
const commandCategories = {
'review-code': ['development', 'quality'],
'debug-issue': ['development'],
'optimize-performance': ['development', 'quality'],
'create-astro-component': ['development'],
'create-content-page': ['development', 'workflow'],
'update-navigation': ['workflow'],
'create-nextjs-page': ['development'],
'create-api-route': ['development'],
'improve-types': ['development', 'quality'],
};
const cmdCategories = commandCategories[cmd.name] || ['development'];
return cmdCategories.some((cat) => allowedCategories.includes(cat));
});
}
return commands;
}
/**
* Transform repository templates into Claude Code command format
* @param {Array} templates - Templates from repository
* @param {Object} projectContext - Project context
* @returns {Array} Commands in Claude Code format
*/
transformTemplatesIntoCommands(templates, projectContext) {
const commands = [];
for (const template of templates) {
try {
// Parse the template content as a command
const parsedCommand = this.parseClaudeCodeCommand(template.content);
if (parsedCommand) {
commands.push({
name: template.name.replace('.md', ''),
content: template.content,
metadata: parsedCommand,
category: this.getCategoryFromPath(template.path),
source: 'repository',
relevanceScore: template.relevanceScore || 0.5,
});
}
} catch (error) {
console.log(`Warning: Could not parse command ${template.name}: ${error.message}`);
}
}
return commands.sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0));
}
/**
* Extract category from file path
* @param {string} path - File path
* @returns {string} Category name
*/
getCategoryFromPath(path) {
const pathParts = path.split('/');
// Path structure: .ai/commands/claude-code/category/command.md
if (pathParts.length >= 4) {
return pathParts[3]; // Get the category directory name
}
return 'general';
}
/**
* Fetch commands from VDK-Blueprints repository
*/
async fetchRemoteCommands(platform = 'claude-code', projectContext) {
const VDK_RULES_REPO_API_URL = 'https://api.github.com/repos/entro314-labs/VDK-Blueprints';
const commands = [];
try {
// Fetch command categories for the platform
const response = await fetch(`${VDK_RULES_REPO_API_URL}/contents/.ai/commands/${platform}`);
if (!response.ok) return [];
const categories = await response.json();
// Fetch commands from each category
for (const category of categories.filter((item) => item.type === 'dir')) {
try {
const categoryResponse = await fetch(category.url);
if (categoryResponse.ok) {
const commandFiles = await categoryResponse.json();
for (const file of commandFiles.filter((f) => f.name.endsWith('.md'))) {
const commandContent = await this.downloadFile(file.download_url);
if (commandContent) {
// Parse and validate command content
const parsedCommand = this.parseClaudeCodeCommand(commandContent);
if (parsedCommand && (await this.validateClaudeCodeCommand(parsedCommand))) {
commands.push({
name: file.name.replace('.md', ''),
content: commandContent,
metadata: parsedCommand,
category: category.name,
source: 'repository',
relevanceScore: this.calculateCommandRelevance(parsedCommand, projectContext),
});
}
}
}
}
} catch (error) {
console.log(`Could not fetch commands from ${category.name}: ${error.message}`);
}
}
} catch (error) {
console.log(`Failed to fetch command categories: ${error.message}`);
}
// Sort by relevance score
return commands.sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0));
}
/**
* Parse Claude Code command frontmatter
*/
parseClaudeCodeCommand(content) {
try {
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
if (!frontmatterMatch) return null;
// Simple YAML parsing for the schema fields
const yamlContent = frontmatterMatch[1];
const parsed = {};
const lines = yamlContent.split('\n');
let currentKey = null;
let currentObject = null;
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
if (line.match(/^[a-zA-Z]/)) {
// Top-level key
const [key, value] = trimmed.split(':').map((s) => s.trim());
if (value && value !== '') {
parsed[key] = value.replace(/['"]/g, '');
} else {
currentKey = key;
currentObject = {};
parsed[key] = currentObject;
}
} else if (currentObject && line.match(/^\s+[a-zA-Z]/)) {
// Nested key
const [key, value] = trimmed.split(':').map((s) => s.trim());
if (value && value !== '') {
currentObject[key] = value.replace(/['"]/g, '');
}
}
}
return parsed;
} catch (error) {
console.log(`Failed to parse command frontmatter: ${error.message}`);
return null;
}
}
/**
* Validate Claude Code command against the official schema
*/
async validateClaudeCodeCommand(commandData) {
if (!commandData) return false;
try {
const validation = await validateCommand(commandData);
if (!validation.valid) {
if (this.verbose) {
console.log(`Command validation failed:`);
validation.errors.forEach((error) => console.log(` - ${error}`));
}
return false;
}
return true;
} catch (error) {
console.log(`Schema validation error: ${error.message}`);
return false;
}
}
/**
* Calculate command relevance based on project context
*/
calculateCommandRelevance(commandData, projectContext) {
let score = 0.5; // Base score
const frameworks = projectContext.techStack?.frameworks || [];
const languages = projectContext.techStack?.primaryLanguages || [];
const tags = commandData.tags || [];
const category = commandData.category || '';
// Framework matching
frameworks.forEach((framework) => {
if (tags.some((tag) => tag.toLowerCase().includes(framework.toLowerCase()))) {
score += 0.3;
}
});
// Language matching
languages.forEach((language) => {
if (tags.some((tag) => tag.toLowerCase().includes(language.toLowerCase()))) {
score += 0.2;
}
});
// Category relevance
if