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

482 lines (408 loc) 15.9 kB
/** * GitHub Copilot Integration Module * -------------------------------- * Provides integration with GitHub Copilot Enterprise coding guidelines * and best practices for code completion and review features. */ import { execSync } from 'child_process'; import fs from 'fs'; import os from 'os'; import path from 'path'; import { BaseIntegration } from './base-integration.js'; /** * GitHub Copilot configuration and integration utilities */ export class GitHubCopilotIntegration extends BaseIntegration { constructor(projectPath = process.cwd()) { super('GitHub Copilot', projectPath); this.copilotConfigPath = path.join(projectPath, '.github'); this.copilotGuidelinesPath = path.join(this.copilotConfigPath, 'copilot'); } /** * Get GitHub Copilot configuration paths * @returns {Object} Configuration paths for GitHub Copilot */ getConfigPaths() { return { // GitHub Copilot Enterprise guidelines (repository level) githubDirectory: this.copilotConfigPath, copilotDirectory: this.copilotGuidelinesPath, guidelinesConfig: path.join(this.copilotGuidelinesPath, 'guidelines.json'), // Documentation files guidelinesDocs: path.join(this.copilotGuidelinesPath, 'README.md'), // VDK-specific Copilot configuration vdkCopilotConfig: path.join(this.copilotGuidelinesPath, 'vdk-config.json'), // Global GitHub CLI config (for detection) globalGitHubConfig: path.join(os.homedir(), '.config', 'gh'), }; } /** * Detect if GitHub Copilot is being used in the project * @returns {Object} Detection result with details */ detectUsage() { const detection = { isUsed: false, confidence: 'none', // none, low, medium, high indicators: [], recommendations: [], }; // 1. Check for .github directory and Copilot configuration if (this.directoryExists(this.copilotConfigPath)) { detection.indicators.push('Project has .github directory'); // Check for Copilot-specific files const copilotFiles = ['copilot/', 'CODEOWNERS', 'pull_request_template.md']; copilotFiles.forEach((file) => { const filePath = path.join(this.copilotConfigPath, file); if (this.directoryExists(filePath) || this.fileExists(filePath)) { detection.indicators.push(`Found .github/${file}`); if (file === 'copilot/') { detection.confidence = 'high'; detection.isUsed = true; } else if (detection.confidence === 'none') { detection.confidence = 'low'; } } }); } // 2. Check for GitHub CLI configuration const platformPaths = this.getPlatformPaths(); const githubPaths = [ path.join(platformPaths.home, '.config', 'gh'), path.join(platformPaths.home, '.gitconfig'), ]; githubPaths.forEach((githubPath) => { if (this.directoryExists(githubPath) || this.fileExists(githubPath)) { detection.indicators.push(`GitHub configuration found at ${githubPath}`); if (detection.confidence === 'none') { detection.confidence = 'low'; } } }); // 3. Check for GitHub CLI command availability if (this.commandExists('gh')) { detection.indicators.push('GitHub CLI (gh) is available'); if (detection.confidence === 'none') { detection.confidence = 'low'; } const version = this.getCommandVersion('gh', '--version'); if (version) { detection.indicators.push(`GitHub CLI version: ${version}`); } } // 4. Check for Git remote origins pointing to GitHub try { // execSync is already imported at the top const remoteOutput = execSync('git remote -v', { cwd: this.projectPath, encoding: 'utf8', stdio: 'pipe', }); if (remoteOutput.includes('github.com')) { detection.indicators.push('Repository has GitHub remote origin'); detection.isUsed = true; if (detection.confidence === 'none' || detection.confidence === 'low') { detection.confidence = 'medium'; } } } catch (error) { // Not a git repository or git not available } // 5. Check for existing Copilot guidelines if (this.directoryExists(this.copilotGuidelinesPath)) { detection.indicators.push('Found GitHub Copilot guidelines directory'); detection.confidence = 'high'; detection.isUsed = true; } // 6. Check .gitignore for GitHub-specific patterns const gitignorePatterns = this.checkGitignore(['.github']); if (gitignorePatterns.length > 0) { detection.indicators.push( `GitHub patterns found in .gitignore: ${gitignorePatterns.join(', ')}` ); } // 7. Generate recommendations based on detection if (detection.confidence === 'none') { detection.recommendations.push( 'GitHub Copilot not detected. Requires GitHub repository and Copilot Enterprise subscription' ); detection.recommendations.push('Install GitHub CLI: https://cli.github.com/'); } else if (detection.confidence === 'low') { detection.recommendations.push('GitHub detected but Copilot guidelines not configured'); detection.recommendations.push( 'Run: vdk init --ide-integration to set up Copilot integration' ); } else if (detection.confidence === 'medium') { detection.recommendations.push('GitHub repository detected'); detection.recommendations.push( 'Configure Copilot Enterprise guidelines in repository settings' ); } else if (detection.confidence === 'high') { detection.recommendations.push('GitHub Copilot guidelines are configured'); detection.recommendations.push( 'Consider reviewing and updating guidelines with VDK patterns' ); } return detection; } /** * Initialize GitHub Copilot configuration for VDK integration * @param {Object} options - Configuration options * @returns {boolean} Success status */ async initialize(options = {}) { const paths = this.getConfigPaths(); try { // Create .github/copilot directory structure await this.ensureDirectory(this.copilotConfigPath); await this.ensureDirectory(this.copilotGuidelinesPath); // Create VDK-specific Copilot configuration await this.createCopilotVDKConfig(options); // Create documentation for Copilot guidelines await this.createCopilotGuidelines(options); // Generate example guidelines based on project analysis await this.generateProjectSpecificGuidelines(options); return true; } catch (error) { console.error('Failed to initialize GitHub Copilot configuration:', error.message); return false; } } /** * Create VDK-specific Copilot configuration * @param {Object} options - Configuration options */ async createCopilotVDKConfig(options = {}) { const paths = this.getConfigPaths(); if (this.fileExists(paths.vdkCopilotConfig)) { return; // Don't overwrite existing config } const vdkConfig = { vdk: { enabled: true, version: '1.0.0', integration: 'github-copilot', projectName: options.projectName || path.basename(this.projectPath), }, copilot: { enterprise: options.hasEnterprise || false, codeReview: true, codeCompletion: true, guidelinesVersion: '1.0', }, guidelines: { maxGuidelines: 6, enforcementLevel: 'strict', languageSupport: options.languages || ['javascript', 'typescript', 'python'], autoUpdate: true, }, generated: { timestamp: new Date().toISOString(), source: 'vdk-cli', }, }; await this.writeJsonFile(paths.vdkCopilotConfig, vdkConfig); } /** * Create documentation for Copilot guidelines setup * @param {Object} options - Configuration options */ async createCopilotGuidelines(options = {}) { const paths = this.getConfigPaths(); if (this.fileExists(paths.guidelinesDocs)) { return; // Don't overwrite existing docs } const guidelinesContent = `# GitHub Copilot Guidelines for VDK Integration ## Overview This directory contains GitHub Copilot Enterprise coding guidelines generated by VDK CLI. These guidelines help ensure consistent code quality and adherence to project standards. ## Setup Instructions ### Prerequisites - GitHub Copilot Enterprise subscription - Repository admin access - VDK CLI configured for this project ### Configuration Steps 1. **Access Repository Settings** - Go to your repository on GitHub - Navigate to Settings → Code & automation → Copilot → Code review 2. **Add Guidelines** - Maximum 6 guidelines per repository - Each guideline: name + description (max 600 characters) - Optional file path patterns using fnmatch syntax 3. **Generated Guidelines** The VDK CLI has generated project-specific guidelines based on your codebase analysis: ${this.generateGuidelinesList(options)} ## File Path Patterns Use these patterns to scope guidelines to specific files: - \`**/*.js\` - All JavaScript files - \`**/*.ts\` - All TypeScript files - \`**/*.py\` - All Python files - \`src/**/*\` - All files in src directory - \`tests/**/*\` - All test files - \`**/*.test.*\` - All test files by extension ## Best Practices ### Effective Guidelines - Be specific about what Copilot should look for - Use clear, concise language - Focus on project-specific patterns - Avoid rules that linters can handle ### Guidelines to Avoid - Generic style rules (use ESLint/Prettier instead) - Ambiguous wording with multiple interpretations - Multiple different ideas in one guideline ## VDK Integration - Guidelines updated automatically with \`vdk sync\` - Project patterns detected and incorporated - Technology stack considerations included - Architecture patterns enforced --- *Generated by VDK CLI - Update with \`vdk copilot --refresh\`* `; await fs.promises.writeFile(paths.guidelinesDocs, guidelinesContent, 'utf8'); } /** * Generate project-specific guidelines based on VDK analysis * @param {Object} options - Project analysis results */ async generateProjectSpecificGuidelines(options = {}) { const guidelines = []; // Generate guidelines based on detected technology stack if (options.techStack) { if (options.techStack.frameworks?.includes('React')) { guidelines.push({ title: 'React Component Standards', description: 'Use functional components with hooks. Include proper prop typing with TypeScript. Add error boundaries for complex components.', paths: ['**/*.tsx', '**/*.jsx'], }); } if ( options.techStack.frameworks?.includes('Node.js') || options.techStack.frameworks?.includes('Express') ) { guidelines.push({ title: 'API Validation Requirements', description: 'Validate all input parameters. Use proper HTTP status codes. Implement error handling middleware. Add rate limiting where appropriate.', paths: ['src/api/**/*', 'src/routes/**/*', '**/*route*'], }); } if (options.techStack.primaryLanguages?.includes('TypeScript')) { guidelines.push({ title: 'TypeScript Best Practices', description: "Use strict type checking. Avoid 'any' types. Define proper interfaces for data structures. Use generic types for reusable components.", paths: ['**/*.ts', '**/*.tsx'], }); } if (options.techStack.primaryLanguages?.includes('Python')) { guidelines.push({ title: 'Python Code Standards', description: 'Follow PEP 8 guidelines. Use type hints for function parameters and returns. Include docstrings for classes and functions.', paths: ['**/*.py'], }); } } // Add general VDK guidelines guidelines.push({ title: 'VDK Integration Standards', description: 'Follow VDK CLI naming conventions. Use unified rule formats. Include proper error handling and logging patterns. Update documentation when adding features.', paths: [], }); guidelines.push({ title: 'Security Best Practices', description: 'Never commit secrets or API keys. Validate all user inputs. Use environment variables for configuration. Implement proper authentication patterns.', paths: [], }); // Save guidelines configuration const paths = this.getConfigPaths(); const guidelinesConfig = { guidelines: guidelines.slice(0, 6), // GitHub Copilot max 6 guidelines generated: { timestamp: new Date().toISOString(), source: 'vdk-cli', projectAnalysis: { techStack: options.techStack, patterns: options.patterns, }, }, }; await this.writeJsonFile(paths.guidelinesConfig, guidelinesConfig); } /** * Generate guidelines list for documentation * @param {Object} options - Configuration options * @returns {string} Formatted guidelines list */ generateGuidelinesList(options = {}) { const commonGuidelines = [ '**VDK Integration Standards** - Follow VDK CLI conventions and patterns', '**Security Best Practices** - Never commit secrets, validate inputs', '**Error Handling** - Implement proper error boundaries and logging', '**Documentation** - Update docs when adding features', '**Testing** - Include tests for new functionality', '**Performance** - Consider performance implications of changes', ]; return commonGuidelines.map((guideline) => ` - ${guideline}`).join('\n'); } /** * Check if GitHub Copilot Enterprise features are available * @returns {Promise<Object>} Feature availability status */ async getCopilotFeatures() { const features = { enterpriseAccess: false, codeReview: false, codeCompletion: false, customGuidelines: false, repositoryConfigured: false, }; try { // Check if we're in a GitHub repository // execSync is already imported at the top const remoteOutput = execSync('git remote -v', { cwd: this.projectPath, encoding: 'utf8', stdio: 'pipe', }); if (remoteOutput.includes('github.com')) { features.repositoryConfigured = true; // Basic features assume GitHub repository features.codeCompletion = true; // Enterprise features require subscription (can't detect programmatically) // User would need to configure manually } } catch (error) { // Not a git repository or no GitHub remote } // Check for Copilot configuration const paths = this.getConfigPaths(); if (this.fileExists(paths.vdkCopilotConfig)) { const config = await this.readJsonFile(paths.vdkCopilotConfig); features.enterpriseAccess = config?.copilot?.enterprise || false; features.customGuidelines = config?.copilot?.enterprise || false; features.codeReview = config?.copilot?.codeReview || false; } return features; } /** * Get GitHub Copilot status summary * @returns {Promise<Object>} Status summary object */ async getStatusSummary() { const detection = this.getCachedDetection(); const features = await this.getCopilotFeatures(); const paths = this.getConfigPaths(); return { isConfigured: detection.isUsed, confidence: detection.confidence, features, configPaths: paths, recommendations: detection.recommendations, enterpriseRequired: true, setupInstructions: 'Configure guidelines in GitHub repository settings', }; } }