@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.
Files changed (47) hide show
  1. package/CHANGELOG.md +801 -0
  2. package/LICENSE +21 -0
  3. package/README.md +393 -0
  4. package/ai-changelog-mcp.sh +93 -0
  5. package/ai-changelog.sh +103 -0
  6. package/bin/ai-changelog-dxt.js +35 -0
  7. package/bin/ai-changelog-mcp.js +34 -0
  8. package/bin/ai-changelog.js +18 -0
  9. package/package.json +135 -0
  10. package/src/ai-changelog-generator.js +258 -0
  11. package/src/application/orchestrators/changelog.orchestrator.js +730 -0
  12. package/src/application/services/application.service.js +301 -0
  13. package/src/cli.js +157 -0
  14. package/src/domains/ai/ai-analysis.service.js +486 -0
  15. package/src/domains/analysis/analysis.engine.js +445 -0
  16. package/src/domains/changelog/changelog.service.js +1761 -0
  17. package/src/domains/changelog/workspace-changelog.service.js +505 -0
  18. package/src/domains/git/git-repository.analyzer.js +588 -0
  19. package/src/domains/git/git.service.js +302 -0
  20. package/src/infrastructure/cli/cli.controller.js +517 -0
  21. package/src/infrastructure/config/configuration.manager.js +538 -0
  22. package/src/infrastructure/interactive/interactive-workflow.service.js +444 -0
  23. package/src/infrastructure/mcp/mcp-server.service.js +540 -0
  24. package/src/infrastructure/metrics/metrics.collector.js +362 -0
  25. package/src/infrastructure/providers/core/base-provider.js +184 -0
  26. package/src/infrastructure/providers/implementations/anthropic.js +329 -0
  27. package/src/infrastructure/providers/implementations/azure.js +296 -0
  28. package/src/infrastructure/providers/implementations/bedrock.js +393 -0
  29. package/src/infrastructure/providers/implementations/dummy.js +112 -0
  30. package/src/infrastructure/providers/implementations/google.js +320 -0
  31. package/src/infrastructure/providers/implementations/huggingface.js +301 -0
  32. package/src/infrastructure/providers/implementations/lmstudio.js +189 -0
  33. package/src/infrastructure/providers/implementations/mock.js +275 -0
  34. package/src/infrastructure/providers/implementations/ollama.js +151 -0
  35. package/src/infrastructure/providers/implementations/openai.js +273 -0
  36. package/src/infrastructure/providers/implementations/vertex.js +438 -0
  37. package/src/infrastructure/providers/provider-management.service.js +415 -0
  38. package/src/infrastructure/providers/provider-manager.service.js +363 -0
  39. package/src/infrastructure/providers/utils/base-provider-helpers.js +660 -0
  40. package/src/infrastructure/providers/utils/model-config.js +610 -0
  41. package/src/infrastructure/providers/utils/provider-utils.js +286 -0
  42. package/src/shared/constants/colors.js +370 -0
  43. package/src/shared/utils/cli-entry-utils.js +525 -0
  44. package/src/shared/utils/error-classes.js +423 -0
  45. package/src/shared/utils/json-utils.js +318 -0
  46. package/src/shared/utils/utils.js +1997 -0
  47. 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;