UNPKG

@simonecoelhosfo/optimizely-mcp-server

Version:

Optimizely MCP Server for AI assistants with integrated CLI tools

160 lines 7.29 kB
/** * Compare Environments Tool - Individual Module * @description Compares configuration and entities between different environments * @since 2025-08-04 * @author Tool Modularization Team * * Migration Status: COMPLETED * Original Method: OptimizelyMCPTools.compareEnvironments * Complexity: LOW * Dependencies: storage.query, logger, errorMapper, cacheManager */ /** * Creates the Compare Environments tool with injected dependencies * @param deps - Injected dependencies (storage, logger, errorMapper, etc.) * @returns Tool definition with handler */ export function createCompareEnvironmentsTool(deps) { return { name: 'compare_environments', requiresCache: true, category: 'analytics', description: 'Compares configuration and entities between different environments', handler: async (args) => { try { const { project_id, flag_key, environments: envFilter } = args; // Get all environments if not specified let environments; if (envFilter && envFilter.length > 0) { environments = envFilter; } else { const envQuery = await deps.storage.query(` SELECT key FROM environments WHERE project_id = ? ORDER BY priority, key `, [project_id]); environments = envQuery.map(e => e.key); } if (environments.length < 2) { throw deps.errorMapper.toMCPError(new Error('At least 2 environments are required for comparison'), { operation: 'Compare environments', metadata: { environments: args.environments } }); } // Build query for flags let flagQuery = ` SELECT DISTINCT f.key, f.name FROM flags f WHERE f.project_id = ? AND f.archived = 0 `; const queryParams = [project_id]; if (flag_key) { flagQuery += ' AND f.key = ?'; queryParams.push(flag_key); } const flags = await deps.storage.query(flagQuery, queryParams); const flagsWithDifferences = []; const environmentOnlyFlags = {}; environments.forEach(env => { environmentOnlyFlags[env] = 0; }); // Compare each flag across environments for (const flag of flags) { const envData = {}; const differences = []; // Get flag environment data for all environments const feQuery = await deps.storage.query(` SELECT environment_key, enabled, data_json FROM flag_environments WHERE project_id = ? AND flag_key = ? AND environment_key IN (${environments.map(() => '?').join(',')}) `, [project_id, flag.key, ...environments]); // Build environment data map for (const fe of feQuery) { let rulesetData = {}; try { if (fe.data_json) rulesetData = JSON.parse(fe.data_json); } catch (e) { deps.logger.warn('Could not parse ruleset', { flagKey: flag.key, environmentKey: fe.environment_key }); } envData[fe.environment_key] = { enabled: Boolean(fe.enabled), ruleset: rulesetData }; } // Add missing environments with default values for (const env of environments) { if (!envData[env]) { envData[env] = { enabled: false, ruleset: null }; } } // Check for differences in enabled state const enabledValues = {}; let hasEnabledDiff = false; let firstEnabled = null; for (const env of environments) { enabledValues[env] = envData[env].enabled; if (firstEnabled === null) { firstEnabled = envData[env].enabled; } else if (firstEnabled !== envData[env].enabled) { hasEnabledDiff = true; } } if (hasEnabledDiff) { differences.push({ field: 'enabled', values: enabledValues }); } // Check for differences in rulesets (simplified comparison) const rulesetHashes = {}; let hasRulesetDiff = false; let firstHash = null; for (const env of environments) { const ruleset = envData[env].ruleset; const hash = ruleset ? JSON.stringify(ruleset).substring(0, 50) + '...' : 'none'; rulesetHashes[env] = hash; if (firstHash === null) { firstHash = hash; } else if (firstHash !== hash) { hasRulesetDiff = true; } } if (hasRulesetDiff) { differences.push({ field: 'ruleset', values: rulesetHashes }); } // Add to results if differences found if (differences.length > 0) { flagsWithDifferences.push({ key: flag.key, name: flag.name, differences }); } // Count environment-only flags const configuredEnvs = environments.filter(env => envData[env].enabled || envData[env].ruleset); if (configuredEnvs.length === 1) { environmentOnlyFlags[configuredEnvs[0]]++; } } return { environments, flags: flagsWithDifferences, summary: { total_flags: flags.length, flags_with_differences: flagsWithDifferences.length, environment_only_flags: environmentOnlyFlags } }; } catch (error) { deps.logger.error({ error: error.message, stack: error.stack }, 'OptimizelyMCPTools.compareEnvironments failed'); throw deps.errorMapper.toMCPError(error, 'Failed to compare environments'); } } }; } //# sourceMappingURL=CompareEnvironments.js.map