UNPKG

@vfarcic/dot-ai

Version:

AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance

160 lines (159 loc) 6.68 kB
"use strict"; /** * Deploy Operation - Handles Kubernetes manifest deployment with readiness checking * PRD #343: Uses plugin system for kubectl operations */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DeployOperation = void 0; const promises_1 = require("fs/promises"); const path_1 = require("path"); const error_handling_1 = require("./error-handling"); const plugin_registry_1 = require("./plugin-registry"); class DeployOperation { /** * PRD #359: Uses unified plugin registry for kubectl operations */ constructor() { if (!(0, plugin_registry_1.isPluginInitialized)()) { throw new Error('Plugin system not available. DeployOperation requires agentic-tools plugin.'); } } /** * Deploy Kubernetes manifests from generated solution * PRD #343: Uses plugin for kubectl operations */ async deploy(options) { return error_handling_1.ErrorHandler.withErrorHandling(async () => { const manifestPath = this.getManifestPath(options); // Verify manifest file exists await this.verifyManifestExists(manifestPath); // Apply manifests with kubectl via plugin const kubectlOutput = await this.applyManifests(manifestPath, options.timeout || 30); return { success: true, solutionId: options.solutionId, manifestPath, readinessTimeout: false, message: 'Deployment completed successfully', kubectlOutput, }; }, { operation: 'deploy', component: 'deploy-operation', }); } /** * Get the manifest file path for the solution */ getManifestPath(options) { // Use sessionDir if provided, otherwise use tmp directory (for recommend tool compatibility) const tmpDir = options.sessionDir || (0, path_1.join)(process.cwd(), 'tmp'); return (0, path_1.join)(tmpDir, `${options.solutionId}.yaml`); } /** * Verify that the manifest file exists */ async verifyManifestExists(manifestPath) { try { await (0, promises_1.access)(manifestPath); } catch { throw new Error(`Manifest file not found: ${manifestPath}`); } } /** * Execute kubectl command via plugin * PRD #359: All kubectl operations go through unified plugin registry */ async executeKubectl(args) { const response = await (0, plugin_registry_1.invokePluginTool)('agentic-tools', 'kubectl_exec_command', { args }); if (response.success) { if (typeof response.result === 'object' && response.result !== null) { const result = response.result; // Check for nested error - plugin wraps kubectl errors in { success: false, error: "..." } if (result.success === false) { throw new Error(result.error || result.message || 'kubectl command failed'); } // Return only the data field - never pass JSON wrapper to consumers if (result.data !== undefined) { return String(result.data); } if (typeof result === 'string') { return result; } throw new Error('Plugin returned unexpected response format - missing data field'); } return String(response.result || ''); } else { throw new Error(response.error?.message || 'kubectl command failed via plugin'); } } /** * Apply manifests using kubectl with readiness checking * PRD #343: Uses kubectl_apply tool with manifest content (not file path) * File paths don't work across containers - must pass content via stdin */ async applyManifests(manifestPath, timeout) { // Read manifest content from file (file is in MCP server container) const manifestContent = await (0, promises_1.readFile)(manifestPath, 'utf8'); // Apply using kubectl_apply tool which accepts content via stdin const applyResult = await this.applyManifestContent(manifestContent); // Try to wait for deployments to be ready (ignore failures for other resource types) let waitOutput; try { const waitResult = await this.executeKubectl([ 'wait', '--for=condition=available', 'deployments', '--all', `--timeout=${timeout}s`, '--all-namespaces', ]); waitOutput = `\n\nWait output:\n${waitResult}`; } catch (waitError) { // If no deployments found or wait fails, that's OK for other resource types (Services, etc.) const errorMsg = waitError instanceof Error ? waitError.message : String(waitError); if (errorMsg.includes('no matching resources found')) { waitOutput = '\n\nWait output: No deployments found to wait for (likely Services, CRs, etc.)'; } else { waitOutput = `\n\nWait output: Warning - ${errorMsg}`; } } return `Apply output:\n${applyResult}${waitOutput}`; } /** * Apply manifest content using kubectl_apply tool * PRD #359: Uses unified plugin registry's kubectl_apply tool with stdin */ async applyManifestContent(manifest) { const response = await (0, plugin_registry_1.invokePluginTool)('agentic-tools', 'kubectl_apply', { manifest, }); if (response.success) { if (typeof response.result === 'object' && response.result !== null) { const result = response.result; // Check for nested error if (result.success === false) { throw new Error(result.error || result.message || 'kubectl apply failed'); } // Return only the data field if (result.data !== undefined) { return String(result.data); } if (typeof result === 'string') { return result; } throw new Error('Plugin returned unexpected response format - missing data field'); } return String(response.result || ''); } else { throw new Error(response.error?.message || 'kubectl apply failed via plugin'); } } } exports.DeployOperation = DeployOperation;