diff --git a/mcp-server/src/tools/rules.js b/mcp-server/src/tools/rules.js index c5df5504..8e9ac636 100644 --- a/mcp-server/src/tools/rules.js +++ b/mcp-server/src/tools/rules.js @@ -19,8 +19,7 @@ import { RULES_PROFILES } from '../../../src/constants/profiles.js'; export function registerRulesTool(server) { server.addTool({ name: 'rules', - description: - 'Add or remove rules profiles from the project.', + description: 'Add or remove rules profiles from the project.', parameters: z.object({ action: z .enum(['add', 'remove']) diff --git a/src/utils/mcp-utils.js b/src/utils/mcp-utils.js index 433e7997..ef731c97 100644 --- a/src/utils/mcp-utils.js +++ b/src/utils/mcp-utils.js @@ -28,12 +28,12 @@ export function setupMCPConfiguration(projectDir, mcpConfigPath) { } } }; - + // Create config directory if it doesn't exist if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } - + if (fs.existsSync(mcpPath)) { log( 'info', diff --git a/src/utils/rule-transformer.js b/src/utils/rule-transformer.js index 0b45d4be..68f9d37c 100644 --- a/src/utils/rule-transformer.js +++ b/src/utils/rule-transformer.js @@ -203,7 +203,9 @@ export function convertRuleToProfileRule(sourcePath, targetPath, profile) { * Convert all Cursor rules to profile rules for a specific profile */ export function convertAllRulesToProfileRules(projectDir, profile) { - const sourceDir = fileURLToPath(new URL('../../assets/rules', import.meta.url)); + const sourceDir = fileURLToPath( + new URL('../../assets/rules', import.meta.url) + ); const targetDir = path.join(projectDir, profile.rulesDir); // Ensure target directory exists @@ -213,10 +215,7 @@ export function convertAllRulesToProfileRules(projectDir, profile) { // Setup MCP configuration if enabled if (profile.mcpConfig !== false) { - setupMCPConfiguration( - projectDir, - profile.mcpConfigPath - ); + setupMCPConfiguration(projectDir, profile.mcpConfigPath); } let success = 0; @@ -228,10 +227,13 @@ export function convertAllRulesToProfileRules(projectDir, profile) { for (const sourceFile of sourceFiles) { try { const sourcePath = path.join(sourceDir, sourceFile); - + // Check if source file exists if (!fs.existsSync(sourcePath)) { - log('warn', `[Rule Transformer] Source file not found: ${sourceFile}, skipping`); + log( + 'warn', + `[Rule Transformer] Source file not found: ${sourceFile}, skipping` + ); continue; } diff --git a/tests/unit/mcp-config-validation.test.js b/tests/unit/mcp-config-validation.test.js index c4a638b8..0dec221d 100644 --- a/tests/unit/mcp-config-validation.test.js +++ b/tests/unit/mcp-config-validation.test.js @@ -31,24 +31,29 @@ describe('MCP Configuration Validation', () => { } }; - Object.entries(expectedMcpConfigurations).forEach(([profileName, expected]) => { - test(`should have correct MCP configuration for ${profileName} profile`, () => { - const profile = getRulesProfile(profileName); - expect(profile).toBeDefined(); - expect(profile.mcpConfig).toBe(expected.shouldHaveMcp); - expect(profile.profileDir).toBe(expected.expectedDir); - expect(profile.mcpConfigName).toBe(expected.expectedConfigName); - expect(profile.mcpConfigPath).toBe(expected.expectedPath); - }); - }); + Object.entries(expectedMcpConfigurations).forEach( + ([profileName, expected]) => { + test(`should have correct MCP configuration for ${profileName} profile`, () => { + const profile = getRulesProfile(profileName); + expect(profile).toBeDefined(); + expect(profile.mcpConfig).toBe(expected.shouldHaveMcp); + expect(profile.profileDir).toBe(expected.expectedDir); + expect(profile.mcpConfigName).toBe(expected.expectedConfigName); + expect(profile.mcpConfigPath).toBe(expected.expectedPath); + }); + } + ); }); describe('MCP Configuration Path Consistency', () => { test('should ensure all profiles have consistent mcpConfigPath construction', () => { - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); if (profile.mcpConfig !== false) { - const expectedPath = path.join(profile.profileDir, profile.mcpConfigName); + const expectedPath = path.join( + profile.profileDir, + profile.mcpConfigName + ); expect(profile.mcpConfigPath).toBe(expectedPath); } }); @@ -56,7 +61,7 @@ describe('MCP Configuration Validation', () => { test('should ensure no two profiles have the same MCP config path', () => { const mcpPaths = new Set(); - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); if (profile.mcpConfig !== false) { expect(mcpPaths.has(profile.mcpConfigPath)).toBe(false); @@ -66,7 +71,7 @@ describe('MCP Configuration Validation', () => { }); test('should ensure all MCP-enabled profiles use proper directory structure', () => { - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); if (profile.mcpConfig !== false) { expect(profile.mcpConfigPath).toMatch(/^\.[\w-]+\/[\w_.]+$/); @@ -75,7 +80,7 @@ describe('MCP Configuration Validation', () => { }); test('should ensure all profiles have required MCP properties', () => { - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); expect(profile).toHaveProperty('mcpConfig'); expect(profile).toHaveProperty('profileDir'); @@ -88,7 +93,7 @@ describe('MCP Configuration Validation', () => { describe('MCP Configuration File Names', () => { test('should use standard mcp.json for MCP-enabled profiles', () => { const standardMcpProfiles = ['cursor', 'windsurf', 'roo']; - standardMcpProfiles.forEach(profileName => { + standardMcpProfiles.forEach((profileName) => { const profile = getRulesProfile(profileName); expect(profile.mcpConfigName).toBe('mcp.json'); }); @@ -103,7 +108,7 @@ describe('MCP Configuration Validation', () => { describe('Profile Directory Structure', () => { test('should ensure each profile has a unique directory', () => { const profileDirs = new Set(); - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); expect(profileDirs.has(profile.profileDir)).toBe(false); profileDirs.add(profile.profileDir); @@ -111,7 +116,7 @@ describe('MCP Configuration Validation', () => { }); test('should ensure profile directories follow expected naming convention', () => { - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); expect(profile.profileDir).toMatch(/^\.[\w-]+$/); }); @@ -120,11 +125,11 @@ describe('MCP Configuration Validation', () => { describe('MCP Configuration Creation Logic', () => { test('should indicate which profiles require MCP configuration creation', () => { - const mcpEnabledProfiles = RULES_PROFILES.filter(profileName => { + const mcpEnabledProfiles = RULES_PROFILES.filter((profileName) => { const profile = getRulesProfile(profileName); return profile.mcpConfig !== false; }); - + expect(mcpEnabledProfiles).toContain('cursor'); expect(mcpEnabledProfiles).toContain('windsurf'); expect(mcpEnabledProfiles).toContain('roo'); @@ -132,7 +137,7 @@ describe('MCP Configuration Validation', () => { }); test('should provide all necessary information for MCP config creation', () => { - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); if (profile.mcpConfig !== false) { expect(profile.mcpConfigPath).toBeDefined(); @@ -147,13 +152,13 @@ describe('MCP Configuration Validation', () => { test('should verify that rule transformer functions use mcpConfigPath correctly', () => { // This test verifies that the mcpConfigPath property exists and is properly formatted // for use with the setupMCPConfiguration function - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); if (profile.mcpConfig !== false) { // Verify the path is properly formatted for path.join usage expect(profile.mcpConfigPath.startsWith('/')).toBe(false); expect(profile.mcpConfigPath).toContain('/'); - + // Verify it matches the expected pattern: profileDir/configName const expectedPath = `${profile.profileDir}/${profile.mcpConfigName}`; expect(profile.mcpConfigPath).toBe(expectedPath); @@ -162,13 +167,13 @@ describe('MCP Configuration Validation', () => { }); test('should verify that mcpConfigPath is properly constructed for path.join usage', () => { - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); if (profile.mcpConfig !== false) { // Test that path.join works correctly with the mcpConfigPath const testProjectRoot = '/test/project'; const fullPath = path.join(testProjectRoot, profile.mcpConfigPath); - + // Should result in a proper absolute path expect(fullPath).toBe(`${testProjectRoot}/${profile.mcpConfigPath}`); expect(fullPath).toContain(profile.profileDir); @@ -181,14 +186,14 @@ describe('MCP Configuration Validation', () => { describe('MCP Configuration Function Integration', () => { test('should verify that setupMCPConfiguration receives the correct mcpConfigPath parameter', () => { // This test verifies the integration between rule transformer and mcp-utils - RULES_PROFILES.forEach(profileName => { + RULES_PROFILES.forEach((profileName) => { const profile = getRulesProfile(profileName); if (profile.mcpConfig !== false) { // Verify that the mcpConfigPath can be used directly with setupMCPConfiguration // The function signature is: setupMCPConfiguration(projectDir, mcpConfigPath) expect(profile.mcpConfigPath).toBeDefined(); expect(typeof profile.mcpConfigPath).toBe('string'); - + // Verify the path structure is correct for the new function signature const parts = profile.mcpConfigPath.split('/'); expect(parts).toHaveLength(2); // Should be profileDir/configName @@ -198,4 +203,4 @@ describe('MCP Configuration Validation', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/tests/unit/rule-transformer.test.js b/tests/unit/rule-transformer.test.js index f7542231..c0e5499b 100644 --- a/tests/unit/rule-transformer.test.js +++ b/tests/unit/rule-transformer.test.js @@ -10,10 +10,10 @@ describe('Rule Transformer - General', () => { // Ensure RULES_PROFILES is properly defined and contains expected profiles expect(Array.isArray(RULES_PROFILES)).toBe(true); expect(RULES_PROFILES.length).toBeGreaterThan(0); - + // Verify expected profiles are present const expectedProfiles = ['cline', 'cursor', 'roo', 'windsurf']; - expectedProfiles.forEach(profile => { + expectedProfiles.forEach((profile) => { expect(RULES_PROFILES).toContain(profile); }); }); @@ -82,8 +82,13 @@ describe('Rule Transformer - General', () => { }); it('should have valid fileMap with required files for each profile', () => { - const expectedFiles = ['cursor_rules.mdc', 'dev_workflow.mdc', 'self_improve.mdc', 'taskmaster.mdc']; - + const expectedFiles = [ + 'cursor_rules.mdc', + 'dev_workflow.mdc', + 'self_improve.mdc', + 'taskmaster.mdc' + ]; + RULES_PROFILES.forEach((profile) => { const profileConfig = getRulesProfile(profile); @@ -97,7 +102,7 @@ describe('Rule Transformer - General', () => { expect(fileMapKeys.length).toBeGreaterThan(0); // Check that all expected source files are defined in fileMap - expectedFiles.forEach(expectedFile => { + expectedFiles.forEach((expectedFile) => { expect(fileMapKeys).toContain(expectedFile); expect(typeof profileConfig.fileMap[expectedFile]).toBe('string'); expect(profileConfig.fileMap[expectedFile].length).toBeGreaterThan(0); @@ -171,12 +176,16 @@ describe('Rule Transformer - General', () => { // The mcpConfigPath should start with the profileDir expect(profileConfig.mcpConfigPath).toMatch( - new RegExp(`^${profileConfig.profileDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/`) + new RegExp( + `^${profileConfig.profileDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/` + ) ); // The mcpConfigPath should end with the mcpConfigName expect(profileConfig.mcpConfigPath).toMatch( - new RegExp(`${profileConfig.mcpConfigName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`) + new RegExp( + `${profileConfig.mcpConfigName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$` + ) ); }); });