@entro314labs/ai-changelog-generator 3.1.1 → 3.2.1

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 +412 -875
  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 +91 -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 +328 -192
  15. package/src/domains/changelog/changelog.service.js +1174 -783
  16. package/src/domains/changelog/workspace-changelog.service.js +487 -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
@@ -1,9 +1,10 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import yaml from 'js-yaml';
4
- import colors from '../../shared/constants/colors.js';
5
- import { ConfigError } from '../../shared/utils/error-classes.js';
6
- import JsonUtils from '../../shared/utils/json-utils.js';
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import process from 'node:process'
4
+
5
+ import yaml from 'js-yaml'
6
+
7
+ import colors from '../../shared/constants/colors.js'
7
8
 
8
9
  // Model configurations - moved from lib/utils/model-config.js
9
10
  const MODEL_CONFIGS = {
@@ -11,14 +12,14 @@ const MODEL_CONFIGS = {
11
12
  'gpt-3.5-turbo': { maxTokens: 4096, cost: 0.002 },
12
13
  'claude-3-opus': { maxTokens: 200000, cost: 0.015 },
13
14
  'claude-3-sonnet': { maxTokens: 200000, cost: 0.003 },
14
- 'claude-3-haiku': { maxTokens: 200000, cost: 0.00025 }
15
- };
15
+ 'claude-3-haiku': { maxTokens: 200000, cost: 0.00025 },
16
+ }
16
17
 
17
18
  /**
18
19
  * Unified Configuration Manager
19
20
  * Consolidates config.js, model-config.js, and interactive-config.js logic
20
21
  * Enhanced with YAML changelog configuration support
21
- *
22
+ *
22
23
  * Responsibilities:
23
24
  * - Environment configuration loading
24
25
  * - Model configuration management
@@ -28,12 +29,12 @@ const MODEL_CONFIGS = {
28
29
  */
29
30
  export class ConfigurationManager {
30
31
  constructor(configPath = null, changelogConfigPath = null) {
31
- this.configPath = configPath || this.findConfigFile();
32
- this.changelogConfigPath = changelogConfigPath || this.findChangelogConfigFile();
33
- this.config = this.loadConfig();
34
- this.changelogConfig = this.loadChangelogConfig();
35
- this.modelConfigs = MODEL_CONFIGS;
36
- this.validate();
32
+ this.configPath = configPath || this.findConfigFile()
33
+ this.changelogConfigPath = changelogConfigPath || this.findChangelogConfigFile()
34
+ this.config = this.loadConfig()
35
+ this.changelogConfig = this.loadChangelogConfig()
36
+ this.modelConfigs = MODEL_CONFIGS
37
+ this.validate()
37
38
  }
38
39
 
39
40
  findConfigFile() {
@@ -41,16 +42,16 @@ export class ConfigurationManager {
41
42
  '.env.local',
42
43
  '.changelog.config.js',
43
44
  'changelog.config.json',
44
- path.join(process.cwd(), '.env.local')
45
- ];
45
+ path.join(process.cwd(), '.env.local'),
46
+ ]
46
47
 
47
48
  for (const configPath of possiblePaths) {
48
49
  if (fs.existsSync(configPath)) {
49
- return configPath;
50
+ return configPath
50
51
  }
51
52
  }
52
53
 
53
- return '.env.local'; // Default
54
+ return '.env.local' // Default
54
55
  }
55
56
 
56
57
  findChangelogConfigFile() {
@@ -60,16 +61,16 @@ export class ConfigurationManager {
60
61
  '.ai-changelog.yaml',
61
62
  '.ai-changelog.yml',
62
63
  'changelog.config.yaml',
63
- 'changelog.config.yml'
64
- ];
64
+ 'changelog.config.yml',
65
+ ]
65
66
 
66
67
  for (const configPath of possiblePaths) {
67
68
  if (fs.existsSync(configPath)) {
68
- return configPath;
69
+ return configPath
69
70
  }
70
71
  }
71
72
 
72
- return null; // No changelog config found
73
+ return null // No changelog config found
73
74
  }
74
75
 
75
76
  loadConfig() {
@@ -100,30 +101,32 @@ export class ConfigurationManager {
100
101
  // General Settings
101
102
  GIT_PATH: process.env.GIT_PATH || process.cwd(),
102
103
  DEFAULT_ANALYSIS_MODE: process.env.DEFAULT_ANALYSIS_MODE || 'standard',
103
- RATE_LIMIT_DELAY: parseInt(process.env.RATE_LIMIT_DELAY || '1000'),
104
- MAX_RETRIES: parseInt(process.env.MAX_RETRIES || '3'),
104
+ RATE_LIMIT_DELAY: Number.parseInt(process.env.RATE_LIMIT_DELAY || '1000', 10),
105
+ MAX_RETRIES: Number.parseInt(process.env.MAX_RETRIES || '3', 10),
105
106
 
106
107
  // Output Settings
107
108
  OUTPUT_FORMAT: process.env.OUTPUT_FORMAT || 'markdown',
108
109
  INCLUDE_ATTRIBUTION: process.env.INCLUDE_ATTRIBUTION !== 'false',
109
-
110
+
110
111
  // Debug Settings
111
112
  DEBUG: process.env.DEBUG === 'true',
112
- VERBOSE: process.env.VERBOSE === 'true'
113
- };
113
+ VERBOSE: process.env.VERBOSE === 'true',
114
+ }
114
115
 
115
116
  // Load from .env.local if it exists
116
117
  if (fs.existsSync(this.configPath)) {
117
118
  try {
118
- const content = fs.readFileSync(this.configPath, 'utf8');
119
- const envVars = this.parseEnvFile(content);
120
- Object.assign(defaults, envVars);
121
- } catch (error) {
122
- console.warn(colors.warningMessage(`Warning: Could not load config from ${this.configPath}`));
119
+ const content = fs.readFileSync(this.configPath, 'utf8')
120
+ const envVars = this.parseEnvFile(content)
121
+ Object.assign(defaults, envVars)
122
+ } catch (_error) {
123
+ console.warn(
124
+ colors.warningMessage(`Warning: Could not load config from ${this.configPath}`)
125
+ )
123
126
  }
124
127
  }
125
128
 
126
- return defaults;
129
+ return defaults
127
130
  }
128
131
 
129
132
  loadChangelogConfig() {
@@ -131,21 +134,21 @@ export class ConfigurationManager {
131
134
  const defaultConfig = {
132
135
  convention: {
133
136
  commitTypes: [
134
- 'feat', // Features
135
- 'fix', // Bug fixes
136
- 'docs', // Documentation
137
- 'style', // Code style (formatting, missing semicolons, etc)
137
+ 'feat', // Features
138
+ 'fix', // Bug fixes
139
+ 'docs', // Documentation
140
+ 'style', // Code style (formatting, missing semicolons, etc)
138
141
  'refactor', // Code refactoring
139
- 'perf', // Performance improvements
140
- 'test', // Tests
141
- 'build', // Build system or external dependencies
142
- 'ci', // CI/CD changes
143
- 'chore', // Maintenance tasks
144
- 'revert', // Reverting commits
145
- 'merge' // Merge commits
142
+ 'perf', // Performance improvements
143
+ 'test', // Tests
144
+ 'build', // Build system or external dependencies
145
+ 'ci', // CI/CD changes
146
+ 'chore', // Maintenance tasks
147
+ 'revert', // Reverting commits
148
+ 'merge', // Merge commits
146
149
  ],
147
150
  commitScopes: [],
148
- releaseTagGlobPattern: 'v[0-9]*.[0-9]*.[0-9]*'
151
+ releaseTagGlobPattern: 'v[0-9]*.[0-9]*.[0-9]*',
149
152
  },
150
153
  changelog: {
151
154
  commitTypes: ['feat', 'fix', 'perf', 'refactor', 'docs'],
@@ -164,212 +167,237 @@ export class ConfigurationManager {
164
167
  style: '💄 Code Style',
165
168
  revert: '⏪ Reverts',
166
169
  merge: '🔀 Merges',
167
- breakingChange: '🚨 BREAKING CHANGES'
170
+ breakingChange: '🚨 BREAKING CHANGES',
168
171
  },
169
172
  // Link generation support
170
173
  commitUrl: null,
171
174
  commitRangeUrl: null,
172
175
  issueUrl: null,
173
- issueRegexPattern: '#[0-9]+'
174
- }
175
- };
176
+ issueRegexPattern: '#[0-9]+',
177
+ },
178
+ }
176
179
 
177
180
  if (!this.changelogConfigPath) {
178
- return defaultConfig;
181
+ return defaultConfig
179
182
  }
180
183
 
181
184
  try {
182
- const content = fs.readFileSync(this.changelogConfigPath, 'utf8');
183
- const yamlConfig = yaml.load(content);
184
-
185
+ const content = fs.readFileSync(this.changelogConfigPath, 'utf8')
186
+ const yamlConfig = yaml.load(content)
187
+
185
188
  // Deep merge with defaults
186
- return this.deepMergeConfig(defaultConfig, yamlConfig);
187
- } catch (error) {
188
- console.warn(colors.warningMessage(`Warning: Could not load changelog config from ${this.changelogConfigPath}, using defaults`));
189
- return defaultConfig;
189
+ return this.deepMergeConfig(defaultConfig, yamlConfig)
190
+ } catch (_error) {
191
+ console.warn(
192
+ colors.warningMessage(
193
+ `Warning: Could not load changelog config from ${this.changelogConfigPath}, using defaults`
194
+ )
195
+ )
196
+ return defaultConfig
190
197
  }
191
198
  }
192
199
 
193
200
  deepMergeConfig(defaults, override) {
194
- const result = JSON.parse(JSON.stringify(defaults));
195
-
201
+ const result = JSON.parse(JSON.stringify(defaults))
202
+
196
203
  if (!override || typeof override !== 'object') {
197
- return result;
204
+ return result
198
205
  }
199
206
 
200
207
  for (const key in override) {
201
208
  if (override[key] && typeof override[key] === 'object' && !Array.isArray(override[key])) {
202
- result[key] = this.deepMergeConfig(result[key] || {}, override[key]);
209
+ result[key] = this.deepMergeConfig(result[key] || {}, override[key])
203
210
  } else {
204
- result[key] = override[key];
211
+ result[key] = override[key]
205
212
  }
206
213
  }
207
214
 
208
- return result;
215
+ return result
209
216
  }
210
217
 
211
218
  parseEnvFile(content) {
212
- const envVars = {};
213
- const lines = content.split('\n');
214
-
219
+ const envVars = {}
220
+ const lines = content.split('\n')
221
+
215
222
  for (const line of lines) {
216
- const trimmed = line.trim();
223
+ const trimmed = line.trim()
217
224
  if (trimmed && !trimmed.startsWith('#')) {
218
- const [key, ...valueParts] = trimmed.split('=');
225
+ const [key, ...valueParts] = trimmed.split('=')
219
226
  if (key && valueParts.length > 0) {
220
- const value = valueParts.join('=').replace(/^["']|["']$/g, '');
221
- envVars[key.trim()] = value;
227
+ const value = valueParts.join('=').replace(/^["']|["']$/g, '')
228
+ envVars[key.trim()] = value
222
229
  }
223
230
  }
224
231
  }
225
-
226
- return envVars;
232
+
233
+ return envVars
227
234
  }
228
235
 
229
236
  validate() {
230
- const issues = [];
231
- const recommendations = [];
237
+ const issues = []
238
+ const recommendations = []
232
239
 
233
240
  // Check for AI provider configuration
234
- const hasAnyProvider = this.hasOpenAI() || this.hasAnthropic() ||
235
- this.hasGoogle() || this.hasHuggingFace() ||
236
- this.hasOllama() || this.hasAzureOpenAI() ||
237
- this.hasVertexAI() || this.hasLMStudio();
241
+ const hasAnyProvider =
242
+ this.hasOpenAI() ||
243
+ this.hasAnthropic() ||
244
+ this.hasGoogle() ||
245
+ this.hasHuggingFace() ||
246
+ this.hasOllama() ||
247
+ this.hasAzureOpenAI() ||
248
+ this.hasVertexAI() ||
249
+ this.hasLMStudio()
238
250
 
239
251
  if (!hasAnyProvider) {
240
- issues.push('No AI provider configured');
241
- recommendations.push('Configure at least one AI provider (OpenAI, Anthropic, Google, etc.)');
252
+ issues.push('No AI provider configured')
253
+ recommendations.push('Configure at least one AI provider (OpenAI, Anthropic, Google, etc.)')
242
254
  }
243
255
 
244
256
  // Git path validation
245
257
  if (!fs.existsSync(this.config.GIT_PATH)) {
246
- issues.push('Git path does not exist');
247
- recommendations.push('Set GIT_PATH to a valid git repository');
258
+ issues.push('Git path does not exist')
259
+ recommendations.push('Set GIT_PATH to a valid git repository')
248
260
  }
249
261
 
250
262
  // Provider-specific validations
251
263
  if (this.config.AI_PROVIDER === 'azure' && !this.hasAzureOpenAI()) {
252
- issues.push('Azure OpenAI selected but not properly configured');
253
- recommendations.push('Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_KEY');
264
+ issues.push('Azure OpenAI selected but not properly configured')
265
+ recommendations.push('Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_KEY')
254
266
  }
255
267
 
256
268
  if (this.config.AI_PROVIDER === 'vertex' && !this.hasVertexAI()) {
257
- issues.push('Vertex AI selected but not properly configured');
258
- recommendations.push('Set VERTEX_PROJECT_ID and GOOGLE_APPLICATION_CREDENTIALS');
269
+ issues.push('Vertex AI selected but not properly configured')
270
+ recommendations.push('Set VERTEX_PROJECT_ID and GOOGLE_APPLICATION_CREDENTIALS')
259
271
  }
260
272
 
261
- this.validationResult = { issues, recommendations };
273
+ this.validationResult = { issues, recommendations }
262
274
  }
263
275
 
264
276
  // Provider availability checks
265
277
  hasOpenAI() {
266
- return !!this.config.OPENAI_API_KEY;
278
+ return !!this.config.OPENAI_API_KEY
267
279
  }
268
280
 
269
281
  hasAnthropic() {
270
- return !!this.config.ANTHROPIC_API_KEY;
282
+ return !!this.config.ANTHROPIC_API_KEY
271
283
  }
272
284
 
273
285
  hasGoogle() {
274
- return !!this.config.GOOGLE_API_KEY;
286
+ return !!this.config.GOOGLE_API_KEY
275
287
  }
276
288
 
277
289
  hasHuggingFace() {
278
- return !!this.config.HUGGINGFACE_API_KEY;
290
+ return !!this.config.HUGGINGFACE_API_KEY
279
291
  }
280
292
 
281
293
  hasOllama() {
282
- return !!this.config.OLLAMA_HOST;
294
+ return !!this.config.OLLAMA_HOST
283
295
  }
284
296
 
285
297
  hasAzureOpenAI() {
286
- return !!(this.config.AZURE_OPENAI_ENDPOINT && this.config.AZURE_OPENAI_KEY);
298
+ return !!(this.config.AZURE_OPENAI_ENDPOINT && this.config.AZURE_OPENAI_KEY)
287
299
  }
288
300
 
289
301
  hasVertexAI() {
290
- return !!(this.config.VERTEX_PROJECT_ID && this.config.GOOGLE_APPLICATION_CREDENTIALS);
302
+ return !!(this.config.VERTEX_PROJECT_ID && this.config.GOOGLE_APPLICATION_CREDENTIALS)
291
303
  }
292
304
 
293
305
  hasLMStudio() {
294
- return !!this.config.LMSTUDIO_BASE_URL;
306
+ return !!this.config.LMSTUDIO_BASE_URL
295
307
  }
296
308
 
297
309
  // Model configuration methods
298
- getOptimalModelConfig(analysisMode = 'standard', complexity = 'medium') {
310
+ getOptimalModelConfig(analysisMode = 'standard', _complexity = 'medium') {
299
311
  const modes = {
300
312
  simple: 'simple',
301
- standard: 'standard',
313
+ standard: 'standard',
302
314
  detailed: 'complex',
303
- enterprise: 'complex'
304
- };
315
+ enterprise: 'complex',
316
+ }
317
+
318
+ const modelType = modes[analysisMode] || 'standard'
305
319
 
306
- const modelType = modes[analysisMode] || 'standard';
307
-
308
320
  // Return configuration for the active provider
309
- const provider = this.getActiveProvider();
310
- const providerConfig = this.modelConfigs[provider];
311
-
321
+ const provider = this.getActiveProvider()
322
+ const providerConfig = this.modelConfigs[provider]
323
+
312
324
  if (!providerConfig) {
313
- return { model: 'auto', capabilities: {} };
325
+ return { model: 'auto', capabilities: {} }
314
326
  }
315
327
 
316
- const modelKey = `${modelType}Model`;
317
- const model = providerConfig[modelKey] || providerConfig.standardModel;
318
-
328
+ const modelKey = `${modelType}Model`
329
+ const model = providerConfig[modelKey] || providerConfig.standardModel
330
+
319
331
  return {
320
332
  model,
321
333
  capabilities: providerConfig.capabilities || {},
322
334
  contextWindow: providerConfig.contextWindow || 8192,
323
- maxTokens: providerConfig.maxTokens || 4096
324
- };
335
+ maxTokens: providerConfig.maxTokens || 4096,
336
+ }
325
337
  }
326
338
 
327
339
  getModelRecommendation(commitInfo) {
328
- const { files = 0, lines = 0, breaking = false, complex = false } = commitInfo;
329
-
340
+ const { files = 0, lines = 0, breaking = false, complex = false } = commitInfo
341
+
330
342
  // Determine complexity
331
- let analysisMode = 'standard';
332
-
343
+ let analysisMode = 'standard'
344
+
333
345
  if (breaking || complex || files > 20 || lines > 500) {
334
- analysisMode = 'detailed';
346
+ analysisMode = 'detailed'
335
347
  } else if (files > 5 || lines > 100) {
336
- analysisMode = 'standard';
348
+ analysisMode = 'standard'
337
349
  } else {
338
- analysisMode = 'simple';
350
+ analysisMode = 'simple'
339
351
  }
340
-
341
- return this.getOptimalModelConfig(analysisMode);
352
+
353
+ return this.getOptimalModelConfig(analysisMode)
342
354
  }
343
355
 
344
356
  getActiveProvider() {
345
357
  if (this.config.AI_PROVIDER !== 'auto') {
346
- return this.config.AI_PROVIDER;
358
+ return this.config.AI_PROVIDER
347
359
  }
348
360
 
349
361
  // Auto-detect available provider
350
- if (this.hasOpenAI()) return 'openai';
351
- if (this.hasAnthropic()) return 'anthropic';
352
- if (this.hasGoogle()) return 'google';
353
- if (this.hasAzureOpenAI()) return 'azure';
354
- if (this.hasVertexAI()) return 'vertex';
355
- if (this.hasOllama()) return 'ollama';
356
- if (this.hasHuggingFace()) return 'huggingface';
357
- if (this.hasLMStudio()) return 'lmstudio';
358
-
359
- return 'none';
362
+ if (this.hasOpenAI()) {
363
+ return 'openai'
364
+ }
365
+ if (this.hasAnthropic()) {
366
+ return 'anthropic'
367
+ }
368
+ if (this.hasGoogle()) {
369
+ return 'google'
370
+ }
371
+ if (this.hasAzureOpenAI()) {
372
+ return 'azure'
373
+ }
374
+ if (this.hasVertexAI()) {
375
+ return 'vertex'
376
+ }
377
+ if (this.hasOllama()) {
378
+ return 'ollama'
379
+ }
380
+ if (this.hasHuggingFace()) {
381
+ return 'huggingface'
382
+ }
383
+ if (this.hasLMStudio()) {
384
+ return 'lmstudio'
385
+ }
386
+
387
+ return 'none'
360
388
  }
361
389
 
362
390
  // Configuration getters
363
391
  get(key) {
364
- return this.config[key];
392
+ return this.config[key]
365
393
  }
366
394
 
367
395
  getAll() {
368
- return { ...this.config };
396
+ return { ...this.config }
369
397
  }
370
398
 
371
399
  set(key, value) {
372
- this.config[key] = value;
400
+ this.config[key] = value
373
401
  }
374
402
 
375
403
  // Provider configuration
@@ -377,41 +405,41 @@ export class ConfigurationManager {
377
405
  const configs = {
378
406
  openai: {
379
407
  apiKey: this.config.OPENAI_API_KEY,
380
- baseURL: 'https://api.openai.com/v1'
408
+ baseURL: 'https://api.openai.com/v1',
381
409
  },
382
410
  anthropic: {
383
411
  apiKey: this.config.ANTHROPIC_API_KEY,
384
- baseURL: 'https://api.anthropic.com/v1'
412
+ baseURL: 'https://api.anthropic.com/v1',
385
413
  },
386
414
  google: {
387
415
  apiKey: this.config.GOOGLE_API_KEY,
388
- baseURL: 'https://generativelanguage.googleapis.com/v1'
416
+ baseURL: 'https://generativelanguage.googleapis.com/v1',
389
417
  },
390
418
  azure: {
391
419
  apiKey: this.config.AZURE_OPENAI_KEY,
392
420
  endpoint: this.config.AZURE_OPENAI_ENDPOINT,
393
421
  deploymentName: this.config.AZURE_OPENAI_DEPLOYMENT_NAME,
394
- apiVersion: this.config.AZURE_OPENAI_API_VERSION
422
+ apiVersion: this.config.AZURE_OPENAI_API_VERSION,
395
423
  },
396
424
  vertex: {
397
425
  projectId: this.config.VERTEX_PROJECT_ID,
398
426
  location: this.config.VERTEX_LOCATION,
399
- credentials: this.config.GOOGLE_APPLICATION_CREDENTIALS
427
+ credentials: this.config.GOOGLE_APPLICATION_CREDENTIALS,
400
428
  },
401
429
  ollama: {
402
430
  host: this.config.OLLAMA_HOST,
403
- model: this.config.OLLAMA_MODEL
431
+ model: this.config.OLLAMA_MODEL,
404
432
  },
405
433
  huggingface: {
406
434
  apiKey: this.config.HUGGINGFACE_API_KEY,
407
- baseURL: 'https://api-inference.huggingface.co'
435
+ baseURL: 'https://api-inference.huggingface.co',
408
436
  },
409
437
  lmstudio: {
410
- baseURL: this.config.LMSTUDIO_BASE_URL
411
- }
412
- };
438
+ baseURL: this.config.LMSTUDIO_BASE_URL,
439
+ },
440
+ }
413
441
 
414
- return configs[providerName] || {};
442
+ return configs[providerName] || {}
415
443
  }
416
444
 
417
445
  // Environment setup helpers
@@ -424,115 +452,117 @@ export class ConfigurationManager {
424
452
  vertex: ['VERTEX_PROJECT_ID', 'GOOGLE_APPLICATION_CREDENTIALS'],
425
453
  huggingface: ['HUGGINGFACE_API_KEY'],
426
454
  ollama: ['OLLAMA_HOST'],
427
- lmstudio: ['LMSTUDIO_BASE_URL']
428
- };
455
+ lmstudio: ['LMSTUDIO_BASE_URL'],
456
+ }
429
457
 
430
- return requirements[provider] || [];
458
+ return requirements[provider] || []
431
459
  }
432
460
 
433
461
  validateProvider(providerName) {
434
- const required = this.getRequiredEnvVars(providerName);
435
- const missing = required.filter(key => !this.config[key]);
436
-
462
+ const required = this.getRequiredEnvVars(providerName)
463
+ const missing = required.filter((key) => !this.config[key])
464
+
437
465
  return {
438
466
  valid: missing.length === 0,
439
467
  missing,
440
- configured: required.filter(key => !!this.config[key])
441
- };
468
+ configured: required.filter((key) => !!this.config[key]),
469
+ }
442
470
  }
443
471
 
444
472
  // Configuration update methods
445
473
  async updateConfig(updates) {
446
- Object.assign(this.config, updates);
447
- await this.saveConfig();
448
- this.validate();
474
+ Object.assign(this.config, updates)
475
+ await this.saveConfig()
476
+ this.validate()
449
477
  }
450
478
 
451
479
  async saveConfig() {
452
480
  try {
453
481
  const envContent = Object.entries(this.config)
454
482
  .map(([key, value]) => `${key}=${value || ''}`)
455
- .join('\n');
456
-
457
- await fs.promises.writeFile(this.configPath, envContent, 'utf8');
458
- console.log(colors.successMessage(`✅ Configuration saved to ${this.configPath}`));
483
+ .join('\n')
484
+
485
+ await fs.promises.writeFile(this.configPath, envContent, 'utf8')
486
+ console.log(colors.successMessage(`✅ Configuration saved to ${this.configPath}`))
459
487
  } catch (error) {
460
- console.error(colors.errorMessage(`Failed to save configuration: ${error.message}`));
461
- throw error;
488
+ console.error(colors.errorMessage(`Failed to save configuration: ${error.message}`))
489
+ throw error
462
490
  }
463
491
  }
464
492
 
465
493
  // Validation results
466
494
  getValidationResult() {
467
- return this.validationResult;
495
+ return this.validationResult
468
496
  }
469
497
 
470
498
  isValid() {
471
- return this.validationResult.issues.length === 0;
499
+ return this.validationResult.issues.length === 0
472
500
  }
473
501
 
474
502
  // Debug and logging
475
503
  logConfiguration() {
476
- if (!this.config.DEBUG) return;
477
-
478
- console.log(colors.header('🔧 Configuration Debug:'));
479
- console.log(`Config path: ${colors.file(this.configPath)}`);
480
- console.log(`Changelog config path: ${colors.file(this.changelogConfigPath || 'default')}`);
481
- console.log(`Active provider: ${colors.highlight(this.getActiveProvider())}`);
482
- console.log(`Git path: ${colors.file(this.config.GIT_PATH)}`);
483
-
504
+ if (!this.config.DEBUG) {
505
+ return
506
+ }
507
+
508
+ console.log(colors.header('🔧 Configuration Debug:'))
509
+ console.log(`Config path: ${colors.file(this.configPath)}`)
510
+ console.log(`Changelog config path: ${colors.file(this.changelogConfigPath || 'default')}`)
511
+ console.log(`Active provider: ${colors.highlight(this.getActiveProvider())}`)
512
+ console.log(`Git path: ${colors.file(this.config.GIT_PATH)}`)
513
+
484
514
  if (this.validationResult.issues.length > 0) {
485
- console.log(colors.warningMessage('Issues:'));
486
- this.validationResult.issues.forEach(issue => {
487
- console.log(` - ${issue}`);
488
- });
515
+ console.log(colors.warningMessage('Issues:'))
516
+ this.validationResult.issues.forEach((issue) => {
517
+ console.log(` - ${issue}`)
518
+ })
489
519
  }
490
520
  }
491
521
 
492
522
  // Changelog configuration getters
493
523
  getChangelogConfig() {
494
- return this.changelogConfig;
524
+ return this.changelogConfig
495
525
  }
496
526
 
497
527
  getConventionConfig() {
498
- return this.changelogConfig.convention;
528
+ return this.changelogConfig?.convention || {}
499
529
  }
500
530
 
501
531
  getCommitTypes() {
502
- return this.changelogConfig.convention.commitTypes;
532
+ return this.changelogConfig?.convention?.commitTypes || ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert']
503
533
  }
504
534
 
505
535
  getChangelogCommitTypes() {
506
- return this.changelogConfig.changelog.commitTypes;
536
+ return this.changelogConfig?.changelog?.commitTypes || this.getCommitTypes()
507
537
  }
508
538
 
509
539
  getHeadlines() {
510
- return this.changelogConfig.changelog.headlines;
540
+ return this.changelogConfig.changelog.headlines
511
541
  }
512
542
 
513
543
  getCommitUrl() {
514
- return this.changelogConfig.changelog.commitUrl;
544
+ return this.changelogConfig.changelog.commitUrl
515
545
  }
516
546
 
517
547
  getCommitRangeUrl() {
518
- return this.changelogConfig.changelog.commitRangeUrl;
548
+ return this.changelogConfig.changelog.commitRangeUrl
519
549
  }
520
550
 
521
551
  getIssueUrl() {
522
- return this.changelogConfig.changelog.issueUrl;
552
+ return this.changelogConfig.changelog.issueUrl
523
553
  }
524
554
 
525
555
  getIssueRegexPattern() {
526
- const pattern = this.changelogConfig.changelog.issueRegexPattern;
527
- return pattern ? new RegExp(pattern, 'g') : /#[0-9]+/g;
556
+ const pattern = this.changelogConfig.changelog.issueRegexPattern
557
+ return pattern ? new RegExp(pattern, 'g') : /#[0-9]+/g
528
558
  }
529
559
 
530
560
  shouldIncludeInvalidCommits() {
531
- return this.changelogConfig.changelog.includeInvalidCommits;
561
+ return this.changelogConfig.changelog.includeInvalidCommits
532
562
  }
533
563
 
534
564
  getCommitIgnoreRegex() {
535
- const pattern = this.changelogConfig.changelog.commitIgnoreRegexPattern;
536
- return pattern ? new RegExp(pattern) : /^WIP /;
565
+ const pattern = this.changelogConfig.changelog.commitIgnoreRegexPattern
566
+ return pattern ? new RegExp(pattern) : /^WIP /
537
567
  }
538
- }
568
+ }