@entro314labs/ai-changelog-generator 3.0.5 → 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.
- package/CHANGELOG.md +383 -785
- package/README.md +30 -3
- package/ai-changelog-mcp.sh +0 -0
- package/ai-changelog.sh +0 -0
- package/bin/ai-changelog-dxt.js +9 -9
- package/bin/ai-changelog-mcp.js +19 -17
- package/bin/ai-changelog.js +6 -6
- package/package.json +84 -52
- package/src/ai-changelog-generator.js +83 -81
- package/src/application/orchestrators/changelog.orchestrator.js +1040 -296
- package/src/application/services/application.service.js +145 -123
- package/src/cli.js +76 -57
- package/src/domains/ai/ai-analysis.service.js +289 -209
- package/src/domains/analysis/analysis.engine.js +253 -193
- package/src/domains/changelog/changelog.service.js +1062 -784
- package/src/domains/changelog/workspace-changelog.service.js +420 -249
- package/src/domains/git/git-repository.analyzer.js +348 -258
- package/src/domains/git/git.service.js +132 -112
- package/src/infrastructure/cli/cli.controller.js +415 -247
- package/src/infrastructure/config/configuration.manager.js +220 -190
- package/src/infrastructure/interactive/interactive-staging.service.js +332 -0
- package/src/infrastructure/interactive/interactive-workflow.service.js +200 -159
- package/src/infrastructure/mcp/mcp-server.service.js +208 -207
- package/src/infrastructure/metrics/metrics.collector.js +140 -123
- package/src/infrastructure/providers/core/base-provider.js +87 -40
- package/src/infrastructure/providers/implementations/anthropic.js +101 -99
- package/src/infrastructure/providers/implementations/azure.js +124 -101
- package/src/infrastructure/providers/implementations/bedrock.js +136 -126
- package/src/infrastructure/providers/implementations/dummy.js +23 -23
- package/src/infrastructure/providers/implementations/google.js +123 -114
- package/src/infrastructure/providers/implementations/huggingface.js +94 -87
- package/src/infrastructure/providers/implementations/lmstudio.js +75 -60
- package/src/infrastructure/providers/implementations/mock.js +69 -73
- package/src/infrastructure/providers/implementations/ollama.js +89 -66
- package/src/infrastructure/providers/implementations/openai.js +88 -89
- package/src/infrastructure/providers/implementations/vertex.js +227 -197
- package/src/infrastructure/providers/provider-management.service.js +245 -207
- package/src/infrastructure/providers/provider-manager.service.js +145 -125
- package/src/infrastructure/providers/utils/base-provider-helpers.js +308 -302
- package/src/infrastructure/providers/utils/model-config.js +220 -195
- package/src/infrastructure/providers/utils/provider-utils.js +105 -100
- package/src/infrastructure/validation/commit-message-validation.service.js +556 -0
- package/src/shared/constants/colors.js +467 -172
- package/src/shared/utils/cli-demo.js +285 -0
- package/src/shared/utils/cli-entry-utils.js +257 -249
- package/src/shared/utils/cli-ui.js +447 -0
- package/src/shared/utils/diff-processor.js +513 -0
- package/src/shared/utils/error-classes.js +125 -156
- package/src/shared/utils/json-utils.js +93 -89
- package/src/shared/utils/utils.js +1299 -775
- 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
|
-
|
|
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
|
|
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
|
|
158
|
-
providerConfig[providerPrefix
|
|
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')
|
|
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
|
-
|
|
226
|
-
|
|
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:
|
|
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
|
+
}
|