UNPKG

@wangkanai/devops-mcp

Version:

Dynamic Azure DevOps MCP Server for directory-based environment switching

188 lines 7.24 kB
"use strict"; /** * Local Configuration Loader * Reads .azure-devops.json files from repository directories */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.LocalConfigLoader = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); class LocalConfigLoader { /** * Load Azure DevOps configuration from local file in current directory */ static loadLocalConfig(directory) { const workingDir = directory || process.cwd(); const configPath = path.join(workingDir, this.CONFIG_FILE_NAME); try { if (!fs.existsSync(configPath)) { console.log(`No local Azure DevOps config found in ${workingDir}`); return null; } const configData = fs.readFileSync(configPath, 'utf8'); const localConfig = JSON.parse(configData); // Validate required fields if (!localConfig.organizationUrl || !localConfig.project || !localConfig.pat) { throw new Error('Missing required fields: organizationUrl, project, or pat'); } // Convert to internal config format const config = { organizationUrl: localConfig.organizationUrl, project: localConfig.project, pat: localConfig.pat }; if (process.env.DEBUG === 'true') { console.debug(`Loaded Azure DevOps config from ${configPath}`); console.debug(`Organization: ${config.organizationUrl}`); console.debug(`Project: ${config.project}`); } return config; } catch (error) { console.error(`Failed to load local config from ${configPath}:`, error); return null; } } /** * Check if local configuration file exists in directory */ static hasLocalConfig(directory) { const workingDir = directory || process.cwd(); const configPath = path.join(workingDir, this.CONFIG_FILE_NAME); return fs.existsSync(configPath); } /** * Search for configuration file in current directory and parent directories */ static findLocalConfig(startDirectory) { let currentDir = startDirectory || process.cwd(); const rootDir = path.parse(currentDir).root; while (currentDir !== rootDir) { const config = this.loadLocalConfig(currentDir); if (config) { return config; } // Move to parent directory const parentDir = path.dirname(currentDir); if (parentDir === currentDir) { break; // Reached root } currentDir = parentDir; } console.log('No Azure DevOps configuration found in current directory tree'); return null; } /** * Type guard to check if a string is a valid key of LocalAzureDevOpsConfig */ static isRequiredField(field) { return ['organizationUrl', 'project', 'pat'].includes(field); } /** * Check if hostname is a valid Azure DevOps domain */ static isValidAzureDevOpsHostname(hostname) { // Support dev.azure.com, visualstudio.com, and custom domains return hostname === 'dev.azure.com' || hostname.endsWith('.visualstudio.com') || hostname.endsWith('.dev.azure.com'); } /** * Validate local configuration structure */ static validateLocalConfig(config) { const requiredFields = ['organizationUrl', 'project', 'pat']; for (const field of requiredFields) { if (this.isRequiredField(field) && (!config[field] || typeof config[field] !== 'string')) { console.error(`Missing or invalid required field: ${field}`); return false; } } // Validate organization URL format try { const url = new URL(config.organizationUrl); if (!this.isValidAzureDevOpsHostname(url.hostname)) { console.error('Invalid organization URL: hostname is not recognized as a valid Azure DevOps domain'); return false; } } catch { console.error('Invalid organization URL format'); return false; } return true; } /** * Create example configuration file */ static createExampleConfig(directory) { const workingDir = directory || process.cwd(); const configPath = path.join(workingDir, this.CONFIG_FILE_NAME); const exampleConfig = { organizationUrl: "https://dev.azure.com/your-org", project: "YourProject", pat: "your-pat-token-here", description: "Azure DevOps configuration for this repository", settings: { timeout: 30000, retries: 3, apiVersion: "7.1" }, tools: { workItems: true, repositories: true, builds: true, pullRequests: true, pipelines: true }, meta: { configVersion: "1.0", lastUpdated: new Date().toISOString().split('T')[0], createdBy: "devops-enhanced-mcp" } }; try { fs.writeFileSync(configPath, JSON.stringify(exampleConfig, null, 2)); console.log(`Created example configuration at ${configPath}`); } catch (error) { console.error(`Failed to create example configuration:`, error); } } } exports.LocalConfigLoader = LocalConfigLoader; LocalConfigLoader.CONFIG_FILE_NAME = '.azure-devops.json'; //# sourceMappingURL=local-config-loader.js.map