@vfarcic/dot-ai 0.124.0 → 0.126.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/assets/project-setup/templates/.github/CODEOWNERS.hbs +25 -0
- package/assets/project-setup/templates/.github/FUNDING.yml.hbs +35 -0
- package/assets/project-setup/templates/.github/ISSUE_TEMPLATE/bug_report.yml.hbs +175 -0
- package/assets/project-setup/templates/.github/ISSUE_TEMPLATE/config.yml.hbs +32 -0
- package/assets/project-setup/templates/.github/ISSUE_TEMPLATE/feature_request.yml.hbs +134 -0
- package/assets/project-setup/templates/.github/PULL_REQUEST_TEMPLATE.md.hbs +172 -0
- package/assets/project-setup/templates/.github/labeler.yml.hbs +123 -0
- package/assets/project-setup/templates/.github/release.yml.hbs +51 -0
- package/assets/project-setup/templates/.github/workflows/labeler.yml.hbs +21 -0
- package/assets/project-setup/templates/.github/workflows/scorecard.yml.hbs +71 -0
- package/assets/project-setup/templates/.github/workflows/stale.yml.hbs +57 -0
- package/dist/core/ai-provider-factory.d.ts.map +1 -1
- package/dist/core/ai-provider-factory.js +22 -5
- package/dist/core/ai-provider.interface.d.ts +16 -0
- package/dist/core/ai-provider.interface.d.ts.map +1 -1
- package/dist/core/capability-scan-workflow.d.ts +4 -9
- package/dist/core/capability-scan-workflow.d.ts.map +1 -1
- package/dist/core/capability-scan-workflow.js +203 -456
- package/dist/core/discovery.d.ts +6 -0
- package/dist/core/discovery.d.ts.map +1 -1
- package/dist/core/discovery.js +39 -3
- package/dist/core/embedding-service.d.ts +9 -36
- package/dist/core/embedding-service.d.ts.map +1 -1
- package/dist/core/embedding-service.js +137 -246
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/kubernetes-utils.d.ts +1 -0
- package/dist/core/kubernetes-utils.d.ts.map +1 -1
- package/dist/core/kubernetes-utils.js +53 -48
- package/dist/core/model-config.d.ts +2 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +3 -1
- package/dist/core/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/core/providers/anthropic-provider.js +352 -282
- package/dist/core/providers/provider-debug-utils.d.ts +4 -0
- package/dist/core/providers/provider-debug-utils.d.ts.map +1 -1
- package/dist/core/providers/provider-debug-utils.js +25 -3
- package/dist/core/providers/vercel-provider.d.ts +1 -0
- package/dist/core/providers/vercel-provider.d.ts.map +1 -1
- package/dist/core/providers/vercel-provider.js +412 -345
- package/dist/core/tracing/ai-tracing.d.ts +80 -0
- package/dist/core/tracing/ai-tracing.d.ts.map +1 -0
- package/dist/core/tracing/ai-tracing.js +122 -0
- package/dist/core/tracing/config.d.ts +15 -0
- package/dist/core/tracing/config.d.ts.map +1 -0
- package/dist/core/tracing/config.js +133 -0
- package/dist/core/tracing/http-tracing.d.ts +28 -0
- package/dist/core/tracing/http-tracing.d.ts.map +1 -0
- package/dist/core/tracing/http-tracing.js +119 -0
- package/dist/core/tracing/index.d.ts +14 -0
- package/dist/core/tracing/index.d.ts.map +1 -0
- package/dist/core/tracing/index.js +40 -0
- package/dist/core/tracing/k8s-tracing.d.ts +57 -0
- package/dist/core/tracing/k8s-tracing.d.ts.map +1 -0
- package/dist/core/tracing/k8s-tracing.js +155 -0
- package/dist/core/tracing/qdrant-tracing.d.ts +68 -0
- package/dist/core/tracing/qdrant-tracing.d.ts.map +1 -0
- package/dist/core/tracing/qdrant-tracing.js +102 -0
- package/dist/core/tracing/tool-tracing.d.ts +31 -0
- package/dist/core/tracing/tool-tracing.d.ts.map +1 -0
- package/dist/core/tracing/tool-tracing.js +76 -0
- package/dist/core/tracing/tracer.d.ts +21 -0
- package/dist/core/tracing/tracer.d.ts.map +1 -0
- package/dist/core/tracing/tracer.js +215 -0
- package/dist/core/tracing/types.d.ts +86 -0
- package/dist/core/tracing/types.d.ts.map +1 -0
- package/dist/core/tracing/types.js +41 -0
- package/dist/core/unified-creation-session.js +1 -1
- package/dist/core/vector-db-service.d.ts.map +1 -1
- package/dist/core/vector-db-service.js +238 -163
- package/dist/interfaces/mcp.d.ts.map +1 -1
- package/dist/interfaces/mcp.js +71 -43
- package/dist/mcp/server.js +12 -2
- package/dist/tools/organizational-data.d.ts.map +1 -1
- package/dist/tools/organizational-data.js +2 -4
- package/dist/tools/version.d.ts +12 -1
- package/dist/tools/version.d.ts.map +1 -1
- package/dist/tools/version.js +24 -4
- package/package.json +11 -1
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.handleResourceSelection = handleResourceSelection;
|
|
10
10
|
exports.handleResourceSpecification = handleResourceSpecification;
|
|
11
|
-
exports.handleProcessingMode = handleProcessingMode;
|
|
12
11
|
exports.handleScanning = handleScanning;
|
|
13
12
|
const discovery_1 = require("./discovery");
|
|
14
13
|
const capabilities_1 = require("./capabilities");
|
|
@@ -36,7 +35,7 @@ function createResourceDefinitionErrorMessage(resourceName, error) {
|
|
|
36
35
|
/**
|
|
37
36
|
* Handle resource selection step
|
|
38
37
|
*/
|
|
39
|
-
async function handleResourceSelection(session, args,
|
|
38
|
+
async function handleResourceSelection(session, args, logger, requestId, capabilityService, parseNumericResponse, transitionCapabilitySession, cleanupCapabilitySession, createCapabilityScanCompletionResponse, handleScanningFn) {
|
|
40
39
|
if (!args.response) {
|
|
41
40
|
// Show initial resource selection prompt
|
|
42
41
|
return {
|
|
@@ -83,49 +82,13 @@ async function handleResourceSelection(session, args, _logger, _requestId, parse
|
|
|
83
82
|
// Process user response
|
|
84
83
|
const normalizedResponse = parseNumericResponse(args.response, ['all', 'specific']);
|
|
85
84
|
if (normalizedResponse === 'all') {
|
|
86
|
-
// Transition to
|
|
87
|
-
transitionCapabilitySession(session, '
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
REQUIRED_NEXT_CALL: {
|
|
94
|
-
tool: 'dot-ai:manageOrgData',
|
|
95
|
-
parameters: {
|
|
96
|
-
dataType: 'capabilities',
|
|
97
|
-
operation: 'scan',
|
|
98
|
-
sessionId: session.sessionId,
|
|
99
|
-
step: 'processing-mode', // MANDATORY PARAMETER
|
|
100
|
-
response: 'user_choice_here' // Replace with actual user choice
|
|
101
|
-
},
|
|
102
|
-
note: 'The step parameter is MANDATORY when sessionId is provided'
|
|
103
|
-
},
|
|
104
|
-
workflow: {
|
|
105
|
-
step: 'processing-mode',
|
|
106
|
-
question: 'Processing mode: auto (batch process) or manual (review each)?',
|
|
107
|
-
options: [
|
|
108
|
-
{ number: 1, value: 'auto', display: '1. auto - Batch process automatically' },
|
|
109
|
-
{ number: 2, value: 'manual', display: '2. manual - Review each step' }
|
|
110
|
-
],
|
|
111
|
-
sessionId: session.sessionId,
|
|
112
|
-
selectedResources: 'all',
|
|
113
|
-
instruction: 'IMPORTANT: You MUST ask the user to make a choice. Do NOT automatically select a processing mode.',
|
|
114
|
-
userPrompt: 'How would you like to process the resources?',
|
|
115
|
-
clientInstructions: {
|
|
116
|
-
behavior: 'interactive',
|
|
117
|
-
requirement: 'Ask user to choose processing mode',
|
|
118
|
-
prohibit: 'Do not auto-select processing mode',
|
|
119
|
-
nextStep: `Call with step='processing-mode', sessionId='${session.sessionId}', and response parameter containing the semantic value (auto or manual)`,
|
|
120
|
-
responseFormat: 'Convert user input to semantic values: 1→auto, 2→manual, or pass through semantic words directly',
|
|
121
|
-
requiredParameters: {
|
|
122
|
-
step: 'processing-mode',
|
|
123
|
-
sessionId: session.sessionId,
|
|
124
|
-
response: 'user choice (auto or manual)'
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
};
|
|
85
|
+
// Transition directly to scanning (auto mode only - manual mode removed)
|
|
86
|
+
transitionCapabilitySession(session, 'scanning', {
|
|
87
|
+
selectedResources: 'all',
|
|
88
|
+
currentResourceIndex: 0 // Start with first resource
|
|
89
|
+
}, args);
|
|
90
|
+
// Begin actual capability scanning and return completion summary
|
|
91
|
+
return await handleScanningFn(session, { ...args, response: undefined }, logger, requestId, capabilityService, parseNumericResponse, transitionCapabilitySession, cleanupCapabilitySession, createCapabilityScanCompletionResponse);
|
|
129
92
|
}
|
|
130
93
|
if (normalizedResponse === 'specific') {
|
|
131
94
|
// Transition to resource specification
|
|
@@ -190,7 +153,7 @@ async function handleResourceSelection(session, args, _logger, _requestId, parse
|
|
|
190
153
|
/**
|
|
191
154
|
* Handle resource specification step
|
|
192
155
|
*/
|
|
193
|
-
async function handleResourceSpecification(session, args,
|
|
156
|
+
async function handleResourceSpecification(session, args, logger, requestId, capabilityService, parseNumericResponse, transitionCapabilitySession, cleanupCapabilitySession, createCapabilityScanCompletionResponse, handleScanningFn) {
|
|
194
157
|
if (!args.resourceList) {
|
|
195
158
|
return {
|
|
196
159
|
success: false,
|
|
@@ -218,176 +181,49 @@ async function handleResourceSpecification(session, args, _logger, _requestId, t
|
|
|
218
181
|
}
|
|
219
182
|
};
|
|
220
183
|
}
|
|
221
|
-
// Transition to
|
|
222
|
-
transitionCapabilitySession(session, 'processing-mode', {
|
|
223
|
-
selectedResources: resources,
|
|
224
|
-
resourceList: args.resourceList
|
|
225
|
-
}, args);
|
|
226
|
-
return {
|
|
227
|
-
success: true,
|
|
228
|
-
operation: 'scan',
|
|
229
|
-
dataType: 'capabilities',
|
|
230
|
-
// CRITICAL: Put required parameters at top level for maximum visibility
|
|
231
|
-
REQUIRED_NEXT_CALL: {
|
|
232
|
-
tool: 'dot-ai:manageOrgData',
|
|
233
|
-
parameters: {
|
|
234
|
-
dataType: 'capabilities',
|
|
235
|
-
operation: 'scan',
|
|
236
|
-
sessionId: session.sessionId,
|
|
237
|
-
step: 'processing-mode', // MANDATORY PARAMETER
|
|
238
|
-
response: 'user_choice_here' // Replace with actual user choice
|
|
239
|
-
},
|
|
240
|
-
note: 'The step parameter is MANDATORY when sessionId is provided'
|
|
241
|
-
},
|
|
242
|
-
workflow: {
|
|
243
|
-
step: 'processing-mode',
|
|
244
|
-
question: `Processing mode for ${resources.length} selected resources: auto (batch process) or manual (review each)?`,
|
|
245
|
-
options: [
|
|
246
|
-
{ number: 1, value: 'auto', display: '1. auto - Batch process automatically' },
|
|
247
|
-
{ number: 2, value: 'manual', display: '2. manual - Review each step' }
|
|
248
|
-
],
|
|
249
|
-
sessionId: session.sessionId,
|
|
250
|
-
selectedResources: resources,
|
|
251
|
-
instruction: 'IMPORTANT: You MUST ask the user to choose processing mode for the specified resources.',
|
|
252
|
-
userPrompt: `How would you like to process these ${resources.length} resources?`,
|
|
253
|
-
clientInstructions: {
|
|
254
|
-
behavior: 'interactive',
|
|
255
|
-
requirement: 'Ask user to choose processing mode for specific resources',
|
|
256
|
-
context: `Processing ${resources.length} user-specified resources: ${resources.join(', ')}`,
|
|
257
|
-
prohibit: 'Do not auto-select processing mode',
|
|
258
|
-
nextStep: `Call with step='processing-mode', sessionId='${session.sessionId}', and response parameter containing the semantic value (auto or manual)`,
|
|
259
|
-
responseFormat: 'Convert user input to semantic values: 1→auto, 2→manual, or pass through semantic words directly',
|
|
260
|
-
requiredParameters: {
|
|
261
|
-
step: 'processing-mode',
|
|
262
|
-
sessionId: session.sessionId,
|
|
263
|
-
response: 'user choice (auto or manual)'
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Handle processing mode step
|
|
271
|
-
*/
|
|
272
|
-
async function handleProcessingMode(session, args, logger, requestId, capabilityService, parseNumericResponse, transitionCapabilitySession, cleanupCapabilitySession, createCapabilityScanCompletionResponse, handleScanningFn) {
|
|
273
|
-
if (!args.response) {
|
|
274
|
-
return {
|
|
275
|
-
success: false,
|
|
276
|
-
operation: 'scan',
|
|
277
|
-
dataType: 'capabilities',
|
|
278
|
-
error: {
|
|
279
|
-
message: 'Missing processing mode response',
|
|
280
|
-
details: 'Expected response parameter with processing mode choice',
|
|
281
|
-
currentStep: session.currentStep,
|
|
282
|
-
expectedCall: `Call with step='processing-mode' and response parameter (auto or manual)`
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
// Process user response
|
|
287
|
-
const processingModeResponse = parseNumericResponse(args.response, ['auto', 'manual']);
|
|
288
|
-
if (processingModeResponse !== 'auto' && processingModeResponse !== 'manual') {
|
|
289
|
-
return {
|
|
290
|
-
success: false,
|
|
291
|
-
operation: 'scan',
|
|
292
|
-
dataType: 'capabilities',
|
|
293
|
-
error: {
|
|
294
|
-
message: 'Invalid processing mode response',
|
|
295
|
-
details: `Expected 'auto' or 'manual', got: ${args.response}`,
|
|
296
|
-
currentStep: session.currentStep
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
// Transition to scanning with processing mode and initialize resource tracking
|
|
184
|
+
// Transition directly to scanning (auto mode only - manual mode removed)
|
|
301
185
|
transitionCapabilitySession(session, 'scanning', {
|
|
302
|
-
|
|
186
|
+
selectedResources: resources,
|
|
187
|
+
resourceList: args.resourceList,
|
|
303
188
|
currentResourceIndex: 0 // Start with first resource
|
|
304
189
|
}, args);
|
|
305
|
-
// Begin actual capability scanning
|
|
190
|
+
// Begin actual capability scanning and return completion summary
|
|
306
191
|
return await handleScanningFn(session, { ...args, response: undefined }, logger, requestId, capabilityService, parseNumericResponse, transitionCapabilitySession, cleanupCapabilitySession, createCapabilityScanCompletionResponse);
|
|
307
192
|
}
|
|
308
193
|
/**
|
|
309
|
-
* Handle scanning step (actual capability analysis)
|
|
194
|
+
* Handle scanning step (actual capability analysis - auto mode only)
|
|
310
195
|
*/
|
|
311
196
|
async function handleScanning(session, args, logger, requestId, capabilityService, parseNumericResponse, transitionCapabilitySession, cleanupCapabilitySession, createCapabilityScanCompletionResponse) {
|
|
312
197
|
try {
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
transitionCapabilitySession(session, 'complete', {}, args);
|
|
319
|
-
cleanupCapabilitySession(session, args, logger, requestId);
|
|
320
|
-
const currentIndex = session.currentResourceIndex || 0;
|
|
321
|
-
const totalResources = Array.isArray(session.selectedResources) ? session.selectedResources.length : 1;
|
|
322
|
-
return createCapabilityScanCompletionResponse(session.sessionId, totalResources, currentIndex, // Resources processed so far
|
|
323
|
-
0, 'stopped interactively', 'manual', true // stopped = true
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
if (userResponse === 'yes' || userResponse === 'no') {
|
|
327
|
-
// TODO: If 'yes', store the capability in Vector DB (Milestone 2)
|
|
328
|
-
// For now, just log the decision
|
|
329
|
-
logger.info(`User ${userResponse === 'yes' ? 'accepted' : 'skipped'} capability for resource`, {
|
|
330
|
-
requestId,
|
|
331
|
-
sessionId: session.sessionId,
|
|
332
|
-
resourceIndex: session.currentResourceIndex,
|
|
333
|
-
decision: userResponse
|
|
334
|
-
});
|
|
335
|
-
// Move to the next resource
|
|
336
|
-
const nextIndex = (session.currentResourceIndex || 0) + 1;
|
|
337
|
-
transitionCapabilitySession(session, 'scanning', { currentResourceIndex: nextIndex }, args);
|
|
338
|
-
// Continue processing (will handle the next resource or complete if done)
|
|
339
|
-
return await handleScanning(session, { ...args, response: undefined }, logger, requestId, capabilityService, parseNumericResponse, transitionCapabilitySession, cleanupCapabilitySession, createCapabilityScanCompletionResponse);
|
|
340
|
-
}
|
|
341
|
-
// Invalid response
|
|
342
|
-
return {
|
|
343
|
-
success: false,
|
|
344
|
-
operation: 'scan',
|
|
345
|
-
dataType: 'capabilities',
|
|
346
|
-
error: {
|
|
347
|
-
message: 'Invalid response to capability preview',
|
|
348
|
-
details: `Expected 'yes', 'no', or 'stop', got: ${args.response}`,
|
|
349
|
-
currentStep: session.currentStep
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
// Import capability engine
|
|
354
|
-
// Already imported at top of file
|
|
355
|
-
// Validate AI provider - skip in test environment
|
|
356
|
-
const isTestEnvironment = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID;
|
|
357
|
-
if (!isTestEnvironment) {
|
|
358
|
-
try {
|
|
359
|
-
const aiProvider = (0, ai_provider_factory_1.createAIProvider)();
|
|
360
|
-
if (!aiProvider.isInitialized()) {
|
|
361
|
-
return {
|
|
362
|
-
success: false,
|
|
363
|
-
operation: 'scan',
|
|
364
|
-
dataType: 'capabilities',
|
|
365
|
-
error: {
|
|
366
|
-
message: 'AI provider API key required for capability inference',
|
|
367
|
-
details: 'Configure AI provider credentials to enable AI-powered capability analysis'
|
|
368
|
-
}
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
198
|
+
// Validate and initialize AI provider
|
|
199
|
+
let aiProvider;
|
|
200
|
+
try {
|
|
201
|
+
aiProvider = (0, ai_provider_factory_1.createAIProvider)();
|
|
202
|
+
if (!aiProvider.isInitialized()) {
|
|
373
203
|
return {
|
|
374
204
|
success: false,
|
|
375
205
|
operation: 'scan',
|
|
376
206
|
dataType: 'capabilities',
|
|
377
207
|
error: {
|
|
378
|
-
message: 'AI provider
|
|
379
|
-
details:
|
|
208
|
+
message: 'AI provider API key required for capability inference',
|
|
209
|
+
details: 'Configure AI provider credentials to enable AI-powered capability analysis'
|
|
380
210
|
}
|
|
381
211
|
};
|
|
382
212
|
}
|
|
383
213
|
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
return {
|
|
216
|
+
success: false,
|
|
217
|
+
operation: 'scan',
|
|
218
|
+
dataType: 'capabilities',
|
|
219
|
+
error: {
|
|
220
|
+
message: 'AI provider initialization failed',
|
|
221
|
+
details: error instanceof Error ? error.message : 'Unknown error'
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
384
225
|
// Initialize capability engine
|
|
385
|
-
const aiProvider = (0, ai_provider_factory_1.createAIProvider)();
|
|
386
226
|
const engine = new capabilities_1.CapabilityInferenceEngine(aiProvider, logger);
|
|
387
|
-
// Get the resource to analyze
|
|
388
|
-
let resourceName;
|
|
389
|
-
let currentIndex;
|
|
390
|
-
let totalResources;
|
|
391
227
|
if (session.selectedResources === 'all') {
|
|
392
228
|
// For 'all' mode, discover actual cluster resources first
|
|
393
229
|
try {
|
|
@@ -435,13 +271,9 @@ async function handleScanning(session, args, logger, requestId, capabilityServic
|
|
|
435
271
|
// Update session with discovered resources and start batch processing
|
|
436
272
|
transitionCapabilitySession(session, 'scanning', {
|
|
437
273
|
selectedResources: discoveredResourceNames,
|
|
438
|
-
processingMode: session.processingMode,
|
|
439
274
|
currentResourceIndex: 0
|
|
440
275
|
}, args);
|
|
441
|
-
//
|
|
442
|
-
resourceName = discoveredResourceNames[0]; // First resource for manual mode
|
|
443
|
-
currentIndex = 0;
|
|
444
|
-
totalResources = discoveredResourceNames.length;
|
|
276
|
+
// Fall through to batch processing with discovered resources
|
|
445
277
|
}
|
|
446
278
|
catch (error) {
|
|
447
279
|
logger.error('Failed to discover cluster resources', error, {
|
|
@@ -465,286 +297,201 @@ async function handleScanning(session, args, logger, requestId, capabilityServic
|
|
|
465
297
|
};
|
|
466
298
|
}
|
|
467
299
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if (currentIndex >= totalResources) {
|
|
473
|
-
// All resources processed - mark as complete
|
|
474
|
-
transitionCapabilitySession(session, 'complete', {}, args);
|
|
475
|
-
cleanupCapabilitySession(session, args, logger, requestId);
|
|
476
|
-
return createCapabilityScanCompletionResponse(session.sessionId, totalResources, totalResources, // Assume all successful for manual mode
|
|
477
|
-
0, 'completed interactively', 'manual');
|
|
478
|
-
}
|
|
479
|
-
resourceName = session.selectedResources[currentIndex];
|
|
480
|
-
if (!resourceName) {
|
|
481
|
-
throw new Error(`No resource found at index ${currentIndex}`);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
else {
|
|
485
|
-
throw new Error('Invalid selectedResources in session state');
|
|
300
|
+
// Auto mode: Process ALL resources in batch without user interaction
|
|
301
|
+
// At this point, selectedResources should always be an array (either discovered or specified)
|
|
302
|
+
if (!Array.isArray(session.selectedResources)) {
|
|
303
|
+
throw new Error(`Invalid selectedResources state: expected array, got ${typeof session.selectedResources}. This indicates a bug in resource discovery.`);
|
|
486
304
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
await discovery.connect();
|
|
493
|
-
// Get complete CRD definition if it's a custom resource
|
|
494
|
-
if (resourceName.includes('.')) {
|
|
495
|
-
const crdOutput = await discovery.executeKubectl(['get', 'crd', resourceName, '-o', 'yaml']);
|
|
496
|
-
resourceDefinition = crdOutput;
|
|
497
|
-
logger.info('Found complete CRD definition for capability analysis', {
|
|
498
|
-
requestId,
|
|
499
|
-
sessionId: session.sessionId,
|
|
500
|
-
resource: resourceName,
|
|
501
|
-
hasDefinition: !!resourceDefinition,
|
|
502
|
-
definitionSize: resourceDefinition?.length || 0
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
// For core resources, use kubectl explain to get schema information
|
|
507
|
-
const explainOutput = await discovery.explainResource(resourceName);
|
|
508
|
-
resourceDefinition = explainOutput;
|
|
509
|
-
logger.info('Found core resource explanation for capability analysis', {
|
|
510
|
-
requestId,
|
|
511
|
-
sessionId: session.sessionId,
|
|
512
|
-
resource: resourceName,
|
|
513
|
-
hasDefinition: !!resourceDefinition
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
catch (error) {
|
|
518
|
-
logger.error('Failed to retrieve resource definition for capability analysis', error, {
|
|
519
|
-
requestId,
|
|
520
|
-
sessionId: session.sessionId,
|
|
521
|
-
resource: resourceName
|
|
522
|
-
});
|
|
523
|
-
throw new Error(createResourceDefinitionErrorMessage(resourceName, error));
|
|
524
|
-
}
|
|
525
|
-
logger.info('Analyzing resource for capability inference', {
|
|
305
|
+
const resources = session.selectedResources;
|
|
306
|
+
const totalResources = resources.length;
|
|
307
|
+
const processedResults = [];
|
|
308
|
+
const errors = [];
|
|
309
|
+
logger.info('Starting auto batch processing', {
|
|
526
310
|
requestId,
|
|
527
311
|
sessionId: session.sessionId,
|
|
528
|
-
|
|
529
|
-
|
|
312
|
+
totalResources,
|
|
313
|
+
resources: resources
|
|
530
314
|
});
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
}
|
|
560
|
-
}
|
|
315
|
+
// Initialize progress tracking
|
|
316
|
+
const startTime = Date.now();
|
|
317
|
+
const updateProgress = (current, currentResource, successful, failed, recentErrors) => {
|
|
318
|
+
const elapsed = Date.now() - startTime;
|
|
319
|
+
const percentage = Math.round((current / totalResources) * 100);
|
|
320
|
+
// Calculate estimated time remaining
|
|
321
|
+
let estimatedTimeRemaining;
|
|
322
|
+
if (current > 0) {
|
|
323
|
+
const avgTimePerResource = elapsed / current;
|
|
324
|
+
const remainingResources = totalResources - current;
|
|
325
|
+
const estimatedRemainingMs = remainingResources * avgTimePerResource;
|
|
326
|
+
const estimatedMinutes = Math.round(estimatedRemainingMs / 60000 * 10) / 10;
|
|
327
|
+
estimatedTimeRemaining = estimatedMinutes > 1 ?
|
|
328
|
+
`${estimatedMinutes} minutes` :
|
|
329
|
+
`${Math.round(estimatedRemainingMs / 1000)} seconds`;
|
|
330
|
+
}
|
|
331
|
+
const progressData = {
|
|
332
|
+
status: 'processing',
|
|
333
|
+
current: current,
|
|
334
|
+
total: totalResources,
|
|
335
|
+
percentage: percentage,
|
|
336
|
+
currentResource: currentResource,
|
|
337
|
+
startedAt: new Date(startTime).toISOString(),
|
|
338
|
+
lastUpdated: new Date().toISOString(),
|
|
339
|
+
estimatedTimeRemaining,
|
|
340
|
+
successfulResources: successful,
|
|
341
|
+
failedResources: failed,
|
|
342
|
+
errors: recentErrors.slice(-5) // Keep last 5 errors for troubleshooting
|
|
561
343
|
};
|
|
344
|
+
// Update session file with progress
|
|
345
|
+
transitionCapabilitySession(session, 'scanning', {
|
|
346
|
+
selectedResources: session.selectedResources,
|
|
347
|
+
currentResourceIndex: current - 1,
|
|
348
|
+
progress: progressData
|
|
349
|
+
}, args);
|
|
350
|
+
};
|
|
351
|
+
// Setup kubectl access for getting complete resource definitions
|
|
352
|
+
let discovery;
|
|
353
|
+
try {
|
|
354
|
+
discovery = new discovery_1.KubernetesDiscovery();
|
|
355
|
+
await discovery.connect();
|
|
356
|
+
logger.info('Connected to Kubernetes for batch resource definition retrieval', {
|
|
357
|
+
requestId,
|
|
358
|
+
sessionId: session.sessionId
|
|
359
|
+
});
|
|
562
360
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
// At this point, selectedResources should always be an array (either discovered or specified)
|
|
566
|
-
if (!Array.isArray(session.selectedResources)) {
|
|
567
|
-
throw new Error(`Invalid selectedResources state: expected array, got ${typeof session.selectedResources}. This indicates a bug in resource discovery.`);
|
|
568
|
-
}
|
|
569
|
-
const resources = session.selectedResources;
|
|
570
|
-
const totalResources = resources.length;
|
|
571
|
-
const processedResults = [];
|
|
572
|
-
const errors = [];
|
|
573
|
-
logger.info('Starting auto batch processing', {
|
|
361
|
+
catch (error) {
|
|
362
|
+
logger.warn('Could not connect to Kubernetes for batch processing, falling back to name-based inference', {
|
|
574
363
|
requestId,
|
|
575
364
|
sessionId: session.sessionId,
|
|
576
|
-
|
|
577
|
-
resources: resources
|
|
365
|
+
error: error instanceof Error ? error.message : String(error)
|
|
578
366
|
});
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const remainingResources = totalResources - current;
|
|
589
|
-
const estimatedRemainingMs = remainingResources * avgTimePerResource;
|
|
590
|
-
const estimatedMinutes = Math.round(estimatedRemainingMs / 60000 * 10) / 10;
|
|
591
|
-
estimatedTimeRemaining = estimatedMinutes > 1 ?
|
|
592
|
-
`${estimatedMinutes} minutes` :
|
|
593
|
-
`${Math.round(estimatedRemainingMs / 1000)} seconds`;
|
|
594
|
-
}
|
|
595
|
-
const progressData = {
|
|
596
|
-
status: 'processing',
|
|
597
|
-
current: current,
|
|
598
|
-
total: totalResources,
|
|
599
|
-
percentage: percentage,
|
|
600
|
-
currentResource: currentResource,
|
|
601
|
-
startedAt: new Date(startTime).toISOString(),
|
|
602
|
-
lastUpdated: new Date().toISOString(),
|
|
603
|
-
estimatedTimeRemaining,
|
|
604
|
-
successfulResources: successful,
|
|
605
|
-
failedResources: failed,
|
|
606
|
-
errors: recentErrors.slice(-5) // Keep last 5 errors for troubleshooting
|
|
607
|
-
};
|
|
608
|
-
// Update session file with progress
|
|
609
|
-
transitionCapabilitySession(session, 'scanning', {
|
|
610
|
-
processingMode: session.processingMode,
|
|
611
|
-
selectedResources: session.selectedResources,
|
|
612
|
-
currentResourceIndex: current - 1,
|
|
613
|
-
progress: progressData
|
|
614
|
-
}, args);
|
|
615
|
-
};
|
|
616
|
-
// Setup kubectl access for getting complete resource definitions
|
|
617
|
-
let discovery;
|
|
618
|
-
try {
|
|
619
|
-
discovery = new discovery_1.KubernetesDiscovery();
|
|
620
|
-
await discovery.connect();
|
|
621
|
-
logger.info('Connected to Kubernetes for batch resource definition retrieval', {
|
|
622
|
-
requestId,
|
|
623
|
-
sessionId: session.sessionId
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
catch (error) {
|
|
627
|
-
logger.warn('Could not connect to Kubernetes for batch processing, falling back to name-based inference', {
|
|
628
|
-
requestId,
|
|
629
|
-
sessionId: session.sessionId,
|
|
630
|
-
error: error instanceof Error ? error.message : String(error)
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
// Process each resource in the batch with progress tracking
|
|
634
|
-
for (let i = 0; i < resources.length; i++) {
|
|
635
|
-
const currentResource = resources[i];
|
|
636
|
-
// Get complete resource definition for this resource
|
|
637
|
-
let currentResourceDefinition;
|
|
638
|
-
if (discovery) {
|
|
367
|
+
}
|
|
368
|
+
// Process each resource in the batch with progress tracking
|
|
369
|
+
for (let i = 0; i < resources.length; i++) {
|
|
370
|
+
const currentResource = resources[i];
|
|
371
|
+
// Get complete resource definition for this resource
|
|
372
|
+
let currentResourceDefinition;
|
|
373
|
+
if (discovery) {
|
|
374
|
+
try {
|
|
375
|
+
// Try kubectl explain with full name first (works for CRDs and core resources)
|
|
639
376
|
try {
|
|
377
|
+
currentResourceDefinition = await discovery.explainResource(currentResource);
|
|
378
|
+
}
|
|
379
|
+
catch (explainError) {
|
|
380
|
+
// If explain fails and resource has a dot (like Deployment.apps), try with just the Kind
|
|
640
381
|
if (currentResource.includes('.')) {
|
|
641
|
-
|
|
642
|
-
|
|
382
|
+
const resourceKind = currentResource.split('.')[0];
|
|
383
|
+
logger.info(`kubectl explain failed for ${currentResource}, attempting with Kind only: ${resourceKind}`, {
|
|
384
|
+
requestId,
|
|
385
|
+
sessionId: session.sessionId,
|
|
386
|
+
resource: currentResource,
|
|
387
|
+
resourceKind
|
|
388
|
+
});
|
|
389
|
+
currentResourceDefinition = await discovery.explainResource(resourceKind);
|
|
643
390
|
}
|
|
644
391
|
else {
|
|
645
|
-
//
|
|
646
|
-
|
|
392
|
+
// Re-throw explain error for resources without dots
|
|
393
|
+
throw explainError;
|
|
647
394
|
}
|
|
648
395
|
}
|
|
649
|
-
catch (error) {
|
|
650
|
-
logger.error(`Failed to get resource definition for ${currentResource}`, error, {
|
|
651
|
-
requestId,
|
|
652
|
-
sessionId: session.sessionId,
|
|
653
|
-
resource: currentResource
|
|
654
|
-
});
|
|
655
|
-
// Add to errors array and skip processing this resource
|
|
656
|
-
errors.push({
|
|
657
|
-
resource: currentResource,
|
|
658
|
-
error: createResourceDefinitionErrorMessage(currentResource, error),
|
|
659
|
-
timestamp: new Date().toISOString()
|
|
660
|
-
});
|
|
661
|
-
// Skip processing this resource
|
|
662
|
-
continue;
|
|
663
|
-
}
|
|
664
396
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
try {
|
|
668
|
-
logger.info(`Processing resource ${i + 1}/${totalResources}`, {
|
|
669
|
-
requestId,
|
|
670
|
-
sessionId: session.sessionId,
|
|
671
|
-
resource: currentResource,
|
|
672
|
-
percentage: Math.round(((i + 1) / totalResources) * 100)
|
|
673
|
-
});
|
|
674
|
-
const capability = await engine.inferCapabilities(currentResource, currentResourceDefinition, args.interaction_id);
|
|
675
|
-
const capabilityId = capabilities_1.CapabilityInferenceEngine.generateCapabilityId(currentResource);
|
|
676
|
-
// Store capability in Vector DB
|
|
677
|
-
await capabilityService.storeCapability(capability);
|
|
678
|
-
processedResults.push({
|
|
679
|
-
resource: currentResource,
|
|
680
|
-
id: capabilityId,
|
|
681
|
-
capabilities: capability.capabilities,
|
|
682
|
-
providers: capability.providers,
|
|
683
|
-
complexity: capability.complexity,
|
|
684
|
-
confidence: capability.confidence
|
|
685
|
-
});
|
|
686
|
-
logger.info(`Successfully processed resource ${i + 1}/${totalResources}`, {
|
|
397
|
+
catch (error) {
|
|
398
|
+
logger.error(`Failed to get resource definition for ${currentResource}`, error, {
|
|
687
399
|
requestId,
|
|
688
400
|
sessionId: session.sessionId,
|
|
689
|
-
resource: currentResource
|
|
690
|
-
capabilitiesFound: capability.capabilities.length,
|
|
691
|
-
percentage: Math.round(((i + 1) / totalResources) * 100)
|
|
401
|
+
resource: currentResource
|
|
692
402
|
});
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
696
|
-
const errorDetail = {
|
|
403
|
+
// Add to errors array and skip processing this resource
|
|
404
|
+
errors.push({
|
|
697
405
|
resource: currentResource,
|
|
698
|
-
error:
|
|
699
|
-
index: i + 1,
|
|
406
|
+
error: createResourceDefinitionErrorMessage(currentResource, error),
|
|
700
407
|
timestamp: new Date().toISOString()
|
|
701
|
-
};
|
|
702
|
-
logger.error(`Failed to process resource ${i + 1}/${totalResources}`, error, {
|
|
703
|
-
requestId,
|
|
704
|
-
sessionId: session.sessionId,
|
|
705
|
-
resource: currentResource,
|
|
706
|
-
percentage: Math.round(((i + 1) / totalResources) * 100)
|
|
707
408
|
});
|
|
708
|
-
|
|
409
|
+
// Skip processing this resource
|
|
410
|
+
continue;
|
|
709
411
|
}
|
|
710
412
|
}
|
|
711
|
-
//
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
413
|
+
// Update progress before processing
|
|
414
|
+
updateProgress(i + 1, currentResource, processedResults.length, errors.length, errors);
|
|
415
|
+
try {
|
|
416
|
+
logger.info(`Processing resource ${i + 1}/${totalResources}`, {
|
|
417
|
+
requestId,
|
|
418
|
+
sessionId: session.sessionId,
|
|
419
|
+
resource: currentResource,
|
|
420
|
+
percentage: Math.round(((i + 1) / totalResources) * 100)
|
|
421
|
+
});
|
|
422
|
+
const capability = await engine.inferCapabilities(currentResource, currentResourceDefinition, args.interaction_id);
|
|
423
|
+
const capabilityId = capabilities_1.CapabilityInferenceEngine.generateCapabilityId(currentResource);
|
|
424
|
+
// Store capability in Vector DB
|
|
425
|
+
await capabilityService.storeCapability(capability);
|
|
426
|
+
processedResults.push({
|
|
427
|
+
resource: currentResource,
|
|
428
|
+
id: capabilityId,
|
|
429
|
+
capabilities: capability.capabilities,
|
|
430
|
+
providers: capability.providers,
|
|
431
|
+
complexity: capability.complexity,
|
|
432
|
+
confidence: capability.confidence
|
|
433
|
+
});
|
|
434
|
+
logger.info(`Successfully processed resource ${i + 1}/${totalResources}`, {
|
|
435
|
+
requestId,
|
|
436
|
+
sessionId: session.sessionId,
|
|
437
|
+
resource: currentResource,
|
|
438
|
+
capabilitiesFound: capability.capabilities.length,
|
|
439
|
+
percentage: Math.round(((i + 1) / totalResources) * 100)
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
catch (error) {
|
|
443
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
444
|
+
const errorDetail = {
|
|
445
|
+
resource: currentResource,
|
|
446
|
+
error: errorMessage,
|
|
447
|
+
index: i + 1,
|
|
448
|
+
timestamp: new Date().toISOString()
|
|
449
|
+
};
|
|
450
|
+
logger.error(`Failed to process resource ${i + 1}/${totalResources}`, error, {
|
|
451
|
+
requestId,
|
|
452
|
+
sessionId: session.sessionId,
|
|
453
|
+
resource: currentResource,
|
|
454
|
+
percentage: Math.round(((i + 1) / totalResources) * 100)
|
|
455
|
+
});
|
|
456
|
+
errors.push(errorDetail);
|
|
457
|
+
}
|
|
747
458
|
}
|
|
459
|
+
// Final progress update - mark as completed
|
|
460
|
+
const finalElapsed = Date.now() - startTime;
|
|
461
|
+
const finalMinutes = Math.round(finalElapsed / 60000 * 10) / 10;
|
|
462
|
+
const successful = processedResults.length;
|
|
463
|
+
const failed = errors.length;
|
|
464
|
+
const completionData = {
|
|
465
|
+
status: 'completed',
|
|
466
|
+
current: totalResources,
|
|
467
|
+
total: totalResources,
|
|
468
|
+
percentage: 100,
|
|
469
|
+
currentResource: 'Processing complete',
|
|
470
|
+
startedAt: new Date(startTime).toISOString(),
|
|
471
|
+
lastUpdated: new Date().toISOString(),
|
|
472
|
+
completedAt: new Date().toISOString(),
|
|
473
|
+
totalProcessingTime: finalMinutes > 1 ? `${finalMinutes} minutes` : `${Math.round(finalElapsed / 1000)} seconds`,
|
|
474
|
+
successfulResources: successful,
|
|
475
|
+
failedResources: failed,
|
|
476
|
+
errors: errors.slice(-5)
|
|
477
|
+
};
|
|
478
|
+
// Update session with completion status
|
|
479
|
+
transitionCapabilitySession(session, 'complete', {
|
|
480
|
+
progress: completionData
|
|
481
|
+
}, args);
|
|
482
|
+
logger.info('Auto batch processing completed', {
|
|
483
|
+
requestId,
|
|
484
|
+
sessionId: session.sessionId,
|
|
485
|
+
processed: totalResources,
|
|
486
|
+
successful,
|
|
487
|
+
failed,
|
|
488
|
+
processingTime: completionData.totalProcessingTime
|
|
489
|
+
});
|
|
490
|
+
// Clean up session file after a brief delay to allow progress viewing
|
|
491
|
+
setTimeout(() => {
|
|
492
|
+
cleanupCapabilitySession(session, args, logger, requestId);
|
|
493
|
+
}, 30000); // Keep for 30 seconds after completion
|
|
494
|
+
return createCapabilityScanCompletionResponse(session.sessionId, totalResources, successful, failed, completionData.totalProcessingTime || 'completed', 'auto');
|
|
748
495
|
}
|
|
749
496
|
catch (error) {
|
|
750
497
|
logger.error('Capability scanning failed', error, {
|