@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
581 lines (505 loc) • 18.8 kB
JavaScript
/**
* Windsurf Integration Module
* ---------------------------
* Provides enhanced integration with Windsurf AI Editor,
* including Codeium AI features, Windsurf-specific configurations, and optimized workflows.
*/
import fs from 'fs';
import os from 'os';
import path from 'path';
import { BaseIntegration } from './base-integration.js';
/**
* Windsurf AI Editor configuration and integration utilities
*/
export class WindsurfIntegration extends BaseIntegration {
constructor(projectPath = process.cwd()) {
super('Windsurf', projectPath);
this.windsurfConfigPath = path.join(projectPath, '.windsurf');
this.globalWindsurfConfigPath = path.join(os.homedir(), '.codeium', 'windsurf');
}
/**
* Get Windsurf configuration paths (updated for native memories system)
* @returns {Object} Configuration paths for Windsurf
*/
getConfigPaths() {
return {
// Project-specific configurations
projectConfig: path.join(this.windsurfConfigPath, 'config.json'),
projectSettings: path.join(this.windsurfConfigPath, 'settings.json'),
rulesDirectory: path.join(this.windsurfConfigPath, 'rules'),
workspaceConfig: path.join(this.windsurfConfigPath, 'workspace.json'),
aiConfig: path.join(this.windsurfConfigPath, 'ai_settings.json'),
// Native Windsurf memories system
globalMemories: path.join(os.homedir(), '.codeium', 'windsurf', 'memories'),
globalRulesFile: path.join(
os.homedir(),
'.codeium',
'windsurf',
'memories',
'global_rules.md'
),
// Global configurations
globalConfig: path.join(this.globalWindsurfConfigPath, 'config.json'),
globalMcp: path.join(this.globalWindsurfConfigPath, 'mcp_config.json'),
projectMcp: path.join(this.windsurfConfigPath, 'mcp_config.json'),
codeiumConfig: path.join(os.homedir(), '.codeium', 'config'),
};
}
/**
* Detect if Windsurf is actively 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 .windsurf directory structure
if (this.directoryExists(this.windsurfConfigPath)) {
detection.indicators.push('Project has .windsurf directory');
detection.confidence = 'high';
detection.isUsed = true;
// Check for specific Windsurf files
const windsurfFiles = [
'config.json',
'settings.json',
'workspace.json',
'mcp_config.json',
'ai_settings.json',
];
windsurfFiles.forEach((file) => {
const filePath = path.join(this.windsurfConfigPath, file);
if (this.fileExists(filePath)) {
detection.indicators.push(`Found .windsurf/${file}`);
if (file === 'config.json' || file === 'ai_settings.json') {
detection.confidence = 'high';
}
}
});
// Check for rules directory and memories system
const rulesPath = path.join(this.windsurfConfigPath, 'rules');
if (this.directoryExists(rulesPath)) {
detection.indicators.push('Found .windsurf/rules directory');
detection.confidence = 'high';
}
// Check for native memories system
const memoriesPath = path.join(os.homedir(), '.codeium', 'windsurf', 'memories');
if (this.directoryExists(memoriesPath)) {
detection.indicators.push('Found Windsurf native memories directory');
detection.confidence = 'high';
}
}
// 2. Check for global Codeium/Windsurf installation
const platformPaths = this.getPlatformPaths();
const windsurfPaths = [
platformPaths.applications ? path.join(platformPaths.applications, 'Windsurf.app') : null,
platformPaths.applications ? path.join(platformPaths.applications, 'Codeium.app') : null,
platformPaths.home ? path.join(platformPaths.home, '.codeium') : null,
platformPaths.appData ? path.join(platformPaths.appData, 'Codeium') : null,
platformPaths.appData ? path.join(platformPaths.appData, 'Windsurf') : null,
].filter(Boolean);
windsurfPaths.forEach((windsurfPath) => {
if (this.directoryExists(windsurfPath)) {
detection.indicators.push(`Windsurf/Codeium installation found at ${windsurfPath}`);
if (detection.confidence === 'none') {
detection.confidence = 'low';
}
}
});
// 3. Check for Windsurf command availability
const commands = ['windsurf', 'codeium'];
commands.forEach((command) => {
if (this.commandExists(command)) {
detection.indicators.push(`${command} CLI command is available`);
if (detection.confidence === 'none') {
detection.confidence = 'medium';
}
const version = this.getCommandVersion(command, '--version');
if (version) {
detection.indicators.push(`${command} version: ${version}`);
}
}
});
// 4. Check for Windsurf-specific workspace indicators
const workspaceIndicators = ['.windsurf/', '.windsurf/rules/', '.codeium/'];
workspaceIndicators.forEach((indicator) => {
const indicatorPath = path.join(this.projectPath, indicator);
if (this.directoryExists(indicatorPath)) {
detection.indicators.push(`Workspace has ${indicator}`);
detection.isUsed = true;
if (detection.confidence === 'none' || detection.confidence === 'low') {
detection.confidence = 'medium';
}
}
});
// 5. Check for Codeium API configuration
try {
const codeiumConfigPath = path.join(os.homedir(), '.codeium', 'config');
if (this.fileExists(codeiumConfigPath)) {
detection.indicators.push('Codeium API configuration found');
if (detection.confidence === 'none') {
detection.confidence = 'low';
}
}
} catch (error) {
// Skip if homedir is not available
}
// 6. Check .gitignore for Windsurf patterns
const gitignorePatterns = this.checkGitignore(['.windsurf', '.codeium']);
if (gitignorePatterns.length > 0) {
detection.indicators.push(
`Windsurf paths found in .gitignore: ${gitignorePatterns.join(', ')}`
);
}
// 7. Check for recent Windsurf activity
const windsurfLogPaths = [
platformPaths.logs ? path.join(platformPaths.logs, 'Windsurf') : null,
platformPaths.logs ? path.join(platformPaths.logs, 'Codeium') : null,
platformPaths.home ? path.join(platformPaths.home, '.codeium', 'logs') : null,
].filter(Boolean);
windsurfLogPaths.forEach((logPath) => {
const recentLogs = this.getRecentActivity(logPath, 7);
if (recentLogs.length > 0) {
detection.indicators.push(`Recent Windsurf activity (${recentLogs.length} log files)`);
detection.isUsed = true;
detection.confidence = 'high';
}
});
// 8. Generate recommendations based on detection
if (detection.confidence === 'none') {
detection.recommendations.push(
'Windsurf not detected. Install from: https://codeium.com/windsurf'
);
} else if (detection.confidence === 'low') {
detection.recommendations.push(
'Windsurf may be installed but not configured for this project'
);
detection.recommendations.push(
'Run: vdk init --ide-integration to configure Windsurf integration'
);
} else if (detection.confidence === 'medium') {
detection.recommendations.push('Windsurf appears to be configured');
detection.recommendations.push('Consider optimizing AI rules for better Codeium assistance');
} else if (detection.confidence === 'high') {
detection.recommendations.push('Windsurf is actively configured and being used');
detection.recommendations.push(
'Consider leveraging Codeium supercomplete features with custom rules'
);
}
return detection;
}
/**
* Initialize Windsurf configuration for VDK integration
* @param {Object} options - Configuration options
* @returns {boolean} Success status
*/
async initialize(options = {}) {
const paths = this.getConfigPaths();
try {
// Create .windsurf directory structure
await this.ensureDirectory(this.windsurfConfigPath);
await this.ensureDirectory(paths.rulesDirectory);
// Create project-specific Windsurf configuration
if (!this.fileExists(paths.projectConfig)) {
const windsurfConfig = {
codeium: {
enabled: true,
supercomplete: true,
chat: true,
search: true,
},
ai: {
modelPreferences: {
chat: 'claude-3-5-sonnet',
autocomplete: 'codeium',
explanation: 'gpt-4',
},
features: {
contextAwareness: true,
projectScanning: true,
documentationGeneration: true,
},
},
vdk: {
enabled: true,
version: '1.0.0',
integration: 'windsurf',
rulesPath: '.windsurf/rules',
},
workspace: {
autoSave: true,
formatOnSave: true,
linting: true,
},
};
await this.writeJsonFile(paths.projectConfig, windsurfConfig);
}
// Create AI-specific settings
await this.createWindsurfAISettings(options);
// Create MCP configuration for Windsurf
await this.createWindsurfMCPConfig(options);
// Create Windsurf-specific AI rules
await this.createWindsurfAIRules(options);
// Create workspace configuration
await this.createWindsurfWorkspaceConfig(options);
return true;
} catch (error) {
console.error('Failed to initialize Windsurf configuration:', error.message);
return false;
}
}
/**
* Create Windsurf AI settings configuration
* @param {Object} options - Configuration options
*/
async createWindsurfAISettings(options = {}) {
const paths = this.getConfigPaths();
if (this.fileExists(paths.aiConfig)) {
return; // Don't overwrite existing AI config
}
const aiSettings = {
codeium: {
enableSupercomplete: true,
enableChat: true,
enableSearch: true,
contextLines: 100,
maxSuggestions: 5,
},
models: {
primary: 'claude-3-5-sonnet',
fallback: 'gpt-4',
autocomplete: 'codeium-proprietary',
},
features: {
explainCode: true,
generateTests: true,
documentCode: true,
refactorCode: true,
findBugs: true,
},
projectAwareness: {
enabled: true,
includeFiles: ['README.md', 'package.json', '*.config.*', '.ai/rules/**'],
excludePatterns: ['node_modules/**', 'dist/**', '*.log', '.git/**'],
},
};
await this.writeJsonFile(paths.aiConfig, aiSettings);
}
/**
* Create MCP configuration for Windsurf
* @param {Object} options - Configuration options
*/
async createWindsurfMCPConfig(options = {}) {
const paths = this.getConfigPaths();
if (this.fileExists(paths.projectMcp)) {
return; // Don't overwrite existing MCP config
}
const mcpConfig = {
mcpServers: {
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', this.projectPath],
env: {},
},
git: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-git', '--repository', this.projectPath],
env: {},
},
codeium: {
command: 'codeium-server',
args: ['--project-path', this.projectPath],
env: {
CODEIUM_API_KEY: '${CODEIUM_API_KEY}',
},
},
},
vdk: {
enabled: true,
projectName: options.projectName || path.basename(this.projectPath),
rulesPath: '.windsurf/rules',
integration: 'windsurf',
},
};
await this.writeJsonFile(paths.projectMcp, mcpConfig);
}
/**
* Create Windsurf workspace configuration
* @param {Object} options - Configuration options
*/
async createWindsurfWorkspaceConfig(options = {}) {
const paths = this.getConfigPaths();
if (this.fileExists(paths.workspaceConfig)) {
return; // Don't overwrite existing workspace config
}
const workspaceConfig = {
folders: [
{
path: '.',
},
],
settings: {
'codeium.enabled': true,
'ai.chat.enabled': true,
'ai.supercomplete.enabled': true,
'files.autoSave': 'onWindowChange',
'editor.formatOnSave': true,
'editor.codeActionsOnSave': {
'source.fixAll': true,
'source.organizeImports': true,
},
},
extensions: {
recommendations: ['codeium.codeium', 'ms-vscode.vscode-typescript-next'],
},
vdk: {
projectName: options.projectName || path.basename(this.projectPath),
rulesDirectory: '.windsurf/rules',
lastUpdated: new Date().toISOString(),
},
};
await this.writeJsonFile(paths.workspaceConfig, workspaceConfig);
}
/**
* Create Windsurf-specific AI rules following official format
* @param {Object} options - Configuration options
*/
async createWindsurfAIRules(options = {}) {
const paths = this.getConfigPaths();
const rulesPath = paths.rulesDirectory;
// Create global rules file (proper Windsurf format)
await this.createGlobalRules(options);
// Create workspace rules (following 6K character limit)
const windsurfRulePath = path.join(rulesPath, 'vdk-integration.md');
if (this.fileExists(windsurfRulePath)) {
return; // Don't overwrite existing rules
}
// Create workspace rule following Windsurf format (under 6K chars)
const windsurfRuleContent = `# VDK Integration - Windsurf Rules
## VDK-Specific Guidelines for Windsurf
<development-standards>
- Follow existing project architecture patterns
- Use VDK CLI for AI rule generation and management
- Maintain consistent naming conventions across files
- Leverage Codeium's context awareness for better suggestions
</development-standards>
<ai-workflow>
- **Supercomplete**: Multi-line code generation and boilerplate
- **Chat**: Complex reasoning and architecture discussions
- **Search**: Find existing patterns in codebase
- **Context Scanning**: Let Codeium analyze project structure
</ai-workflow>
<model-selection>
- **Claude 3.5 Sonnet**: System design and complex reasoning
- **GPT-4**: General coding tasks and documentation
- **Codeium**: Fast autocomplete and pattern matching
</model-selection>
<vdk-integration>
- Rules stored in \`.windsurf/rules/\` directory
- Global rules in \`~/.codeium/windsurf/memories/\`
- Update with VDK CLI when project evolves
- Character limits: 6K per file, 12K total
</vdk-integration>
<quality-standards>
- Proper error handling and logging patterns
- Tests for new functionality
- Documentation updates
- Security best practices
- Performance considerations
</quality-standards>
*Generated by VDK CLI - Keep under 6K characters*`;
await fs.promises.writeFile(windsurfRulePath, windsurfRuleContent, 'utf8');
}
/**
* Create global Windsurf rules following native memories format
* @param {Object} options - Configuration options
*/
async createGlobalRules(options = {}) {
const paths = this.getConfigPaths();
// Ensure the global memories directory exists
await this.ensureDirectory(paths.globalMemories);
if (this.fileExists(paths.globalRulesFile)) {
return; // Don't overwrite existing global rules
}
const globalRulesContent = `# Global Windsurf Rules - VDK Enhanced
## Organization Standards
<coding-standards>
- Use consistent indentation (2 spaces for JS/TS, 4 for Python)
- Follow conventional commit messages (feat:, fix:, docs:)
- Prefer descriptive variable names over abbreviations
- Add meaningful comments for complex logic
- Use TypeScript for new JavaScript projects
</coding-standards>
<security-requirements>
- Never commit secrets or API keys
- Validate all user inputs
- Use environment variables for configuration
- Implement proper authentication patterns
- Keep dependencies updated
</security-requirements>
<documentation-standards>
- Write clear README files with setup instructions
- Document API endpoints with examples
- Include code examples in documentation
- Update docs when code changes
- Use JSDoc for complex functions
</documentation-standards>
<vdk-integration>
- VDK CLI generates project-aware AI rules
- Rules follow platform-specific formats
- Automatic detection of IDE configurations
- Memory management for project context
</vdk-integration>
*Organization-wide standards - Applied across all Windsurf workspaces*`;
await fs.promises.writeFile(paths.globalRulesFile, globalRulesContent, 'utf8');
}
/**
* Check if Windsurf has specific features enabled
* @returns {Promise<Object>} Feature availability status
*/
async getWindsurfFeatures() {
const paths = this.getConfigPaths();
const features = {
codeiumEnabled: false,
supercompleteEnabled: false,
chatEnabled: false,
searchEnabled: false,
mcpConfigured: false,
rulesConfigured: false,
workspaceConfigured: false,
};
try {
if (this.fileExists(paths.projectConfig)) {
const config = await this.readJsonFile(paths.projectConfig);
features.codeiumEnabled = config?.codeium?.enabled || false;
features.supercompleteEnabled = config?.codeium?.supercomplete || false;
features.chatEnabled = config?.codeium?.chat || false;
features.searchEnabled = config?.codeium?.search || false;
}
features.mcpConfigured = this.fileExists(paths.projectMcp);
features.rulesConfigured = await this.directoryExistsAsync(paths.rulesDirectory);
features.workspaceConfigured = this.fileExists(paths.workspaceConfig);
} catch (error) {
// Features remain false if we can't read config
}
return features;
}
/**
* Get Windsurf status summary
* @returns {Promise<Object>} Status summary object
*/
async getStatusSummary() {
const detection = this.getCachedDetection();
const features = await this.getWindsurfFeatures();
const paths = this.getConfigPaths();
return {
isConfigured: detection.isUsed,
confidence: detection.confidence,
features,
configPaths: paths,
recommendations: detection.recommendations,
};
}
}