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