@entro314labs/ai-changelog-generator 3.0.5
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/CHANGELOG.md +801 -0
- package/LICENSE +21 -0
- package/README.md +393 -0
- package/ai-changelog-mcp.sh +93 -0
- package/ai-changelog.sh +103 -0
- package/bin/ai-changelog-dxt.js +35 -0
- package/bin/ai-changelog-mcp.js +34 -0
- package/bin/ai-changelog.js +18 -0
- package/package.json +135 -0
- package/src/ai-changelog-generator.js +258 -0
- package/src/application/orchestrators/changelog.orchestrator.js +730 -0
- package/src/application/services/application.service.js +301 -0
- package/src/cli.js +157 -0
- package/src/domains/ai/ai-analysis.service.js +486 -0
- package/src/domains/analysis/analysis.engine.js +445 -0
- package/src/domains/changelog/changelog.service.js +1761 -0
- package/src/domains/changelog/workspace-changelog.service.js +505 -0
- package/src/domains/git/git-repository.analyzer.js +588 -0
- package/src/domains/git/git.service.js +302 -0
- package/src/infrastructure/cli/cli.controller.js +517 -0
- package/src/infrastructure/config/configuration.manager.js +538 -0
- package/src/infrastructure/interactive/interactive-workflow.service.js +444 -0
- package/src/infrastructure/mcp/mcp-server.service.js +540 -0
- package/src/infrastructure/metrics/metrics.collector.js +362 -0
- package/src/infrastructure/providers/core/base-provider.js +184 -0
- package/src/infrastructure/providers/implementations/anthropic.js +329 -0
- package/src/infrastructure/providers/implementations/azure.js +296 -0
- package/src/infrastructure/providers/implementations/bedrock.js +393 -0
- package/src/infrastructure/providers/implementations/dummy.js +112 -0
- package/src/infrastructure/providers/implementations/google.js +320 -0
- package/src/infrastructure/providers/implementations/huggingface.js +301 -0
- package/src/infrastructure/providers/implementations/lmstudio.js +189 -0
- package/src/infrastructure/providers/implementations/mock.js +275 -0
- package/src/infrastructure/providers/implementations/ollama.js +151 -0
- package/src/infrastructure/providers/implementations/openai.js +273 -0
- package/src/infrastructure/providers/implementations/vertex.js +438 -0
- package/src/infrastructure/providers/provider-management.service.js +415 -0
- package/src/infrastructure/providers/provider-manager.service.js +363 -0
- package/src/infrastructure/providers/utils/base-provider-helpers.js +660 -0
- package/src/infrastructure/providers/utils/model-config.js +610 -0
- package/src/infrastructure/providers/utils/provider-utils.js +286 -0
- package/src/shared/constants/colors.js +370 -0
- package/src/shared/utils/cli-entry-utils.js +525 -0
- package/src/shared/utils/error-classes.js +423 -0
- package/src/shared/utils/json-utils.js +318 -0
- package/src/shared/utils/utils.js +1997 -0
- package/types/index.d.ts +464 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { ProviderError } from '../../shared/utils/utils.js';
|
|
4
|
+
import colors from '../../shared/constants/colors.js';
|
|
5
|
+
|
|
6
|
+
// Import all providers from new location
|
|
7
|
+
import { AnthropicProvider } from './implementations/anthropic.js';
|
|
8
|
+
import AzureOpenAIProvider from './implementations/azure.js';
|
|
9
|
+
import DummyProvider from './implementations/dummy.js';
|
|
10
|
+
import GoogleProvider from './implementations/google.js';
|
|
11
|
+
import HuggingFaceProvider from './implementations/huggingface.js';
|
|
12
|
+
import LMStudioProvider from './implementations/lmstudio.js';
|
|
13
|
+
import MockProvider from './implementations/mock.js';
|
|
14
|
+
import OllamaProvider from './implementations/ollama.js';
|
|
15
|
+
import { OpenAIProvider } from './implementations/openai.js';
|
|
16
|
+
import VertexAIProvider from './implementations/vertex.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* ProviderManager Service
|
|
20
|
+
*
|
|
21
|
+
* Manages AI provider loading, selection, and fallback logic
|
|
22
|
+
*/
|
|
23
|
+
export class ProviderManagerService {
|
|
24
|
+
constructor(config = {}, options = {}) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.providers = [];
|
|
27
|
+
this.activeProvider = null;
|
|
28
|
+
this.options = {
|
|
29
|
+
fallbackToDefault: true,
|
|
30
|
+
defaultProviderName: 'openai',
|
|
31
|
+
...options
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Static provider mapping with new classes
|
|
35
|
+
this.providerClasses = {
|
|
36
|
+
'anthropic': AnthropicProvider,
|
|
37
|
+
'azure': AzureOpenAIProvider,
|
|
38
|
+
'dummy': DummyProvider,
|
|
39
|
+
'google': GoogleProvider,
|
|
40
|
+
'huggingface': HuggingFaceProvider,
|
|
41
|
+
'lmstudio': LMStudioProvider,
|
|
42
|
+
'mock': MockProvider,
|
|
43
|
+
'ollama': OllamaProvider,
|
|
44
|
+
'openai': OpenAIProvider,
|
|
45
|
+
'vertex': VertexAIProvider
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
this.loadProviders();
|
|
49
|
+
this.determineActiveProvider();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Load all provider implementations
|
|
54
|
+
*/
|
|
55
|
+
loadProviders() {
|
|
56
|
+
try {
|
|
57
|
+
for (const [name, ProviderClass] of Object.entries(this.providerClasses)) {
|
|
58
|
+
try {
|
|
59
|
+
const provider = new ProviderClass(this.config);
|
|
60
|
+
this.providers.push({
|
|
61
|
+
name: provider.getName(),
|
|
62
|
+
instance: provider,
|
|
63
|
+
available: provider.isAvailable(),
|
|
64
|
+
capabilities: provider.getCapabilities ? provider.getCapabilities() : {}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Collect provider status for summary instead of individual messages
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(colors.errorMessage(`Failed to load provider ${name}: ${error.message}`));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!process.env.MCP_SERVER_MODE) {
|
|
74
|
+
const available = this.providers.filter(p => p.available).length;
|
|
75
|
+
const isDevelopmentProvider = name => ['dummy', 'mock'].includes(name);
|
|
76
|
+
const productionProviders = this.providers.filter(p => !isDevelopmentProvider(p.name));
|
|
77
|
+
const availableProduction = productionProviders.filter(p => p.available);
|
|
78
|
+
|
|
79
|
+
if (availableProduction.length > 0) {
|
|
80
|
+
console.log(colors.infoMessage(`✅ ${availableProduction.length} provider${availableProduction.length > 1 ? 's' : ''} ready: ${availableProduction.map(p => p.name).join(', ')}`));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error(colors.errorMessage(`Failed to load providers: ${error.message}`));
|
|
85
|
+
this.providers = [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Determine the active provider based on configuration and availability
|
|
91
|
+
*/
|
|
92
|
+
determineActiveProvider() {
|
|
93
|
+
const { AI_PROVIDER: requestedProvider } = this.config;
|
|
94
|
+
|
|
95
|
+
// Handle explicit provider request
|
|
96
|
+
if (requestedProvider && requestedProvider.toLowerCase() !== 'auto') {
|
|
97
|
+
const provider = this.findProviderByName(requestedProvider);
|
|
98
|
+
|
|
99
|
+
if (provider && provider.instance.isAvailable()) {
|
|
100
|
+
this.activeProvider = provider.instance;
|
|
101
|
+
if (!process.env.MCP_SERVER_MODE) {
|
|
102
|
+
console.log(colors.successMessage(`🎯 Using provider: ${provider.instance.getName()}`));
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
} else if (provider) {
|
|
106
|
+
console.log(colors.warningMessage(`Requested provider ${requestedProvider} is not available, auto-selecting...`));
|
|
107
|
+
} else {
|
|
108
|
+
console.log(colors.warningMessage(`Requested provider ${requestedProvider} not found, auto-selecting...`));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Auto-select the first available provider
|
|
113
|
+
const availableProviders = this.providers.filter(p => p.available);
|
|
114
|
+
|
|
115
|
+
if (availableProviders.length === 0) {
|
|
116
|
+
console.log(colors.warningMessage('⚠️ No AI providers configured'));
|
|
117
|
+
console.log(colors.infoMessage('💡 To enable AI-powered analysis:'));
|
|
118
|
+
console.log(colors.infoMessage(' 1. Run: ai-changelog init'));
|
|
119
|
+
console.log(colors.infoMessage(' 2. Or set API keys in .env.local'));
|
|
120
|
+
console.log(colors.infoMessage(' 3. Supported providers: OpenAI, Anthropic, Azure, Google'));
|
|
121
|
+
console.log(colors.dim(' Using pattern-based analysis for now...'));
|
|
122
|
+
this.activeProvider = null;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Priority order for auto-selection
|
|
127
|
+
const priorityOrder = ['openai', 'anthropic', 'azure', 'google', 'vertex', 'huggingface', 'ollama', 'lmstudio'];
|
|
128
|
+
|
|
129
|
+
for (const providerName of priorityOrder) {
|
|
130
|
+
const provider = availableProviders.find(p => p.name === providerName);
|
|
131
|
+
if (provider) {
|
|
132
|
+
this.activeProvider = provider.instance;
|
|
133
|
+
console.log(colors.successMessage(`Auto-selected provider: ${provider.instance.getName()}`));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Fallback to first available
|
|
139
|
+
this.activeProvider = availableProviders[0].instance;
|
|
140
|
+
if (!process.env.MCP_SERVER_MODE) {
|
|
141
|
+
console.log(colors.successMessage(`Using first available provider: ${this.activeProvider.getName()}`));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get the active provider instance
|
|
147
|
+
*/
|
|
148
|
+
getActiveProvider() {
|
|
149
|
+
return this.activeProvider;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get all loaded providers
|
|
154
|
+
*/
|
|
155
|
+
getAllProviders() {
|
|
156
|
+
return this.providers;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Find provider by name
|
|
161
|
+
*/
|
|
162
|
+
findProviderByName(name) {
|
|
163
|
+
return this.providers.find(p => p.name.toLowerCase() === name.toLowerCase());
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Switch to a different provider
|
|
168
|
+
*/
|
|
169
|
+
switchProvider(providerName) {
|
|
170
|
+
const provider = this.findProviderByName(providerName);
|
|
171
|
+
|
|
172
|
+
if (!provider) {
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
error: `Provider '${providerName}' not found`
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!provider.instance.isAvailable()) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
error: `Provider '${providerName}' is not properly configured`
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.activeProvider = provider.instance;
|
|
187
|
+
return {
|
|
188
|
+
success: true,
|
|
189
|
+
provider: providerName
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* List all providers with their status
|
|
195
|
+
*/
|
|
196
|
+
listProviders() {
|
|
197
|
+
return this.providers.map(p => ({
|
|
198
|
+
name: p.name,
|
|
199
|
+
available: p.available,
|
|
200
|
+
active: this.activeProvider?.getName() === p.name,
|
|
201
|
+
capabilities: p.capabilities,
|
|
202
|
+
configuration: p.instance.getConfiguration ? p.instance.getConfiguration() : {}
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Test connection to a specific provider
|
|
208
|
+
*/
|
|
209
|
+
async testProvider(providerName) {
|
|
210
|
+
const provider = this.findProviderByName(providerName);
|
|
211
|
+
|
|
212
|
+
if (!provider) {
|
|
213
|
+
return {
|
|
214
|
+
success: false,
|
|
215
|
+
error: `Provider '${providerName}' not found`
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (!provider.instance.isAvailable()) {
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: `Provider '${providerName}' is not properly configured`
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
return await provider.instance.testConnection();
|
|
228
|
+
} catch (error) {
|
|
229
|
+
return {
|
|
230
|
+
success: false,
|
|
231
|
+
error: error.message
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get provider capabilities
|
|
238
|
+
*/
|
|
239
|
+
getProviderCapabilities(providerName) {
|
|
240
|
+
const provider = this.findProviderByName(providerName);
|
|
241
|
+
|
|
242
|
+
if (!provider) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return provider.instance.getCapabilities ? provider.instance.getCapabilities() : {};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Validate all providers
|
|
251
|
+
*/
|
|
252
|
+
async validateAll() {
|
|
253
|
+
const results = {};
|
|
254
|
+
|
|
255
|
+
for (const provider of this.providers) {
|
|
256
|
+
if (provider.available) {
|
|
257
|
+
try {
|
|
258
|
+
results[provider.name] = await provider.instance.testConnection();
|
|
259
|
+
} catch (error) {
|
|
260
|
+
results[provider.name] = {
|
|
261
|
+
success: false,
|
|
262
|
+
error: error.message
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
results[provider.name] = {
|
|
267
|
+
success: false,
|
|
268
|
+
error: 'Provider not configured'
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return results;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get provider statistics
|
|
278
|
+
*/
|
|
279
|
+
getStats() {
|
|
280
|
+
const total = this.providers.length;
|
|
281
|
+
const available = this.providers.filter(p => p.available).length;
|
|
282
|
+
const configured = available;
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
total,
|
|
286
|
+
available,
|
|
287
|
+
configured,
|
|
288
|
+
active: this.activeProvider?.getName() || null,
|
|
289
|
+
providers: this.providers.map(p => ({
|
|
290
|
+
name: p.name,
|
|
291
|
+
available: p.available,
|
|
292
|
+
active: this.activeProvider?.getName() === p.name
|
|
293
|
+
}))
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Reload providers (useful for configuration changes)
|
|
299
|
+
*/
|
|
300
|
+
reload(newConfig = null) {
|
|
301
|
+
if (newConfig) {
|
|
302
|
+
this.config = { ...this.config, ...newConfig };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
this.providers = [];
|
|
306
|
+
this.activeProvider = null;
|
|
307
|
+
this.loadProviders();
|
|
308
|
+
this.determineActiveProvider();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Check if any provider is available
|
|
313
|
+
*/
|
|
314
|
+
hasAvailableProvider() {
|
|
315
|
+
return this.activeProvider !== null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Get available providers with full details
|
|
320
|
+
*/
|
|
321
|
+
getAvailableProviders() {
|
|
322
|
+
return this.providers
|
|
323
|
+
.filter(p => p.available)
|
|
324
|
+
.map(p => ({
|
|
325
|
+
name: p.name,
|
|
326
|
+
instance: p.instance,
|
|
327
|
+
capabilities: p.capabilities
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Get simple list of available provider names
|
|
333
|
+
*/
|
|
334
|
+
getAvailableProviderNames() {
|
|
335
|
+
return this.providers
|
|
336
|
+
.filter(p => p.available)
|
|
337
|
+
.map(p => p.name);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Get configured provider priority order
|
|
342
|
+
*/
|
|
343
|
+
getProviderPriority() {
|
|
344
|
+
return ['openai', 'anthropic', 'azure', 'google', 'vertex', 'huggingface', 'ollama', 'lmstudio'];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Validate if provider name exists in available providers
|
|
349
|
+
*/
|
|
350
|
+
validateProviderName(name) {
|
|
351
|
+
return Object.keys(this.providerClasses).includes(name.toLowerCase());
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Get the default fallback provider
|
|
356
|
+
*/
|
|
357
|
+
getDefaultProvider() {
|
|
358
|
+
return this.findProviderByName(this.options.defaultProviderName);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Backward compatibility export
|
|
363
|
+
export default ProviderManagerService;
|