UNPKG

@vfarcic/dot-ai

Version:

Universal Kubernetes application deployment agent with CLI and MCP interfaces

172 lines (171 loc) 7.92 kB
"use strict"; /** * Choose Solution Tool - Select a solution and return its questions */ 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.CHOOSESOLUTION_TOOL_INPUT_SCHEMA = exports.CHOOSESOLUTION_TOOL_DESCRIPTION = exports.CHOOSESOLUTION_TOOL_NAME = void 0; exports.handleChooseSolutionTool = handleChooseSolutionTool; const zod_1 = require("zod"); const error_handling_1 = require("../core/error-handling"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const session_utils_1 = require("../core/session-utils"); // Tool metadata for direct MCP registration exports.CHOOSESOLUTION_TOOL_NAME = 'chooseSolution'; exports.CHOOSESOLUTION_TOOL_DESCRIPTION = 'Select a solution by ID and return its questions for configuration'; // Zod schema for MCP registration exports.CHOOSESOLUTION_TOOL_INPUT_SCHEMA = { solutionId: zod_1.z.string().regex(/^sol_[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{6}_[a-f0-9]+$/).describe('The solution ID to choose (e.g., sol_2025-07-01T154349_1e1e242592ff)') }; /** * Load solution file by ID */ function loadSolutionFile(solutionId, sessionDir) { const solutionPath = path.join(sessionDir, `${solutionId}.json`); if (!fs.existsSync(solutionPath)) { throw new Error(`Solution file not found: ${solutionPath}. Available files: ${fs.readdirSync(sessionDir).filter(f => f.endsWith('.json')).join(', ')}`); } try { const content = fs.readFileSync(solutionPath, 'utf8'); const solution = JSON.parse(content); // Validate solution structure if (!solution.solutionId || !solution.questions) { throw new Error(`Invalid solution file structure: ${solutionId}. Missing required fields: solutionId or questions`); } return solution; } catch (error) { if (error instanceof SyntaxError) { throw new Error(`Invalid JSON in solution file: ${solutionId}. ${error.message}`); } throw error; } } /** * Direct MCP tool handler for chooseSolution functionality */ async function handleChooseSolutionTool(args, dotAI, logger, requestId) { return await error_handling_1.ErrorHandler.withErrorHandling(async () => { logger.debug('Handling chooseSolution request', { requestId, solutionId: args?.solutionId }); // Input validation is handled automatically by MCP SDK with Zod schema // args are already validated and typed when we reach this point // Get session directory from environment let sessionDir; try { sessionDir = (0, session_utils_1.getAndValidateSessionDirectory)(args, false); // requireWrite=false logger.debug('Session directory resolved and validated', { sessionDir }); } catch (error) { throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, error instanceof Error ? error.message : 'Session directory validation failed', { operation: 'session_directory_validation', component: 'ChooseSolutionTool', requestId, suggestedActions: [ 'Ensure session directory exists and is readable', 'Check directory permissions', 'Verify the directory path is correct', 'Verify DOT_AI_SESSION_DIR environment variable is correctly set' ] }); } // Load solution file let solution; try { solution = loadSolutionFile(args.solutionId, sessionDir); logger.debug('Solution file loaded successfully', { solutionId: args.solutionId, hasQuestions: !!solution.questions, questionCategories: { required: solution.questions?.required?.length || 0, basic: solution.questions?.basic?.length || 0, advanced: solution.questions?.advanced?.length || 0, hasOpen: !!solution.questions?.open } }); } catch (error) { throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.STORAGE, error_handling_1.ErrorSeverity.HIGH, error instanceof Error ? error.message : 'Failed to load solution file', { operation: 'solution_file_load', component: 'ChooseSolutionTool', requestId, input: { solutionId: args.solutionId, sessionDir }, suggestedActions: [ 'Check that the solution ID is correct', 'Verify the solution file exists in the session directory', 'Ensure the solution was created by a recent recommend tool call', 'List available solution files in the session directory' ] }); } // Prepare response with solution details and questions const response = { status: 'stage_questions', solutionId: solution.solutionId, currentStage: 'required', questions: solution.questions.required || [], nextStage: 'basic', message: 'Please provide the required configuration for your application.', nextAction: 'answerQuestion', guidance: 'Answer questions in this stage or skip to proceed to the next stage. Do NOT try to generate manifests yet.', timestamp: new Date().toISOString() }; logger.info('Choose solution completed successfully', { solutionId: args.solutionId, sessionDir, questionCategories: { required: solution.questions.required?.length || 0, basic: solution.questions.basic?.length || 0, advanced: solution.questions.advanced?.length || 0, hasOpen: !!solution.questions.open }, totalQuestions: (solution.questions.required?.length || 0) + (solution.questions.basic?.length || 0) + (solution.questions.advanced?.length || 0) + (solution.questions.open ? 1 : 0) }); return { content: [{ type: 'text', text: JSON.stringify(response, null, 2) }] }; }, { operation: 'choose_solution', component: 'ChooseSolutionTool', requestId, input: args }); }