@vfarcic/dot-ai 0.104.0 → 0.105.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +0 -1
  2. package/dist/core/ai-provider-factory.d.ts +90 -0
  3. package/dist/core/ai-provider-factory.d.ts.map +1 -0
  4. package/dist/core/ai-provider-factory.js +187 -0
  5. package/dist/core/ai-provider.interface.d.ts +116 -0
  6. package/dist/core/ai-provider.interface.d.ts.map +1 -0
  7. package/dist/core/ai-provider.interface.js +14 -0
  8. package/dist/core/capabilities.d.ts +3 -3
  9. package/dist/core/capabilities.d.ts.map +1 -1
  10. package/dist/core/capabilities.js +4 -4
  11. package/dist/core/capability-scan-workflow.d.ts.map +1 -1
  12. package/dist/core/capability-scan-workflow.js +29 -14
  13. package/dist/core/doc-testing-session.d.ts +1 -1
  14. package/dist/core/doc-testing-session.js +1 -1
  15. package/dist/core/error-handling.js +2 -2
  16. package/dist/core/index.d.ts +4 -6
  17. package/dist/core/index.d.ts.map +1 -1
  18. package/dist/core/index.js +11 -22
  19. package/dist/core/platform-operations.d.ts +3 -3
  20. package/dist/core/platform-operations.d.ts.map +1 -1
  21. package/dist/core/platform-operations.js +6 -6
  22. package/dist/core/providers/anthropic-provider.d.ts +32 -0
  23. package/dist/core/providers/anthropic-provider.d.ts.map +1 -0
  24. package/dist/core/providers/anthropic-provider.js +177 -0
  25. package/dist/core/providers/vercel-provider.d.ts +34 -0
  26. package/dist/core/providers/vercel-provider.d.ts.map +1 -0
  27. package/dist/core/providers/vercel-provider.js +202 -0
  28. package/dist/core/schema.d.ts +4 -7
  29. package/dist/core/schema.d.ts.map +1 -1
  30. package/dist/core/schema.js +13 -11
  31. package/dist/core/unified-creation-session.d.ts.map +1 -1
  32. package/dist/core/unified-creation-session.js +13 -14
  33. package/dist/interfaces/mcp.d.ts +1 -1
  34. package/dist/interfaces/mcp.js +1 -1
  35. package/dist/interfaces/rest-api.js +1 -1
  36. package/dist/mcp/server.d.ts +1 -1
  37. package/dist/mcp/server.js +2 -2
  38. package/dist/tools/answer-question.d.ts.map +1 -1
  39. package/dist/tools/answer-question.js +8 -10
  40. package/dist/tools/build-platform.js +3 -3
  41. package/dist/tools/generate-manifests.d.ts.map +1 -1
  42. package/dist/tools/generate-manifests.js +7 -8
  43. package/dist/tools/organizational-data.d.ts.map +1 -1
  44. package/dist/tools/organizational-data.js +3 -2
  45. package/dist/tools/recommend.d.ts.map +1 -1
  46. package/dist/tools/recommend.js +50 -30
  47. package/dist/tools/remediate.d.ts.map +1 -1
  48. package/dist/tools/remediate.js +23 -39
  49. package/dist/tools/version.d.ts +3 -2
  50. package/dist/tools/version.d.ts.map +1 -1
  51. package/dist/tools/version.js +35 -23
  52. package/package.json +5 -2
  53. package/prompts/question-generation.md +31 -3
  54. package/dist/core/claude.d.ts +0 -88
  55. package/dist/core/claude.d.ts.map +0 -1
  56. package/dist/core/claude.js +0 -414
@@ -1,414 +0,0 @@
1
- "use strict";
2
- /**
3
- * Claude Integration Module
4
- *
5
- * Handles AI communication, YAML generation, and learning integration
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.ClaudeIntegration = void 0;
45
- const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
46
- const fs = __importStar(require("fs"));
47
- const path = __importStar(require("path"));
48
- const shared_prompt_loader_1 = require("./shared-prompt-loader");
49
- const crypto = __importStar(require("crypto"));
50
- class ClaudeIntegration {
51
- client = null;
52
- apiKey;
53
- conversationHistory = [];
54
- interactions = [];
55
- debugMode;
56
- constructor(apiKey) {
57
- this.apiKey = apiKey;
58
- this.debugMode = process.env.DEBUG_DOT_AI === 'true';
59
- this.validateApiKey();
60
- if (this.apiKey && this.shouldInitializeClient()) {
61
- this.client = new sdk_1.default({
62
- apiKey: this.apiKey,
63
- });
64
- }
65
- }
66
- validateApiKey() {
67
- // Allow test-friendly initialization
68
- if (this.apiKey === 'test-key' || this.apiKey === 'mock-key') {
69
- return; // Allow test keys
70
- }
71
- if (!this.apiKey) {
72
- throw new Error('API key is required for Claude integration');
73
- }
74
- if (this.apiKey.length === 0) {
75
- throw new Error('Invalid API key: API key cannot be empty');
76
- }
77
- }
78
- shouldInitializeClient() {
79
- // Don't initialize for test configurations
80
- const testKeys = ['test-key', 'mock-key', 'invalid-key'];
81
- return !testKeys.includes(this.apiKey);
82
- }
83
- isTestKey() {
84
- const testKeys = ['test-key', 'mock-key', 'invalid-key'];
85
- return testKeys.includes(this.apiKey);
86
- }
87
- /**
88
- * Create debug directory if it doesn't exist
89
- */
90
- ensureDebugDirectory() {
91
- const debugDir = path.join(process.cwd(), 'tmp', 'debug-ai');
92
- if (!fs.existsSync(debugDir)) {
93
- fs.mkdirSync(debugDir, { recursive: true });
94
- }
95
- return debugDir;
96
- }
97
- /**
98
- * Generate unique identifier for debug files with operation context
99
- */
100
- generateDebugId(operation) {
101
- const timestamp = new Date().toISOString().replace(/[:.]/g, '').split('T');
102
- const dateTime = timestamp[0] + 'T' + timestamp[1].substring(0, 6);
103
- const randomHex = crypto.randomBytes(4).toString('hex');
104
- return `${dateTime}_${randomHex}_${operation}`;
105
- }
106
- /**
107
- * Save AI interaction for debugging when DEBUG_DOT_AI=true
108
- */
109
- debugLogInteraction(debugId, prompt, response, operation = 'ai_call') {
110
- if (!this.debugMode)
111
- return;
112
- try {
113
- const debugDir = this.ensureDebugDirectory();
114
- // Save prompt with descriptive naming
115
- const promptFile = path.join(debugDir, `${debugId}_prompt.md`);
116
- fs.writeFileSync(promptFile, `# AI Prompt - ${operation}\n\nTimestamp: ${new Date().toISOString()}\nOperation: ${operation}\n\n---\n\n${prompt}`);
117
- // Save response with matching naming
118
- const responseFile = path.join(debugDir, `${debugId}_response.md`);
119
- const responseContent = `# AI Response - ${operation}
120
-
121
- Timestamp: ${new Date().toISOString()}
122
- Operation: ${operation}
123
- Input Tokens: ${response.usage.input_tokens}
124
- Output Tokens: ${response.usage.output_tokens}
125
-
126
- ---
127
-
128
- ${response.content}`;
129
- fs.writeFileSync(responseFile, responseContent);
130
- console.log(`🐛 DEBUG: AI interaction logged to tmp/debug-ai/${debugId}_*.md`);
131
- }
132
- catch (error) {
133
- console.warn('Failed to log AI debug interaction:', error);
134
- }
135
- }
136
- async sendMessage(message, operation = 'generic') {
137
- // For test keys, skip client initialization check and continue to mock responses
138
- if (!this.client && !this.isTestKey()) {
139
- throw new Error('Claude client not initialized due to missing API key');
140
- }
141
- if (this.apiKey === 'invalid-key') {
142
- throw new Error('Authentication failed: Invalid API key');
143
- }
144
- try {
145
- // Add message to conversation history
146
- this.conversationHistory.push({ role: 'user', content: message });
147
- // Use real Claude API if we have a real API key, otherwise fall back to mocks
148
- if (this.apiKey.startsWith('sk-ant-') && this.client) {
149
- // Make real API call to Claude with streaming
150
- const stream = await this.client.messages.create({
151
- model: process.env.MODEL || 'claude-sonnet-4-5-20250929', // Latest Claude Sonnet 4.5
152
- max_tokens: 64000,
153
- messages: [{ role: 'user', content: message }],
154
- stream: true // Enable streaming by default to support long operations (>10 minutes)
155
- });
156
- let content = '';
157
- let input_tokens = 0;
158
- let output_tokens = 0;
159
- for await (const chunk of stream) {
160
- if (chunk.type === 'message_start') {
161
- input_tokens = chunk.message.usage.input_tokens;
162
- }
163
- else if (chunk.type === 'content_block_delta') {
164
- if (chunk.delta.type === 'text_delta') {
165
- content += chunk.delta.text;
166
- }
167
- }
168
- else if (chunk.type === 'message_delta') {
169
- output_tokens = chunk.usage.output_tokens;
170
- }
171
- }
172
- const response = {
173
- content,
174
- usage: {
175
- input_tokens,
176
- output_tokens
177
- }
178
- };
179
- this.conversationHistory.push({ role: 'assistant', content: response.content });
180
- // Debug log the interaction if enabled
181
- if (this.debugMode) {
182
- const debugId = this.generateDebugId(operation);
183
- this.debugLogInteraction(debugId, message, response, operation);
184
- }
185
- return response;
186
- }
187
- // For testing purposes, return mock responses
188
- let response;
189
- if (message.toLowerCase().includes('deploy a web application')) {
190
- response = {
191
- content: 'I can help you deploy a web application to Kubernetes. Let me guide you through the process of creating the necessary YAML manifests for your deployment.',
192
- usage: { input_tokens: 10, output_tokens: 25 }
193
- };
194
- }
195
- else if (message.toLowerCase().includes('recommended resources') &&
196
- this.conversationHistory.some(msg => msg.content.toLowerCase().includes('nginx'))) {
197
- response = {
198
- content: 'For nginx deployment, I recommend starting with 2 replicas, 500m CPU and 512Mi memory per pod. You can adjust these based on your traffic patterns.',
199
- usage: { input_tokens: 8, output_tokens: 30 }
200
- };
201
- }
202
- else {
203
- // Default mock response
204
- response = {
205
- content: 'I understand you want help with Kubernetes deployment. Could you provide more specific details about what you\'d like to deploy?',
206
- usage: { input_tokens: message.length / 4, output_tokens: 20 }
207
- };
208
- }
209
- this.conversationHistory.push({ role: 'assistant', content: response.content });
210
- // Debug log the interaction if enabled (for mocks too)
211
- if (this.debugMode) {
212
- const debugId = this.generateDebugId(`mock-${operation}`);
213
- this.debugLogInteraction(debugId, message, response, `mock-${operation}`);
214
- }
215
- return response;
216
- }
217
- catch (error) {
218
- throw new Error(`Claude API error: ${error}`);
219
- }
220
- }
221
- async generateYAML(resourceType, config) {
222
- if (!this.client && !this.isTestKey()) {
223
- throw new Error('Claude client not initialized');
224
- }
225
- // Mock YAML generation for testing
226
- if (resourceType === 'deployment' && config.app === 'nginx') {
227
- return {
228
- yaml: `apiVersion: apps/v1
229
- kind: Deployment
230
- metadata:
231
- name: ${config.app}
232
- labels:
233
- app: ${config.app}
234
- spec:
235
- replicas: ${config.replicas || 1}
236
- selector:
237
- matchLabels:
238
- app: ${config.app}
239
- template:
240
- metadata:
241
- labels:
242
- app: ${config.app}
243
- spec:
244
- containers:
245
- - name: ${config.app}
246
- image: ${config.image}
247
- ports:
248
- - containerPort: 80`,
249
- explanation: `This deployment creates ${config.replicas || 1} replica(s) of ${config.app} using the ${config.image} image. The container exposes port 80 for web traffic.`
250
- };
251
- }
252
- // Default YAML response
253
- return {
254
- yaml: `apiVersion: apps/v1
255
- kind: ${resourceType.charAt(0).toUpperCase() + resourceType.slice(1)}
256
- metadata:
257
- name: example-${resourceType}
258
- spec:
259
- # Generated configuration would go here`,
260
- explanation: `This is a basic ${resourceType} manifest. You should customize it based on your specific requirements.`
261
- };
262
- }
263
- async recordInteraction(interaction) {
264
- const recordedInteraction = {
265
- ...interaction,
266
- timestamp: new Date()
267
- };
268
- this.interactions.push(recordedInteraction);
269
- }
270
- async getSuccessfulPatterns() {
271
- return this.interactions.filter(interaction => interaction.success);
272
- }
273
- getConversationHistory() {
274
- return [...this.conversationHistory];
275
- }
276
- clearConversationHistory() {
277
- this.conversationHistory = [];
278
- }
279
- async generateManifest(spec) {
280
- if (!this.client && !this.isTestKey()) {
281
- throw new Error('Claude client not initialized');
282
- }
283
- // Simulate manifest generation
284
- const yamlContent = `
285
- apiVersion: apps/v1
286
- kind: Deployment
287
- metadata:
288
- name: ${spec.name || 'app'}
289
- spec:
290
- replicas: ${spec.replicas || 1}
291
- selector:
292
- matchLabels:
293
- app: ${spec.name || 'app'}
294
- template:
295
- metadata:
296
- labels:
297
- app: ${spec.name || 'app'}
298
- spec:
299
- containers:
300
- - name: app
301
- image: ${spec.image || 'nginx:latest'}
302
- ports:
303
- - containerPort: 80
304
- `;
305
- return yamlContent.trim();
306
- }
307
- async analyzeError(error, _context) {
308
- if (!this.client && !this.isTestKey()) {
309
- throw new Error('Claude client not initialized');
310
- }
311
- // Simulate error analysis
312
- return `Error analysis: ${error}. Suggested fix: Check the configuration and try again.`;
313
- }
314
- async suggestImprovements(_manifest) {
315
- if (!this.client && !this.isTestKey()) {
316
- throw new Error('Claude client not initialized');
317
- }
318
- // Simulate improvement suggestions
319
- return [
320
- 'Add resource limits and requests',
321
- 'Consider adding health checks',
322
- 'Add labels for better organization'
323
- ];
324
- }
325
- async processUserInput(input, context) {
326
- if (!this.client && !this.isTestKey()) {
327
- throw new Error('Claude client not initialized');
328
- }
329
- // Simulate interactive workflow processing
330
- if (input.toLowerCase().includes('deploy') && context?.interactive) {
331
- return {
332
- phase: 'Planning',
333
- questions: ['What type of database do you need?']
334
- };
335
- }
336
- if (context?.responses) {
337
- return {
338
- phase: 'Validation',
339
- nextSteps: ['Review generated manifest']
340
- };
341
- }
342
- // Default response
343
- return {
344
- phase: 'Discovery',
345
- suggestions: ['Start by exploring your cluster resources']
346
- };
347
- }
348
- /**
349
- * Analyze user intent for clarification opportunities
350
- *
351
- * @param intent User's deployment intent
352
- * @param organizationalPatterns Available organizational patterns context
353
- * @returns Analysis result with clarification opportunities
354
- */
355
- async analyzeIntentForClarification(intent, organizationalPatterns = '') {
356
- if (!this.client && !this.isTestKey()) {
357
- throw new Error('Claude client not initialized');
358
- }
359
- try {
360
- // Load intent analysis prompt template
361
- const analysisPrompt = (0, shared_prompt_loader_1.loadPrompt)('intent-analysis', {
362
- intent,
363
- organizational_patterns: organizationalPatterns || 'No specific organizational patterns available'
364
- });
365
- // Send to Claude for analysis
366
- const response = await this.sendMessage(analysisPrompt, 'intent-analysis');
367
- // Parse JSON response with robust error handling
368
- let jsonContent = response.content;
369
- // Try to find JSON object wrapped in code blocks
370
- const codeBlockMatch = response.content.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/);
371
- if (codeBlockMatch) {
372
- jsonContent = codeBlockMatch[1];
373
- }
374
- else {
375
- // Try to find JSON object that starts with { and find the matching closing }
376
- const jsonMatch = response.content.match(/\{[\s\S]*\}/);
377
- if (jsonMatch) {
378
- jsonContent = jsonMatch[0];
379
- }
380
- }
381
- // Parse the JSON
382
- const analysisResult = JSON.parse(jsonContent);
383
- // Validate the response structure
384
- if (!analysisResult.clarificationOpportunities || !Array.isArray(analysisResult.clarificationOpportunities)) {
385
- throw new Error('Invalid analysis result structure: missing clarificationOpportunities array');
386
- }
387
- if (!analysisResult.overallAssessment || !analysisResult.intentQuality) {
388
- throw new Error('Invalid analysis result structure: missing overallAssessment or intentQuality');
389
- }
390
- return analysisResult;
391
- }
392
- catch (error) {
393
- // If parsing fails or API call fails, return a fallback minimal analysis
394
- console.warn('Intent analysis failed, returning minimal analysis:', error);
395
- return {
396
- clarificationOpportunities: [],
397
- overallAssessment: {
398
- enhancementPotential: 'LOW',
399
- primaryGaps: [],
400
- recommendedFocus: 'Proceed with original intent - analysis unavailable'
401
- },
402
- intentQuality: {
403
- currentSpecificity: 'Unable to analyze - using original intent',
404
- strengthAreas: ['User provided clear deployment intent'],
405
- improvementAreas: []
406
- }
407
- };
408
- }
409
- }
410
- isInitialized() {
411
- return this.client !== null;
412
- }
413
- }
414
- exports.ClaudeIntegration = ClaudeIntegration;