@entro314labs/ai-changelog-generator 3.1.1 → 3.2.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +383 -877
  2. package/README.md +8 -3
  3. package/ai-changelog-mcp.sh +0 -0
  4. package/ai-changelog.sh +0 -0
  5. package/bin/ai-changelog-dxt.js +9 -9
  6. package/bin/ai-changelog-mcp.js +19 -17
  7. package/bin/ai-changelog.js +6 -6
  8. package/package.json +80 -48
  9. package/src/ai-changelog-generator.js +83 -81
  10. package/src/application/orchestrators/changelog.orchestrator.js +791 -516
  11. package/src/application/services/application.service.js +137 -128
  12. package/src/cli.js +76 -57
  13. package/src/domains/ai/ai-analysis.service.js +289 -209
  14. package/src/domains/analysis/analysis.engine.js +253 -193
  15. package/src/domains/changelog/changelog.service.js +1062 -784
  16. package/src/domains/changelog/workspace-changelog.service.js +420 -249
  17. package/src/domains/git/git-repository.analyzer.js +348 -258
  18. package/src/domains/git/git.service.js +132 -112
  19. package/src/infrastructure/cli/cli.controller.js +390 -274
  20. package/src/infrastructure/config/configuration.manager.js +220 -190
  21. package/src/infrastructure/interactive/interactive-staging.service.js +154 -135
  22. package/src/infrastructure/interactive/interactive-workflow.service.js +200 -159
  23. package/src/infrastructure/mcp/mcp-server.service.js +208 -207
  24. package/src/infrastructure/metrics/metrics.collector.js +140 -123
  25. package/src/infrastructure/providers/core/base-provider.js +87 -40
  26. package/src/infrastructure/providers/implementations/anthropic.js +101 -99
  27. package/src/infrastructure/providers/implementations/azure.js +124 -101
  28. package/src/infrastructure/providers/implementations/bedrock.js +136 -126
  29. package/src/infrastructure/providers/implementations/dummy.js +23 -23
  30. package/src/infrastructure/providers/implementations/google.js +123 -114
  31. package/src/infrastructure/providers/implementations/huggingface.js +94 -87
  32. package/src/infrastructure/providers/implementations/lmstudio.js +75 -60
  33. package/src/infrastructure/providers/implementations/mock.js +69 -73
  34. package/src/infrastructure/providers/implementations/ollama.js +89 -66
  35. package/src/infrastructure/providers/implementations/openai.js +88 -89
  36. package/src/infrastructure/providers/implementations/vertex.js +227 -197
  37. package/src/infrastructure/providers/provider-management.service.js +245 -207
  38. package/src/infrastructure/providers/provider-manager.service.js +145 -125
  39. package/src/infrastructure/providers/utils/base-provider-helpers.js +308 -302
  40. package/src/infrastructure/providers/utils/model-config.js +220 -195
  41. package/src/infrastructure/providers/utils/provider-utils.js +105 -100
  42. package/src/infrastructure/validation/commit-message-validation.service.js +259 -161
  43. package/src/shared/constants/colors.js +453 -180
  44. package/src/shared/utils/cli-demo.js +285 -0
  45. package/src/shared/utils/cli-entry-utils.js +257 -249
  46. package/src/shared/utils/cli-ui.js +447 -0
  47. package/src/shared/utils/diff-processor.js +513 -0
  48. package/src/shared/utils/error-classes.js +125 -156
  49. package/src/shared/utils/json-utils.js +93 -89
  50. package/src/shared/utils/utils.js +1117 -945
  51. package/types/index.d.ts +353 -344
@@ -12,40 +12,40 @@
12
12
  export function selectModelByComplexity(commitDetails, modelConfig) {
13
13
  const {
14
14
  complexModel = 'default-complex',
15
- standardModel = 'default-standard',
15
+ standardModel = 'default-standard',
16
16
  mediumModel = 'default-medium',
17
- smallModel = 'default-small'
18
- } = modelConfig;
17
+ smallModel = 'default-small',
18
+ } = modelConfig
19
19
 
20
20
  // Breaking or complex changes need the most capable model
21
21
  if (commitDetails.breaking || commitDetails.complex || commitDetails.files > 20) {
22
- return {
23
- model: complexModel,
24
- reason: 'Complex or breaking change requiring advanced reasoning'
25
- };
22
+ return {
23
+ model: complexModel,
24
+ reason: 'Complex or breaking change requiring advanced reasoning',
25
+ }
26
26
  }
27
-
27
+
28
28
  // Large commits need standard model
29
29
  if (commitDetails.lines > 1000 || commitDetails.files > 10) {
30
- return {
31
- model: standardModel,
32
- reason: 'Large change requiring standard capabilities'
33
- };
30
+ return {
31
+ model: standardModel,
32
+ reason: 'Large change requiring standard capabilities',
33
+ }
34
34
  }
35
-
35
+
36
36
  // Medium commits
37
37
  if (commitDetails.lines > 200 || commitDetails.files > 5) {
38
- return {
39
- model: mediumModel,
40
- reason: 'Medium-sized change'
41
- };
38
+ return {
39
+ model: mediumModel,
40
+ reason: 'Medium-sized change',
41
+ }
42
42
  }
43
-
43
+
44
44
  // Small commits can use the most efficient model
45
- return {
46
- model: smallModel,
47
- reason: 'Small change, optimized for efficiency'
48
- };
45
+ return {
46
+ model: smallModel,
47
+ reason: 'Small change, optimized for efficiency',
48
+ }
49
49
  }
50
50
 
51
51
  /**
@@ -56,24 +56,22 @@ export function selectModelByComplexity(commitDetails, modelConfig) {
56
56
  */
57
57
  export async function standardConnectionTest(generateCompletion, defaultModel) {
58
58
  try {
59
- const response = await generateCompletion([
60
- { role: 'user', content: 'Test connection' }
61
- ], {
62
- max_tokens: 5,
59
+ const response = await generateCompletion([{ role: 'user', content: 'Test connection' }], {
60
+ max_tokens: 5,
63
61
  model: defaultModel,
64
- temperature: 0.1
65
- });
66
-
67
- return {
68
- success: true,
69
- response: response.content || response.text || 'Connection successful',
70
- model: response.model || defaultModel
71
- };
62
+ temperature: 0.1,
63
+ })
64
+
65
+ return {
66
+ success: true,
67
+ response: response.content || response.text || 'Connection successful',
68
+ model: response.model || defaultModel,
69
+ }
72
70
  } catch (error) {
73
- return {
74
- success: false,
75
- error: error.message
76
- };
71
+ return {
72
+ success: false,
73
+ error: error.message,
74
+ }
77
75
  }
78
76
  }
79
77
 
@@ -92,8 +90,8 @@ export function createProviderErrorResponse(providerName, operation, reason, alt
92
90
  operation,
93
91
  error: reason,
94
92
  alternatives: alternatives.length > 0 ? alternatives : [`Check ${providerName} configuration`],
95
- timestamp: new Date().toISOString()
96
- };
93
+ timestamp: new Date().toISOString(),
94
+ }
97
95
  }
98
96
 
99
97
  /**
@@ -107,8 +105,8 @@ export function createProviderSuccessResponse(providerName, data = {}) {
107
105
  available: true,
108
106
  provider: providerName,
109
107
  ...data,
110
- timestamp: new Date().toISOString()
111
- };
108
+ timestamp: new Date().toISOString(),
109
+ }
112
110
  }
113
111
 
114
112
  /**
@@ -126,14 +124,14 @@ export function buildCapabilities(baseCapabilities = {}, modelSpecificCapabiliti
126
124
  large_context: false,
127
125
  streaming: false,
128
126
  temperature_control: true,
129
- max_tokens_control: true
130
- };
127
+ max_tokens_control: true,
128
+ }
131
129
 
132
130
  return {
133
131
  ...defaultCapabilities,
134
132
  ...baseCapabilities,
135
- ...modelSpecificCapabilities
136
- };
133
+ ...modelSpecificCapabilities,
134
+ }
137
135
  }
138
136
 
139
137
  /**
@@ -144,28 +142,28 @@ export function buildCapabilities(baseCapabilities = {}, modelSpecificCapabiliti
144
142
  * @returns {Object} Provider-specific configuration
145
143
  */
146
144
  export function extractProviderConfig(config, providerPrefix, defaults = {}) {
147
- const providerConfig = {};
148
-
145
+ const providerConfig = {}
146
+
149
147
  // Extract all config keys that start with the provider prefix
150
- Object.keys(config).forEach(key => {
151
- if (key.startsWith(providerPrefix + '_') || key === providerPrefix) {
152
- providerConfig[key] = config[key];
148
+ Object.keys(config).forEach((key) => {
149
+ if (key.startsWith(`${providerPrefix}_`) || key === providerPrefix) {
150
+ providerConfig[key] = config[key]
153
151
  }
154
- });
155
-
152
+ })
153
+
156
154
  // Add fallback AI_MODEL configs
157
- if (config.AI_MODEL && !providerConfig[providerPrefix + '_MODEL']) {
158
- providerConfig[providerPrefix + '_MODEL'] = config.AI_MODEL;
155
+ if (config.AI_MODEL && !providerConfig[`${providerPrefix}_MODEL`]) {
156
+ providerConfig[`${providerPrefix}_MODEL`] = config.AI_MODEL
159
157
  }
160
-
158
+
161
159
  // Apply defaults for missing values
162
- Object.keys(defaults).forEach(key => {
160
+ Object.keys(defaults).forEach((key) => {
163
161
  if (providerConfig[key] === undefined) {
164
- providerConfig[key] = defaults[key];
162
+ providerConfig[key] = defaults[key]
165
163
  }
166
- });
167
-
168
- return providerConfig;
164
+ })
165
+
166
+ return providerConfig
169
167
  }
170
168
 
171
169
  /**
@@ -175,12 +173,14 @@ export function extractProviderConfig(config, providerPrefix, defaults = {}) {
175
173
  * @returns {number} Parsed numeric value
176
174
  */
177
175
  export function parseNumericConfig(value, defaultValue) {
178
- if (typeof value === 'number') return value;
176
+ if (typeof value === 'number') {
177
+ return value
178
+ }
179
179
  if (typeof value === 'string') {
180
- const parsed = parseInt(value, 10);
181
- return isNaN(parsed) ? defaultValue : parsed;
180
+ const parsed = Number.parseInt(value, 10)
181
+ return Number.isNaN(parsed) ? defaultValue : parsed
182
182
  }
183
- return defaultValue;
183
+ return defaultValue
184
184
  }
185
185
 
186
186
  /**
@@ -192,17 +192,21 @@ export function parseNumericConfig(value, defaultValue) {
192
192
  */
193
193
  export async function validateModelWithFallbacks(testModelFn, modelName, fallbackModels = []) {
194
194
  try {
195
- const result = await testModelFn(modelName);
195
+ const result = await testModelFn(modelName)
196
196
  if (result.success || result.available) {
197
197
  return createProviderSuccessResponse('validation', {
198
198
  model: modelName,
199
- capabilities: result.capabilities || {}
200
- });
201
- } else {
202
- return createProviderErrorResponse('validation', 'model_test', result.error || 'Model not available', fallbackModels);
199
+ capabilities: result.capabilities || {},
200
+ })
203
201
  }
202
+ return createProviderErrorResponse(
203
+ 'validation',
204
+ 'model_test',
205
+ result.error || 'Model not available',
206
+ fallbackModels
207
+ )
204
208
  } catch (error) {
205
- return createProviderErrorResponse('validation', 'model_test', error.message, fallbackModels);
209
+ return createProviderErrorResponse('validation', 'model_test', error.message, fallbackModels)
206
210
  }
207
211
  }
208
212
 
@@ -214,27 +218,27 @@ export async function validateModelWithFallbacks(testModelFn, modelName, fallbac
214
218
  */
215
219
  export function formatMessagesForProvider(messages, format) {
216
220
  switch (format) {
217
- case 'anthropic':
218
- const systemMessage = messages.find(m => m.role === 'system');
219
- const userMessages = messages.filter(m => m.role !== 'system');
221
+ case 'anthropic': {
222
+ const systemMessage = messages.find((m) => m.role === 'system')
223
+ const userMessages = messages.filter((m) => m.role !== 'system')
220
224
  return {
221
225
  system: systemMessage ? systemMessage.content : undefined,
222
- messages: userMessages
223
- };
224
-
225
- case 'google':
226
- const systemInstruction = messages.find(m => m.role === 'system')?.content;
226
+ messages: userMessages,
227
+ }
228
+ }
229
+
230
+ case 'google': {
231
+ const systemInstruction = messages.find((m) => m.role === 'system')?.content
227
232
  const history = messages
228
- .filter(m => m.role !== 'system')
229
- .map(m => ({
233
+ .filter((m) => m.role !== 'system')
234
+ .map((m) => ({
230
235
  role: m.role === 'assistant' ? 'model' : 'user',
231
- parts: [{ text: m.content }]
232
- }));
233
- return { systemInstruction, history };
234
-
235
- case 'openai':
236
+ parts: [{ text: m.content }],
237
+ }))
238
+ return { systemInstruction, history }
239
+ }
236
240
  default:
237
- return { messages };
241
+ return { messages }
238
242
  }
239
243
  }
240
244
 
@@ -245,24 +249,24 @@ export function formatMessagesForProvider(messages, format) {
245
249
  * @returns {Object} Client initialization options
246
250
  */
247
251
  export function buildClientOptions(config, defaults = {}) {
248
- const options = { ...defaults };
249
-
252
+ const options = { ...defaults }
253
+
250
254
  // Common timeout handling
251
255
  if (config.timeout || config.TIMEOUT) {
252
- options.timeout = parseNumericConfig(config.timeout || config.TIMEOUT, 60000);
256
+ options.timeout = parseNumericConfig(config.timeout || config.TIMEOUT, 60000)
253
257
  }
254
-
258
+
255
259
  // Common retry handling
256
260
  if (config.maxRetries || config.MAX_RETRIES) {
257
- options.maxRetries = parseNumericConfig(config.maxRetries || config.MAX_RETRIES, 2);
261
+ options.maxRetries = parseNumericConfig(config.maxRetries || config.MAX_RETRIES, 2)
258
262
  }
259
-
263
+
260
264
  // Common base URL handling
261
265
  if (config.baseURL || config.BASE_URL || config.API_URL) {
262
- options.baseURL = config.baseURL || config.BASE_URL || config.API_URL;
266
+ options.baseURL = config.baseURL || config.BASE_URL || config.API_URL
263
267
  }
264
-
265
- return options;
268
+
269
+ return options
266
270
  }
267
271
 
268
272
  /**
@@ -277,10 +281,11 @@ export function buildRequestParams(messages, options, defaults = {}) {
277
281
  messages,
278
282
  model: options.model || defaults.model,
279
283
  max_tokens: options.max_tokens || defaults.max_tokens || 1000,
280
- temperature: options.temperature !== undefined ? options.temperature : (defaults.temperature || 0.3),
284
+ temperature:
285
+ options.temperature !== undefined ? options.temperature : defaults.temperature || 0.3,
281
286
  stream: !!options.stream,
282
287
  ...(options.tools && { tools: options.tools }),
283
288
  ...(options.tool_choice && { tool_choice: options.tool_choice }),
284
- ...defaults.extraParams
285
- };
286
- }
289
+ ...defaults.extraParams,
290
+ }
291
+ }