@vfarcic/dot-ai 0.150.0 → 0.152.0

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.
Files changed (56) hide show
  1. package/README.md +1 -1
  2. package/dist/core/ai-provider-factory.d.ts +0 -9
  3. package/dist/core/ai-provider-factory.d.ts.map +1 -1
  4. package/dist/core/ai-provider-factory.js +2 -34
  5. package/dist/core/ai-provider.interface.d.ts +2 -14
  6. package/dist/core/ai-provider.interface.d.ts.map +1 -1
  7. package/dist/core/artifacthub.d.ts +85 -0
  8. package/dist/core/artifacthub.d.ts.map +1 -0
  9. package/dist/core/artifacthub.js +106 -0
  10. package/dist/core/embedding-service.js +1 -1
  11. package/dist/core/helm-types.d.ts +39 -0
  12. package/dist/core/helm-types.d.ts.map +1 -0
  13. package/dist/core/helm-types.js +5 -0
  14. package/dist/core/helm-utils.d.ts +66 -0
  15. package/dist/core/helm-utils.d.ts.map +1 -0
  16. package/dist/core/helm-utils.js +196 -0
  17. package/dist/core/index.d.ts +7 -1
  18. package/dist/core/index.d.ts.map +1 -1
  19. package/dist/core/index.js +12 -0
  20. package/dist/core/providers/noop-provider.d.ts +0 -4
  21. package/dist/core/providers/noop-provider.d.ts.map +1 -1
  22. package/dist/core/providers/noop-provider.js +0 -6
  23. package/dist/core/providers/vercel-provider.d.ts +0 -1
  24. package/dist/core/providers/vercel-provider.d.ts.map +1 -1
  25. package/dist/core/providers/vercel-provider.js +1 -4
  26. package/dist/core/schema.d.ts +32 -4
  27. package/dist/core/schema.d.ts.map +1 -1
  28. package/dist/core/schema.js +200 -18
  29. package/dist/core/solution-cr.d.ts.map +1 -1
  30. package/dist/core/solution-cr.js +2 -3
  31. package/dist/tools/answer-question.d.ts +1 -1
  32. package/dist/tools/answer-question.d.ts.map +1 -1
  33. package/dist/tools/answer-question.js +85 -16
  34. package/dist/tools/choose-solution.d.ts.map +1 -1
  35. package/dist/tools/choose-solution.js +36 -24
  36. package/dist/tools/deploy-manifests.d.ts +2 -1
  37. package/dist/tools/deploy-manifests.d.ts.map +1 -1
  38. package/dist/tools/deploy-manifests.js +86 -2
  39. package/dist/tools/generate-manifests.d.ts +1 -0
  40. package/dist/tools/generate-manifests.d.ts.map +1 -1
  41. package/dist/tools/generate-manifests.js +204 -1
  42. package/dist/tools/recommend.d.ts +3 -2
  43. package/dist/tools/recommend.d.ts.map +1 -1
  44. package/dist/tools/recommend.js +116 -3
  45. package/package.json +11 -12
  46. package/prompts/helm-chart-selection.md +65 -0
  47. package/prompts/helm-generation.md +85 -0
  48. package/prompts/intent-analysis.md +17 -0
  49. package/prompts/question-generation.md +34 -24
  50. package/prompts/resource-selection.md +52 -8
  51. package/shared-prompts/prd-start.md +20 -10
  52. package/shared-prompts/prd-update-progress.md +18 -8
  53. package/dist/core/providers/anthropic-provider.d.ts +0 -51
  54. package/dist/core/providers/anthropic-provider.d.ts.map +0 -1
  55. package/dist/core/providers/anthropic-provider.js +0 -468
  56. /package/prompts/{manifest-generation.md → capabilities-generation.md} +0 -0
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
- * Deploy Manifests Tool - Apply Kubernetes manifests with readiness checking
3
+ * Deploy Manifests Tool - Apply Kubernetes manifests or execute Helm installations
4
+ * Supports both capability-based solutions (kubectl apply) and Helm-based solutions (helm install)
4
5
  */
5
6
  Object.defineProperty(exports, "__esModule", { value: true });
6
7
  exports.DEPLOYMANIFESTS_TOOL_INPUT_SCHEMA = exports.DEPLOYMANIFESTS_TOOL_DESCRIPTION = exports.DEPLOYMANIFESTS_TOOL_NAME = void 0;
@@ -9,6 +10,9 @@ const zod_1 = require("zod");
9
10
  const error_handling_1 = require("../core/error-handling");
10
11
  const deploy_operation_1 = require("../core/deploy-operation");
11
12
  const cluster_utils_1 = require("../core/cluster-utils");
13
+ const generic_session_manager_1 = require("../core/generic-session-manager");
14
+ const solution_utils_1 = require("../core/solution-utils");
15
+ const helm_utils_1 = require("../core/helm-utils");
12
16
  // Tool metadata for direct MCP registration
13
17
  exports.DEPLOYMANIFESTS_TOOL_NAME = 'deployManifests';
14
18
  exports.DEPLOYMANIFESTS_TOOL_DESCRIPTION = 'Deploy Kubernetes manifests from generated solution with kubectl apply --wait';
@@ -31,10 +35,89 @@ async function handleDeployManifestsTool(args, dotAI, logger, requestId) {
31
35
  // args are already validated and typed when we reach this point
32
36
  // Ensure cluster connectivity before proceeding
33
37
  await (0, cluster_utils_1.ensureClusterConnection)(dotAI, logger, requestId, 'DeployManifestsTool');
38
+ // Load solution session to determine solution type
39
+ const sessionManager = new generic_session_manager_1.GenericSessionManager('sol');
40
+ const session = sessionManager.getSession(args.solutionId);
41
+ if (!session) {
42
+ throw new Error(`Solution not found: ${args.solutionId}`);
43
+ }
44
+ const solution = session.data;
45
+ const timeout = args.timeout || 30;
46
+ logger.debug('Solution loaded successfully', {
47
+ solutionId: args.solutionId,
48
+ solutionType: solution.type
49
+ });
50
+ // Branch based on solution type
51
+ if (solution.type === 'helm') {
52
+ logger.info('Detected Helm solution, using Helm deployment flow', {
53
+ solutionId: args.solutionId,
54
+ chart: solution.chart ? `${solution.chart.repositoryName}/${solution.chart.chartName}` : 'unknown'
55
+ });
56
+ if (!solution.chart) {
57
+ throw new Error('Helm solution missing chart information');
58
+ }
59
+ const chart = solution.chart;
60
+ const userAnswers = (0, solution_utils_1.extractUserAnswers)(solution);
61
+ const releaseName = userAnswers.name;
62
+ const namespace = userAnswers.namespace || 'default';
63
+ if (!releaseName) {
64
+ throw new Error('Release name (name) is required for Helm deployment');
65
+ }
66
+ // Get values path if values file exists
67
+ const valuesPath = (0, helm_utils_1.helmValuesExist)(args.solutionId)
68
+ ? (0, helm_utils_1.getHelmValuesPath)(args.solutionId)
69
+ : undefined;
70
+ logger.info('Starting Helm deployment', {
71
+ solutionId: args.solutionId,
72
+ chart: `${chart.repositoryName}/${chart.chartName}`,
73
+ releaseName,
74
+ namespace,
75
+ hasValuesFile: !!valuesPath,
76
+ timeout,
77
+ requestId
78
+ });
79
+ const result = await (0, helm_utils_1.deployHelmRelease)(chart, releaseName, namespace, valuesPath, timeout);
80
+ logger.info('Helm deployment completed', {
81
+ success: result.success,
82
+ solutionId: args.solutionId,
83
+ releaseName,
84
+ namespace,
85
+ requestId
86
+ });
87
+ const response = {
88
+ success: result.success,
89
+ solutionId: args.solutionId,
90
+ solutionType: 'helm',
91
+ releaseName,
92
+ namespace,
93
+ chart: {
94
+ repository: chart.repository,
95
+ repositoryName: chart.repositoryName,
96
+ chartName: chart.chartName,
97
+ version: chart.version
98
+ },
99
+ message: result.success
100
+ ? `Helm release "${releaseName}" deployed successfully to namespace "${namespace}"`
101
+ : `Helm deployment failed: ${result.error}`,
102
+ helmOutput: result.output || result.error,
103
+ deploymentComplete: result.success,
104
+ timestamp: new Date().toISOString()
105
+ };
106
+ return {
107
+ content: [{
108
+ type: 'text',
109
+ text: JSON.stringify(response, null, 2)
110
+ }]
111
+ };
112
+ }
113
+ // Capability-based solution: Use existing DeployOperation
114
+ logger.info('Using capability-based deployment flow', {
115
+ solutionId: args.solutionId
116
+ });
34
117
  const deployOp = new deploy_operation_1.DeployOperation();
35
118
  const deployOptions = {
36
119
  solutionId: args.solutionId,
37
- timeout: args.timeout || 30
120
+ timeout
38
121
  };
39
122
  logger.info('Starting deployment operation', {
40
123
  solutionId: args.solutionId,
@@ -53,6 +136,7 @@ async function handleDeployManifestsTool(args, dotAI, logger, requestId) {
53
136
  const response = {
54
137
  success: result.success,
55
138
  solutionId: result.solutionId,
139
+ solutionType: 'capability',
56
140
  manifestPath: result.manifestPath,
57
141
  readinessTimeout: result.readinessTimeout,
58
142
  message: result.message,
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Generate Manifests Tool - AI-driven manifest generation with validation loop
3
+ * Supports both capability-based solutions (K8s manifests) and Helm-based solutions (values.yaml)
3
4
  */
4
5
  import { z } from 'zod';
5
6
  import { DotAI } from '../core/index';
@@ -1 +1 @@
1
- {"version":3,"file":"generate-manifests.d.ts","sourceRoot":"","sources":["../../src/tools/generate-manifests.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,EAA2B,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAehD,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAC/D,eAAO,MAAM,kCAAkC,+IAA+I,CAAC;AAG/L,eAAO,MAAM,mCAAmC;;;CAG/C,CAAC;AAsMF;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EACrD,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAqNxD"}
1
+ {"version":3,"file":"generate-manifests.d.ts","sourceRoot":"","sources":["../../src/tools/generate-manifests.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,EAA2B,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAsBhD,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAC/D,eAAO,MAAM,kCAAkC,+IAA+I,CAAC;AAG/L,eAAO,MAAM,mCAAmC;;;CAG/C,CAAC;AAmdF;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EACrD,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CA2OxD"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * Generate Manifests Tool - AI-driven manifest generation with validation loop
4
+ * Supports both capability-based solutions (K8s manifests) and Helm-based solutions (values.yaml)
4
5
  */
5
6
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
7
  if (k2 === undefined) k2 = k;
@@ -52,6 +53,7 @@ const solution_utils_1 = require("../core/solution-utils");
52
53
  const platform_utils_1 = require("../core/platform-utils");
53
54
  const crd_availability_1 = require("../core/crd-availability");
54
55
  const solution_cr_1 = require("../core/solution-cr");
56
+ const helm_utils_1 = require("../core/helm-utils");
55
57
  // Tool metadata for direct MCP registration
56
58
  exports.GENERATEMANIFESTS_TOOL_NAME = 'generateManifests';
57
59
  exports.GENERATEMANIFESTS_TOOL_DESCRIPTION = 'Generate final Kubernetes manifests from fully configured solution (ONLY after completing ALL stages: required, basic, advanced, and open)';
@@ -180,7 +182,7 @@ ${errorContext.previousManifests}
180
182
  // Prepare template variables
181
183
  const schemasData = JSON.stringify(resourceSchemas, null, 2);
182
184
  const labelsData = dotAiLabels ? JSON.stringify(dotAiLabels, null, 2) : '{}';
183
- const aiPrompt = (0, shared_prompt_loader_1.loadPrompt)('manifest-generation', {
185
+ const aiPrompt = (0, shared_prompt_loader_1.loadPrompt)('capabilities-generation', {
184
186
  solution: solutionData,
185
187
  schemas: schemasData,
186
188
  previous_attempt: previousAttempt,
@@ -211,6 +213,194 @@ ${errorContext.previousManifests}
211
213
  });
212
214
  return manifestContent;
213
215
  }
216
+ /**
217
+ * Generate Helm values.yaml using AI provider
218
+ */
219
+ async function generateHelmValuesWithAI(solution, solutionId, dotAI, logger, errorContext, interaction_id) {
220
+ // Fetch chart values.yaml for reference
221
+ const chart = solution.chart;
222
+ const { valuesYaml } = await dotAI.schema.fetchHelmChartContent(chart);
223
+ // Prepare template variables
224
+ const solutionData = JSON.stringify(solution, null, 2);
225
+ const previousAttempt = errorContext ? `
226
+ ### Generated Values:
227
+ \`\`\`yaml
228
+ ${errorContext.previousValues}
229
+ \`\`\`
230
+ ` : 'None - this is the first attempt.';
231
+ const errorDetails = errorContext ? `
232
+ **Attempt**: ${errorContext.attempt}
233
+ **Validation Errors**: ${errorContext.validationResult.errors.join(', ')}
234
+ **Validation Warnings**: ${errorContext.validationResult.warnings.join(', ')}
235
+ ` : 'None - this is the first attempt.';
236
+ const aiPrompt = (0, shared_prompt_loader_1.loadPrompt)('helm-generation', {
237
+ solution: solutionData,
238
+ chart_values: valuesYaml || '# No default values available',
239
+ previous_attempt: previousAttempt,
240
+ error_details: errorDetails
241
+ });
242
+ const isRetry = !!errorContext;
243
+ logger.info('Generating Helm values with AI', {
244
+ isRetry,
245
+ attempt: errorContext?.attempt,
246
+ hasErrorContext: !!errorContext,
247
+ solutionId,
248
+ chart: `${chart.repositoryName}/${chart.chartName}`
249
+ });
250
+ // Get AI provider from dotAI
251
+ const aiProvider = dotAI.ai;
252
+ // Send prompt to AI
253
+ const response = await aiProvider.sendMessage(aiPrompt, 'helm-values-generation', {
254
+ user_intent: solution.intent || 'Helm chart installation',
255
+ interaction_id: interaction_id
256
+ });
257
+ // Extract YAML content from response
258
+ const valuesContent = (0, platform_utils_1.extractContentFromMarkdownCodeBlocks)(response.content, 'yaml');
259
+ logger.info('AI Helm values generation completed', {
260
+ valuesLength: valuesContent.length,
261
+ isRetry,
262
+ solutionId
263
+ });
264
+ return valuesContent;
265
+ }
266
+ /**
267
+ * Validate Helm installation using dry-run (wrapper around shared utility)
268
+ */
269
+ async function validateHelmInstallation(chart, releaseName, namespace, valuesPath, logger) {
270
+ logger.info('Running Helm dry-run validation', {
271
+ chart: `${chart.repositoryName}/${chart.chartName}`,
272
+ releaseName,
273
+ namespace
274
+ });
275
+ const result = await (0, helm_utils_1.validateHelmDryRun)(chart, releaseName, namespace, valuesPath);
276
+ if (result.success) {
277
+ logger.info('Helm dry-run validation successful');
278
+ return {
279
+ valid: true,
280
+ errors: [],
281
+ warnings: []
282
+ };
283
+ }
284
+ logger.warn('Helm dry-run validation failed', { error: result.error });
285
+ return {
286
+ valid: false,
287
+ errors: [result.error || 'Unknown Helm validation error'],
288
+ warnings: []
289
+ };
290
+ }
291
+ /**
292
+ * Handle Helm solution generation
293
+ */
294
+ async function handleHelmGeneration(solution, solutionId, dotAI, logger, requestId, interaction_id) {
295
+ const maxAttempts = 10;
296
+ const chart = solution.chart;
297
+ const userAnswers = (0, solution_utils_1.extractUserAnswers)(solution);
298
+ // Extract release name and namespace from answers
299
+ const releaseName = userAnswers.name;
300
+ const namespace = userAnswers.namespace || 'default';
301
+ if (!releaseName) {
302
+ throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.VALIDATION, error_handling_1.ErrorSeverity.HIGH, 'Release name (name) is required for Helm installation', {
303
+ operation: 'helm_generation',
304
+ component: 'GenerateManifestsTool',
305
+ requestId,
306
+ suggestedActions: ['Ensure the "name" question was answered in the configuration']
307
+ });
308
+ }
309
+ // Prepare file paths using shared utilities
310
+ (0, helm_utils_1.ensureTmpDir)();
311
+ const valuesPath = (0, helm_utils_1.getHelmValuesPath)(solutionId);
312
+ // AI generation and validation loop
313
+ let lastError;
314
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
315
+ logger.info('Helm values generation attempt', {
316
+ attempt,
317
+ maxAttempts,
318
+ isRetry: attempt > 1,
319
+ requestId,
320
+ chart: `${chart.repositoryName}/${chart.chartName}`
321
+ });
322
+ try {
323
+ // Generate values.yaml with AI
324
+ const valuesYaml = await generateHelmValuesWithAI(solution, solutionId, dotAI, logger, lastError, interaction_id);
325
+ // Save values to file
326
+ fs.writeFileSync(valuesPath, valuesYaml, 'utf8');
327
+ logger.info('Helm values saved to file', { valuesPath, attempt, requestId });
328
+ // Save attempt for debugging
329
+ const attemptPath = valuesPath.replace('.yaml', `_attempt_${attempt.toString().padStart(2, '0')}.yaml`);
330
+ fs.writeFileSync(attemptPath, valuesYaml, 'utf8');
331
+ // Validate with helm dry-run
332
+ const validation = await validateHelmInstallation(chart, releaseName, namespace, valuesPath, logger);
333
+ if (validation.valid) {
334
+ logger.info('Helm validation successful', {
335
+ attempt,
336
+ valuesPath,
337
+ requestId
338
+ });
339
+ // Build user-friendly helm command with generic values file path
340
+ // (internal valuesPath is used for actual execution, not shown to user)
341
+ const helmCommand = (0, helm_utils_1.buildHelmCommand)(chart, releaseName, namespace, 'values.yaml');
342
+ // Check if we should show feedback message
343
+ const feedbackMessage = (0, index_1.maybeGetFeedbackMessage)();
344
+ const response = {
345
+ success: true,
346
+ status: 'helm_command_generated',
347
+ solutionId: solutionId,
348
+ solutionType: 'helm',
349
+ helmCommand: helmCommand,
350
+ valuesYaml: valuesYaml,
351
+ chart: {
352
+ repository: chart.repository,
353
+ repositoryName: chart.repositoryName,
354
+ chartName: chart.chartName,
355
+ version: chart.version
356
+ },
357
+ releaseName: releaseName,
358
+ namespace: namespace,
359
+ validationAttempts: attempt,
360
+ timestamp: new Date().toISOString(),
361
+ ...(feedbackMessage ? { message: feedbackMessage } : {})
362
+ };
363
+ return {
364
+ content: [{
365
+ type: 'text',
366
+ text: JSON.stringify(response, null, 2)
367
+ }]
368
+ };
369
+ }
370
+ // Validation failed, prepare error context for next attempt
371
+ lastError = {
372
+ attempt,
373
+ previousValues: valuesYaml,
374
+ validationResult: validation
375
+ };
376
+ logger.warn('Helm validation failed', {
377
+ attempt,
378
+ maxAttempts,
379
+ validationErrors: validation.errors,
380
+ validationWarnings: validation.warnings,
381
+ requestId
382
+ });
383
+ }
384
+ catch (error) {
385
+ logger.error('Error during Helm values generation attempt', error);
386
+ if (attempt === maxAttempts) {
387
+ throw error;
388
+ }
389
+ // Prepare error context for retry
390
+ lastError = {
391
+ attempt,
392
+ previousValues: lastError?.previousValues || '',
393
+ validationResult: {
394
+ valid: false,
395
+ errors: [error instanceof Error ? error.message : String(error)],
396
+ warnings: []
397
+ }
398
+ };
399
+ }
400
+ }
401
+ // All attempts failed
402
+ throw new Error(`Failed to generate valid Helm values after ${maxAttempts} attempts. Last errors: ${lastError?.validationResult.errors.join(', ')}`);
403
+ }
214
404
  /**
215
405
  * Direct MCP tool handler for generateManifests functionality
216
406
  */
@@ -247,9 +437,22 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId) {
247
437
  const solution = session.data;
248
438
  logger.debug('Solution loaded successfully', {
249
439
  solutionId: args.solutionId,
440
+ solutionType: solution.type,
250
441
  hasQuestions: !!solution.questions,
251
442
  primaryResources: solution.resources
252
443
  });
444
+ // Branch based on solution type
445
+ if (solution.type === 'helm') {
446
+ logger.info('Detected Helm solution, using Helm generation flow', {
447
+ solutionId: args.solutionId,
448
+ chart: solution.chart ? `${solution.chart.repositoryName}/${solution.chart.chartName}` : 'unknown'
449
+ });
450
+ return await handleHelmGeneration(solution, args.solutionId, dotAI, logger, requestId, args.interaction_id);
451
+ }
452
+ // Capability-based solution: Generate Kubernetes manifests
453
+ logger.info('Using capability-based manifest generation flow', {
454
+ solutionId: args.solutionId
455
+ });
253
456
  // Prepare file path for manifests (store in tmp directory)
254
457
  const tmpDir = path.join(process.cwd(), 'tmp');
255
458
  if (!fs.existsSync(tmpDir)) {
@@ -4,6 +4,7 @@
4
4
  import { z } from 'zod';
5
5
  import { DotAI } from '../core/index';
6
6
  import { Logger } from '../core/error-handling';
7
+ import { HelmChartInfo } from '../core/helm-types';
7
8
  export declare const RECOMMEND_TOOL_NAME = "recommend";
8
9
  export declare const RECOMMEND_TOOL_DESCRIPTION = "Deploy applications, infrastructure, and services using Kubernetes resources with AI recommendations. Supports cloud resources via operators like Crossplane, cluster management via CAPI, and traditional Kubernetes workloads. Describe what you want to deploy. Does NOT handle policy creation, organizational patterns, or resource capabilities - use manageOrgData for those.";
9
10
  export declare const RECOMMEND_TOOL_INPUT_SCHEMA: {
@@ -21,13 +22,13 @@ export interface SolutionData {
21
22
  score: number;
22
23
  description: string;
23
24
  reasons: string[];
24
- analysis: string;
25
- resources: Array<{
25
+ resources?: Array<{
26
26
  kind: string;
27
27
  apiVersion: string;
28
28
  group: string;
29
29
  description: string;
30
30
  }>;
31
+ chart?: HelmChartInfo;
31
32
  questions: {
32
33
  required?: any[];
33
34
  basic?: any[];
@@ -1 +1 @@
1
- {"version":3,"file":"recommend.d.ts","sourceRoot":"","sources":["../../src/tools/recommend.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAWhD,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAC/C,eAAO,MAAM,0BAA0B,yXAAyX,CAAC;AAGja,eAAO,MAAM,2BAA2B;;;;;;;;CAWvC,CAAC;AAGF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;IACH,SAAS,EAAE;QACT,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;QACd,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;IACF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAuED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,GAAG,EACT,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAgPxD"}
1
+ {"version":3,"file":"recommend.d.ts","sourceRoot":"","sources":["../../src/tools/recommend.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAUhD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAC/C,eAAO,MAAM,0BAA0B,yXAAyX,CAAC;AAGja,eAAO,MAAM,2BAA2B;;;;;;;;CAWvC,CAAC;AAIF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE;QACT,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;QACd,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;IACF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAuED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,GAAG,EACT,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAuXxD"}
@@ -16,6 +16,7 @@ const generate_manifests_1 = require("./generate-manifests");
16
16
  const deploy_manifests_1 = require("./deploy-manifests");
17
17
  const shared_prompt_loader_1 = require("../core/shared-prompt-loader");
18
18
  const platform_utils_1 = require("../core/platform-utils");
19
+ const artifacthub_1 = require("../core/artifacthub");
19
20
  // Tool metadata for direct MCP registration
20
21
  exports.RECOMMEND_TOOL_NAME = 'recommend';
21
22
  exports.RECOMMEND_TOOL_DESCRIPTION = 'Deploy applications, infrastructure, and services using Kubernetes resources with AI recommendations. Supports cloud resources via operators like Crossplane, cluster management via CAPI, and traditional Kubernetes workloads. Describe what you want to deploy. Does NOT handle policy creation, organizational patterns, or resource capabilities - use manageOrgData for those.';
@@ -187,7 +188,121 @@ async function handleRecommendTool(args, dotAI, logger, requestId) {
187
188
  };
188
189
  // Find best solutions for the user intent
189
190
  logger.debug('Generating recommendations with AI', { requestId });
190
- const solutions = await recommender.findBestSolutions(args.intent, explainResourceFn, args.interaction_id);
191
+ const solutionResult = await recommender.findBestSolutions(args.intent, explainResourceFn, args.interaction_id);
192
+ // Handle Helm recommendation case
193
+ if (solutionResult.helmRecommendation) {
194
+ logger.info('Helm installation recommended, searching ArtifactHub', {
195
+ requestId,
196
+ suggestedTool: solutionResult.helmRecommendation.suggestedTool,
197
+ searchQuery: solutionResult.helmRecommendation.searchQuery,
198
+ reason: solutionResult.helmRecommendation.reason
199
+ });
200
+ // Search ArtifactHub for matching charts
201
+ const artifactHub = new artifacthub_1.ArtifactHubService();
202
+ const charts = await artifactHub.searchCharts(solutionResult.helmRecommendation.searchQuery, 10 // Get top 10 results for AI to analyze
203
+ );
204
+ if (charts.length === 0) {
205
+ // No charts found on ArtifactHub
206
+ logger.warn('No charts found on ArtifactHub', { requestId, searchQuery: solutionResult.helmRecommendation.searchQuery });
207
+ return {
208
+ content: [{
209
+ type: 'text',
210
+ text: JSON.stringify({
211
+ status: 'no_charts_found',
212
+ searchQuery: solutionResult.helmRecommendation.searchQuery,
213
+ reason: solutionResult.helmRecommendation.reason,
214
+ message: `No Helm charts found on ArtifactHub for "${solutionResult.helmRecommendation.suggestedTool}". We currently only support charts available on ArtifactHub. If you need support for charts from other sources, please open an issue at https://github.com/vfarcic/dot-ai/issues/new`
215
+ }, null, 2)
216
+ }]
217
+ };
218
+ }
219
+ // Format charts for AI analysis
220
+ const chartsText = artifactHub.formatChartsForAI(charts);
221
+ // Load prompt and send to AI for chart selection
222
+ const chartSelectionPrompt = (0, shared_prompt_loader_1.loadPrompt)('helm-chart-selection', {
223
+ intent: args.intent,
224
+ charts: chartsText
225
+ });
226
+ const aiResponse = await dotAI.ai.sendMessage(chartSelectionPrompt, 'recommend-helm-chart-selection', {
227
+ user_intent: args.intent,
228
+ interaction_id: args.interaction_id
229
+ });
230
+ // Parse AI response
231
+ const aiSelection = (0, platform_utils_1.extractJsonFromAIResponse)(aiResponse.content);
232
+ if (!aiSelection.solutions || aiSelection.solutions.length === 0) {
233
+ // AI couldn't find matching charts
234
+ logger.warn('AI found no matching charts', { requestId, noMatchReason: aiSelection.noMatchReason });
235
+ return {
236
+ content: [{
237
+ type: 'text',
238
+ text: JSON.stringify({
239
+ status: 'no_matching_charts',
240
+ reason: aiSelection.noMatchReason || 'No charts matched the user intent',
241
+ searchQuery: solutionResult.helmRecommendation.searchQuery,
242
+ instruction: 'Consider refining your request or manually specifying a Helm chart.'
243
+ }, null, 2)
244
+ }]
245
+ };
246
+ }
247
+ // Create sessions for Helm solutions
248
+ const timestamp = new Date().toISOString();
249
+ const helmSolutionSummaries = [];
250
+ for (const aiSolution of aiSelection.solutions) {
251
+ // Find the original chart data from ArtifactHub results
252
+ const originalChart = charts.find(c => c.name === aiSolution.chartName);
253
+ const solutionData = {
254
+ intent: args.intent,
255
+ type: 'helm',
256
+ score: aiSolution.score,
257
+ description: aiSolution.description,
258
+ reasons: aiSolution.reasons,
259
+ chart: {
260
+ repository: aiSolution.repositoryUrl,
261
+ repositoryName: aiSolution.repositoryName,
262
+ chartName: aiSolution.chartName,
263
+ version: aiSolution.version,
264
+ appVersion: aiSolution.appVersion,
265
+ official: originalChart?.official || originalChart?.repository?.official,
266
+ verifiedPublisher: originalChart?.verified_publisher || originalChart?.repository?.verified_publisher
267
+ },
268
+ questions: { required: [], basic: [], advanced: [] }, // Will be generated from chart values later
269
+ answers: {},
270
+ timestamp
271
+ };
272
+ const session = sessionManager.createSession(solutionData);
273
+ const solutionId = session.sessionId;
274
+ logger.debug('Helm solution session created', { requestId, solutionId });
275
+ helmSolutionSummaries.push({
276
+ solutionId,
277
+ type: 'helm',
278
+ score: aiSolution.score,
279
+ description: aiSolution.description,
280
+ chart: solutionData.chart,
281
+ reasons: aiSolution.reasons
282
+ });
283
+ }
284
+ // Build Helm solutions response
285
+ const helmResponse = {
286
+ intent: args.intent,
287
+ solutions: helmSolutionSummaries,
288
+ helmInstallation: true,
289
+ nextAction: 'Call recommend tool with stage: chooseSolution and your preferred solutionId',
290
+ guidance: '🔴 CRITICAL: Present these Helm chart options to the user and ask them to choose. DO NOT automatically call chooseSolution() without user input. Show the chart details (repository, version, official status) to help users decide.',
291
+ timestamp
292
+ };
293
+ logger.info('Helm solutions prepared', {
294
+ requestId,
295
+ solutionCount: helmSolutionSummaries.length,
296
+ topScore: helmSolutionSummaries[0]?.score
297
+ });
298
+ return {
299
+ content: [{
300
+ type: 'text',
301
+ text: JSON.stringify(helmResponse, null, 2)
302
+ }]
303
+ };
304
+ }
305
+ const solutions = solutionResult.solutions;
191
306
  logger.info('Recommendation process completed', {
192
307
  requestId,
193
308
  solutionCount: solutions.length,
@@ -206,7 +321,6 @@ async function handleRecommendTool(args, dotAI, logger, requestId) {
206
321
  score: solution.score,
207
322
  description: solution.description,
208
323
  reasons: solution.reasons,
209
- analysis: solution.analysis,
210
324
  resources: solution.resources.map(r => ({
211
325
  kind: r.kind,
212
326
  apiVersion: r.apiVersion,
@@ -236,7 +350,6 @@ async function handleRecommendTool(args, dotAI, logger, requestId) {
236
350
  description: r.description?.split('\n')[0] || `${r.kind} resource` // Use first line of description or fallback
237
351
  })),
238
352
  reasons: solution.reasons,
239
- analysis: solution.analysis,
240
353
  appliedPatterns: solution.appliedPatterns || [],
241
354
  relevantPolicies: solution.questions?.relevantPolicies || []
242
355
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vfarcic/dot-ai",
3
- "version": "0.150.0",
3
+ "version": "0.152.0",
4
4
  "description": "AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance",
5
5
  "mcpName": "io.github.vfarcic/dot-ai",
6
6
  "main": "dist/index.js",
@@ -18,16 +18,16 @@
18
18
  "test:integration:server": "KUBECONFIG=./kubeconfig-test.yaml PORT=3456 DOT_AI_SESSION_DIR=./tmp/sessions TRANSPORT_TYPE=http QDRANT_URL=http://localhost:6335 QDRANT_CAPABILITIES_COLLECTION=capabilities-policies ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY OPENAI_API_KEY=$OPENAI_API_KEY node dist/mcp/server.js",
19
19
  "test:integration": "./tests/integration/infrastructure/run-integration-tests.sh",
20
20
  "test:integration:watch": "vitest --config=vitest.integration.config.ts --test-timeout=1200000",
21
- "test:integration:sonnet": "AI_PROVIDER=anthropic AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
22
- "test:integration:opus": "AI_PROVIDER=anthropic_opus AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
23
- "test:integration:haiku": "AI_PROVIDER=anthropic_haiku AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
24
- "test:integration:gpt": "AI_PROVIDER=openai AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
25
- "test:integration:gemini": "AI_PROVIDER=google AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
26
- "test:integration:grok": "AI_PROVIDER=xai AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
27
- "test:integration:kimi": "AI_PROVIDER=kimi AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
28
- "test:integration:kimi-thinking": "AI_PROVIDER=kimi_thinking AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
29
- "test:integration:bedrock": "AI_PROVIDER=amazon_bedrock AI_MODEL=global.anthropic.claude-sonnet-4-20250514-v1:0 AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
30
- "test:integration:custom-endpoint": "AI_PROVIDER=openai AI_PROVIDER_SDK=vercel DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
21
+ "test:integration:sonnet": "AI_PROVIDER=anthropic DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
22
+ "test:integration:opus": "AI_PROVIDER=anthropic_opus DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
23
+ "test:integration:haiku": "AI_PROVIDER=anthropic_haiku DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
24
+ "test:integration:gpt": "AI_PROVIDER=openai DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
25
+ "test:integration:gemini": "AI_PROVIDER=google DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
26
+ "test:integration:grok": "AI_PROVIDER=xai DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
27
+ "test:integration:kimi": "AI_PROVIDER=kimi DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
28
+ "test:integration:kimi-thinking": "AI_PROVIDER=kimi_thinking DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
29
+ "test:integration:bedrock": "AI_PROVIDER=amazon_bedrock AI_MODEL=global.anthropic.claude-sonnet-4-20250514-v1:0 DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
30
+ "test:integration:custom-endpoint": "AI_PROVIDER=openai DEBUG_DOT_AI=true ./tests/integration/infrastructure/run-integration-tests.sh",
31
31
  "eval:comparative": "DEBUG_DOT_AI=true npx tsx src/evaluation/eval-runner.ts",
32
32
  "eval:platform-synthesis": "DEBUG_DOT_AI=true npx tsx src/evaluation/run-platform-synthesis.ts",
33
33
  "clean": "rm -rf dist",
@@ -100,7 +100,6 @@
100
100
  "@ai-sdk/google": "^2.0.17",
101
101
  "@ai-sdk/openai": "^2.0.42",
102
102
  "@ai-sdk/xai": "^2.0.26",
103
- "@anthropic-ai/sdk": "^0.65.0",
104
103
  "@kubernetes/client-node": "^1.3.0",
105
104
  "@modelcontextprotocol/sdk": "^1.13.2",
106
105
  "@openrouter/ai-sdk-provider": "^1.2.0",