@commitsage/mcp-server 1.0.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/README.md +434 -0
- package/dist/adapters/sse.d.ts +26 -0
- package/dist/adapters/sse.d.ts.map +1 -0
- package/dist/adapters/sse.js +45 -0
- package/dist/adapters/sse.js.map +1 -0
- package/dist/auth/jwt.d.ts +70 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +171 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/oauth.d.ts +71 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +213 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/models/errors.d.ts +34 -0
- package/dist/models/errors.d.ts.map +1 -0
- package/dist/models/errors.js +67 -0
- package/dist/models/errors.js.map +1 -0
- package/dist/models/types.d.ts +39 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +9 -0
- package/dist/models/types.js.map +1 -0
- package/dist/server/mcpServer.d.ts +11 -0
- package/dist/server/mcpServer.d.ts.map +1 -0
- package/dist/server/mcpServer.js +216 -0
- package/dist/server/mcpServer.js.map +1 -0
- package/dist/server/tools.d.ts +93 -0
- package/dist/server/tools.d.ts.map +1 -0
- package/dist/server/tools.js +272 -0
- package/dist/server/tools.js.map +1 -0
- package/dist/services/aiService.d.ts +12 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +86 -0
- package/dist/services/aiService.js.map +1 -0
- package/dist/services/baseAIService.d.ts +47 -0
- package/dist/services/baseAIService.d.ts.map +1 -0
- package/dist/services/baseAIService.js +153 -0
- package/dist/services/baseAIService.js.map +1 -0
- package/dist/services/codestralService.d.ts +7 -0
- package/dist/services/codestralService.d.ts.map +1 -0
- package/dist/services/codestralService.js +49 -0
- package/dist/services/codestralService.js.map +1 -0
- package/dist/services/geminiService.d.ts +18 -0
- package/dist/services/geminiService.d.ts.map +1 -0
- package/dist/services/geminiService.js +139 -0
- package/dist/services/geminiService.js.map +1 -0
- package/dist/services/gitBlameAnalyzer.d.ts +15 -0
- package/dist/services/gitBlameAnalyzer.d.ts.map +1 -0
- package/dist/services/gitBlameAnalyzer.js +135 -0
- package/dist/services/gitBlameAnalyzer.js.map +1 -0
- package/dist/services/gitService.d.ts +54 -0
- package/dist/services/gitService.d.ts.map +1 -0
- package/dist/services/gitService.js +394 -0
- package/dist/services/gitService.js.map +1 -0
- package/dist/services/ollamaService.d.ts +7 -0
- package/dist/services/ollamaService.d.ts.map +1 -0
- package/dist/services/ollamaService.js +43 -0
- package/dist/services/ollamaService.js.map +1 -0
- package/dist/services/openaiService.d.ts +9 -0
- package/dist/services/openaiService.d.ts.map +1 -0
- package/dist/services/openaiService.js +69 -0
- package/dist/services/openaiService.js.map +1 -0
- package/dist/services/promptService.d.ts +10 -0
- package/dist/services/promptService.d.ts.map +1 -0
- package/dist/services/promptService.js +136 -0
- package/dist/services/promptService.js.map +1 -0
- package/dist/utils/config.d.ts +27 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +80 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/httpUtils.d.ts +33 -0
- package/dist/utils/httpUtils.d.ts.map +1 -0
- package/dist/utils/httpUtils.js +54 -0
- package/dist/utils/httpUtils.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/retryUtils.d.ts +29 -0
- package/dist/utils/retryUtils.d.ts.map +1 -0
- package/dist/utils/retryUtils.js +49 -0
- package/dist/utils/retryUtils.js.map +1 -0
- package/dist/utils/textProcessing.d.ts +8 -0
- package/dist/utils/textProcessing.d.ts.map +1 -0
- package/dist/utils/textProcessing.js +10 -0
- package/dist/utils/textProcessing.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main AI service for MCP server
|
|
3
|
+
* Coordinates between different AI providers
|
|
4
|
+
*/
|
|
5
|
+
import { Logger } from '../utils/logger.js';
|
|
6
|
+
import { ConfigService } from '../utils/config.js';
|
|
7
|
+
import { NoopProgressReporter } from '../models/types.js';
|
|
8
|
+
import { PromptService } from './promptService.js';
|
|
9
|
+
import { GitService } from './gitService.js';
|
|
10
|
+
import { GitBlameAnalyzer } from './gitBlameAnalyzer.js';
|
|
11
|
+
import { removeThinkTags } from '../utils/textProcessing.js';
|
|
12
|
+
import { GeminiService } from './geminiService.js';
|
|
13
|
+
import { OpenAIService } from './openaiService.js';
|
|
14
|
+
import { CodestralService } from './codestralService.js';
|
|
15
|
+
import { OllamaService } from './ollamaService.js';
|
|
16
|
+
const MAX_DIFF_LENGTH = 100000;
|
|
17
|
+
export class AIService {
|
|
18
|
+
static requiresApiKey(provider) {
|
|
19
|
+
return ['gemini', 'openai', 'codestral'].includes(provider.toLowerCase());
|
|
20
|
+
}
|
|
21
|
+
static async generateCommitMessage(diff, blameAnalysis, progress = new NoopProgressReporter(), provider) {
|
|
22
|
+
if (!diff) {
|
|
23
|
+
throw new Error('No changes detected');
|
|
24
|
+
}
|
|
25
|
+
const truncatedDiff = this.truncateDiff(diff);
|
|
26
|
+
const prompt = PromptService.generatePrompt(truncatedDiff, blameAnalysis);
|
|
27
|
+
progress.report({ message: 'Generating commit message...', increment: 50 });
|
|
28
|
+
try {
|
|
29
|
+
const providerType = provider || ConfigService.getProvider();
|
|
30
|
+
Logger.log(`Using provider: ${providerType}`);
|
|
31
|
+
let result;
|
|
32
|
+
switch (providerType) {
|
|
33
|
+
case 'gemini':
|
|
34
|
+
result = await GeminiService.generateCommitMessage(prompt, progress);
|
|
35
|
+
break;
|
|
36
|
+
case 'openai':
|
|
37
|
+
result = await OpenAIService.generateCommitMessage(prompt, progress);
|
|
38
|
+
break;
|
|
39
|
+
case 'codestral':
|
|
40
|
+
result = await CodestralService.generateCommitMessage(prompt, progress);
|
|
41
|
+
break;
|
|
42
|
+
case 'ollama':
|
|
43
|
+
result = await OllamaService.generateCommitMessage(prompt, progress);
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Unknown provider: ${providerType}`);
|
|
47
|
+
}
|
|
48
|
+
// Post-process the commit message to remove think tags
|
|
49
|
+
result.message = removeThinkTags(result.message);
|
|
50
|
+
Logger.log('Commit message generation completed');
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
Logger.error('Failed to generate commit message:', error);
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
static truncateDiff(diff) {
|
|
59
|
+
return diff.length > MAX_DIFF_LENGTH
|
|
60
|
+
? `${diff.substring(0, MAX_DIFF_LENGTH)}\n...(truncated)`
|
|
61
|
+
: diff;
|
|
62
|
+
}
|
|
63
|
+
static async generateCommitMessageForRepo(repoPath, onlyStaged = false, provider) {
|
|
64
|
+
try {
|
|
65
|
+
// Validate repository
|
|
66
|
+
await GitService.validateRepository(repoPath);
|
|
67
|
+
// Get diff
|
|
68
|
+
const diff = await GitService.getDiff(repoPath, onlyStaged);
|
|
69
|
+
if (!diff) {
|
|
70
|
+
throw new Error('No changes to commit');
|
|
71
|
+
}
|
|
72
|
+
// Get changed files and analyze blame
|
|
73
|
+
const changedFiles = await GitService.getChangedFiles(repoPath, onlyStaged);
|
|
74
|
+
const blameAnalyses = await Promise.all(changedFiles.map((file) => GitBlameAnalyzer.analyzeChanges(repoPath, file)));
|
|
75
|
+
const blameAnalysis = blameAnalyses.filter((analysis) => analysis).join('\n\n');
|
|
76
|
+
// Generate commit message
|
|
77
|
+
const progress = new NoopProgressReporter();
|
|
78
|
+
return await this.generateCommitMessage(diff, blameAnalysis, progress, provider);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
Logger.error('Error generating commit message for repo:', error);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=aiService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiService.js","sourceRoot":"","sources":["../../src/services/aiService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base AI service utilities
|
|
3
|
+
* Adapted from VSCode extension
|
|
4
|
+
*/
|
|
5
|
+
import { HttpUtils } from '../utils/httpUtils.js';
|
|
6
|
+
import { RetryUtils, ApiErrorResult } from '../utils/retryUtils.js';
|
|
7
|
+
export declare class BaseAIService {
|
|
8
|
+
/**
|
|
9
|
+
* Clean commit message
|
|
10
|
+
*/
|
|
11
|
+
static cleanCommitMessage(message: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Validate commit message is not empty
|
|
14
|
+
*/
|
|
15
|
+
static validateCommitMessage(message: string): string;
|
|
16
|
+
static createRequestHeaders: typeof HttpUtils.createRequestHeaders;
|
|
17
|
+
static createRequestConfig: typeof HttpUtils.createRequestConfig;
|
|
18
|
+
static updateProgressForAttempt: typeof RetryUtils.updateProgressForAttempt;
|
|
19
|
+
static calculateRetryDelay: typeof RetryUtils.calculateRetryDelay;
|
|
20
|
+
static delay: typeof RetryUtils.delay;
|
|
21
|
+
static handleGenerationError: typeof RetryUtils.handleGenerationError;
|
|
22
|
+
/**
|
|
23
|
+
* Extract and validate commit message from response
|
|
24
|
+
*/
|
|
25
|
+
static extractAndValidateMessage(content: string | undefined | null, serviceName: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Universal HTTP error handler for all AI services
|
|
28
|
+
*/
|
|
29
|
+
static handleHttpError(error: Error, serviceName: string): ApiErrorResult;
|
|
30
|
+
/**
|
|
31
|
+
* Gemini-specific error handling
|
|
32
|
+
*/
|
|
33
|
+
static handleGeminiError(error: Error): ApiErrorResult;
|
|
34
|
+
/**
|
|
35
|
+
* OpenAI-specific error handling
|
|
36
|
+
*/
|
|
37
|
+
static handleOpenAIError(error: Error): ApiErrorResult;
|
|
38
|
+
/**
|
|
39
|
+
* Codestral-specific error handling
|
|
40
|
+
*/
|
|
41
|
+
static handleCodestralError(error: Error): ApiErrorResult;
|
|
42
|
+
/**
|
|
43
|
+
* Ollama-specific error handling
|
|
44
|
+
*/
|
|
45
|
+
static handleOllamaError(error: Error): ApiErrorResult;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=baseAIService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseAIService.d.ts","sourceRoot":"","sources":["../../src/services/baseAIService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAWpE,qBAAa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIlD;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IASrD,MAAM,CAAC,oBAAoB,wCAAkC;IAC7D,MAAM,CAAC,mBAAmB,uCAAiC;IAG3D,MAAM,CAAC,wBAAwB,6CAAuC;IACtE,MAAM,CAAC,mBAAmB,wCAAkC;IAC5D,MAAM,CAAC,KAAK,0BAAoB;IAChC,MAAM,CAAC,qBAAqB,0CAAoC;IAEhE;;OAEG;IACH,MAAM,CAAC,yBAAyB,CAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAClC,WAAW,EAAE,MAAM,GAClB,MAAM;IAOT;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc;IA8DzE;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc;IAItD;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc;IAItD;;OAEG;IACH,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc;IAWzD;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc;CAyBvD"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base AI service utilities
|
|
3
|
+
* Adapted from VSCode extension
|
|
4
|
+
*/
|
|
5
|
+
import { HttpUtils } from '../utils/httpUtils.js';
|
|
6
|
+
import { RetryUtils } from '../utils/retryUtils.js';
|
|
7
|
+
const errorMessages = {
|
|
8
|
+
authenticationError: 'Authentication failed. Please check your API key.',
|
|
9
|
+
paymentRequired: 'Payment required. Please check your account billing.',
|
|
10
|
+
rateLimitExceeded: 'Rate limit exceeded. Please try again later.',
|
|
11
|
+
invalidRequest: 'Invalid request. Please check your parameters.',
|
|
12
|
+
serverError: 'Server error. Please try again later.',
|
|
13
|
+
apiError: 'API error (status {0})',
|
|
14
|
+
};
|
|
15
|
+
export class BaseAIService {
|
|
16
|
+
/**
|
|
17
|
+
* Clean commit message
|
|
18
|
+
*/
|
|
19
|
+
static cleanCommitMessage(message) {
|
|
20
|
+
return message.trim();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Validate commit message is not empty
|
|
24
|
+
*/
|
|
25
|
+
static validateCommitMessage(message) {
|
|
26
|
+
const cleanMessage = this.cleanCommitMessage(message);
|
|
27
|
+
if (!cleanMessage.trim()) {
|
|
28
|
+
throw new Error('Generated commit message is empty.');
|
|
29
|
+
}
|
|
30
|
+
return cleanMessage;
|
|
31
|
+
}
|
|
32
|
+
// Delegate HTTP operations to HttpUtils
|
|
33
|
+
static createRequestHeaders = HttpUtils.createRequestHeaders;
|
|
34
|
+
static createRequestConfig = HttpUtils.createRequestConfig;
|
|
35
|
+
// Delegate retry operations to RetryUtils
|
|
36
|
+
static updateProgressForAttempt = RetryUtils.updateProgressForAttempt;
|
|
37
|
+
static calculateRetryDelay = RetryUtils.calculateRetryDelay;
|
|
38
|
+
static delay = RetryUtils.delay;
|
|
39
|
+
static handleGenerationError = RetryUtils.handleGenerationError;
|
|
40
|
+
/**
|
|
41
|
+
* Extract and validate commit message from response
|
|
42
|
+
*/
|
|
43
|
+
static extractAndValidateMessage(content, serviceName) {
|
|
44
|
+
if (!content) {
|
|
45
|
+
throw new Error(`Invalid response format from ${serviceName} API`);
|
|
46
|
+
}
|
|
47
|
+
return this.validateCommitMessage(content);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Universal HTTP error handler for all AI services
|
|
51
|
+
*/
|
|
52
|
+
static handleHttpError(error, serviceName) {
|
|
53
|
+
const axiosError = error;
|
|
54
|
+
if (axiosError.response) {
|
|
55
|
+
const status = axiosError.response.status;
|
|
56
|
+
const data = axiosError.response.data;
|
|
57
|
+
const errorMessage = data.error?.message;
|
|
58
|
+
switch (status) {
|
|
59
|
+
case 401:
|
|
60
|
+
return {
|
|
61
|
+
errorMessage: errorMessages.authenticationError,
|
|
62
|
+
shouldRetry: false,
|
|
63
|
+
};
|
|
64
|
+
case 402:
|
|
65
|
+
return {
|
|
66
|
+
errorMessage: errorMessages.paymentRequired,
|
|
67
|
+
shouldRetry: false,
|
|
68
|
+
};
|
|
69
|
+
case 429:
|
|
70
|
+
return {
|
|
71
|
+
errorMessage: errorMessages.rateLimitExceeded,
|
|
72
|
+
shouldRetry: true,
|
|
73
|
+
};
|
|
74
|
+
case 422:
|
|
75
|
+
return {
|
|
76
|
+
errorMessage: errorMessage || errorMessages.invalidRequest,
|
|
77
|
+
shouldRetry: false,
|
|
78
|
+
};
|
|
79
|
+
case 500:
|
|
80
|
+
return {
|
|
81
|
+
errorMessage: errorMessages.serverError,
|
|
82
|
+
shouldRetry: true,
|
|
83
|
+
};
|
|
84
|
+
default:
|
|
85
|
+
const responseData = JSON.stringify(axiosError.response.data);
|
|
86
|
+
return {
|
|
87
|
+
errorMessage: `${errorMessages.apiError.replace('{0}', String(status))}: ${errorMessage || responseData}`,
|
|
88
|
+
shouldRetry: status >= 500,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Network errors
|
|
93
|
+
if (axiosError.code === 'ECONNREFUSED' ||
|
|
94
|
+
axiosError.code === 'ETIMEDOUT' ||
|
|
95
|
+
axiosError.message?.includes('ECONNREFUSED') ||
|
|
96
|
+
axiosError.message?.includes('ETIMEDOUT')) {
|
|
97
|
+
return {
|
|
98
|
+
errorMessage: `Could not connect to ${serviceName}. Please check your internet connection.`,
|
|
99
|
+
shouldRetry: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
errorMessage: axiosError.message || 'Unknown error',
|
|
104
|
+
shouldRetry: false,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Gemini-specific error handling
|
|
109
|
+
*/
|
|
110
|
+
static handleGeminiError(error) {
|
|
111
|
+
return this.handleHttpError(error, 'Gemini API');
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* OpenAI-specific error handling
|
|
115
|
+
*/
|
|
116
|
+
static handleOpenAIError(error) {
|
|
117
|
+
return this.handleHttpError(error, 'OpenAI API');
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Codestral-specific error handling
|
|
121
|
+
*/
|
|
122
|
+
static handleCodestralError(error) {
|
|
123
|
+
const result = this.handleHttpError(error, 'Codestral API');
|
|
124
|
+
if (error.response?.status === 401) {
|
|
125
|
+
result.errorMessage =
|
|
126
|
+
'Invalid API key. Please check your Codestral API key.';
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Ollama-specific error handling
|
|
132
|
+
*/
|
|
133
|
+
static handleOllamaError(error) {
|
|
134
|
+
const axiosError = error;
|
|
135
|
+
if (axiosError.response?.status === 404) {
|
|
136
|
+
return {
|
|
137
|
+
errorMessage: 'Model not found. Please check if Ollama is running and the model is installed.',
|
|
138
|
+
shouldRetry: false,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const result = this.handleHttpError(error, 'Ollama');
|
|
142
|
+
if (result.shouldRetry && error.response?.status === 500) {
|
|
143
|
+
result.errorMessage =
|
|
144
|
+
'Server error. Please check if Ollama is running properly.';
|
|
145
|
+
}
|
|
146
|
+
if (result.shouldRetry && !error.response) {
|
|
147
|
+
result.errorMessage =
|
|
148
|
+
'Could not connect to Ollama. Please make sure Ollama is running.';
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=baseAIService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseAIService.js","sourceRoot":"","sources":["../../src/services/baseAIService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CommitMessage, ProgressReporter } from "../models/types.js";
|
|
2
|
+
export declare class CodestralService {
|
|
3
|
+
private static readonly apiUrl;
|
|
4
|
+
static generateCommitMessage(prompt: string, progress: ProgressReporter, attempt?: number): Promise<CommitMessage>;
|
|
5
|
+
private static extractCommitMessage;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=codestralService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codestralService.d.ts","sourceRoot":"","sources":["../../src/services/codestralService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAsBrE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CACuB;WAExC,qBAAqB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,MAAU,GAClB,OAAO,CAAC,aAAa,CAAC;IAkDzB,OAAO,CAAC,MAAM,CAAC,oBAAoB;CAIpC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { Logger } from "../utils/logger.js";
|
|
3
|
+
import { ConfigService } from "../utils/config.js";
|
|
4
|
+
import { ApiKeyInvalidError } from "../models/errors.js";
|
|
5
|
+
import { BaseAIService } from "./baseAIService.js";
|
|
6
|
+
import { HttpUtils } from "../utils/httpUtils.js";
|
|
7
|
+
import { RetryUtils } from "../utils/retryUtils.js";
|
|
8
|
+
// AI сервис для работы с Mistral Codestral API
|
|
9
|
+
// Реализует интерфейс IAIService со статическими методами
|
|
10
|
+
export class CodestralService {
|
|
11
|
+
static apiUrl = "https://codestral.mistral.ai/v1/chat/completions";
|
|
12
|
+
static async generateCommitMessage(prompt, progress, attempt = 1) {
|
|
13
|
+
try {
|
|
14
|
+
const apiKey = ConfigService.getApiKey("codestral");
|
|
15
|
+
const model = ConfigService.getCodestralModel();
|
|
16
|
+
const payload = {
|
|
17
|
+
model: model,
|
|
18
|
+
messages: [{ role: "user", content: prompt }],
|
|
19
|
+
};
|
|
20
|
+
void Logger.log(`Attempt ${attempt}: Sending request to Codestral API`);
|
|
21
|
+
await RetryUtils.updateProgressForAttempt(progress, attempt);
|
|
22
|
+
const headers = HttpUtils.createRequestHeaders(apiKey);
|
|
23
|
+
const requestConfig = HttpUtils.createRequestConfig(headers);
|
|
24
|
+
const response = await axios.post(this.apiUrl, payload, requestConfig);
|
|
25
|
+
void Logger.log("Codestral API response received successfully");
|
|
26
|
+
progress.report({
|
|
27
|
+
message: "Processing generated message...",
|
|
28
|
+
increment: 90,
|
|
29
|
+
});
|
|
30
|
+
const commitMessage = this.extractCommitMessage(response.data);
|
|
31
|
+
void Logger.log(`Commit message generated using ${model} model`);
|
|
32
|
+
return { message: commitMessage, model };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// Обработка специальных случаев для Codestral
|
|
36
|
+
const axiosError = error;
|
|
37
|
+
if (axiosError.response?.status === 401) {
|
|
38
|
+
throw new ApiKeyInvalidError("Codestral");
|
|
39
|
+
}
|
|
40
|
+
// Используем retry utils для retry логики
|
|
41
|
+
return RetryUtils.handleGenerationError(error, prompt, progress, attempt, this.generateCommitMessage.bind(this), BaseAIService.handleCodestralError.bind(BaseAIService));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
static extractCommitMessage(response) {
|
|
45
|
+
const content = response.choices?.[0]?.message?.content;
|
|
46
|
+
return BaseAIService.extractAndValidateMessage(content, "Codestral");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=codestralService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codestralService.js","sourceRoot":"","sources":["../../src/services/codestralService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAepD,+CAA+C;AAC/C,0DAA0D;AAC1D,MAAM,OAAO,gBAAgB;IACnB,MAAM,CAAU,MAAM,GAC5B,kDAAkD,CAAC;IAErD,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAChC,MAAc,EACd,QAA0B,EAC1B,UAAkB,CAAC;QAEnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YACpD,MAAM,KAAK,GAAG,aAAa,CAAC,iBAAiB,EAAE,CAAC;YAEhD,MAAM,OAAO,GAAG;gBACd,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC;YAEF,KAAK,MAAM,CAAC,GAAG,CAAC,WAAW,OAAO,oCAAoC,CAAC,CAAC;YACxE,MAAM,UAAU,CAAC,wBAAwB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAE7D,MAAM,OAAO,GAAG,SAAS,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;YACvD,MAAM,aAAa,GAAG,SAAS,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;YAE7D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAC/B,IAAI,CAAC,MAAM,EACX,OAAO,EACP,aAAa,CACd,CAAC;YAEF,KAAK,MAAM,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;YAChE,QAAQ,CAAC,MAAM,CAAC;gBACd,OAAO,EAAE,iCAAiC;gBAC1C,SAAS,EAAE,EAAE;aACd,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/D,KAAK,MAAM,CAAC,GAAG,CAAC,kCAAkC,KAAK,QAAQ,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,8CAA8C;YAC9C,MAAM,UAAU,GAAG,KAAmB,CAAC;YACvC,IAAI,UAAU,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;gBACxC,MAAM,IAAI,kBAAkB,CAAC,WAAW,CAAC,CAAC;YAC5C,CAAC;YAED,0CAA0C;YAC1C,OAAO,UAAU,CAAC,qBAAqB,CACrC,KAAc,EACd,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EACrC,aAAa,CAAC,oBAAoB,CAAC,IAAI,CAAC,aAAa,CAAC,CACvD,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,oBAAoB,CAAC,QAA2B;QAC7D,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC;QACxD,OAAO,aAAa,CAAC,yBAAyB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACvE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini AI service for MCP server
|
|
3
|
+
* Adapted from VSCode extension
|
|
4
|
+
*/
|
|
5
|
+
import { ProgressReporter, CommitMessage } from '../models/types.js';
|
|
6
|
+
export declare class GeminiService {
|
|
7
|
+
/**
|
|
8
|
+
* Get available Gemini models via API
|
|
9
|
+
*/
|
|
10
|
+
private static getAvailableModels;
|
|
11
|
+
/**
|
|
12
|
+
* Try to generate commit message with multiple models
|
|
13
|
+
*/
|
|
14
|
+
private static tryGenerateWithModels;
|
|
15
|
+
static generateCommitMessage(prompt: string, progress: ProgressReporter, attempt?: number): Promise<CommitMessage>;
|
|
16
|
+
private static extractCommitMessage;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=geminiService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geminiService.d.ts","sourceRoot":"","sources":["../../src/services/geminiService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA0BrE,qBAAa,aAAa;IACxB;;OAEG;mBACkB,kBAAkB;IAgCvC;;OAEG;mBACkB,qBAAqB;WAmE7B,qBAAqB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,MAAU,GAClB,OAAO,CAAC,aAAa,CAAC;IA0EzB,OAAO,CAAC,MAAM,CAAC,oBAAoB;CAIpC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini AI service for MCP server
|
|
3
|
+
* Adapted from VSCode extension
|
|
4
|
+
*/
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
import { Logger } from '../utils/logger.js';
|
|
7
|
+
import { ConfigService } from '../utils/config.js';
|
|
8
|
+
import { ApiKeyInvalidError } from '../models/errors.js';
|
|
9
|
+
import { BaseAIService } from './baseAIService.js';
|
|
10
|
+
import { HttpUtils } from '../utils/httpUtils.js';
|
|
11
|
+
import { RetryUtils } from '../utils/retryUtils.js';
|
|
12
|
+
export class GeminiService {
|
|
13
|
+
/**
|
|
14
|
+
* Get available Gemini models via API
|
|
15
|
+
*/
|
|
16
|
+
static async getAvailableModels(apiKey) {
|
|
17
|
+
try {
|
|
18
|
+
const apiUrl = `https://generativelanguage.googleapis.com/v1/models?key=${apiKey}`;
|
|
19
|
+
const requestConfig = HttpUtils.createRequestConfig({});
|
|
20
|
+
const response = await axios.get(apiUrl, requestConfig);
|
|
21
|
+
const models = response.data.models
|
|
22
|
+
.filter((model) => model.supportedGenerationMethods?.includes('generateContent'))
|
|
23
|
+
.map((model) => model.name.replace('models/', ''));
|
|
24
|
+
Logger.log(`Found ${models.length} available Gemini models: ${models.join(', ')}`);
|
|
25
|
+
return models;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
Logger.error('Failed to fetch available Gemini models:', error);
|
|
29
|
+
const fallbackModels = [
|
|
30
|
+
'gemini-2.0-flash',
|
|
31
|
+
'gemini-2.0-flash-exp',
|
|
32
|
+
'gemini-2.5-flash',
|
|
33
|
+
'gemini-2.5-pro',
|
|
34
|
+
];
|
|
35
|
+
return fallbackModels;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Try to generate commit message with multiple models
|
|
40
|
+
*/
|
|
41
|
+
static async tryGenerateWithModels(prompt, progress, models, apiKey) {
|
|
42
|
+
const errors = [];
|
|
43
|
+
for (let i = 0; i < models.length; i++) {
|
|
44
|
+
const model = models[i];
|
|
45
|
+
const modelProgress = Math.floor(((i + 1) / models.length) * 100);
|
|
46
|
+
try {
|
|
47
|
+
progress.report({
|
|
48
|
+
message: `Trying model ${i + 1}/${models.length}: ${model}...`,
|
|
49
|
+
increment: 0,
|
|
50
|
+
});
|
|
51
|
+
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
|
|
52
|
+
const payload = {
|
|
53
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
54
|
+
generationConfig: {
|
|
55
|
+
temperature: 0.7,
|
|
56
|
+
topK: 40,
|
|
57
|
+
topP: 0.95,
|
|
58
|
+
maxOutputTokens: 1024,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
const requestConfig = HttpUtils.createRequestConfig({
|
|
62
|
+
'content-type': 'application/json',
|
|
63
|
+
});
|
|
64
|
+
const response = await axios.post(apiUrl, payload, requestConfig);
|
|
65
|
+
const message = this.extractCommitMessage(response.data);
|
|
66
|
+
Logger.log(`Commit message successfully generated using ${model} model (auto mode)`);
|
|
67
|
+
progress.report({
|
|
68
|
+
message: 'Processing generated message...',
|
|
69
|
+
increment: 100,
|
|
70
|
+
});
|
|
71
|
+
return { message, model };
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
75
|
+
errors.push({ model, error: errorMsg });
|
|
76
|
+
Logger.log(`Model ${model} failed: ${errorMsg}`);
|
|
77
|
+
if (i === models.length - 1) {
|
|
78
|
+
const errorSummary = errors.map((e) => `${e.model}: ${e.error}`).join('; ');
|
|
79
|
+
throw new Error(`All models failed. Errors: ${errorSummary}`);
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
throw new Error('Failed to generate commit message with any available model');
|
|
85
|
+
}
|
|
86
|
+
static async generateCommitMessage(prompt, progress, attempt = 1) {
|
|
87
|
+
try {
|
|
88
|
+
const apiKey = ConfigService.getApiKey('gemini');
|
|
89
|
+
const configuredModel = ConfigService.getGeminiModel();
|
|
90
|
+
// Check for "auto" mode
|
|
91
|
+
if (configuredModel === 'auto') {
|
|
92
|
+
progress.report({
|
|
93
|
+
message: 'Fetching available Gemini models...',
|
|
94
|
+
increment: 0,
|
|
95
|
+
});
|
|
96
|
+
const availableModels = await this.getAvailableModels(apiKey);
|
|
97
|
+
if (availableModels.length === 0) {
|
|
98
|
+
throw new Error('No available Gemini models found');
|
|
99
|
+
}
|
|
100
|
+
return await this.tryGenerateWithModels(prompt, progress, availableModels, apiKey);
|
|
101
|
+
}
|
|
102
|
+
// Standard mode with single model
|
|
103
|
+
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${configuredModel}:generateContent?key=${apiKey}`;
|
|
104
|
+
const payload = {
|
|
105
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
106
|
+
generationConfig: {
|
|
107
|
+
temperature: 0.7,
|
|
108
|
+
topK: 40,
|
|
109
|
+
topP: 0.95,
|
|
110
|
+
maxOutputTokens: 1024,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
await RetryUtils.updateProgressForAttempt(progress, attempt);
|
|
114
|
+
const requestConfig = HttpUtils.createRequestConfig({
|
|
115
|
+
'content-type': 'application/json',
|
|
116
|
+
});
|
|
117
|
+
const response = await axios.post(apiUrl, payload, requestConfig);
|
|
118
|
+
progress.report({
|
|
119
|
+
message: 'Processing generated message...',
|
|
120
|
+
increment: 90,
|
|
121
|
+
});
|
|
122
|
+
const message = this.extractCommitMessage(response.data);
|
|
123
|
+
Logger.log(`Commit message generated using ${configuredModel} model`);
|
|
124
|
+
return { message, model: configuredModel };
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const axiosError = error;
|
|
128
|
+
if (axiosError.response?.status === 401) {
|
|
129
|
+
throw new ApiKeyInvalidError('Gemini');
|
|
130
|
+
}
|
|
131
|
+
return RetryUtils.handleGenerationError(error, prompt, progress, attempt, this.generateCommitMessage.bind(this), BaseAIService.handleGeminiError.bind(BaseAIService));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
static extractCommitMessage(response) {
|
|
135
|
+
const content = response.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
136
|
+
return BaseAIService.extractAndValidateMessage(content, 'Gemini');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=geminiService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geminiService.js","sourceRoot":"","sources":["../../src/services/geminiService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git blame analyzer for MCP server
|
|
3
|
+
* Adapted from VSCode extension
|
|
4
|
+
*/
|
|
5
|
+
export declare class GitBlameAnalyzer {
|
|
6
|
+
private static getGitBlame;
|
|
7
|
+
private static executeGitBlame;
|
|
8
|
+
private static parseBlameOutput;
|
|
9
|
+
private static getDiff;
|
|
10
|
+
static analyzeChanges(repoPath: string, filePath: string): Promise<string>;
|
|
11
|
+
private static parseChangedLines;
|
|
12
|
+
private static analyzeBlameInfo;
|
|
13
|
+
private static formatAnalysis;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=gitBlameAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitBlameAnalyzer.d.ts","sourceRoot":"","sources":["../../src/services/gitBlameAnalyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAsBH,qBAAa,gBAAgB;mBACN,WAAW;mBAqBX,eAAe;IAWpC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAmCV,OAAO;WAWf,cAAc,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC;IAyBlB,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAoBhC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAmB/B,OAAO,CAAC,MAAM,CAAC,cAAc;CAkB9B"}
|