@vfarcic/dot-ai 0.1.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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +203 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +51 -0
  6. package/dist/core/claude.d.ts +42 -0
  7. package/dist/core/claude.d.ts.map +1 -0
  8. package/dist/core/claude.js +229 -0
  9. package/dist/core/deploy-operation.d.ts +38 -0
  10. package/dist/core/deploy-operation.d.ts.map +1 -0
  11. package/dist/core/deploy-operation.js +101 -0
  12. package/dist/core/discovery.d.ts +162 -0
  13. package/dist/core/discovery.d.ts.map +1 -0
  14. package/dist/core/discovery.js +758 -0
  15. package/dist/core/error-handling.d.ts +167 -0
  16. package/dist/core/error-handling.d.ts.map +1 -0
  17. package/dist/core/error-handling.js +399 -0
  18. package/dist/core/index.d.ts +42 -0
  19. package/dist/core/index.d.ts.map +1 -0
  20. package/dist/core/index.js +123 -0
  21. package/dist/core/kubernetes-utils.d.ts +38 -0
  22. package/dist/core/kubernetes-utils.d.ts.map +1 -0
  23. package/dist/core/kubernetes-utils.js +177 -0
  24. package/dist/core/memory.d.ts +45 -0
  25. package/dist/core/memory.d.ts.map +1 -0
  26. package/dist/core/memory.js +113 -0
  27. package/dist/core/schema.d.ts +187 -0
  28. package/dist/core/schema.d.ts.map +1 -0
  29. package/dist/core/schema.js +655 -0
  30. package/dist/core/session-utils.d.ts +29 -0
  31. package/dist/core/session-utils.d.ts.map +1 -0
  32. package/dist/core/session-utils.js +121 -0
  33. package/dist/core/workflow.d.ts +70 -0
  34. package/dist/core/workflow.d.ts.map +1 -0
  35. package/dist/core/workflow.js +161 -0
  36. package/dist/index.d.ts +15 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +32 -0
  39. package/dist/interfaces/cli.d.ts +74 -0
  40. package/dist/interfaces/cli.d.ts.map +1 -0
  41. package/dist/interfaces/cli.js +769 -0
  42. package/dist/interfaces/mcp.d.ts +30 -0
  43. package/dist/interfaces/mcp.d.ts.map +1 -0
  44. package/dist/interfaces/mcp.js +105 -0
  45. package/dist/mcp/server.d.ts +9 -0
  46. package/dist/mcp/server.d.ts.map +1 -0
  47. package/dist/mcp/server.js +151 -0
  48. package/dist/tools/answer-question.d.ts +27 -0
  49. package/dist/tools/answer-question.d.ts.map +1 -0
  50. package/dist/tools/answer-question.js +696 -0
  51. package/dist/tools/choose-solution.d.ts +23 -0
  52. package/dist/tools/choose-solution.d.ts.map +1 -0
  53. package/dist/tools/choose-solution.js +171 -0
  54. package/dist/tools/deploy-manifests.d.ts +25 -0
  55. package/dist/tools/deploy-manifests.d.ts.map +1 -0
  56. package/dist/tools/deploy-manifests.js +74 -0
  57. package/dist/tools/generate-manifests.d.ts +23 -0
  58. package/dist/tools/generate-manifests.d.ts.map +1 -0
  59. package/dist/tools/generate-manifests.js +424 -0
  60. package/dist/tools/index.d.ts +11 -0
  61. package/dist/tools/index.d.ts.map +1 -0
  62. package/dist/tools/index.js +34 -0
  63. package/dist/tools/recommend.d.ts +23 -0
  64. package/dist/tools/recommend.d.ts.map +1 -0
  65. package/dist/tools/recommend.js +332 -0
  66. package/package.json +124 -0
  67. package/prompts/intent-validation.md +65 -0
  68. package/prompts/manifest-generation.md +79 -0
  69. package/prompts/question-generation.md +128 -0
  70. package/prompts/resource-analysis.md +127 -0
  71. package/prompts/resource-selection.md +55 -0
  72. package/prompts/resource-solution-ranking.md +77 -0
  73. package/prompts/solution-enhancement.md +129 -0
@@ -0,0 +1,769 @@
1
+ "use strict";
2
+ /**
3
+ * CLI Interface Module
4
+ *
5
+ * Command-line interface for dot-ai
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.CliInterface = void 0;
45
+ const commander_1 = require("commander");
46
+ const yaml = __importStar(require("js-yaml"));
47
+ const cli_table3_1 = __importDefault(require("cli-table3"));
48
+ const recommend_1 = require("../tools/recommend");
49
+ const choose_solution_1 = require("../tools/choose-solution");
50
+ const answer_question_1 = require("../tools/answer-question");
51
+ const generate_manifests_1 = require("../tools/generate-manifests");
52
+ const deploy_manifests_1 = require("../tools/deploy-manifests");
53
+ const error_handling_1 = require("../core/error-handling");
54
+ const fs_1 = require("fs");
55
+ const path_1 = require("path");
56
+ class CliInterface {
57
+ dotAI;
58
+ program;
59
+ config;
60
+ logger;
61
+ constructor(dotAI, config = {}) {
62
+ this.dotAI = dotAI;
63
+ this.config = config;
64
+ this.program = new commander_1.Command();
65
+ this.logger = new error_handling_1.ConsoleLogger('CLI');
66
+ this.program.name('dot-ai').description('AI-powered Kubernetes deployment agent');
67
+ // Add global options that apply to all commands
68
+ this.program
69
+ .option('--kubeconfig <path>', 'Path to kubeconfig file (overrides KUBECONFIG env var and default location)')
70
+ .option('--verbose', 'Enable verbose output globally')
71
+ .option('--output-file <path>', 'Write clean formatted output to file (respects --output format)')
72
+ .option('--quiet', 'Suppress tool registration and info logs');
73
+ this.setupCommands();
74
+ }
75
+ setDotAI(dotAI) {
76
+ this.dotAI = dotAI;
77
+ }
78
+ ensureDotAI() {
79
+ if (!this.dotAI) {
80
+ throw new Error('Cluster connection required. Please ensure your kubeconfig is valid and cluster is accessible.');
81
+ }
82
+ return this.dotAI;
83
+ }
84
+ getPackageInfo() {
85
+ try {
86
+ const packagePath = (0, path_1.join)(__dirname, '../../package.json');
87
+ const packageJson = JSON.parse((0, fs_1.readFileSync)(packagePath, 'utf8'));
88
+ return { name: packageJson.name, version: packageJson.version };
89
+ }
90
+ catch (error) {
91
+ return { name: '@vfarcic/dot-ai', version: '0.1.0' }; // fallback
92
+ }
93
+ }
94
+ setupCommands() {
95
+ const { name, version } = this.getPackageInfo();
96
+ this.program
97
+ .name('dot-ai')
98
+ .description('Kubernetes application deployment agent with AI-powered orchestration')
99
+ .version(version, '-v, --version', 'output the version number');
100
+ // Add custom help with installation and usage examples
101
+ this.program.addHelpText('after', `
102
+
103
+ Installation:
104
+ npm install -g ${name} Install globally
105
+ npx ${name} <command> Run without installing
106
+
107
+ Examples:
108
+ npx ${name} recommend --intent "deploy my Node.js app"
109
+ npx ${name} status --deployment my-app
110
+ npx ${name} learn --pattern microservice
111
+
112
+ For more help on specific commands, use:
113
+ npx ${name} help <command>
114
+ `);
115
+ // Status command
116
+ this.program
117
+ .command('status')
118
+ .description('Check deployment status')
119
+ .option('--deployment <id>', 'Deployment/workflow ID to check')
120
+ .option('--output <format>', 'Output format (json|yaml|table)', 'json')
121
+ .action(async (options, command) => {
122
+ // Get global options from parent command
123
+ const globalOptions = command.parent?.opts() || {};
124
+ this.processGlobalOptions(globalOptions);
125
+ // Validate output format
126
+ if (options.output && !['json', 'yaml', 'table'].includes(options.output)) {
127
+ console.error('Error: Invalid output format. Supported: json, yaml, table');
128
+ process.exit(1);
129
+ }
130
+ const result = await this.executeCommand('status', options);
131
+ this.outputResult(result, options.output || this.config.defaultOutput || 'json', this.config.outputFile);
132
+ });
133
+ // Learn command
134
+ this.program
135
+ .command('learn')
136
+ .description('Show learned deployment patterns and recommendations')
137
+ .option('--pattern <type>', 'Filter by pattern type')
138
+ .option('--output <format>', 'Output format (json|yaml|table)', 'json')
139
+ .action(async (options, command) => {
140
+ // Get global options from parent command
141
+ const globalOptions = command.parent?.opts() || {};
142
+ this.processGlobalOptions(globalOptions);
143
+ // Validate output format
144
+ if (options.output && !['json', 'yaml', 'table'].includes(options.output)) {
145
+ console.error('Error: Invalid output format. Supported: json, yaml, table');
146
+ process.exit(1);
147
+ }
148
+ const result = await this.executeCommand('learn', options);
149
+ this.outputResult(result, options.output || this.config.defaultOutput || 'json', this.config.outputFile);
150
+ });
151
+ // Recommend command
152
+ this.program
153
+ .command('recommend')
154
+ .description('Get AI-powered Kubernetes resource recommendations based on your intent')
155
+ .requiredOption('--intent <description>', 'Describe what you want to deploy or accomplish')
156
+ .option('--session-dir <path>', 'Directory to store solution files (defaults to DOT_AI_SESSION_DIR env var)')
157
+ .option('--output <format>', 'Output format (json|yaml|table)', 'json')
158
+ .action(async (options, command) => {
159
+ // Get global options from parent command
160
+ const globalOptions = command.parent?.opts() || {};
161
+ this.processGlobalOptions(globalOptions);
162
+ // Validate output format
163
+ if (options.output && !['json', 'yaml', 'table'].includes(options.output)) {
164
+ console.error('Error: Invalid output format. Supported: json, yaml, table');
165
+ process.exit(1);
166
+ }
167
+ const result = await this.executeCommand('recommend', options);
168
+ this.outputResult(result, options.output || this.config.defaultOutput || 'json', this.config.outputFile);
169
+ });
170
+ // Choose Solution command
171
+ this.program
172
+ .command('choose-solution')
173
+ .description('Select a solution by ID and return its questions for configuration')
174
+ .requiredOption('--solution-id <id>', 'Solution ID to choose (e.g., sol_2025-07-01T154349_1e1e242592ff)')
175
+ .requiredOption('--session-dir <path>', 'Directory containing solution files')
176
+ .option('--output <format>', 'Output format (json|yaml|table)', 'json')
177
+ .action(async (options, command) => {
178
+ // Get global options from parent command
179
+ const globalOptions = command.parent?.opts() || {};
180
+ this.processGlobalOptions(globalOptions);
181
+ // Validate output format
182
+ if (options.output && !['json', 'yaml', 'table'].includes(options.output)) {
183
+ console.error('Error: Invalid output format. Supported: json, yaml, table');
184
+ process.exit(1);
185
+ }
186
+ const result = await this.executeCommand('chooseSolution', options);
187
+ this.outputResult(result, options.output || this.config.defaultOutput || 'json', this.config.outputFile);
188
+ });
189
+ // Answer Question command
190
+ this.program
191
+ .command('answer-question')
192
+ .description('Process user answers and return remaining questions or completion status')
193
+ .requiredOption('--solution-id <id>', 'Solution ID to update (e.g., sol_2025-07-01T154349_1e1e242592ff)')
194
+ .requiredOption('--session-dir <path>', 'Directory containing solution files')
195
+ .requiredOption('--answers <json>', 'User answers as JSON object')
196
+ .requiredOption('--stage <stage>', 'Configuration stage (required, basic, advanced, open)')
197
+ .option('--done', 'Set when providing final open question answer', false)
198
+ .option('--output <format>', 'Output format (json|yaml|table)', 'json')
199
+ .action(async (options, command) => {
200
+ // Get global options from parent command
201
+ const globalOptions = command.parent?.opts() || {};
202
+ this.processGlobalOptions(globalOptions);
203
+ // Parse answers JSON
204
+ try {
205
+ options.answers = JSON.parse(options.answers);
206
+ }
207
+ catch (error) {
208
+ console.error('Error: Invalid JSON in --answers parameter');
209
+ process.exit(1);
210
+ }
211
+ // Validate output format
212
+ if (options.output && !['json', 'yaml', 'table'].includes(options.output)) {
213
+ console.error('Error: Invalid output format. Supported: json, yaml, table');
214
+ process.exit(1);
215
+ }
216
+ const result = await this.executeCommand('answerQuestion', options);
217
+ this.outputResult(result, options.output || this.config.defaultOutput || 'json', this.config.outputFile);
218
+ });
219
+ // Generate Manifests command
220
+ this.program
221
+ .command('generate-manifests')
222
+ .description('Generate Kubernetes manifests from solution configuration using AI')
223
+ .requiredOption('--solution-id <id>', 'Solution ID to generate manifests for (e.g., sol_2025-07-01T154349_1e1e242592ff)')
224
+ .requiredOption('--session-dir <path>', 'Directory containing solution files')
225
+ .option('--output <format>', 'Output format (json|yaml|table)', 'json')
226
+ .action(async (options, command) => {
227
+ // Get global options from parent command
228
+ const globalOptions = command.parent?.opts() || {};
229
+ this.processGlobalOptions(globalOptions);
230
+ // Validate output format
231
+ if (options.output && !['json', 'yaml', 'table'].includes(options.output)) {
232
+ console.error('Error: Invalid output format. Supported: json, yaml, table');
233
+ process.exit(1);
234
+ }
235
+ const result = await this.executeCommand('generateManifests', options);
236
+ this.outputResult(result, options.output || this.config.defaultOutput || 'json', this.config.outputFile);
237
+ });
238
+ // Deploy Manifests command
239
+ this.program
240
+ .command('deploy-manifests')
241
+ .description('Deploy Kubernetes manifests from generated solution')
242
+ .requiredOption('--solution-id <id>', 'Solution ID to deploy')
243
+ .requiredOption('--session-dir <path>', 'Session directory path')
244
+ .option('--timeout <seconds>', 'Deployment timeout in seconds', '30')
245
+ .option('--output <format>', 'Output format (json|yaml|table)', 'json')
246
+ .action(async (options, command) => {
247
+ // Get global options from parent command
248
+ const globalOptions = command.parent?.opts() || {};
249
+ this.processGlobalOptions(globalOptions);
250
+ // Validate output format
251
+ if (options.output && !['json', 'yaml', 'table'].includes(options.output)) {
252
+ console.error('Error: Invalid output format. Supported: json, yaml, table');
253
+ process.exit(1);
254
+ }
255
+ const result = await this.executeCommand('deployManifests', options);
256
+ this.outputResult(result, options.output || this.config.defaultOutput || 'json', this.config.outputFile);
257
+ });
258
+ // REMOVED: enhance command - moved to legacy reference
259
+ // See src/legacy/tools/enhance-solution.ts for reference implementation
260
+ }
261
+ getCommands() {
262
+ return ['dot-ai'];
263
+ }
264
+ getSubcommands() {
265
+ return this.program.commands.map(cmd => cmd.name());
266
+ }
267
+ async getHelp() {
268
+ const { name } = this.getPackageInfo();
269
+ const basicHelp = this.program.helpInformation();
270
+ const customHelp = `
271
+
272
+ Installation:
273
+ npm install -g ${name} Install globally
274
+ npx ${name} <command> Run without installing
275
+
276
+ Examples:
277
+ npx ${name} recommend --intent "deploy my Node.js app"
278
+ npx ${name} status --deployment my-app
279
+ npx ${name} learn --pattern microservice
280
+
281
+ For more help on specific commands, use:
282
+ npx ${name} help <command>
283
+ `;
284
+ return basicHelp + customHelp;
285
+ }
286
+ async getCommandHelp(commandName) {
287
+ const command = this.program.commands.find(cmd => cmd.name() === commandName);
288
+ if (!command) {
289
+ throw new Error(`Unknown command: ${commandName}`);
290
+ }
291
+ return command.helpInformation();
292
+ }
293
+ async parseArguments(args) {
294
+ if (args.length === 0) {
295
+ throw new Error('No command provided');
296
+ }
297
+ const commandName = args[0];
298
+ const validCommands = this.getSubcommands();
299
+ if (!validCommands.includes(commandName)) {
300
+ throw new Error(`Unknown command: ${commandName}`);
301
+ }
302
+ // Validate options based on command
303
+ const options = {};
304
+ for (let i = 1; i < args.length; i += 2) {
305
+ const option = args[i];
306
+ const value = args[i + 1];
307
+ if (!option.startsWith('--')) {
308
+ throw new Error(`Invalid option format: ${option}`);
309
+ }
310
+ const optionName = option.substring(2);
311
+ // Validate known options for each command
312
+ const validOptions = this.getValidOptionsForCommand(commandName);
313
+ if (!validOptions.includes(optionName)) {
314
+ throw new Error(`Unknown option: ${option}`);
315
+ }
316
+ // Validate specific option values
317
+ if (optionName === 'output' && value && !['json', 'yaml', 'table'].includes(value)) {
318
+ throw new Error('Invalid output format. Supported: json, yaml, table');
319
+ }
320
+ options[optionName] = value || true;
321
+ }
322
+ // Check required options
323
+ // (no required option checks needed for current commands)
324
+ return {
325
+ command: commandName,
326
+ options
327
+ };
328
+ }
329
+ getValidOptionsForCommand(command) {
330
+ const commonOptions = ['output', 'verbose'];
331
+ switch (command) {
332
+ case 'discover':
333
+ return [...commonOptions, 'cluster', 'remember'];
334
+ case 'status':
335
+ return [...commonOptions, 'deployment'];
336
+ case 'learn':
337
+ return [...commonOptions, 'pattern'];
338
+ case 'recommend':
339
+ return [...commonOptions, 'intent', 'session-dir'];
340
+ case 'chooseSolution':
341
+ return [...commonOptions, 'solution-id', 'session-dir'];
342
+ case 'answerQuestion':
343
+ return [...commonOptions, 'solution-id', 'session-dir', 'stage', 'answers', 'done'];
344
+ case 'generateManifests':
345
+ return [...commonOptions, 'solution-id', 'session-dir'];
346
+ case 'deployManifests':
347
+ return [...commonOptions, 'solution-id', 'session-dir', 'timeout'];
348
+ // REMOVED: enhance command, deploy command
349
+ default:
350
+ return commonOptions;
351
+ }
352
+ }
353
+ async executeCommand(command, options = {}) {
354
+ try {
355
+ // Only initialize DotAI for commands that need cluster access
356
+ if (command !== 'chooseSolution' && command !== 'answerQuestion' && command !== 'generateManifests') {
357
+ await this.ensureDotAI().initialize();
358
+ }
359
+ switch (command) {
360
+ case 'status':
361
+ return await this.handleStatusCommand(options);
362
+ case 'learn':
363
+ return await this.handleLearnCommand(options);
364
+ case 'recommend':
365
+ return await this.handleRecommendCommand(options);
366
+ case 'chooseSolution':
367
+ return await this.handleChooseSolutionCommand(options);
368
+ case 'answerQuestion':
369
+ return await this.handleAnswerQuestionCommand(options);
370
+ case 'generateManifests':
371
+ return await this.handleGenerateManifestsCommand(options);
372
+ case 'deployManifests':
373
+ return await this.handleDeployManifestsCommand(options);
374
+ // REMOVED: enhance command, deploy command
375
+ default:
376
+ return {
377
+ success: false,
378
+ error: `Unknown command: ${command}`
379
+ };
380
+ }
381
+ }
382
+ catch (error) {
383
+ return this.handleError(error, command);
384
+ }
385
+ }
386
+ async handleStatusCommand(options) {
387
+ try {
388
+ const phase = this.ensureDotAI().workflow.getCurrentPhase();
389
+ return {
390
+ success: true,
391
+ data: {
392
+ workflowId: options.deployment,
393
+ phase,
394
+ status: 'active'
395
+ }
396
+ };
397
+ }
398
+ catch (error) {
399
+ return {
400
+ success: false,
401
+ error: `Status check failed: ${error.message}`
402
+ };
403
+ }
404
+ }
405
+ async handleLearnCommand(options) {
406
+ try {
407
+ const recommendations = await this.ensureDotAI().memory.getRecommendations(options.pattern || 'deployment', {});
408
+ return {
409
+ success: true,
410
+ data: {
411
+ recommendations,
412
+ patternType: options.pattern || 'deployment'
413
+ }
414
+ };
415
+ }
416
+ catch (error) {
417
+ return {
418
+ success: false,
419
+ error: `Learning retrieval failed: ${error.message}`
420
+ };
421
+ }
422
+ }
423
+ async handleRecommendCommand(options) {
424
+ try {
425
+ // Show progress for long-running AI operations
426
+ this.showProgress('🔍 Analyzing your intent and discovering cluster resources...');
427
+ // Prepare arguments for the recommend tool including session directory
428
+ const toolArgs = {
429
+ intent: options.intent,
430
+ sessionDir: options.sessionDir // This will be passed to our tool's getSessionDirectory function
431
+ };
432
+ this.showProgress('🤖 AI is analyzing resources and generating solutions...');
433
+ // Execute the recommend tool directly
434
+ const requestId = `cli_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
435
+ const result = await (0, recommend_1.handleRecommendTool)(toolArgs, this.ensureDotAI(), this.logger, requestId);
436
+ this.clearProgress();
437
+ // Parse the tool result
438
+ const responseData = JSON.parse(result.content[0].text);
439
+ return {
440
+ success: true,
441
+ data: responseData
442
+ };
443
+ }
444
+ catch (error) {
445
+ // Give a moment for user to see progress before clearing
446
+ await new Promise(resolve => setTimeout(resolve, 1000));
447
+ this.clearProgress(); // Clear progress indicators on error
448
+ return {
449
+ success: false,
450
+ error: `AI-powered recommendations failed: ${error.message}`
451
+ };
452
+ }
453
+ }
454
+ async handleChooseSolutionCommand(options) {
455
+ try {
456
+ // Show progress for file operations
457
+ this.showProgress('📋 Loading solution and extracting questions...');
458
+ // Prepare arguments for the chooseSolution tool
459
+ const toolArgs = {
460
+ solutionId: options.solutionId,
461
+ sessionDir: options.sessionDir
462
+ };
463
+ // Execute the chooseSolution tool directly
464
+ const requestId = `cli_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
465
+ const result = await (0, choose_solution_1.handleChooseSolutionTool)(toolArgs, null, this.logger, requestId);
466
+ this.clearProgress();
467
+ // Parse the tool result
468
+ const responseData = JSON.parse(result.content[0].text);
469
+ return {
470
+ success: true,
471
+ data: responseData
472
+ };
473
+ }
474
+ catch (error) {
475
+ // Give a moment for user to see progress before clearing
476
+ await new Promise(resolve => setTimeout(resolve, 1000));
477
+ this.clearProgress(); // Clear progress indicators on error
478
+ return {
479
+ success: false,
480
+ error: `Choose solution failed: ${error.message}`
481
+ };
482
+ }
483
+ }
484
+ async handleAnswerQuestionCommand(options) {
485
+ try {
486
+ // Show progress for file operations
487
+ this.showProgress('📝 Processing answers and updating solution...');
488
+ // Prepare arguments for the answerQuestion tool
489
+ const toolArgs = {
490
+ solutionId: options.solutionId,
491
+ sessionDir: options.sessionDir,
492
+ stage: options.stage,
493
+ answers: options.answers,
494
+ done: options.done || false
495
+ };
496
+ // Execute the answerQuestion tool directly
497
+ const requestId = `cli_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
498
+ const result = await (0, answer_question_1.handleAnswerQuestionTool)(toolArgs, null, this.logger, requestId);
499
+ this.clearProgress();
500
+ // Parse the tool result
501
+ const responseData = JSON.parse(result.content[0].text);
502
+ return {
503
+ success: true,
504
+ data: responseData
505
+ };
506
+ }
507
+ catch (error) {
508
+ // Give a moment for user to see progress before clearing
509
+ await new Promise(resolve => setTimeout(resolve, 1000));
510
+ this.clearProgress(); // Clear progress indicators on error
511
+ return {
512
+ success: false,
513
+ error: `Answer question failed: ${error.message}`
514
+ };
515
+ }
516
+ }
517
+ async handleGenerateManifestsCommand(options) {
518
+ try {
519
+ // Show progress for manifest generation
520
+ this.showProgress('🤖 Generating Kubernetes manifests with AI...');
521
+ // Prepare arguments for the generateManifests tool
522
+ const toolArgs = {
523
+ solutionId: options.solutionId,
524
+ sessionDir: options.sessionDir
525
+ };
526
+ // Execute the generateManifests tool directly
527
+ const requestId = `cli_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
528
+ const result = await (0, generate_manifests_1.handleGenerateManifestsTool)(toolArgs, this.dotAI, this.logger, requestId);
529
+ this.clearProgress();
530
+ // Parse the tool result
531
+ const responseData = JSON.parse(result.content[0].text);
532
+ return {
533
+ success: true,
534
+ data: responseData
535
+ };
536
+ }
537
+ catch (error) {
538
+ // Give a moment for user to see progress before clearing
539
+ await new Promise(resolve => setTimeout(resolve, 1000));
540
+ this.clearProgress(); // Clear progress indicators on error
541
+ return {
542
+ success: false,
543
+ error: `Manifest generation failed: ${error.message}`
544
+ };
545
+ }
546
+ }
547
+ async handleDeployManifestsCommand(options) {
548
+ try {
549
+ // Show progress for deployment
550
+ this.showProgress('🚀 Deploying Kubernetes manifests...');
551
+ // Prepare arguments for the deployManifests tool
552
+ const toolArgs = {
553
+ solutionId: options.solutionId,
554
+ timeout: parseInt(options.timeout) || 30
555
+ };
556
+ // Execute the deployManifests tool directly
557
+ const requestId = `cli_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
558
+ const result = await (0, deploy_manifests_1.handleDeployManifestsTool)(toolArgs, this.ensureDotAI(), this.logger, requestId);
559
+ this.clearProgress();
560
+ // Parse the tool result
561
+ const responseData = JSON.parse(result.content[0].text);
562
+ return {
563
+ success: true,
564
+ data: responseData
565
+ };
566
+ }
567
+ catch (error) {
568
+ this.clearProgress(); // Clear progress indicators on error
569
+ return {
570
+ success: false,
571
+ error: `Manifest deployment failed: ${error.message}`
572
+ };
573
+ }
574
+ }
575
+ // REMOVED: handleEnhanceCommand method - moved to legacy reference
576
+ // See src/legacy/tools/enhance-solution.ts for reference implementation
577
+ async continueWorkflow(workflowId, input) {
578
+ try {
579
+ await this.ensureDotAI().workflow.transitionTo('Validation');
580
+ const claudeResponse = await this.ensureDotAI().claude.processUserInput(`Continue workflow ${workflowId} with responses: ${JSON.stringify(input.responses)}`);
581
+ return {
582
+ success: true,
583
+ data: claudeResponse
584
+ };
585
+ }
586
+ catch (error) {
587
+ return {
588
+ success: false,
589
+ error: `Workflow continuation failed: ${error.message}`
590
+ };
591
+ }
592
+ }
593
+ formatOutput(result, format) {
594
+ // Handle raw format for commands that need it
595
+ const isRawFormat = result._rawFormat;
596
+ if (isRawFormat) {
597
+ switch (format) {
598
+ case 'json':
599
+ return JSON.stringify(result.data, null, 2);
600
+ case 'yaml':
601
+ return yaml.dump(result.data);
602
+ case 'table':
603
+ return this.formatAsTable({ success: true, data: result.data });
604
+ default:
605
+ return JSON.stringify(result.data, null, 2);
606
+ }
607
+ }
608
+ // Standard CLI format for other commands
609
+ switch (format) {
610
+ case 'json':
611
+ return JSON.stringify(result, null, 2);
612
+ case 'yaml':
613
+ return yaml.dump(result);
614
+ case 'table':
615
+ return this.formatAsTable(result);
616
+ default:
617
+ return JSON.stringify(result, null, 2);
618
+ }
619
+ }
620
+ formatAsTable(result) {
621
+ if (!result.success) {
622
+ const table = new cli_table3_1.default({
623
+ head: ['Status', 'Error'],
624
+ colWidths: [20, 60]
625
+ });
626
+ table.push(['Failed', result.error || 'Unknown error']);
627
+ return table.toString();
628
+ }
629
+ // Format data as table based on content
630
+ if (result.data && (result.data.resources || result.data.crds)) {
631
+ const table = new cli_table3_1.default({
632
+ head: ['Resource Type', 'Category'],
633
+ colWidths: [40, 20]
634
+ });
635
+ // Add discovered resources
636
+ if (result.data.resources && result.data.resources.resources) {
637
+ result.data.resources.resources.forEach((resource) => {
638
+ const category = resource.group === '' ? 'Core' : resource.group;
639
+ table.push([resource.kind, category]);
640
+ });
641
+ }
642
+ // Add custom resources (CRDs) - handle both string and object formats
643
+ if (result.data.crds && Array.isArray(result.data.crds)) {
644
+ result.data.crds.forEach((crd) => {
645
+ const crdName = typeof crd === 'string' ? crd : crd.name;
646
+ table.push([crdName, 'Custom']);
647
+ });
648
+ }
649
+ return table.toString();
650
+ }
651
+ // Generic table format
652
+ const table = new cli_table3_1.default({
653
+ head: ['Property', 'Value'],
654
+ colWidths: [30, 50]
655
+ });
656
+ if (result.data) {
657
+ Object.entries(result.data).forEach(([key, value]) => {
658
+ table.push([key, JSON.stringify(value)]);
659
+ });
660
+ }
661
+ return table.toString();
662
+ }
663
+ outputResult(result, format, outputFile) {
664
+ const output = this.formatOutput(result, format);
665
+ if (outputFile) {
666
+ // Write clean output to file
667
+ const fs = require('fs');
668
+ const path = require('path');
669
+ // Ensure directory exists
670
+ const dir = path.dirname(outputFile);
671
+ if (!fs.existsSync(dir)) {
672
+ fs.mkdirSync(dir, { recursive: true });
673
+ }
674
+ fs.writeFileSync(outputFile, output);
675
+ }
676
+ else {
677
+ // Write to stdout
678
+ process.stdout.write(`${output}\n`);
679
+ }
680
+ if (!result.success) {
681
+ process.exit(1);
682
+ }
683
+ }
684
+ /**
685
+ * Process global options and update config
686
+ */
687
+ processGlobalOptions(options) {
688
+ if (options.verbose !== undefined) {
689
+ this.config.verboseMode = options.verbose;
690
+ }
691
+ if (options.outputFile !== undefined) {
692
+ this.config.outputFile = options.outputFile;
693
+ }
694
+ if (options.quiet !== undefined) {
695
+ this.config.quietMode = options.quiet;
696
+ }
697
+ }
698
+ handleError(error, _command) {
699
+ this.clearProgress(); // Clear any progress indicators on error
700
+ let errorMessage = error.message;
701
+ // Provide helpful error messages for common issues
702
+ if (errorMessage.includes('ENOTFOUND') || errorMessage.includes('connection')) {
703
+ errorMessage = 'Cannot connect to Kubernetes cluster. Check your kubeconfig and cluster status.';
704
+ }
705
+ else if (errorMessage.includes('Connection failed')) {
706
+ errorMessage = `Failed to initialize DevOps AI Toolkit: ${errorMessage}`;
707
+ }
708
+ return {
709
+ success: false,
710
+ error: errorMessage
711
+ };
712
+ }
713
+ /**
714
+ * Show progress message to user during long-running operations
715
+ */
716
+ showProgress(message) {
717
+ // Only show progress if output is going to console (not when piped or in JSON mode)
718
+ if (process.stdout.isTTY) {
719
+ process.stderr.write(`\r\x1b[K${message}`);
720
+ }
721
+ }
722
+ /**
723
+ * Clear progress indicators
724
+ */
725
+ clearProgress() {
726
+ if (process.stdout.isTTY) {
727
+ process.stderr.write('\r\x1b[K');
728
+ }
729
+ }
730
+ /**
731
+ * Find best solutions with detailed progress feedback
732
+ */
733
+ async findBestSolutionsWithProgress(recommender, intent, discoverResourcesFn, explainResourceFn) {
734
+ this.showProgress('🤖 AI is analyzing your intent...');
735
+ // Start a timer to show elapsed time
736
+ const startTime = Date.now();
737
+ const progressInterval = setInterval(() => {
738
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
739
+ this.showProgress(`🤖 AI analysis in progress... (${elapsed}s)`);
740
+ }, 3000);
741
+ try {
742
+ // The ResourceRecommender handles the three phases internally:
743
+ // 1. Resource discovery and selection
744
+ // 2. Schema fetching and ranking
745
+ // 3. Question generation
746
+ const solutions = await recommender.findBestSolutions(intent, discoverResourcesFn, explainResourceFn);
747
+ clearInterval(progressInterval);
748
+ return solutions;
749
+ }
750
+ catch (error) {
751
+ clearInterval(progressInterval);
752
+ throw error;
753
+ }
754
+ }
755
+ // CLI entry point
756
+ async run(args = process.argv) {
757
+ try {
758
+ await this.program.parseAsync(args);
759
+ }
760
+ catch (error) {
761
+ const result = this.handleError(error, 'general');
762
+ this.outputResult(result, 'json');
763
+ process.exit(1);
764
+ }
765
+ }
766
+ }
767
+ exports.CliInterface = CliInterface;
768
+ // Export for CLI entry point
769
+ exports.default = CliInterface;