@vfarcic/dot-ai 0.4.9 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/context-load.md +11 -0
- package/.claude/commands/context-save.md +16 -0
- package/.claude/commands/prd-done.md +115 -0
- package/.claude/commands/prd-get.md +25 -0
- package/.claude/commands/prd-start.md +87 -0
- package/.claude/commands/task-done.md +77 -0
- package/.claude/commands/tests-reminder.md +32 -0
- package/.claude/settings.local.json +20 -0
- package/.eslintrc.json +25 -0
- package/.github/workflows/ci.yml +170 -0
- package/.prettierrc.json +10 -0
- package/.teller.yml +8 -0
- package/CLAUDE.md +162 -0
- package/assets/images/logo.png +0 -0
- package/bin/dot-ai.ts +47 -0
- package/destroy.sh +45 -0
- package/devbox.json +13 -0
- package/devbox.lock +225 -0
- package/docs/API.md +449 -0
- package/docs/CONTEXT.md +49 -0
- package/docs/DEVELOPMENT.md +203 -0
- package/docs/NEXT_STEPS.md +97 -0
- package/docs/STAGE_BASED_API.md +97 -0
- package/docs/cli-guide.md +798 -0
- package/docs/design.md +750 -0
- package/docs/discovery-engine.md +515 -0
- package/docs/error-handling.md +429 -0
- package/docs/function-registration.md +157 -0
- package/docs/mcp-guide.md +416 -0
- package/package.json +2 -123
- package/renovate.json +51 -0
- package/setup.sh +111 -0
- package/{dist/cli.js → src/cli.ts} +26 -19
- package/src/core/claude.ts +280 -0
- package/src/core/deploy-operation.ts +127 -0
- package/src/core/discovery.ts +900 -0
- package/src/core/error-handling.ts +562 -0
- package/src/core/index.ts +143 -0
- package/src/core/kubernetes-utils.ts +218 -0
- package/src/core/memory.ts +148 -0
- package/src/core/schema.ts +830 -0
- package/src/core/session-utils.ts +97 -0
- package/src/core/workflow.ts +234 -0
- package/src/index.ts +18 -0
- package/src/interfaces/cli.ts +872 -0
- package/src/interfaces/mcp.ts +183 -0
- package/src/mcp/server.ts +131 -0
- package/src/tools/answer-question.ts +807 -0
- package/src/tools/choose-solution.ts +169 -0
- package/src/tools/deploy-manifests.ts +94 -0
- package/src/tools/generate-manifests.ts +502 -0
- package/src/tools/index.ts +41 -0
- package/src/tools/recommend.ts +370 -0
- package/tests/__mocks__/@kubernetes/client-node.ts +106 -0
- package/tests/build-system.test.ts +345 -0
- package/tests/configuration.test.ts +226 -0
- package/tests/core/deploy-operation.test.ts +38 -0
- package/tests/core/discovery.test.ts +1648 -0
- package/tests/core/error-handling.test.ts +632 -0
- package/tests/core/schema.test.ts +1658 -0
- package/tests/core/session-utils.test.ts +245 -0
- package/tests/core.test.ts +439 -0
- package/tests/fixtures/configmap-no-labels.yaml +8 -0
- package/tests/fixtures/crossplane-app-configuration.yaml +6 -0
- package/tests/fixtures/crossplane-providers.yaml +45 -0
- package/tests/fixtures/crossplane-rbac.yaml +48 -0
- package/tests/fixtures/invalid-configmap.yaml +8 -0
- package/tests/fixtures/invalid-deployment.yaml +17 -0
- package/tests/fixtures/test-deployment.yaml +28 -0
- package/tests/fixtures/valid-configmap.yaml +15 -0
- package/tests/infrastructure.test.ts +426 -0
- package/tests/interfaces/cli.test.ts +1036 -0
- package/tests/interfaces/mcp.test.ts +139 -0
- package/tests/kubernetes-utils.test.ts +200 -0
- package/tests/mcp/server.test.ts +126 -0
- package/tests/setup.ts +31 -0
- package/tests/tools/answer-question.test.ts +367 -0
- package/tests/tools/choose-solution.test.ts +481 -0
- package/tests/tools/deploy-manifests.test.ts +185 -0
- package/tests/tools/generate-manifests.test.ts +441 -0
- package/tests/tools/index.test.ts +111 -0
- package/tests/tools/recommend.test.ts +180 -0
- package/tsconfig.json +34 -0
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/core/claude.d.ts +0 -42
- package/dist/core/claude.d.ts.map +0 -1
- package/dist/core/claude.js +0 -229
- package/dist/core/deploy-operation.d.ts +0 -38
- package/dist/core/deploy-operation.d.ts.map +0 -1
- package/dist/core/deploy-operation.js +0 -101
- package/dist/core/discovery.d.ts +0 -162
- package/dist/core/discovery.d.ts.map +0 -1
- package/dist/core/discovery.js +0 -758
- package/dist/core/error-handling.d.ts +0 -167
- package/dist/core/error-handling.d.ts.map +0 -1
- package/dist/core/error-handling.js +0 -399
- package/dist/core/index.d.ts +0 -42
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -123
- package/dist/core/kubernetes-utils.d.ts +0 -38
- package/dist/core/kubernetes-utils.d.ts.map +0 -1
- package/dist/core/kubernetes-utils.js +0 -177
- package/dist/core/memory.d.ts +0 -45
- package/dist/core/memory.d.ts.map +0 -1
- package/dist/core/memory.js +0 -113
- package/dist/core/schema.d.ts +0 -187
- package/dist/core/schema.d.ts.map +0 -1
- package/dist/core/schema.js +0 -655
- package/dist/core/session-utils.d.ts +0 -29
- package/dist/core/session-utils.d.ts.map +0 -1
- package/dist/core/session-utils.js +0 -121
- package/dist/core/workflow.d.ts +0 -70
- package/dist/core/workflow.d.ts.map +0 -1
- package/dist/core/workflow.js +0 -161
- package/dist/index.d.ts +0 -15
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -32
- package/dist/interfaces/cli.d.ts +0 -74
- package/dist/interfaces/cli.d.ts.map +0 -1
- package/dist/interfaces/cli.js +0 -769
- package/dist/interfaces/mcp.d.ts +0 -30
- package/dist/interfaces/mcp.d.ts.map +0 -1
- package/dist/interfaces/mcp.js +0 -105
- package/dist/mcp/server.d.ts +0 -9
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -151
- package/dist/tools/answer-question.d.ts +0 -27
- package/dist/tools/answer-question.d.ts.map +0 -1
- package/dist/tools/answer-question.js +0 -696
- package/dist/tools/choose-solution.d.ts +0 -23
- package/dist/tools/choose-solution.d.ts.map +0 -1
- package/dist/tools/choose-solution.js +0 -171
- package/dist/tools/deploy-manifests.d.ts +0 -25
- package/dist/tools/deploy-manifests.d.ts.map +0 -1
- package/dist/tools/deploy-manifests.js +0 -74
- package/dist/tools/generate-manifests.d.ts +0 -23
- package/dist/tools/generate-manifests.d.ts.map +0 -1
- package/dist/tools/generate-manifests.js +0 -424
- package/dist/tools/index.d.ts +0 -11
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -34
- package/dist/tools/recommend.d.ts +0 -23
- package/dist/tools/recommend.d.ts.map +0 -1
- package/dist/tools/recommend.js +0 -332
package/dist/tools/recommend.js
DELETED
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Recommend Tool - AI-powered Kubernetes resource recommendations
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
-
}) : function(o, v) {
|
|
19
|
-
o["default"] = v;
|
|
20
|
-
});
|
|
21
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
-
var ownKeys = function(o) {
|
|
23
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
-
var ar = [];
|
|
25
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
-
return ar;
|
|
27
|
-
};
|
|
28
|
-
return ownKeys(o);
|
|
29
|
-
};
|
|
30
|
-
return function (mod) {
|
|
31
|
-
if (mod && mod.__esModule) return mod;
|
|
32
|
-
var result = {};
|
|
33
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
-
__setModuleDefault(result, mod);
|
|
35
|
-
return result;
|
|
36
|
-
};
|
|
37
|
-
})();
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.RECOMMEND_TOOL_INPUT_SCHEMA = exports.RECOMMEND_TOOL_DESCRIPTION = exports.RECOMMEND_TOOL_NAME = void 0;
|
|
40
|
-
exports.handleRecommendTool = handleRecommendTool;
|
|
41
|
-
const zod_1 = require("zod");
|
|
42
|
-
const error_handling_1 = require("../core/error-handling");
|
|
43
|
-
const schema_1 = require("../core/schema");
|
|
44
|
-
const claude_1 = require("../core/claude");
|
|
45
|
-
const fs = __importStar(require("fs"));
|
|
46
|
-
const path = __importStar(require("path"));
|
|
47
|
-
const crypto = __importStar(require("crypto"));
|
|
48
|
-
const session_utils_1 = require("../core/session-utils");
|
|
49
|
-
// Tool metadata for direct MCP registration
|
|
50
|
-
exports.RECOMMEND_TOOL_NAME = 'recommend';
|
|
51
|
-
exports.RECOMMEND_TOOL_DESCRIPTION = 'Deploy, create, run, or setup applications on Kubernetes with AI-powered recommendations. Ask the user to describe their application first, then use their response here.';
|
|
52
|
-
// Zod schema for MCP registration
|
|
53
|
-
exports.RECOMMEND_TOOL_INPUT_SCHEMA = {
|
|
54
|
-
intent: zod_1.z.string().min(1).max(1000).describe('What the user wants to deploy, create, run, or setup on Kubernetes (based on their description). Ask the user to describe their application first, then use their response here. Examples: "deploy a web application", "create a database cluster", "run my Node.js API", "setup a Redis cache", "launch a microservice", "build a CI/CD pipeline", "deploy a WordPress site", "create a monitoring stack", "run a Python Flask app", "setup MongoDB", "deploy a React frontend", "create a load balancer"')
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* Validate intent meaningfulness using AI
|
|
58
|
-
*/
|
|
59
|
-
async function validateIntentWithAI(intent, claudeIntegration) {
|
|
60
|
-
try {
|
|
61
|
-
// Load prompt template
|
|
62
|
-
const promptPath = path.join(process.cwd(), 'prompts', 'intent-validation.md');
|
|
63
|
-
const template = fs.readFileSync(promptPath, 'utf8');
|
|
64
|
-
// Replace template variables
|
|
65
|
-
const validationPrompt = template.replace('{intent}', intent);
|
|
66
|
-
// Send to Claude for validation
|
|
67
|
-
const response = await claudeIntegration.sendMessage(validationPrompt);
|
|
68
|
-
// Parse JSON response with robust error handling
|
|
69
|
-
let jsonContent = response.content;
|
|
70
|
-
// Try to find JSON object wrapped in code blocks
|
|
71
|
-
const codeBlockMatch = response.content.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/);
|
|
72
|
-
if (codeBlockMatch) {
|
|
73
|
-
jsonContent = codeBlockMatch[1];
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// Try to find JSON object that starts with { and find the matching closing }
|
|
77
|
-
const startIndex = response.content.indexOf('{');
|
|
78
|
-
if (startIndex !== -1) {
|
|
79
|
-
let braceCount = 0;
|
|
80
|
-
let endIndex = startIndex;
|
|
81
|
-
for (let i = startIndex; i < response.content.length; i++) {
|
|
82
|
-
if (response.content[i] === '{')
|
|
83
|
-
braceCount++;
|
|
84
|
-
if (response.content[i] === '}')
|
|
85
|
-
braceCount--;
|
|
86
|
-
if (braceCount === 0) {
|
|
87
|
-
endIndex = i;
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (braceCount === 0) {
|
|
92
|
-
jsonContent = response.content.substring(startIndex, endIndex + 1);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const validation = JSON.parse(jsonContent.trim());
|
|
97
|
-
// Validate response structure
|
|
98
|
-
if (typeof validation.isSpecific !== 'boolean' ||
|
|
99
|
-
typeof validation.reason !== 'string' ||
|
|
100
|
-
!Array.isArray(validation.suggestions)) {
|
|
101
|
-
throw new Error('AI response has invalid structure');
|
|
102
|
-
}
|
|
103
|
-
// If intent is not specific enough, throw error with suggestions
|
|
104
|
-
if (!validation.isSpecific) {
|
|
105
|
-
const suggestions = validation.suggestions.length
|
|
106
|
-
? validation.suggestions.map((s) => `• ${s}`).join('\n')
|
|
107
|
-
: '• Include specific technology (Node.js, PostgreSQL, React, etc.)\n• Describe the purpose or function\n• Add context about requirements';
|
|
108
|
-
throw new Error(`Intent needs more specificity: ${validation.reason}\n\n` +
|
|
109
|
-
`Suggestions to improve your intent:\n${suggestions}\n\n` +
|
|
110
|
-
`Original intent: "${intent}"`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
// If it's our validation error, re-throw it
|
|
115
|
-
if (error instanceof Error && error.message.includes('Intent needs more specificity')) {
|
|
116
|
-
throw error;
|
|
117
|
-
}
|
|
118
|
-
// For other errors (AI service issues, JSON parsing, etc.),
|
|
119
|
-
// continue without blocking the user - log the issue but don't fail
|
|
120
|
-
console.warn('Intent validation failed, continuing with original intent:', error);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Generate unique solution ID with timestamp and random component
|
|
126
|
-
*/
|
|
127
|
-
function generateSolutionId() {
|
|
128
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '').split('T');
|
|
129
|
-
const dateTime = timestamp[0] + 'T' + timestamp[1].substring(0, 6);
|
|
130
|
-
const randomHex = crypto.randomBytes(6).toString('hex');
|
|
131
|
-
return `sol_${dateTime}_${randomHex}`;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Write solution data to file atomically (temp file + rename)
|
|
135
|
-
*/
|
|
136
|
-
function writeSolutionFile(sessionDir, solutionId, solutionData) {
|
|
137
|
-
const fileName = `${solutionId}.json`;
|
|
138
|
-
const filePath = path.join(sessionDir, fileName);
|
|
139
|
-
const tempPath = filePath + '.tmp';
|
|
140
|
-
try {
|
|
141
|
-
// Write to temporary file first
|
|
142
|
-
fs.writeFileSync(tempPath, JSON.stringify(solutionData, null, 2));
|
|
143
|
-
// Atomically rename to final location
|
|
144
|
-
fs.renameSync(tempPath, filePath);
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
// Clean up temp file if it exists
|
|
148
|
-
try {
|
|
149
|
-
if (fs.existsSync(tempPath)) {
|
|
150
|
-
fs.unlinkSync(tempPath);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
catch (cleanupError) {
|
|
154
|
-
// Ignore cleanup errors
|
|
155
|
-
}
|
|
156
|
-
throw new Error(`Failed to write solution file ${fileName}: ${error}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Direct MCP tool handler for recommend functionality
|
|
161
|
-
*/
|
|
162
|
-
async function handleRecommendTool(args, dotAI, logger, requestId) {
|
|
163
|
-
return await error_handling_1.ErrorHandler.withErrorHandling(async () => {
|
|
164
|
-
logger.debug('Handling recommend request', { requestId, intent: args?.intent });
|
|
165
|
-
// Input validation is handled automatically by MCP SDK with Zod schema
|
|
166
|
-
// args are already validated and typed when we reach this point
|
|
167
|
-
// Check for Claude API key
|
|
168
|
-
const claudeApiKey = dotAI.getAnthropicApiKey();
|
|
169
|
-
if (!claudeApiKey) {
|
|
170
|
-
throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.AI_SERVICE, error_handling_1.ErrorSeverity.HIGH, 'ANTHROPIC_API_KEY environment variable must be set for AI-powered resource recommendations', {
|
|
171
|
-
operation: 'api_key_check',
|
|
172
|
-
component: 'RecommendTool',
|
|
173
|
-
requestId,
|
|
174
|
-
suggestedActions: [
|
|
175
|
-
'Set ANTHROPIC_API_KEY environment variable',
|
|
176
|
-
'Verify the API key is valid and active',
|
|
177
|
-
'Check that the API key has sufficient credits'
|
|
178
|
-
]
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
// Validate session directory configuration
|
|
182
|
-
let sessionDir;
|
|
183
|
-
try {
|
|
184
|
-
sessionDir = (0, session_utils_1.getAndValidateSessionDirectory)(args, true); // requireWrite=true
|
|
185
|
-
logger.debug('Session directory validated', { requestId, sessionDir });
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, `Session directory validation failed: ${error instanceof Error ? error.message : 'Unknown error'}`, {
|
|
189
|
-
operation: 'session_directory_validation',
|
|
190
|
-
component: 'RecommendTool',
|
|
191
|
-
requestId,
|
|
192
|
-
suggestedActions: [
|
|
193
|
-
'Ensure session directory exists and is writable',
|
|
194
|
-
'Set --session-dir parameter or DOT_AI_SESSION_DIR environment variable',
|
|
195
|
-
'Check directory permissions'
|
|
196
|
-
]
|
|
197
|
-
}, error instanceof Error ? error : new Error(String(error)));
|
|
198
|
-
}
|
|
199
|
-
logger.info('Starting resource recommendation process', {
|
|
200
|
-
requestId,
|
|
201
|
-
intent: args.intent,
|
|
202
|
-
hasApiKey: !!claudeApiKey
|
|
203
|
-
});
|
|
204
|
-
// Validate intent specificity with AI before expensive resource discovery
|
|
205
|
-
logger.debug('Validating intent specificity', { requestId, intent: args.intent });
|
|
206
|
-
try {
|
|
207
|
-
const claudeIntegration = new claude_1.ClaudeIntegration(claudeApiKey);
|
|
208
|
-
await validateIntentWithAI(args.intent, claudeIntegration);
|
|
209
|
-
logger.debug('Intent validation passed', { requestId });
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
if (error instanceof Error && error.message.includes('Intent needs more specificity')) {
|
|
213
|
-
// This is a validation error that should be returned to the user
|
|
214
|
-
throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.MEDIUM, error.message, {
|
|
215
|
-
operation: 'intent_validation',
|
|
216
|
-
component: 'RecommendTool',
|
|
217
|
-
requestId,
|
|
218
|
-
input: { intent: args.intent },
|
|
219
|
-
suggestedActions: [
|
|
220
|
-
'Provide more specific details about your deployment',
|
|
221
|
-
'Include technology stack information',
|
|
222
|
-
'Describe the purpose or function of what you want to deploy'
|
|
223
|
-
]
|
|
224
|
-
}, error);
|
|
225
|
-
}
|
|
226
|
-
// For other errors, log but continue (don't block user due to AI service issues)
|
|
227
|
-
logger.warn('Intent validation failed, continuing with recommendation', { requestId, error: error instanceof Error ? error.message : 'Unknown error' });
|
|
228
|
-
}
|
|
229
|
-
// Initialize AI-powered ResourceRecommender
|
|
230
|
-
const rankingConfig = { claudeApiKey };
|
|
231
|
-
const recommender = new schema_1.ResourceRecommender(rankingConfig);
|
|
232
|
-
// Create discovery functions
|
|
233
|
-
const discoverResourcesFn = async () => {
|
|
234
|
-
logger.debug('Discovering cluster resources', { requestId });
|
|
235
|
-
return await dotAI.discovery.discoverResources();
|
|
236
|
-
};
|
|
237
|
-
const explainResourceFn = async (resource) => {
|
|
238
|
-
logger.debug(`Explaining resource: ${resource}`, { requestId });
|
|
239
|
-
return await dotAI.discovery.explainResource(resource);
|
|
240
|
-
};
|
|
241
|
-
// Find best solutions for the user intent
|
|
242
|
-
logger.debug('Generating recommendations with AI', { requestId });
|
|
243
|
-
const solutions = await recommender.findBestSolutions(args.intent, discoverResourcesFn, explainResourceFn);
|
|
244
|
-
logger.info('Recommendation process completed', {
|
|
245
|
-
requestId,
|
|
246
|
-
solutionCount: solutions.length,
|
|
247
|
-
topScore: solutions[0]?.score
|
|
248
|
-
});
|
|
249
|
-
// Create solution files and build response
|
|
250
|
-
const solutionSummaries = [];
|
|
251
|
-
const timestamp = new Date().toISOString();
|
|
252
|
-
// Limit to top 5 solutions (respecting quality thresholds from AI ranking)
|
|
253
|
-
const topSolutions = solutions.slice(0, 5);
|
|
254
|
-
for (const solution of topSolutions) {
|
|
255
|
-
const solutionId = generateSolutionId();
|
|
256
|
-
// Create complete solution file with all data
|
|
257
|
-
const solutionFileData = {
|
|
258
|
-
solutionId,
|
|
259
|
-
intent: args.intent,
|
|
260
|
-
type: solution.type,
|
|
261
|
-
score: solution.score,
|
|
262
|
-
description: solution.description,
|
|
263
|
-
reasons: solution.reasons,
|
|
264
|
-
analysis: solution.analysis,
|
|
265
|
-
resources: solution.resources.map(r => ({
|
|
266
|
-
kind: r.kind,
|
|
267
|
-
apiVersion: r.apiVersion,
|
|
268
|
-
group: r.group,
|
|
269
|
-
description: r.description
|
|
270
|
-
})),
|
|
271
|
-
questions: solution.questions,
|
|
272
|
-
answers: {}, // Empty initially - will be filled by answerQuestion tool
|
|
273
|
-
timestamp
|
|
274
|
-
};
|
|
275
|
-
// Write solution to file
|
|
276
|
-
try {
|
|
277
|
-
writeSolutionFile(sessionDir, solutionId, solutionFileData);
|
|
278
|
-
logger.debug('Solution file created', { requestId, solutionId, fileName: `${solutionId}.json` });
|
|
279
|
-
}
|
|
280
|
-
catch (error) {
|
|
281
|
-
throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.STORAGE, error_handling_1.ErrorSeverity.HIGH, `Failed to store solution file: ${error instanceof Error ? error.message : 'Unknown error'}`, {
|
|
282
|
-
operation: 'solution_file_creation',
|
|
283
|
-
component: 'RecommendTool',
|
|
284
|
-
requestId,
|
|
285
|
-
input: { solutionId },
|
|
286
|
-
suggestedActions: [
|
|
287
|
-
'Check session directory write permissions',
|
|
288
|
-
'Ensure sufficient disk space',
|
|
289
|
-
'Verify session directory is accessible'
|
|
290
|
-
]
|
|
291
|
-
}, error instanceof Error ? error : new Error(String(error)));
|
|
292
|
-
}
|
|
293
|
-
// Add to response summary (decision-making data only)
|
|
294
|
-
solutionSummaries.push({
|
|
295
|
-
solutionId,
|
|
296
|
-
type: solution.type,
|
|
297
|
-
score: solution.score,
|
|
298
|
-
description: solution.description,
|
|
299
|
-
primaryResources: solution.resources.slice(0, 3).map(r => r.kind),
|
|
300
|
-
reasons: solution.reasons,
|
|
301
|
-
analysis: solution.analysis
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
// Build new response format
|
|
305
|
-
const response = {
|
|
306
|
-
intent: args.intent,
|
|
307
|
-
solutions: solutionSummaries,
|
|
308
|
-
nextAction: "Call chooseSolution with your preferred solutionId",
|
|
309
|
-
guidance: "🛑 NEVER choose automatically - Present ALL solutions to user and ask them to choose by calling chooseSolution(solutionId)",
|
|
310
|
-
timestamp
|
|
311
|
-
};
|
|
312
|
-
logger.info('Solution files created and response prepared', {
|
|
313
|
-
requestId,
|
|
314
|
-
solutionCount: solutionSummaries.length,
|
|
315
|
-
sessionDir
|
|
316
|
-
});
|
|
317
|
-
return {
|
|
318
|
-
content: [{
|
|
319
|
-
type: 'text',
|
|
320
|
-
text: JSON.stringify(response, null, 2)
|
|
321
|
-
}]
|
|
322
|
-
};
|
|
323
|
-
}, {
|
|
324
|
-
operation: 'recommend_tool',
|
|
325
|
-
component: 'RecommendTool',
|
|
326
|
-
requestId,
|
|
327
|
-
input: args
|
|
328
|
-
}, {
|
|
329
|
-
convertToMcp: true,
|
|
330
|
-
retryCount: 1
|
|
331
|
-
});
|
|
332
|
-
}
|