From 8250b5cad39a915f76b60acbcff01ac4020b4637 Mon Sep 17 00:00:00 2001 From: Joe Danziger Date: Wed, 4 Jun 2025 18:28:13 -0400 Subject: [PATCH] MCP server path fixes for rules command --- mcp-server/src/core/direct-functions/rules.js | 8 +++- scripts/profiles/claude.js | 19 ++++----- scripts/profiles/codex.js | 19 ++++----- scripts/profiles/roo.js | 40 ++++++++++--------- src/utils/mcp-config-setup.js | 20 ++++++++++ src/utils/rule-transformer.js | 16 +++++++- 6 files changed, 78 insertions(+), 44 deletions(-) diff --git a/mcp-server/src/core/direct-functions/rules.js b/mcp-server/src/core/direct-functions/rules.js index c2e7aa55..437c824f 100644 --- a/mcp-server/src/core/direct-functions/rules.js +++ b/mcp-server/src/core/direct-functions/rules.js @@ -136,10 +136,14 @@ export async function rulesDirect(args, log, context = {}) { const profileRulesDir = path.join(projectRoot, rulesDir); const profileDir = profileConfig.profileDir; const mcpConfig = profileConfig.mcpConfig !== false; - const mcpPath = path.join(projectRoot, profileConfig.mcpConfigPath); + const mcpPath = + mcpConfig && profileConfig.mcpConfigPath + ? path.join(projectRoot, profileConfig.mcpConfigPath) + : null; // Check what was created - const mcpConfigCreated = mcpConfig ? fs.existsSync(mcpPath) : undefined; + const mcpConfigCreated = + mcpConfig && mcpPath ? fs.existsSync(mcpPath) : undefined; const rulesDirCreated = fs.existsSync(profileRulesDir); const profileFolderCreated = fs.existsSync( path.join(projectRoot, profileDir) diff --git a/scripts/profiles/claude.js b/scripts/profiles/claude.js index 8ad6d506..cd28e764 100644 --- a/scripts/profiles/claude.js +++ b/scripts/profiles/claude.js @@ -4,8 +4,9 @@ import fs from 'fs'; import { isSilentMode, log } from '../modules/utils.js'; // Lifecycle functions for Claude Code profile -function onAddRulesProfile(targetDir) { - const sourceFile = path.join(process.cwd(), 'assets', 'AGENTS.md'); +function onAddRulesProfile(targetDir, assetsDir) { + // Use the provided assets directory to find the source file + const sourceFile = path.join(assetsDir, 'AGENTS.md'); const destFile = path.join(targetDir, 'CLAUDE.md'); if (fs.existsSync(sourceFile)) { @@ -13,29 +14,25 @@ function onAddRulesProfile(targetDir) { fs.copyFileSync(sourceFile, destFile); log('debug', `[Claude] Copied AGENTS.md to ${destFile}`); } catch (err) { - log('debug', `[Claude] Failed to copy AGENTS.md: ${err.message}`); + log('error', `[Claude] Failed to copy AGENTS.md: ${err.message}`); } - } else { - log('debug', `[Claude] AGENTS.md not found at ${sourceFile}`); } } function onRemoveRulesProfile(targetDir) { - log('debug', `[Claude] onRemoveRulesProfile called for ${targetDir}`); const claudeFile = path.join(targetDir, 'CLAUDE.md'); if (fs.existsSync(claudeFile)) { try { fs.rmSync(claudeFile, { force: true }); - log('debug', `[Claude] Removed CLAUDE.md from ${targetDir}`); + log('debug', `[Claude] Removed CLAUDE.md from ${claudeFile}`); } catch (err) { - log('debug', `[Claude] Failed to remove CLAUDE.md: ${err.message}`); + log('error', `[Claude] Failed to remove CLAUDE.md: ${err.message}`); } } - log('debug', `[Claude] onRemoveRulesProfile completed for ${targetDir}`); } -function onPostConvertRulesProfile(targetDir) { - onAddRulesProfile(targetDir); +function onPostConvertRulesProfile(targetDir, assetsDir) { + onAddRulesProfile(targetDir, assetsDir); } // Simple filename function diff --git a/scripts/profiles/codex.js b/scripts/profiles/codex.js index 6d59eddf..66d57d3d 100644 --- a/scripts/profiles/codex.js +++ b/scripts/profiles/codex.js @@ -4,8 +4,9 @@ import fs from 'fs'; import { isSilentMode, log } from '../modules/utils.js'; // Lifecycle functions for Codex profile -function onAddRulesProfile(targetDir) { - const sourceFile = path.join(process.cwd(), 'assets', 'AGENTS.md'); +function onAddRulesProfile(targetDir, assetsDir) { + // Use the provided assets directory to find the source file + const sourceFile = path.join(assetsDir, 'AGENTS.md'); const destFile = path.join(targetDir, 'AGENTS.md'); if (fs.existsSync(sourceFile)) { @@ -13,29 +14,25 @@ function onAddRulesProfile(targetDir) { fs.copyFileSync(sourceFile, destFile); log('debug', `[Codex] Copied AGENTS.md to ${destFile}`); } catch (err) { - log('debug', `[Codex] Failed to copy AGENTS.md: ${err.message}`); + log('error', `[Codex] Failed to copy AGENTS.md: ${err.message}`); } - } else { - log('debug', `[Codex] AGENTS.md not found at ${sourceFile}`); } } function onRemoveRulesProfile(targetDir) { - log('debug', `[Codex] onRemoveRulesProfile called for ${targetDir}`); const agentsFile = path.join(targetDir, 'AGENTS.md'); if (fs.existsSync(agentsFile)) { try { fs.rmSync(agentsFile, { force: true }); - log('debug', `[Codex] Removed AGENTS.md from ${targetDir}`); + log('debug', `[Codex] Removed AGENTS.md from ${agentsFile}`); } catch (err) { - log('debug', `[Codex] Failed to remove AGENTS.md: ${err.message}`); + log('error', `[Codex] Failed to remove AGENTS.md: ${err.message}`); } } - log('debug', `[Codex] onRemoveRulesProfile completed for ${targetDir}`); } -function onPostConvertRulesProfile(targetDir) { - onAddRulesProfile(targetDir); +function onPostConvertRulesProfile(targetDir, assetsDir) { + onAddRulesProfile(targetDir, assetsDir); } // Simple filename function diff --git a/scripts/profiles/roo.js b/scripts/profiles/roo.js index bfe06b8a..0c46893a 100644 --- a/scripts/profiles/roo.js +++ b/scripts/profiles/roo.js @@ -6,9 +6,17 @@ import { createProfile, COMMON_TOOL_MAPPINGS } from './base-profile.js'; import { ROO_MODES } from '../../src/constants/profiles.js'; // Lifecycle functions for Roo profile -function onAddRulesProfile(targetDir) { - const sourceDir = path.join(process.cwd(), 'assets', 'roocode'); +function onAddRulesProfile(targetDir, assetsDir) { + // Use the provided assets directory to find the roocode directory + const sourceDir = path.join(assetsDir, 'roocode'); + + if (!fs.existsSync(sourceDir)) { + log('error', `[Roo] Source directory does not exist: ${sourceDir}`); + return; + } + copyRecursiveSync(sourceDir, targetDir); + log('debug', `[Roo] Copied roocode directory to ${targetDir}`); const rooModesDir = path.join(sourceDir, '.roo'); @@ -20,10 +28,8 @@ function onAddRulesProfile(targetDir) { fs.copyFileSync(roomodesSrc, roomodesDest); log('debug', `[Roo] Copied .roomodes to ${roomodesDest}`); } catch (err) { - log('debug', `[Roo] Failed to copy .roomodes: ${err.message}`); + log('error', `[Roo] Failed to copy .roomodes: ${err.message}`); } - } else { - log('debug', `[Roo] .roomodes not found at ${roomodesSrc}`); } for (const mode of ROO_MODES) { @@ -34,12 +40,10 @@ function onAddRulesProfile(targetDir) { const destDir = path.dirname(dest); if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true }); fs.copyFileSync(src, dest); - log('debug', `[Roo] Copied ${src} to ${dest}`); + log('debug', `[Roo] Copied ${mode}-rules to ${dest}`); } catch (err) { - log('debug', `[Roo] Failed to copy ${src} to ${dest}: ${err.message}`); + log('error', `[Roo] Failed to copy ${src} to ${dest}: ${err.message}`); } - } else { - log('debug', `[Roo] Roo rule file not found for mode '${mode}': ${src}`); } } } @@ -62,14 +66,13 @@ function copyRecursiveSync(src, dest) { } function onRemoveRulesProfile(targetDir) { - log('debug', `[Roo] onRemoveRulesProfile called for ${targetDir}`); const roomodesPath = path.join(targetDir, '.roomodes'); if (fs.existsSync(roomodesPath)) { try { fs.rmSync(roomodesPath, { force: true }); - log('debug', `[Roo] Removed .roomodes from ${targetDir}`); + log('debug', `[Roo] Removed .roomodes from ${roomodesPath}`); } catch (err) { - log('debug', `[Roo] Failed to remove .roomodes: ${err.message}`); + log('error', `[Roo] Failed to remove .roomodes: ${err.message}`); } } @@ -80,26 +83,25 @@ function onRemoveRulesProfile(targetDir) { const modeDir = path.join(rooDir, entry); try { fs.rmSync(modeDir, { recursive: true, force: true }); - log('debug', `[Roo] Removed ${modeDir}`); + log('debug', `[Roo] Removed ${entry} directory from ${modeDir}`); } catch (err) { - log('debug', `[Roo] Failed to remove ${modeDir}: ${err.message}`); + log('error', `[Roo] Failed to remove ${modeDir}: ${err.message}`); } } }); if (fs.readdirSync(rooDir).length === 0) { try { fs.rmSync(rooDir, { recursive: true, force: true }); - log('debug', '[Roo] Removed empty .roo directory'); + log('debug', `[Roo] Removed empty .roo directory from ${rooDir}`); } catch (err) { - log('debug', `[Roo] Failed to remove .roo directory: ${err.message}`); + log('error', `[Roo] Failed to remove .roo directory: ${err.message}`); } } } - log('debug', `[Roo] onRemoveRulesProfile completed for ${targetDir}`); } -function onPostConvertRulesProfile(targetDir) { - onAddRulesProfile(targetDir); +function onPostConvertRulesProfile(targetDir, assetsDir) { + onAddRulesProfile(targetDir, assetsDir); } // Create and export roo profile using the base factory diff --git a/src/utils/mcp-config-setup.js b/src/utils/mcp-config-setup.js index e9f82c4a..c630067f 100644 --- a/src/utils/mcp-config-setup.js +++ b/src/utils/mcp-config-setup.js @@ -26,6 +26,15 @@ function formatJSONWithTabs(obj) { // Structure matches project conventions (see scripts/init.js) export function setupMCPConfiguration(projectDir, mcpConfigPath) { + // Handle null mcpConfigPath (e.g., for Claude/Codex profiles) + if (!mcpConfigPath) { + log( + 'debug', + '[MCP Config] No mcpConfigPath provided, skipping MCP configuration setup' + ); + return; + } + // Build the full path to the MCP config file const mcpPath = path.join(projectDir, mcpConfigPath); const configDir = path.dirname(mcpPath); @@ -136,6 +145,17 @@ export function setupMCPConfiguration(projectDir, mcpConfigPath) { * @returns {Object} Result object with success status and details */ export function removeTaskMasterMCPConfiguration(projectDir, mcpConfigPath) { + // Handle null mcpConfigPath (e.g., for Claude/Codex profiles) + if (!mcpConfigPath) { + return { + success: true, + removed: false, + deleted: false, + error: null, + hasOtherServers: false + }; + } + const mcpPath = path.join(projectDir, mcpConfigPath); let result = { diff --git a/src/utils/rule-transformer.js b/src/utils/rule-transformer.js index fa2d5569..4456de7d 100644 --- a/src/utils/rule-transformer.js +++ b/src/utils/rule-transformer.js @@ -199,6 +199,19 @@ export function convertRuleToProfileRule(sourcePath, targetPath, profile) { * Convert all Cursor rules to profile rules for a specific profile */ export function convertAllRulesToProfileRules(projectDir, profile) { + // Handle simple profiles (Claude, Codex) that just copy files to root + const isSimpleProfile = Object.keys(profile.fileMap).length === 0; + if (isSimpleProfile) { + // For simple profiles, just call their post-processing hook and return + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + const assetsDir = path.join(__dirname, '..', '..', 'assets'); + if (typeof profile.onPostConvertRulesProfile === 'function') { + profile.onPostConvertRulesProfile(projectDir, assetsDir); + } + return { success: 1, failed: 0 }; + } + const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const sourceDir = path.join(__dirname, '..', '..', 'assets', 'rules'); @@ -271,7 +284,8 @@ export function convertAllRulesToProfileRules(projectDir, profile) { // Call post-processing hook if defined (e.g., for Roo's rules-*mode* folders) if (typeof profile.onPostConvertRulesProfile === 'function') { - profile.onPostConvertRulesProfile(projectDir); + const assetsDir = path.join(__dirname, '..', '..', 'assets'); + profile.onPostConvertRulesProfile(projectDir, assetsDir); } return { success, failed };