@vfarcic/dot-ai 1.12.0 → 1.14.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/core/ai-provider-factory.d.ts.map +1 -1
- package/dist/core/ai-provider-factory.js +18 -3
- package/dist/core/ai-provider.interface.d.ts +9 -0
- package/dist/core/ai-provider.interface.d.ts.map +1 -1
- package/dist/core/git-utils.d.ts.map +1 -1
- package/dist/core/git-utils.js +4 -1
- package/dist/core/internal-tools.d.ts +34 -1
- package/dist/core/internal-tools.d.ts.map +1 -1
- package/dist/core/internal-tools.js +116 -1
- 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 +40 -5
- package/dist/core/session-events.d.ts +51 -0
- package/dist/core/session-events.d.ts.map +1 -0
- package/dist/core/session-events.js +51 -0
- package/dist/interfaces/rest-api.d.ts +11 -0
- package/dist/interfaces/rest-api.d.ts.map +1 -1
- package/dist/interfaces/rest-api.js +104 -0
- package/dist/interfaces/routes/index.d.ts.map +1 -1
- package/dist/interfaces/routes/index.js +25 -1
- package/dist/interfaces/schemas/index.d.ts +1 -1
- package/dist/interfaces/schemas/index.d.ts.map +1 -1
- package/dist/interfaces/schemas/index.js +8 -2
- package/dist/interfaces/schemas/sessions.d.ts +100 -0
- package/dist/interfaces/schemas/sessions.d.ts.map +1 -1
- package/dist/interfaces/schemas/sessions.js +58 -1
- package/dist/tools/remediate.d.ts +8 -0
- package/dist/tools/remediate.d.ts.map +1 -1
- package/dist/tools/remediate.js +188 -34
- package/package.json +2 -2
- package/prompts/remediate-system.md +5 -2
package/dist/tools/remediate.js
CHANGED
|
@@ -51,6 +51,7 @@ const fs = __importStar(require("fs"));
|
|
|
51
51
|
const path = __importStar(require("path"));
|
|
52
52
|
const request_context_1 = require("../interfaces/request-context");
|
|
53
53
|
const rbac_1 = require("../core/rbac");
|
|
54
|
+
const session_events_1 = require("../core/session-events");
|
|
54
55
|
const internal_tools_1 = require("../core/internal-tools");
|
|
55
56
|
// PRD #143 Milestone 1: Hybrid approach - AI can use kubectl_api_resources tool OR continue with JSON dataRequests
|
|
56
57
|
// Tool metadata for direct MCP registration
|
|
@@ -256,6 +257,13 @@ async function conductInvestigation(session, sessionManager, aiProvider, logger,
|
|
|
256
257
|
finalAnalysis: output,
|
|
257
258
|
status: 'analysis_complete',
|
|
258
259
|
});
|
|
260
|
+
(0, session_events_1.getSessionEventBus)().publish(session_events_1.SESSION_EVENTS.SESSION_UPDATED, {
|
|
261
|
+
sessionId: session.sessionId,
|
|
262
|
+
toolName: 'remediate',
|
|
263
|
+
status: 'analysis_complete',
|
|
264
|
+
issue: session.data.issue,
|
|
265
|
+
timestamp: new Date().toISOString(),
|
|
266
|
+
});
|
|
259
267
|
logger.info('Investigation and analysis completed', {
|
|
260
268
|
requestId,
|
|
261
269
|
sessionId: session.sessionId,
|
|
@@ -271,6 +279,13 @@ async function conductInvestigation(session, sessionManager, aiProvider, logger,
|
|
|
271
279
|
});
|
|
272
280
|
// Mark session as failed
|
|
273
281
|
sessionManager.updateSession(session.sessionId, { status: 'failed' });
|
|
282
|
+
(0, session_events_1.getSessionEventBus)().publish(session_events_1.SESSION_EVENTS.SESSION_UPDATED, {
|
|
283
|
+
sessionId: session.sessionId,
|
|
284
|
+
toolName: 'remediate',
|
|
285
|
+
status: 'failed',
|
|
286
|
+
issue: session.data.issue,
|
|
287
|
+
timestamp: new Date().toISOString(),
|
|
288
|
+
});
|
|
274
289
|
throw error_handling_1.ErrorHandler.createError(error_handling_1.ErrorCategory.AI_SERVICE, error_handling_1.ErrorSeverity.HIGH, `Investigation failed: ${error instanceof Error ? error.message : 'Unknown error'}`, {
|
|
275
290
|
operation: 'investigation_loop',
|
|
276
291
|
component: 'RemediateTool',
|
|
@@ -401,7 +416,31 @@ async function executeUserChoice(sessionManager, sessionId, choice, logger, requ
|
|
|
401
416
|
return await executeRemediationCommands(session, sessionManager, logger, requestId, currentInteractionId);
|
|
402
417
|
case 2: {
|
|
403
418
|
// Execute via agent
|
|
404
|
-
|
|
419
|
+
const actions = session.data.finalAnalysis.remediation.actions;
|
|
420
|
+
const gitSourceActions = actions.filter(a => a.gitSource && !a.command);
|
|
421
|
+
const kubectlActions = actions.filter(a => a.command && !a.gitSource);
|
|
422
|
+
if (gitSourceActions.length > 0 && kubectlActions.length === 0) {
|
|
423
|
+
return {
|
|
424
|
+
content: [
|
|
425
|
+
{
|
|
426
|
+
type: 'text',
|
|
427
|
+
text: JSON.stringify({
|
|
428
|
+
status: 'success',
|
|
429
|
+
sessionId: sessionId,
|
|
430
|
+
message: 'GitOps remediation detected - use automatic execution (choice 1) for PR creation',
|
|
431
|
+
remediation: session.data.finalAnalysis.remediation,
|
|
432
|
+
instructions: {
|
|
433
|
+
nextSteps: [
|
|
434
|
+
'This remediation requires GitOps PR creation which is handled automatically.',
|
|
435
|
+
'Please use choice 1 (Execute automatically) to create the PR.',
|
|
436
|
+
'Alternatively, manually apply the file changes from gitSource.files to your repository.',
|
|
437
|
+
],
|
|
438
|
+
},
|
|
439
|
+
}, null, 2),
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
};
|
|
443
|
+
}
|
|
405
444
|
const validationIntent = session.data.finalAnalysis.validationIntent ||
|
|
406
445
|
'Check the status of the affected resources to verify the issue has been resolved';
|
|
407
446
|
return {
|
|
@@ -453,6 +492,7 @@ async function executeRemediationCommands(session, sessionManager, logger, reque
|
|
|
453
492
|
const finalAnalysis = session.data.finalAnalysis;
|
|
454
493
|
let overallSuccess = true;
|
|
455
494
|
let executedCommandCount = 0;
|
|
495
|
+
let pullRequestInfo;
|
|
456
496
|
logger.info('Starting remediation command execution', {
|
|
457
497
|
requestId,
|
|
458
498
|
sessionId: session.sessionId,
|
|
@@ -463,21 +503,76 @@ async function executeRemediationCommands(session, sessionManager, logger, reque
|
|
|
463
503
|
const action = finalAnalysis.remediation.actions[i];
|
|
464
504
|
const actionId = `action_${i + 1}`;
|
|
465
505
|
try {
|
|
466
|
-
// PRD #
|
|
467
|
-
// instructions for GitOps-managed resources, not executable commands
|
|
506
|
+
// PRD #408: Handle gitSource actions — create PR instead of kubectl
|
|
468
507
|
if (action.gitSource && !action.command) {
|
|
469
|
-
logger.info('
|
|
508
|
+
logger.info('Processing gitSource remediation action', {
|
|
470
509
|
requestId,
|
|
471
510
|
sessionId: session.sessionId,
|
|
472
511
|
actionId,
|
|
473
512
|
repoURL: action.gitSource.repoURL,
|
|
513
|
+
repoPath: action.gitSource.repoPath,
|
|
474
514
|
});
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
515
|
+
if (!action.gitSource.repoPath) {
|
|
516
|
+
results.push({
|
|
517
|
+
action: `${actionId}: ${action.description} (failed: missing repoPath)`,
|
|
518
|
+
success: false,
|
|
519
|
+
output: 'Git-based remediation requires repoPath from investigation phase',
|
|
520
|
+
timestamp: new Date(),
|
|
521
|
+
});
|
|
522
|
+
overallSuccess = false;
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const prInput = {
|
|
526
|
+
repoPath: action.gitSource.repoPath,
|
|
527
|
+
files: action.gitSource.files.map((f) => ({
|
|
528
|
+
path: f.path,
|
|
529
|
+
content: f.content,
|
|
530
|
+
})),
|
|
531
|
+
title: `fix: ${action.description}`,
|
|
532
|
+
body: `## Remediation\n\n${action.rationale}\n\n**Risk Level:** ${action.risk}`,
|
|
533
|
+
branchName: `remediate/${session.sessionId.slice(0, 12)}-${Date.now()}`,
|
|
534
|
+
baseBranch: action.gitSource.branch || 'main',
|
|
535
|
+
};
|
|
536
|
+
const prExecutor = (0, internal_tools_1.createInternalToolExecutor)(session.sessionId);
|
|
537
|
+
const prResult = (await prExecutor('git_create_pr', prInput));
|
|
538
|
+
if (prResult.success && 'prUrl' in prResult) {
|
|
539
|
+
const filesList = prResult.filesChanged && prResult.filesChanged.length > 0
|
|
540
|
+
? prResult.filesChanged.join(', ')
|
|
541
|
+
: 'none';
|
|
542
|
+
results.push({
|
|
543
|
+
action: `${actionId}: ${action.description} (PR created)`,
|
|
544
|
+
success: true,
|
|
545
|
+
output: `PR #${prResult.prNumber}: ${prResult.prUrl}\nBranch: ${prResult.branch}\nFiles changed: ${filesList}`,
|
|
546
|
+
timestamp: new Date(),
|
|
547
|
+
});
|
|
548
|
+
pullRequestInfo = {
|
|
549
|
+
url: prResult.prUrl,
|
|
550
|
+
number: prResult.prNumber,
|
|
551
|
+
branch: prResult.branch,
|
|
552
|
+
baseBranch: prResult.baseBranch,
|
|
553
|
+
filesChanged: prResult.filesChanged,
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
else if (prResult.success && 'error' in prResult) {
|
|
557
|
+
const filesList = prResult.filesChanged && prResult.filesChanged.length > 0
|
|
558
|
+
? prResult.filesChanged.join(', ')
|
|
559
|
+
: 'none';
|
|
560
|
+
results.push({
|
|
561
|
+
action: `${actionId}: ${action.description} (branch pushed, manual PR needed)`,
|
|
562
|
+
success: true,
|
|
563
|
+
output: `Branch: ${prResult.branch}\nFiles changed: ${filesList}\nNote: ${prResult.error}`,
|
|
564
|
+
timestamp: new Date(),
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
overallSuccess = false;
|
|
569
|
+
results.push({
|
|
570
|
+
action: `${actionId}: ${action.description} (failed)`,
|
|
571
|
+
success: false,
|
|
572
|
+
output: prResult.error,
|
|
573
|
+
timestamp: new Date(),
|
|
574
|
+
});
|
|
575
|
+
}
|
|
481
576
|
continue;
|
|
482
577
|
}
|
|
483
578
|
logger.info('Executing remediation action', {
|
|
@@ -620,6 +715,7 @@ IMPORTANT: You MUST respond with the final JSON analysis format as specified in
|
|
|
620
715
|
success: false,
|
|
621
716
|
summary: 'Validation found remaining issues after remediation',
|
|
622
717
|
},
|
|
718
|
+
pullRequest: pullRequestInfo,
|
|
623
719
|
};
|
|
624
720
|
return {
|
|
625
721
|
content: [
|
|
@@ -657,6 +753,7 @@ IMPORTANT: You MUST respond with the final JSON analysis format as specified in
|
|
|
657
753
|
success: true,
|
|
658
754
|
summary: 'Validation confirmed issue resolution',
|
|
659
755
|
},
|
|
756
|
+
pullRequest: pullRequestInfo,
|
|
660
757
|
};
|
|
661
758
|
const content = [
|
|
662
759
|
{
|
|
@@ -684,6 +781,73 @@ IMPORTANT: You MUST respond with the final JSON analysis format as specified in
|
|
|
684
781
|
status: overallSuccess ? 'executed_successfully' : 'executed_with_errors',
|
|
685
782
|
executionResults: results,
|
|
686
783
|
});
|
|
784
|
+
(0, session_events_1.getSessionEventBus)().publish(session_events_1.SESSION_EVENTS.SESSION_UPDATED, {
|
|
785
|
+
sessionId: session.sessionId,
|
|
786
|
+
toolName: 'remediate',
|
|
787
|
+
status: overallSuccess ? 'executed_successfully' : 'executed_with_errors',
|
|
788
|
+
issue: session.data.issue,
|
|
789
|
+
timestamp: new Date().toISOString(),
|
|
790
|
+
});
|
|
791
|
+
const hasOnlyGitOps = executedCommandCount === 0 && pullRequestInfo !== undefined;
|
|
792
|
+
const prInfo = pullRequestInfo;
|
|
793
|
+
let nextSteps;
|
|
794
|
+
if (hasOnlyGitOps && prInfo) {
|
|
795
|
+
nextSteps = [
|
|
796
|
+
'Changes have been pushed to a Git branch for GitOps reconciliation:',
|
|
797
|
+
` PR: ${prInfo.url}`,
|
|
798
|
+
` Branch: ${prInfo.branch} → ${prInfo.baseBranch}`,
|
|
799
|
+
` Files changed: ${prInfo.filesChanged.join(', ')}`,
|
|
800
|
+
'',
|
|
801
|
+
'Next steps:',
|
|
802
|
+
' 1. Review and merge the PR in your Git repository',
|
|
803
|
+
' 2. Wait for Argo CD/Flux to sync the changes',
|
|
804
|
+
' 3. Verify the issue is resolved after reconciliation',
|
|
805
|
+
'',
|
|
806
|
+
`You can verify the fix by running: remediate("Verify that ${finalAnalysis.analysis.rootCause.toLowerCase()} has been resolved")`,
|
|
807
|
+
];
|
|
808
|
+
}
|
|
809
|
+
else if (overallSuccess) {
|
|
810
|
+
if (validationResult) {
|
|
811
|
+
nextSteps = [
|
|
812
|
+
'The following kubectl commands were executed to remediate the issue:',
|
|
813
|
+
...finalAnalysis.remediation.actions
|
|
814
|
+
.filter(a => a.command)
|
|
815
|
+
.map((action, index) => {
|
|
816
|
+
const resultIndex = finalAnalysis.remediation.actions.indexOf(action);
|
|
817
|
+
return ` ${index + 1}. ${action.command} ${results[resultIndex]?.success ? '✓' : '✗'}`;
|
|
818
|
+
}),
|
|
819
|
+
'Automatic validation has been completed - see validation results above',
|
|
820
|
+
'Monitor your cluster to ensure the issue remains resolved',
|
|
821
|
+
];
|
|
822
|
+
}
|
|
823
|
+
else {
|
|
824
|
+
nextSteps = [
|
|
825
|
+
'The following kubectl commands were executed to remediate the issue:',
|
|
826
|
+
...finalAnalysis.remediation.actions
|
|
827
|
+
.filter(a => a.command)
|
|
828
|
+
.map((action, index) => {
|
|
829
|
+
const resultIndex = finalAnalysis.remediation.actions.indexOf(action);
|
|
830
|
+
return ` ${index + 1}. ${action.command} ${results[resultIndex]?.success ? '✓' : '✗'}`;
|
|
831
|
+
}),
|
|
832
|
+
`You can verify the fix by running: remediate("Verify that ${finalAnalysis.analysis.rootCause.toLowerCase()} has been resolved")`,
|
|
833
|
+
'Monitor your cluster to ensure the issue is fully resolved',
|
|
834
|
+
];
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
nextSteps = [
|
|
839
|
+
'The following kubectl commands were attempted:',
|
|
840
|
+
...finalAnalysis.remediation.actions
|
|
841
|
+
.filter(a => a.command)
|
|
842
|
+
.map((action, index) => {
|
|
843
|
+
const resultIndex = finalAnalysis.remediation.actions.indexOf(action);
|
|
844
|
+
return ` ${index + 1}. ${action.command} ${results[resultIndex]?.success ? '✓' : '✗'}`;
|
|
845
|
+
}),
|
|
846
|
+
'Some remediation commands failed - check the results above',
|
|
847
|
+
'Review the error messages and address any underlying issues',
|
|
848
|
+
'You may need to run additional commands or investigate further',
|
|
849
|
+
];
|
|
850
|
+
}
|
|
687
851
|
const response = {
|
|
688
852
|
status: overallSuccess ? 'success' : 'failed',
|
|
689
853
|
sessionId: session.sessionId,
|
|
@@ -691,37 +855,20 @@ IMPORTANT: You MUST respond with the final JSON analysis format as specified in
|
|
|
691
855
|
results: results,
|
|
692
856
|
executedCommands: results.map(r => r.action),
|
|
693
857
|
message: overallSuccess
|
|
694
|
-
?
|
|
858
|
+
? hasOnlyGitOps
|
|
859
|
+
? `Successfully created PR for ${results.length} GitOps remediation action(s)`
|
|
860
|
+
: `Successfully executed ${results.length} remediation actions`
|
|
695
861
|
: `Executed ${results.length} actions with ${results.filter(r => !r.success).length} failures`,
|
|
696
862
|
validation: validationResult,
|
|
697
863
|
instructions: {
|
|
698
|
-
showExecutedCommands:
|
|
699
|
-
showActualKubectlCommands:
|
|
700
|
-
nextSteps
|
|
701
|
-
? validationResult
|
|
702
|
-
? [
|
|
703
|
-
'The following kubectl commands were executed to remediate the issue:',
|
|
704
|
-
...finalAnalysis.remediation.actions.map((action, index) => ` ${index + 1}. ${action.command} ${results[index]?.success ? '✓' : '✗'}`),
|
|
705
|
-
'Automatic validation has been completed - see validation results above',
|
|
706
|
-
'Monitor your cluster to ensure the issue remains resolved',
|
|
707
|
-
]
|
|
708
|
-
: [
|
|
709
|
-
'The following kubectl commands were executed to remediate the issue:',
|
|
710
|
-
...finalAnalysis.remediation.actions.map((action, index) => ` ${index + 1}. ${action.command} ${results[index]?.success ? '✓' : '✗'}`),
|
|
711
|
-
`You can verify the fix by running: remediate("Verify that ${finalAnalysis.analysis.rootCause.toLowerCase()} has been resolved")`,
|
|
712
|
-
'Monitor your cluster to ensure the issue is fully resolved',
|
|
713
|
-
]
|
|
714
|
-
: [
|
|
715
|
-
'The following kubectl commands were attempted:',
|
|
716
|
-
...finalAnalysis.remediation.actions.map((action, index) => ` ${index + 1}. ${action.command} ${results[index]?.success ? '✓' : '✗'}`),
|
|
717
|
-
'Some remediation commands failed - check the results above',
|
|
718
|
-
'Review the error messages and address any underlying issues',
|
|
719
|
-
'You may need to run additional commands or investigate further',
|
|
720
|
-
],
|
|
864
|
+
showExecutedCommands: !hasOnlyGitOps,
|
|
865
|
+
showActualKubectlCommands: !hasOnlyGitOps,
|
|
866
|
+
nextSteps,
|
|
721
867
|
},
|
|
722
868
|
investigation: finalAnalysis.investigation,
|
|
723
869
|
analysis: finalAnalysis.analysis,
|
|
724
870
|
remediation: finalAnalysis.remediation,
|
|
871
|
+
pullRequest: pullRequestInfo,
|
|
725
872
|
};
|
|
726
873
|
logger.info('Remediation execution completed', {
|
|
727
874
|
requestId,
|
|
@@ -796,6 +943,13 @@ async function handleRemediateTool(args) {
|
|
|
796
943
|
interaction_id: validatedInput.interaction_id,
|
|
797
944
|
status: 'investigating',
|
|
798
945
|
});
|
|
946
|
+
(0, session_events_1.getSessionEventBus)().publish(session_events_1.SESSION_EVENTS.SESSION_CREATED, {
|
|
947
|
+
sessionId: session.sessionId,
|
|
948
|
+
toolName: 'remediate',
|
|
949
|
+
status: 'investigating',
|
|
950
|
+
issue: validatedInput.issue,
|
|
951
|
+
timestamp: session.createdAt,
|
|
952
|
+
});
|
|
799
953
|
logger.info('Investigation session created', {
|
|
800
954
|
requestId,
|
|
801
955
|
sessionId: session.sessionId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vfarcic/dot-ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance",
|
|
5
5
|
"mcpName": "io.github.vfarcic/dot-ai",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"vitest": "^3.2.4"
|
|
108
108
|
},
|
|
109
109
|
"dependencies": {
|
|
110
|
-
"@ai-sdk/alibaba": "^1.0.
|
|
110
|
+
"@ai-sdk/alibaba": "^1.0.13",
|
|
111
111
|
"@ai-sdk/amazon-bedrock": "^4.0.77",
|
|
112
112
|
"@ai-sdk/anthropic": "^3.0.58",
|
|
113
113
|
"@ai-sdk/google": "^3.0.43",
|
|
@@ -65,6 +65,7 @@ Once investigation is complete, respond with ONLY this JSON format:
|
|
|
65
65
|
"gitSource": {
|
|
66
66
|
"repoURL": "source repository URL — only when resource is GitOps-managed",
|
|
67
67
|
"branch": "branch name",
|
|
68
|
+
"repoPath": "relative path to cloned repo (as returned by git_clone) — required for GitOps remediation",
|
|
68
69
|
"files": [
|
|
69
70
|
{
|
|
70
71
|
"path": "path relative to repo root",
|
|
@@ -104,8 +105,9 @@ Once investigation is complete, respond with ONLY this JSON format:
|
|
|
104
105
|
After identifying the problematic resource, check whether it is managed by a GitOps controller (e.g., Argo CD, Flux).
|
|
105
106
|
|
|
106
107
|
**When GitOps management is detected**:
|
|
107
|
-
- Clone the source repo
|
|
108
|
-
-
|
|
108
|
+
- Clone the source repo and capture the local path for use as `repoPath` in the remediation actions
|
|
109
|
+
- Navigate and read the manifests to find the file(s) that need changing
|
|
110
|
+
- Include `gitSource` in your remediation actions with `repoPath`, `repoURL`, `branch`, and full corrected file contents for each file that needs modification
|
|
109
111
|
|
|
110
112
|
**When GitOps management is NOT detected**:
|
|
111
113
|
- Proceed with standard kubectl-based remediation
|
|
@@ -190,6 +192,7 @@ After identifying the problematic resource, check whether it is managed by a Git
|
|
|
190
192
|
"gitSource": {
|
|
191
193
|
"repoURL": "https://github.com/org/infra-repo.git",
|
|
192
194
|
"branch": "main",
|
|
195
|
+
"repoPath": "session-abc123/org-infra-repo",
|
|
193
196
|
"files": [
|
|
194
197
|
{
|
|
195
198
|
"path": "apps/production/deployment.yaml",
|