@vfarcic/dot-ai 1.2.4 → 1.4.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 (74) hide show
  1. package/dist/core/artifacthub.d.ts.map +1 -1
  2. package/dist/core/artifacthub.js +16 -10
  3. package/dist/core/base-vector-service.d.ts.map +1 -1
  4. package/dist/core/base-vector-service.js +19 -10
  5. package/dist/core/capabilities.d.ts.map +1 -1
  6. package/dist/core/capabilities.js +17 -11
  7. package/dist/core/capability-operations.d.ts.map +1 -1
  8. package/dist/core/capability-operations.js +118 -98
  9. package/dist/core/crd-availability.d.ts.map +1 -1
  10. package/dist/core/crd-availability.js +2 -2
  11. package/dist/core/deploy-operation.d.ts.map +1 -1
  12. package/dist/core/deploy-operation.js +9 -6
  13. package/dist/core/discovery.d.ts.map +1 -1
  14. package/dist/core/discovery.js +157 -56
  15. package/dist/core/embedding-service.d.ts +1 -1
  16. package/dist/core/embedding-service.d.ts.map +1 -1
  17. package/dist/core/embedding-service.js +76 -43
  18. package/dist/core/model-config.d.ts +3 -3
  19. package/dist/core/model-config.js +3 -3
  20. package/dist/core/packaging.d.ts.map +1 -1
  21. package/dist/core/packaging.js +11 -10
  22. package/dist/core/platform-utils.d.ts.map +1 -1
  23. package/dist/core/platform-utils.js +6 -2
  24. package/dist/core/plugin-manager.d.ts.map +1 -1
  25. package/dist/core/plugin-manager.js +26 -20
  26. package/dist/core/policy-operations.d.ts.map +1 -1
  27. package/dist/core/policy-operations.js +111 -65
  28. package/dist/core/providers/host-provider.d.ts.map +1 -1
  29. package/dist/core/providers/host-provider.js +12 -5
  30. package/dist/core/providers/vercel-provider.d.ts.map +1 -1
  31. package/dist/core/providers/vercel-provider.js +4 -2
  32. package/dist/core/schema.d.ts.map +1 -1
  33. package/dist/core/schema.js +173 -95
  34. package/dist/core/session-utils.d.ts.map +1 -1
  35. package/dist/core/session-utils.js +3 -3
  36. package/dist/core/user-prompts-loader.d.ts.map +1 -1
  37. package/dist/core/user-prompts-loader.js +2 -4
  38. package/dist/evaluation/datasets/loader.d.ts.map +1 -1
  39. package/dist/evaluation/datasets/loader.js +7 -3
  40. package/dist/interfaces/embedding-migration-handler.d.ts +16 -0
  41. package/dist/interfaces/embedding-migration-handler.d.ts.map +1 -0
  42. package/dist/interfaces/embedding-migration-handler.js +296 -0
  43. package/dist/interfaces/rest-api.d.ts +8 -0
  44. package/dist/interfaces/rest-api.d.ts.map +1 -1
  45. package/dist/interfaces/rest-api.js +294 -132
  46. package/dist/interfaces/rest-route-registry.js +3 -3
  47. package/dist/interfaces/routes/index.d.ts.map +1 -1
  48. package/dist/interfaces/routes/index.js +72 -12
  49. package/dist/interfaces/schemas/common.d.ts +2 -0
  50. package/dist/interfaces/schemas/common.d.ts.map +1 -1
  51. package/dist/interfaces/schemas/common.js +2 -0
  52. package/dist/interfaces/schemas/embeddings.d.ts +138 -0
  53. package/dist/interfaces/schemas/embeddings.d.ts.map +1 -0
  54. package/dist/interfaces/schemas/embeddings.js +79 -0
  55. package/dist/interfaces/schemas/index.d.ts +2 -1
  56. package/dist/interfaces/schemas/index.d.ts.map +1 -1
  57. package/dist/interfaces/schemas/index.js +14 -2
  58. package/dist/interfaces/schemas/prompts.d.ts +37 -0
  59. package/dist/interfaces/schemas/prompts.d.ts.map +1 -1
  60. package/dist/interfaces/schemas/prompts.js +18 -1
  61. package/dist/tools/answer-question.d.ts.map +1 -1
  62. package/dist/tools/answer-question.js +109 -81
  63. package/dist/tools/generate-manifests.d.ts.map +1 -1
  64. package/dist/tools/generate-manifests.js +163 -103
  65. package/dist/tools/operate-analysis.d.ts.map +1 -1
  66. package/dist/tools/operate-analysis.js +35 -18
  67. package/dist/tools/operate.d.ts.map +1 -1
  68. package/dist/tools/operate.js +47 -17
  69. package/dist/tools/prompts.d.ts.map +1 -1
  70. package/dist/tools/prompts.js +1 -1
  71. package/dist/tools/remediate.d.ts.map +1 -1
  72. package/dist/tools/remediate.js +205 -116
  73. package/package.json +6 -6
  74. package/prompts/remediate-system.md +1 -1
@@ -84,7 +84,7 @@ function buildHelmCommandForDisplay(chart, releaseName, namespace, valuesPath) {
84
84
  releaseName,
85
85
  `${chart.repositoryName}/${chart.chartName}`,
86
86
  `--namespace ${namespace}`,
87
- '--create-namespace'
87
+ '--create-namespace',
88
88
  ];
89
89
  if (chart.version) {
90
90
  parts.push(`--version ${chart.version}`);
@@ -100,8 +100,14 @@ exports.GENERATEMANIFESTS_TOOL_NAME = 'generateManifests';
100
100
  exports.GENERATEMANIFESTS_TOOL_DESCRIPTION = 'Generate final Kubernetes manifests from fully configured solution (ONLY after completing ALL stages: required, basic, advanced, and open)';
101
101
  // Zod schema for MCP registration
102
102
  exports.GENERATEMANIFESTS_TOOL_INPUT_SCHEMA = {
103
- solutionId: zod_1.z.string().regex(/^sol-\d+-[a-f0-9]{8}$/).describe('The solution ID to generate manifests for (e.g., sol-1762983784617-9ddae2b8)'),
104
- interaction_id: zod_1.z.string().optional().describe('INTERNAL ONLY - Do not populate. Used for evaluation dataset generation.')
103
+ solutionId: zod_1.z
104
+ .string()
105
+ .regex(/^sol-\d+-[a-f0-9]{8}$/)
106
+ .describe('The solution ID to generate manifests for (e.g., sol-1762983784617-9ddae2b8)'),
107
+ interaction_id: zod_1.z
108
+ .string()
109
+ .optional()
110
+ .describe('INTERNAL ONLY - Do not populate. Used for evaluation dataset generation.'),
105
111
  };
106
112
  /**
107
113
  * Retrieve schemas for resources specified in the solution
@@ -112,7 +118,7 @@ async function retrieveResourceSchemas(solution, dotAI, logger) {
112
118
  const resourceRefs = (solution.resources || []).map((resource) => ({
113
119
  kind: resource.kind,
114
120
  apiVersion: resource.apiVersion,
115
- group: resource.group
121
+ group: resource.group,
116
122
  }));
117
123
  if (resourceRefs.length === 0) {
118
124
  logger.warn('No resources found in solution for schema retrieval');
@@ -120,7 +126,7 @@ async function retrieveResourceSchemas(solution, dotAI, logger) {
120
126
  }
121
127
  logger.info('Retrieving schemas for solution resources', {
122
128
  resourceCount: resourceRefs.length,
123
- resources: resourceRefs.map((r) => `${r.kind}@${r.apiVersion}`)
129
+ resources: resourceRefs.map((r) => `${r.kind}@${r.apiVersion}`),
124
130
  });
125
131
  const schemas = {};
126
132
  // Retrieve schema for each resource
@@ -134,29 +140,29 @@ async function retrieveResourceSchemas(solution, dotAI, logger) {
134
140
  kind: resourceRef.kind,
135
141
  apiVersion: resourceRef.apiVersion,
136
142
  explanation,
137
- retrievedAt: new Date().toISOString()
143
+ retrievedAt: new Date().toISOString(),
138
144
  };
139
145
  logger.debug('Schema retrieved successfully', {
140
146
  resourceKey,
141
- schemaLength: explanation.length
147
+ schemaLength: explanation.length,
142
148
  });
143
149
  }
144
150
  catch (error) {
145
151
  logger.error('Failed to retrieve schema for resource', error, {
146
- resource: resourceRef
152
+ resource: resourceRef,
147
153
  });
148
154
  // Fail fast - if we can't get schemas, manifest generation will likely fail
149
- throw new Error(`Failed to retrieve schema for ${resourceRef.kind}: ${error instanceof Error ? error.message : String(error)}`);
155
+ throw new Error(`Failed to retrieve schema for ${resourceRef.kind}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
150
156
  }
151
157
  }
152
158
  logger.info('All resource schemas retrieved successfully', {
153
- schemaCount: Object.keys(schemas).length
159
+ schemaCount: Object.keys(schemas).length,
154
160
  });
155
161
  return schemas;
156
162
  }
157
163
  catch (error) {
158
164
  logger.error('Schema retrieval failed', error);
159
- throw new Error(`Failed to retrieve resource schemas: ${error instanceof Error ? error.message : String(error)}`);
165
+ throw new Error(`Failed to retrieve resource schemas: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
160
166
  }
161
167
  }
162
168
  /**
@@ -170,7 +176,7 @@ function validateYamlSyntax(yamlContent) {
170
176
  catch (error) {
171
177
  return {
172
178
  valid: false,
173
- error: error instanceof Error ? error.message : 'Unknown YAML syntax error'
179
+ error: error instanceof Error ? error.message : 'Unknown YAML syntax error',
174
180
  };
175
181
  }
176
182
  }
@@ -227,7 +233,7 @@ async function validateManifests(yamlPath) {
227
233
  return {
228
234
  valid: false,
229
235
  errors: [`Manifest file not found: ${yamlPath}`],
230
- warnings: []
236
+ warnings: [],
231
237
  };
232
238
  }
233
239
  // Read YAML content for syntax validation
@@ -238,7 +244,7 @@ async function validateManifests(yamlPath) {
238
244
  return {
239
245
  valid: false,
240
246
  errors: [`YAML syntax error: ${syntaxCheck.error}`],
241
- warnings: []
247
+ warnings: [],
242
248
  };
243
249
  }
244
250
  // 2. kubectl dry-run validation using ManifestValidator
@@ -254,17 +260,21 @@ async function generateManifestsWithAI(solution, solutionId, dotAI, logger, erro
254
260
  const resourceSchemas = await retrieveResourceSchemas(solution, dotAI, logger);
255
261
  // Prepare template variables
256
262
  const solutionData = JSON.stringify(solution, null, 2);
257
- const previousAttempt = errorContext ? `
263
+ const previousAttempt = errorContext
264
+ ? `
258
265
  ### Generated Manifests:
259
266
  \`\`\`yaml
260
267
  ${errorContext.previousManifests}
261
268
  \`\`\`
262
- ` : 'None - this is the first attempt.';
263
- const errorDetails = errorContext ? `
269
+ `
270
+ : 'None - this is the first attempt.';
271
+ const errorDetails = errorContext
272
+ ? `
264
273
  **Attempt**: ${errorContext.attempt}
265
274
  **Validation Errors**: ${errorContext.validationResult.errors.join(', ')}
266
275
  **Validation Warnings**: ${errorContext.validationResult.warnings.join(', ')}
267
- ` : 'None - this is the first attempt.';
276
+ `
277
+ : 'None - this is the first attempt.';
268
278
  // Prepare template variables
269
279
  const schemasData = JSON.stringify(resourceSchemas, null, 2);
270
280
  const labelsData = dotAiLabels ? JSON.stringify(dotAiLabels, null, 2) : '{}';
@@ -273,21 +283,21 @@ ${errorContext.previousManifests}
273
283
  schemas: schemasData,
274
284
  previous_attempt: previousAttempt,
275
285
  error_details: errorDetails,
276
- labels: labelsData
286
+ labels: labelsData,
277
287
  });
278
288
  const isRetry = !!errorContext;
279
289
  logger.info('Generating manifests with AI', {
280
290
  isRetry,
281
291
  attempt: errorContext?.attempt,
282
292
  hasErrorContext: !!errorContext,
283
- solutionId
293
+ solutionId,
284
294
  });
285
295
  // Get AI provider from dotAI
286
296
  const aiProvider = dotAI.ai;
287
297
  // Send prompt to AI
288
298
  const response = await aiProvider.sendMessage(aiPrompt, 'recommend-manifests-generation', {
289
299
  user_intent: solution.initialIntent || 'Kubernetes manifest generation',
290
- interaction_id: interaction_id
300
+ interaction_id: interaction_id,
291
301
  });
292
302
  // Extract YAML content from response
293
303
  // Use shared utility to extract from code blocks if wrapped
@@ -295,7 +305,7 @@ ${errorContext.previousManifests}
295
305
  logger.info('AI manifest generation completed', {
296
306
  manifestLength: manifestContent.length,
297
307
  isRetry,
298
- solutionId
308
+ solutionId,
299
309
  });
300
310
  return manifestContent;
301
311
  }
@@ -308,22 +318,26 @@ async function generateHelmValuesWithAI(solution, solutionId, dotAI, logger, err
308
318
  const { valuesYaml } = await dotAI.schema.fetchHelmChartContent(chart);
309
319
  // Prepare template variables
310
320
  const solutionData = JSON.stringify(solution, null, 2);
311
- const previousAttempt = errorContext ? `
321
+ const previousAttempt = errorContext
322
+ ? `
312
323
  ### Generated Values:
313
324
  \`\`\`yaml
314
325
  ${errorContext.previousValues}
315
326
  \`\`\`
316
- ` : 'None - this is the first attempt.';
317
- const errorDetails = errorContext ? `
327
+ `
328
+ : 'None - this is the first attempt.';
329
+ const errorDetails = errorContext
330
+ ? `
318
331
  **Attempt**: ${errorContext.attempt}
319
332
  **Validation Errors**: ${errorContext.validationResult.errors.join(', ')}
320
333
  **Validation Warnings**: ${errorContext.validationResult.warnings.join(', ')}
321
- ` : 'None - this is the first attempt.';
334
+ `
335
+ : 'None - this is the first attempt.';
322
336
  const aiPrompt = (0, shared_prompt_loader_1.loadPrompt)('helm-generation', {
323
337
  solution: solutionData,
324
338
  chart_values: valuesYaml || '# No default values available',
325
339
  previous_attempt: previousAttempt,
326
- error_details: errorDetails
340
+ error_details: errorDetails,
327
341
  });
328
342
  const isRetry = !!errorContext;
329
343
  logger.info('Generating Helm values with AI', {
@@ -331,21 +345,21 @@ ${errorContext.previousValues}
331
345
  attempt: errorContext?.attempt,
332
346
  hasErrorContext: !!errorContext,
333
347
  solutionId,
334
- chart: `${chart.repositoryName}/${chart.chartName}`
348
+ chart: `${chart.repositoryName}/${chart.chartName}`,
335
349
  });
336
350
  // Get AI provider from dotAI
337
351
  const aiProvider = dotAI.ai;
338
352
  // Send prompt to AI
339
353
  const response = await aiProvider.sendMessage(aiPrompt, 'helm-values-generation', {
340
354
  user_intent: solution.intent || 'Helm chart installation',
341
- interaction_id: interaction_id
355
+ interaction_id: interaction_id,
342
356
  });
343
357
  // Extract YAML content from response
344
358
  const valuesContent = (0, platform_utils_1.extractContentFromMarkdownCodeBlocks)(response.content, 'yaml');
345
359
  logger.info('AI Helm values generation completed', {
346
360
  valuesLength: valuesContent.length,
347
361
  isRetry,
348
- solutionId
362
+ solutionId,
349
363
  });
350
364
  return valuesContent;
351
365
  }
@@ -360,20 +374,20 @@ async function validateHelmInstallation(chart, releaseName, namespace, valuesYam
360
374
  logger.info('Running Helm dry-run validation via plugin', {
361
375
  chart: `${chart.repositoryName}/${chart.chartName}`,
362
376
  releaseName,
363
- namespace
377
+ namespace,
364
378
  });
365
379
  try {
366
380
  // PRD #359: First, add/update the Helm repository via unified registry
367
381
  const repoResult = await (0, plugin_registry_1.invokePluginTool)('agentic-tools', 'helm_repo_add', {
368
382
  name: chart.repositoryName,
369
- url: chart.repository
383
+ url: chart.repository,
370
384
  });
371
385
  if (!repoResult.success) {
372
386
  logger.warn('Helm repo add failed', { error: repoResult.error?.message });
373
387
  return {
374
388
  valid: false,
375
389
  errors: [repoResult.error?.message || 'Failed to add Helm repository'],
376
- warnings: []
390
+ warnings: [],
377
391
  };
378
392
  }
379
393
  // Run helm install with dry-run
@@ -384,21 +398,23 @@ async function validateHelmInstallation(chart, releaseName, namespace, valuesYam
384
398
  values: valuesYaml,
385
399
  version: chart.version,
386
400
  dryRun: true,
387
- createNamespace: true
401
+ createNamespace: true,
388
402
  });
389
403
  if (installResult.success) {
390
404
  logger.info('Helm dry-run validation successful');
391
405
  return {
392
406
  valid: true,
393
407
  errors: [],
394
- warnings: []
408
+ warnings: [],
395
409
  };
396
410
  }
397
- logger.warn('Helm dry-run validation failed', { error: installResult.error?.message });
411
+ logger.warn('Helm dry-run validation failed', {
412
+ error: installResult.error?.message,
413
+ });
398
414
  return {
399
415
  valid: false,
400
416
  errors: [installResult.error?.message || 'Unknown Helm validation error'],
401
- warnings: []
417
+ warnings: [],
402
418
  };
403
419
  }
404
420
  catch (error) {
@@ -407,7 +423,7 @@ async function validateHelmInstallation(chart, releaseName, namespace, valuesYam
407
423
  return {
408
424
  valid: false,
409
425
  errors: [errorMessage],
410
- warnings: []
426
+ warnings: [],
411
427
  };
412
428
  }
413
429
  }
@@ -427,7 +443,9 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
427
443
  operation: 'helm_generation',
428
444
  component: 'GenerateManifestsTool',
429
445
  requestId,
430
- suggestedActions: ['Ensure the "name" question was answered in the configuration']
446
+ suggestedActions: [
447
+ 'Ensure the "name" question was answered in the configuration',
448
+ ],
431
449
  });
432
450
  }
433
451
  // Prepare file paths using shared utilities
@@ -441,14 +459,18 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
441
459
  maxAttempts,
442
460
  isRetry: attempt > 1,
443
461
  requestId,
444
- chart: `${chart.repositoryName}/${chart.chartName}`
462
+ chart: `${chart.repositoryName}/${chart.chartName}`,
445
463
  });
446
464
  try {
447
465
  // Generate values.yaml with AI
448
466
  const valuesYaml = await generateHelmValuesWithAI(solution, solutionId, dotAI, logger, lastError, interaction_id);
449
467
  // Save values to file
450
468
  fs.writeFileSync(valuesPath, valuesYaml, 'utf8');
451
- logger.info('Helm values saved to file', { valuesPath, attempt, requestId });
469
+ logger.info('Helm values saved to file', {
470
+ valuesPath,
471
+ attempt,
472
+ requestId,
473
+ });
452
474
  // Save attempt for debugging
453
475
  const attemptPath = valuesPath.replace('.yaml', `_attempt_${attempt.toString().padStart(2, '0')}.yaml`);
454
476
  fs.writeFileSync(attemptPath, valuesYaml, 'utf8');
@@ -459,7 +481,7 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
459
481
  logger.info('Helm validation successful', {
460
482
  attempt,
461
483
  valuesPath,
462
- requestId
484
+ requestId,
463
485
  });
464
486
  // Build user-friendly helm command with generic values file path
465
487
  // (internal valuesPath is used for actual execution, not shown to user)
@@ -476,12 +498,12 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
476
498
  repository: chart.repository,
477
499
  repositoryName: chart.repositoryName,
478
500
  chartName: chart.chartName,
479
- version: chart.version || 'latest'
501
+ version: chart.version || 'latest',
480
502
  },
481
503
  releaseName: releaseName,
482
504
  namespace: namespace,
483
- validationAttempts: attempt
484
- }
505
+ validationAttempts: attempt,
506
+ },
485
507
  });
486
508
  // PRD #320: Generate visualization URL
487
509
  const visualizationUrl = (0, visualization_1.getVisualizationUrl)(solutionId);
@@ -496,19 +518,21 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
496
518
  repository: chart.repository,
497
519
  repositoryName: chart.repositoryName,
498
520
  chartName: chart.chartName,
499
- version: chart.version
521
+ version: chart.version,
500
522
  },
501
523
  releaseName: releaseName,
502
524
  namespace: namespace,
503
525
  validationAttempts: attempt,
504
526
  timestamp: new Date().toISOString(),
505
- ...(visualizationUrl ? { visualizationUrl } : {})
527
+ ...(visualizationUrl ? { visualizationUrl } : {}),
506
528
  };
507
529
  // Build content blocks - JSON for REST API, agent instruction for MCP agents
508
- const content = [{
530
+ const content = [
531
+ {
509
532
  type: 'text',
510
- text: JSON.stringify(response, null, 2)
511
- }];
533
+ text: JSON.stringify(response, null, 2),
534
+ },
535
+ ];
512
536
  // Add agent instruction block if visualization URL is present
513
537
  const agentDisplayBlock = (0, index_1.buildAgentDisplayBlock)({ visualizationUrl });
514
538
  if (agentDisplayBlock) {
@@ -520,14 +544,14 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
520
544
  lastError = {
521
545
  attempt,
522
546
  previousValues: valuesYaml,
523
- validationResult: validation
547
+ validationResult: validation,
524
548
  };
525
549
  logger.warn('Helm validation failed', {
526
550
  attempt,
527
551
  maxAttempts,
528
552
  validationErrors: validation.errors,
529
553
  validationWarnings: validation.warnings,
530
- requestId
554
+ requestId,
531
555
  });
532
556
  }
533
557
  catch (error) {
@@ -542,8 +566,8 @@ async function handleHelmGeneration(solution, solutionId, dotAI, logger, request
542
566
  validationResult: {
543
567
  valid: false,
544
568
  errors: [error instanceof Error ? error.message : String(error)],
545
- warnings: []
546
- }
569
+ warnings: [],
570
+ },
547
571
  };
548
572
  }
549
573
  }
@@ -581,7 +605,7 @@ async function renderPackageToYaml(packageDir, format, logger) {
581
605
  return {
582
606
  success: false,
583
607
  error: errorMessage,
584
- isTerminalError // Signal to caller to not retry
608
+ isTerminalError, // Signal to caller to not retry
585
609
  };
586
610
  }
587
611
  }
@@ -620,12 +644,19 @@ async function packageAndValidate(rawManifests, solution, outputFormat, outputPa
620
644
  fs.rmSync(packageDir, { recursive: true });
621
645
  }
622
646
  catch (cleanupError) {
623
- logger.warn('Failed to cleanup temp package directory', { packageDir, error: cleanupError });
647
+ logger.warn('Failed to cleanup temp package directory', {
648
+ packageDir,
649
+ error: cleanupError,
650
+ });
624
651
  }
625
652
  }
626
653
  };
627
654
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
628
- logger.info('Packaging attempt', { attempt, maxAttempts, format: outputFormat });
655
+ logger.info('Packaging attempt', {
656
+ attempt,
657
+ maxAttempts,
658
+ format: outputFormat,
659
+ });
629
660
  try {
630
661
  const packagingResult = await (0, packaging_1.packageManifests)(rawManifests,
631
662
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Different SolutionData types between modules
@@ -643,9 +674,12 @@ async function packageAndValidate(rawManifests, solution, outputFormat, outputPa
643
674
  packagingError = {
644
675
  attempt,
645
676
  previousOutput: JSON.stringify(packagingResult.files.map(f => f.relativePath)),
646
- validationError: `helm lint failed: ${lintResult.errors.join(', ')}`
677
+ validationError: `helm lint failed: ${lintResult.errors.join(', ')}`,
647
678
  };
648
- logger.warn('helm lint failed', { attempt, errors: lintResult.errors });
679
+ logger.warn('helm lint failed', {
680
+ attempt,
681
+ errors: lintResult.errors,
682
+ });
649
683
  continue;
650
684
  }
651
685
  // Log warnings but don't fail on them
@@ -660,16 +694,19 @@ async function packageAndValidate(rawManifests, solution, outputFormat, outputPa
660
694
  if (renderResult.isTerminalError) {
661
695
  const terminalError = new Error(`Infrastructure error (not retryable): ${renderResult.error}`);
662
696
  logger.error('Terminal infrastructure error - cannot retry', terminalError, {
663
- format: outputFormat
697
+ format: outputFormat,
664
698
  });
665
699
  throw terminalError;
666
700
  }
667
701
  packagingError = {
668
702
  attempt,
669
703
  previousOutput: JSON.stringify(packagingResult.files.map(f => f.relativePath)),
670
- validationError: `Failed to render ${outputFormat}: ${renderResult.error}`
704
+ validationError: `Failed to render ${outputFormat}: ${renderResult.error}`,
671
705
  };
672
- logger.warn('Package render failed', { attempt, error: renderResult.error });
706
+ logger.warn('Package render failed', {
707
+ attempt,
708
+ error: renderResult.error,
709
+ });
673
710
  continue;
674
711
  }
675
712
  // Validate rendered YAML
@@ -680,16 +717,22 @@ async function packageAndValidate(rawManifests, solution, outputFormat, outputPa
680
717
  fs.writeFileSync(renderedYamlPath, renderResult.yaml, 'utf8');
681
718
  const validation = await validateManifests(renderedYamlPath);
682
719
  if (validation.valid) {
683
- logger.info('Package validation successful', { format: outputFormat, attempt });
720
+ logger.info('Package validation successful', {
721
+ format: outputFormat,
722
+ attempt,
723
+ });
684
724
  cleanupPackageDir();
685
725
  return { files: packagingResult.files, attempts: attempt };
686
726
  }
687
727
  packagingError = {
688
728
  attempt,
689
729
  previousOutput: JSON.stringify(packagingResult.files.map(f => f.relativePath)),
690
- validationError: validation.errors.join(', ')
730
+ validationError: validation.errors.join(', '),
691
731
  };
692
- logger.warn('Package validation failed', { attempt, errors: validation.errors });
732
+ logger.warn('Package validation failed', {
733
+ attempt,
734
+ errors: validation.errors,
735
+ });
693
736
  }
694
737
  catch (error) {
695
738
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -700,7 +743,7 @@ async function packageAndValidate(rawManifests, solution, outputFormat, outputPa
700
743
  packagingError = {
701
744
  attempt,
702
745
  previousOutput: packagingError?.previousOutput || '',
703
- validationError: errorMessage
746
+ validationError: errorMessage,
704
747
  };
705
748
  }
706
749
  }
@@ -716,7 +759,7 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
716
759
  const maxAttempts = 10;
717
760
  logger.debug('Handling generateManifests request', {
718
761
  requestId,
719
- solutionId: args?.solutionId
762
+ solutionId: args?.solutionId,
720
763
  });
721
764
  // Input validation is handled automatically by MCP SDK with Zod schema
722
765
  // args are already validated and typed when we reach this point
@@ -735,8 +778,8 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
735
778
  'Verify the solution ID is correct',
736
779
  'Ensure the solution was created by the recommend tool',
737
780
  'Ensure all configuration stages were completed',
738
- 'Check that the session has not expired'
739
- ]
781
+ 'Check that the session has not expired',
782
+ ],
740
783
  });
741
784
  }
742
785
  const solution = session.data;
@@ -744,19 +787,21 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
744
787
  solutionId: args.solutionId,
745
788
  solutionType: solution.type,
746
789
  hasQuestions: !!solution.questions,
747
- primaryResources: solution.resources
790
+ primaryResources: solution.resources,
748
791
  });
749
792
  // Branch based on solution type
750
793
  if (solution.type === 'helm') {
751
794
  logger.info('Detected Helm solution, using Helm generation flow', {
752
795
  solutionId: args.solutionId,
753
- chart: solution.chart ? `${solution.chart.repositoryName}/${solution.chart.chartName}` : 'unknown'
796
+ chart: solution.chart
797
+ ? `${solution.chart.repositoryName}/${solution.chart.chartName}`
798
+ : 'unknown',
754
799
  });
755
800
  return await handleHelmGeneration(solution, args.solutionId, dotAI, logger, requestId, sessionManager, pluginManager, args.interaction_id);
756
801
  }
757
802
  // Capability-based solution: Generate Kubernetes manifests
758
803
  logger.info('Using capability-based manifest generation flow', {
759
- solutionId: args.solutionId
804
+ solutionId: args.solutionId,
760
805
  });
761
806
  // Prepare file path for manifests (store in tmp directory)
762
807
  const tmpDir = path.join(process.cwd(), 'tmp');
@@ -771,7 +816,7 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
771
816
  attempt,
772
817
  maxAttempts,
773
818
  isRetry: attempt > 1,
774
- requestId
819
+ requestId,
775
820
  });
776
821
  try {
777
822
  // Extract user answers and generate required labels
@@ -789,9 +834,11 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
789
834
  solutionId: args.solutionId,
790
835
  namespace: userAnswers.namespace || 'default',
791
836
  solution: solution,
792
- generatedManifestsYaml: aiManifests
837
+ generatedManifestsYaml: aiManifests,
838
+ });
839
+ logger.info('Solution CR generated successfully', {
840
+ solutionId: args.solutionId,
793
841
  });
794
- logger.info('Solution CR generated successfully', { solutionId: args.solutionId });
795
842
  }
796
843
  else {
797
844
  logger.info('Solution CRD not available, skipping Solution CR generation (graceful degradation)', { solutionId: args.solutionId });
@@ -800,7 +847,7 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
800
847
  catch (error) {
801
848
  logger.warn('Failed to check CRD availability or generate Solution CR, skipping', {
802
849
  solutionId: args.solutionId,
803
- error: error instanceof Error ? error.message : String(error)
850
+ error: error instanceof Error ? error.message : String(error),
804
851
  });
805
852
  // Graceful degradation - continue without Solution CR
806
853
  }
@@ -810,17 +857,23 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
810
857
  manifestParts.push(solutionCR);
811
858
  }
812
859
  manifestParts.push(aiManifests);
813
- const manifests = manifestParts.length > 1 ? manifestParts.join('---\n') : manifestParts[0];
860
+ const manifests = manifestParts.length > 1
861
+ ? manifestParts.join('---\n')
862
+ : manifestParts[0];
814
863
  // Save manifests to file
815
864
  fs.writeFileSync(yamlPath, manifests, 'utf8');
816
- logger.info('Manifests saved to file', { yamlPath, attempt, requestId });
865
+ logger.info('Manifests saved to file', {
866
+ yamlPath,
867
+ attempt,
868
+ requestId,
869
+ });
817
870
  // Save a copy of this attempt for debugging
818
871
  const attemptPath = yamlPath.replace('.yaml', `_attempt_${attempt.toString().padStart(2, '0')}.yaml`);
819
872
  fs.writeFileSync(attemptPath, manifests, 'utf8');
820
873
  logger.info('Saved manifest attempt for debugging', {
821
874
  attempt,
822
875
  attemptPath,
823
- requestId
876
+ requestId,
824
877
  });
825
878
  // Validate manifests
826
879
  // PRD #359: Uses unified plugin registry for kubectl operations
@@ -829,10 +882,11 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
829
882
  logger.info('Manifest validation successful', {
830
883
  attempt,
831
884
  yamlPath,
832
- requestId
885
+ requestId,
833
886
  });
834
887
  // Extract packaging options from user answers (with defaults)
835
- const outputFormat = (userAnswers.outputFormat || 'raw');
888
+ const outputFormat = (userAnswers.outputFormat ||
889
+ 'raw');
836
890
  const outputPath = userAnswers.outputPath || './manifests';
837
891
  // Handle packaging based on outputFormat
838
892
  if (outputFormat === 'helm' || outputFormat === 'kustomize') {
@@ -846,8 +900,8 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
846
900
  outputPath,
847
901
  files: packagingResult.files,
848
902
  validationAttempts: attempt,
849
- packagingAttempts: packagingResult.attempts
850
- }
903
+ packagingAttempts: packagingResult.attempts,
904
+ },
851
905
  });
852
906
  // PRD #320: Generate visualization URL
853
907
  const visualizationUrl = (0, visualization_1.getVisualizationUrl)(args.solutionId);
@@ -862,15 +916,19 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
862
916
  packagingAttempts: packagingResult.attempts,
863
917
  timestamp: new Date().toISOString(),
864
918
  agentInstructions: `Write the files to "${outputPath}". The output is a ${outputFormat === 'helm' ? 'Helm chart' : 'Kustomize overlay'}. If immediate deployment is desired, call the recommend tool with stage: "deployManifests".`,
865
- ...(visualizationUrl ? { visualizationUrl } : {})
919
+ ...(visualizationUrl ? { visualizationUrl } : {}),
866
920
  };
867
921
  // Build content blocks - JSON for REST API, agent instruction for MCP agents
868
- const content = [{
922
+ const content = [
923
+ {
869
924
  type: 'text',
870
- text: JSON.stringify(response, null, 2)
871
- }];
925
+ text: JSON.stringify(response, null, 2),
926
+ },
927
+ ];
872
928
  // Add agent instruction block if visualization URL is present
873
- const agentDisplayBlock = (0, index_1.buildAgentDisplayBlock)({ visualizationUrl });
929
+ const agentDisplayBlock = (0, index_1.buildAgentDisplayBlock)({
930
+ visualizationUrl,
931
+ });
874
932
  if (agentDisplayBlock) {
875
933
  content.push(agentDisplayBlock);
876
934
  }
@@ -884,8 +942,8 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
884
942
  type: 'raw',
885
943
  outputPath,
886
944
  files: [{ relativePath: 'manifests.yaml', content: manifests }],
887
- validationAttempts: attempt
888
- }
945
+ validationAttempts: attempt,
946
+ },
889
947
  });
890
948
  // PRD #320: Generate visualization URL
891
949
  const visualizationUrl = (0, visualization_1.getVisualizationUrl)(args.solutionId);
@@ -896,21 +954,23 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
896
954
  solutionId: args.solutionId,
897
955
  outputFormat,
898
956
  outputPath,
899
- files: [
900
- { relativePath: 'manifests.yaml', content: manifests }
901
- ],
957
+ files: [{ relativePath: 'manifests.yaml', content: manifests }],
902
958
  validationAttempts: attempt,
903
959
  timestamp: new Date().toISOString(),
904
960
  agentInstructions: `Write the files to "${outputPath}". If immediate deployment is desired, call the recommend tool with stage: "deployManifests".`,
905
- ...(visualizationUrl ? { visualizationUrl } : {})
961
+ ...(visualizationUrl ? { visualizationUrl } : {}),
906
962
  };
907
963
  // Build content blocks - JSON for REST API, agent instruction for MCP agents
908
- const content = [{
964
+ const content = [
965
+ {
909
966
  type: 'text',
910
- text: JSON.stringify(response, null, 2)
911
- }];
967
+ text: JSON.stringify(response, null, 2),
968
+ },
969
+ ];
912
970
  // Add agent instruction block if visualization URL is present
913
- const agentDisplayBlock = (0, index_1.buildAgentDisplayBlock)({ visualizationUrl });
971
+ const agentDisplayBlock = (0, index_1.buildAgentDisplayBlock)({
972
+ visualizationUrl,
973
+ });
914
974
  if (agentDisplayBlock) {
915
975
  content.push(agentDisplayBlock);
916
976
  }
@@ -921,14 +981,14 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
921
981
  lastError = {
922
982
  attempt,
923
983
  previousManifests: aiManifests,
924
- validationResult: validation
984
+ validationResult: validation,
925
985
  };
926
986
  logger.warn('Manifest validation failed', {
927
987
  attempt,
928
988
  maxAttempts,
929
989
  validationErrors: validation.errors,
930
990
  validationWarnings: validation.warnings,
931
- requestId
991
+ requestId,
932
992
  });
933
993
  }
934
994
  catch (error) {
@@ -948,8 +1008,8 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
948
1008
  validationResult: {
949
1009
  valid: false,
950
1010
  errors: [errorMessage],
951
- warnings: []
952
- }
1011
+ warnings: [],
1012
+ },
953
1013
  };
954
1014
  }
955
1015
  }
@@ -959,6 +1019,6 @@ async function handleGenerateManifestsTool(args, dotAI, logger, requestId, plugi
959
1019
  operation: 'generate_manifests',
960
1020
  component: 'GenerateManifestsTool',
961
1021
  requestId,
962
- input: args
1022
+ input: args,
963
1023
  });
964
1024
  }