@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.
Files changed (51) hide show
  1. package/CHANGELOG.md +383 -785
  2. package/README.md +30 -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 +84 -52
  9. package/src/ai-changelog-generator.js +83 -81
  10. package/src/application/orchestrators/changelog.orchestrator.js +1040 -296
  11. package/src/application/services/application.service.js +145 -123
  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 +415 -247
  20. package/src/infrastructure/config/configuration.manager.js +220 -190
  21. package/src/infrastructure/interactive/interactive-staging.service.js +332 -0
  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 +556 -0
  43. package/src/shared/constants/colors.js +467 -172
  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 +1299 -775
  51. package/types/index.d.ts +353 -344
@@ -5,41 +5,41 @@
5
5
  * Provides Model Context Protocol interface for changelog generation
6
6
  */
7
7
 
8
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
- import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
8
+ import fs from 'node:fs'
9
+ import path, { dirname } from 'node:path'
10
+ import process from 'node:process'
11
+ import { fileURLToPath } from 'node:url'
11
12
 
12
- // Import application services
13
- import { ApplicationService } from '../../application/services/application.service.js';
14
- import { ChangelogOrchestrator } from '../../application/orchestrators/changelog.orchestrator.js';
15
- import { GitRepositoryAnalyzer } from '../../domains/git/git-repository.analyzer.js';
16
- import { AnalysisEngine } from '../../domains/analysis/analysis.engine.js';
17
- import { ProviderManagementService } from '../providers/provider-management.service.js';
18
- import { ConfigurationManager } from '../config/configuration.manager.js';
13
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js'
14
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
15
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
19
16
 
20
- import fs from 'fs';
21
- import path from 'path';
22
- import { fileURLToPath } from 'url';
23
- import { dirname } from 'path';
17
+ import { ChangelogOrchestrator } from '../../application/orchestrators/changelog.orchestrator.js'
18
+ // Import application services
19
+ import { ApplicationService } from '../../application/services/application.service.js'
20
+ import { AnalysisEngine } from '../../domains/analysis/analysis.engine.js'
21
+ import { GitRepositoryAnalyzer } from '../../domains/git/git-repository.analyzer.js'
22
+ import { ConfigurationManager } from '../config/configuration.manager.js'
23
+ import { ProviderManagementService } from '../providers/provider-management.service.js'
24
24
 
25
- const __filename = fileURLToPath(import.meta.url);
26
- const __dirname = dirname(__filename);
25
+ const __filename = fileURLToPath(import.meta.url)
26
+ const __dirname = dirname(__filename)
27
27
 
28
28
  class AIChangelogMCPServer {
29
29
  constructor() {
30
- this.initializeServer();
31
- this.initializeServices();
32
- this.setupHandlers();
30
+ this.initializeServer()
31
+ this.initializeServices()
32
+ this.setupHandlers()
33
33
  }
34
34
 
35
35
  initializeServer() {
36
- let packageJson;
36
+ let packageJson
37
37
  try {
38
- const packagePath = path.join(__dirname, '../../../package.json');
39
- const packageContent = fs.readFileSync(packagePath, 'utf8');
40
- packageJson = JSON.parse(packageContent);
41
- } catch (error) {
42
- packageJson = { version: '1.0.0' };
38
+ const packagePath = path.join(__dirname, '../../../package.json')
39
+ const packageContent = fs.readFileSync(packagePath, 'utf8')
40
+ packageJson = JSON.parse(packageContent)
41
+ } catch (_error) {
42
+ packageJson = { version: '1.0.0' }
43
43
  }
44
44
 
45
45
  this.server = new Server(
@@ -53,40 +53,42 @@ class AIChangelogMCPServer {
53
53
  resources: {},
54
54
  },
55
55
  }
56
- );
56
+ )
57
57
  }
58
58
 
59
59
  initializeServices() {
60
60
  try {
61
61
  // Set MCP server mode to suppress verbose logging
62
- process.env.MCP_SERVER_MODE = 'true';
63
-
64
- this.configManager = new ConfigurationManager();
65
- this.applicationService = new ApplicationService();
66
- this.changelogOrchestrator = new ChangelogOrchestrator(this.configManager);
67
- this.gitAnalyzer = new GitRepositoryAnalyzer();
68
- this.analysisEngine = new AnalysisEngine();
69
- this.providerService = new ProviderManagementService();
70
-
62
+ process.env.MCP_SERVER_MODE = 'true'
63
+
64
+ this.configManager = new ConfigurationManager()
65
+ this.applicationService = new ApplicationService()
66
+ this.changelogOrchestrator = new ChangelogOrchestrator(this.configManager)
67
+ this.gitAnalyzer = new GitRepositoryAnalyzer()
68
+ this.analysisEngine = new AnalysisEngine()
69
+ this.providerService = new ProviderManagementService()
70
+
71
71
  // Log available configuration
72
- const hasProvider = process.env.AI_PROVIDER;
73
- const hasApiKey = process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY || process.env.GOOGLE_API_KEY;
74
-
75
- if (!hasProvider || !hasApiKey) {
76
- console.error('[MCP] Warning: No AI provider or API key configured. Tools will provide configuration guidance.');
72
+ const hasProvider = process.env.AI_PROVIDER
73
+ const hasApiKey =
74
+ process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY || process.env.GOOGLE_API_KEY
75
+
76
+ if (!(hasProvider && hasApiKey)) {
77
+ console.error(
78
+ '[MCP] Warning: No AI provider or API key configured. Tools will provide configuration guidance.'
79
+ )
77
80
  } else {
78
- console.error(`[MCP] Configured with provider: ${process.env.AI_PROVIDER}`);
81
+ console.error(`[MCP] Configured with provider: ${process.env.AI_PROVIDER}`)
79
82
  }
80
-
81
83
  } catch (error) {
82
- console.error('[MCP] Failed to initialize services:', error.message);
83
- console.error('[MCP] Server will start but tools may require configuration');
84
+ console.error('[MCP] Failed to initialize services:', error.message)
85
+ console.error('[MCP] Server will start but tools may require configuration')
84
86
  }
85
87
  }
86
88
 
87
89
  setupHandlers() {
88
- this.server.setRequestHandler(ListToolsRequestSchema, this.handleListTools.bind(this));
89
- this.server.setRequestHandler(CallToolRequestSchema, this.handleCallTool.bind(this));
90
+ this.server.setRequestHandler(ListToolsRequestSchema, this.handleListTools.bind(this))
91
+ this.server.setRequestHandler(CallToolRequestSchema, this.handleCallTool.bind(this))
90
92
  }
91
93
 
92
94
  handleListTools() {
@@ -110,7 +112,8 @@ class AIChangelogMCPServer {
110
112
  },
111
113
  since: {
112
114
  type: 'string',
113
- description: 'For commit analysis: since tag/commit/date (e.g., "v1.0.0", "HEAD~10")',
115
+ description:
116
+ 'For commit analysis: since tag/commit/date (e.g., "v1.0.0", "HEAD~10")',
114
117
  },
115
118
  version: {
116
119
  type: 'string',
@@ -219,67 +222,66 @@ class AIChangelogMCPServer {
219
222
  },
220
223
  },
221
224
  ],
222
- };
225
+ }
223
226
  }
224
227
 
225
228
  async handleCallTool(request) {
226
- const { name, arguments: args } = request.params;
227
- console.log(`[MCP] Tool call: ${name}`);
229
+ const { name, arguments: args } = request.params
230
+ console.log(`[MCP] Tool call: ${name}`)
228
231
 
229
232
  try {
230
- console.time(`[MCP-TIMER] ${name}`);
233
+ console.time(`[MCP-TIMER] ${name}`)
231
234
 
232
235
  const timeouts = {
233
- 'generate_changelog': 120000,
234
- 'analyze_repository': 90000,
235
- 'analyze_current_changes': 60000,
236
- 'configure_providers': 30000,
237
- };
236
+ generate_changelog: 120000,
237
+ analyze_repository: 90000,
238
+ analyze_current_changes: 60000,
239
+ configure_providers: 30000,
240
+ }
238
241
 
239
- const timeout = timeouts[name] || 60000;
242
+ const timeout = timeouts[name] || 60000
240
243
  const timeoutPromise = new Promise((_, reject) => {
241
- setTimeout(() => reject(new Error(`Tool '${name}' timed out after ${timeout}ms`)), timeout);
242
- });
243
-
244
- const operationPromise = this.executeOperation(name, args);
245
- const result = await Promise.race([operationPromise, timeoutPromise]);
244
+ setTimeout(() => reject(new Error(`Tool '${name}' timed out after ${timeout}ms`)), timeout)
245
+ })
246
246
 
247
- console.timeEnd(`[MCP-TIMER] ${name}`);
248
- return result;
247
+ const operationPromise = this.executeOperation(name, args)
248
+ const result = await Promise.race([operationPromise, timeoutPromise])
249
249
 
250
+ console.timeEnd(`[MCP-TIMER] ${name}`)
251
+ return result
250
252
  } catch (error) {
251
- console.error(`[MCP] Tool Error [${name}]:`, error.message);
252
- console.timeEnd(`[MCP-TIMER] ${name}`);
253
- return this.formatError(error, name);
253
+ console.error(`[MCP] Tool Error [${name}]:`, error.message)
254
+ console.timeEnd(`[MCP-TIMER] ${name}`)
255
+ return this.formatError(error, name)
254
256
  }
255
257
  }
256
258
 
257
259
  async executeOperation(name, args) {
258
- const originalCwd = process.cwd();
259
-
260
+ const originalCwd = process.cwd()
261
+
260
262
  try {
261
263
  // Change to repository path if specified
262
264
  if (args.repositoryPath && args.repositoryPath !== process.cwd()) {
263
265
  if (!fs.existsSync(args.repositoryPath)) {
264
- throw new Error(`Repository path does not exist: ${args.repositoryPath}`);
266
+ throw new Error(`Repository path does not exist: ${args.repositoryPath}`)
265
267
  }
266
- process.chdir(args.repositoryPath);
268
+ process.chdir(args.repositoryPath)
267
269
  }
268
270
 
269
271
  switch (name) {
270
272
  case 'generate_changelog':
271
- return await this.generateChangelog(args);
273
+ return await this.generateChangelog(args)
272
274
  case 'analyze_repository':
273
- return await this.analyzeRepository(args);
275
+ return await this.analyzeRepository(args)
274
276
  case 'analyze_current_changes':
275
- return await this.analyzeCurrentChanges(args);
277
+ return await this.analyzeCurrentChanges(args)
276
278
  case 'configure_providers':
277
- return await this.configureProviders(args);
279
+ return await this.configureProviders(args)
278
280
  default:
279
- throw new Error(`Unknown tool: ${name}`);
281
+ throw new Error(`Unknown tool: ${name}`)
280
282
  }
281
283
  } finally {
282
- process.chdir(originalCwd);
284
+ process.chdir(originalCwd)
283
285
  }
284
286
  }
285
287
 
@@ -290,251 +292,250 @@ class AIChangelogMCPServer {
290
292
  version,
291
293
  analysisMode = 'detailed',
292
294
  includeAttribution = true,
293
- writeFile = true
294
- } = args;
295
+ writeFile = true,
296
+ } = args
295
297
 
296
298
  try {
297
- let result;
299
+ let result
298
300
 
299
301
  if (source === 'working-dir' || (source === 'auto' && this.hasWorkingDirectoryChanges())) {
300
302
  // Generate from working directory changes
301
303
  result = await this.changelogOrchestrator.generateWorkspaceChangelog({
302
304
  version,
303
305
  analysisMode,
304
- includeAttribution
305
- });
306
+ includeAttribution,
307
+ })
306
308
  } else {
307
309
  // Generate from commits
308
310
  result = await this.changelogOrchestrator.generateChangelog({
309
311
  version,
310
312
  since,
311
313
  analysisMode,
312
- includeAttribution
313
- });
314
+ includeAttribution,
315
+ })
314
316
  }
315
317
 
316
318
  // Write file if requested
317
319
  if (writeFile && result.content) {
318
- const changelogPath = path.join(process.cwd(), 'AI_CHANGELOG.md');
320
+ const changelogPath = path.join(process.cwd(), 'AI_CHANGELOG.md')
319
321
  try {
320
- fs.writeFileSync(changelogPath, result.content, 'utf8');
321
- console.log(`[MCP] Changelog written to: ${changelogPath}`);
322
+ fs.writeFileSync(changelogPath, result.content, 'utf8')
323
+ console.log(`[MCP] Changelog written to: ${changelogPath}`)
322
324
  } catch (writeError) {
323
- console.warn(`[MCP] Could not write file: ${writeError.message}`);
325
+ console.warn(`[MCP] Could not write file: ${writeError.message}`)
324
326
  }
325
327
  }
326
328
 
327
329
  return {
328
- content: [{
329
- type: 'text',
330
- text: result.content || 'No changelog content generated'
331
- }],
332
- metadata: result.metadata
333
- };
334
-
330
+ content: [
331
+ {
332
+ type: 'text',
333
+ text: result.content || 'No changelog content generated',
334
+ },
335
+ ],
336
+ metadata: result.metadata,
337
+ }
335
338
  } catch (error) {
336
- throw new Error(`Changelog generation failed: ${error.message}`);
339
+ throw new Error(`Changelog generation failed: ${error.message}`)
337
340
  }
338
341
  }
339
342
 
340
343
  async analyzeRepository(args) {
341
- const {
342
- analysisType = 'comprehensive',
343
- includeRecommendations = true,
344
- commitLimit = 50
345
- } = args;
344
+ const { analysisType = 'comprehensive', includeRecommendations = true, commitLimit = 50 } = args
346
345
 
347
346
  try {
348
- let result;
347
+ let result
349
348
 
350
349
  switch (analysisType) {
351
350
  case 'health':
352
- result = await this.gitAnalyzer.assessRepositoryHealth(includeRecommendations);
353
- break;
351
+ result = await this.gitAnalyzer.assessRepositoryHealth(includeRecommendations)
352
+ break
354
353
  case 'commits':
355
- result = await this.analysisEngine.analyzeRecentCommits(commitLimit);
356
- break;
354
+ result = await this.analysisEngine.analyzeRecentCommits(commitLimit)
355
+ break
357
356
  case 'branches':
358
- result = await this.gitAnalyzer.analyzeBranches();
359
- break;
357
+ result = await this.gitAnalyzer.analyzeBranches()
358
+ break
360
359
  case 'working-dir':
361
- result = await this.analysisEngine.analyzeCurrentChanges();
362
- break;
363
- case 'comprehensive':
360
+ result = await this.analysisEngine.analyzeCurrentChanges()
361
+ break
364
362
  default:
365
- result = await this.gitAnalyzer.analyzeComprehensive(includeRecommendations);
366
- break;
363
+ result = await this.gitAnalyzer.analyzeComprehensive(includeRecommendations)
364
+ break
367
365
  }
368
366
 
369
367
  return {
370
- content: [{
371
- type: 'text',
372
- text: JSON.stringify(result, null, 2)
373
- }]
374
- };
375
-
368
+ content: [
369
+ {
370
+ type: 'text',
371
+ text: JSON.stringify(result, null, 2),
372
+ },
373
+ ],
374
+ }
376
375
  } catch (error) {
377
- throw new Error(`Repository analysis failed: ${error.message}`);
376
+ throw new Error(`Repository analysis failed: ${error.message}`)
378
377
  }
379
378
  }
380
379
 
381
380
  async analyzeCurrentChanges(args) {
382
- const {
383
- includeAIAnalysis = true,
384
- includeAttribution = true
385
- } = args;
381
+ const { includeAIAnalysis = true, includeAttribution = true } = args
386
382
 
387
383
  try {
388
384
  const result = await this.analysisEngine.analyzeCurrentChanges({
389
385
  includeAIAnalysis,
390
- includeAttribution
391
- });
386
+ includeAttribution,
387
+ })
392
388
 
393
389
  return {
394
- content: [{
395
- type: 'text',
396
- text: JSON.stringify(result, null, 2)
397
- }]
398
- };
399
-
390
+ content: [
391
+ {
392
+ type: 'text',
393
+ text: JSON.stringify(result, null, 2),
394
+ },
395
+ ],
396
+ }
400
397
  } catch (error) {
401
- throw new Error(`Current changes analysis failed: ${error.message}`);
398
+ throw new Error(`Current changes analysis failed: ${error.message}`)
402
399
  }
403
400
  }
404
401
 
405
402
  async configureProviders(args) {
406
- const {
407
- action = 'list',
408
- provider,
409
- testConnection = false
410
- } = args;
403
+ const { action = 'list', provider, testConnection = false } = args
411
404
 
412
405
  try {
413
- let result;
406
+ let result
414
407
 
415
408
  switch (action) {
416
409
  case 'list':
417
- result = await this.providerService.listProviders();
418
- break;
410
+ result = await this.providerService.listProviders()
411
+ break
419
412
  case 'switch':
420
- if (!provider) throw new Error('Provider required for switch action');
421
- result = await this.providerService.switchProvider(provider);
413
+ if (!provider) {
414
+ throw new Error('Provider required for switch action')
415
+ }
416
+ result = await this.providerService.switchProvider(provider)
422
417
  if (testConnection) {
423
- const testResult = await this.providerService.testProvider(provider);
424
- result += `\n${testResult}`;
418
+ const testResult = await this.providerService.testProvider(provider)
419
+ result += `\n${testResult}`
425
420
  }
426
- break;
421
+ break
427
422
  case 'test':
428
- result = await this.providerService.testCurrentProvider();
429
- break;
423
+ result = await this.providerService.testCurrentProvider()
424
+ break
430
425
  case 'configure':
431
- result = await this.providerService.configureProvider(provider);
432
- break;
426
+ result = await this.providerService.configureProvider(provider)
427
+ break
433
428
  case 'validate':
434
- result = await this.providerService.validateModels(provider);
435
- break;
429
+ result = await this.providerService.validateModels(provider)
430
+ break
436
431
  default:
437
- throw new Error(`Unknown action: ${action}`);
432
+ throw new Error(`Unknown action: ${action}`)
438
433
  }
439
434
 
440
435
  return {
441
- content: [{
442
- type: 'text',
443
- text: result
444
- }]
445
- };
446
-
436
+ content: [
437
+ {
438
+ type: 'text',
439
+ text: result,
440
+ },
441
+ ],
442
+ }
447
443
  } catch (error) {
448
- throw new Error(`Provider management failed: ${error.message}`);
444
+ throw new Error(`Provider management failed: ${error.message}`)
449
445
  }
450
446
  }
451
447
 
452
448
  hasWorkingDirectoryChanges() {
453
449
  try {
454
450
  // Simple check for working directory changes
455
- const { execSync } = require('child_process');
456
- const result = execSync('git status --porcelain', { encoding: 'utf8' });
457
- return result.trim().length > 0;
458
- } catch (error) {
459
- return false;
451
+ const { execSync } = require('node:child_process')
452
+ const result = execSync('git status --porcelain', { encoding: 'utf8' })
453
+ return result.trim().length > 0
454
+ } catch (_error) {
455
+ return false
460
456
  }
461
457
  }
462
458
 
463
459
  formatError(error, toolName) {
464
460
  if (error.message.includes('timed out')) {
465
461
  return {
466
- content: [{
467
- type: 'text',
468
- text: `⏱️ Timeout: '${toolName}' exceeded time limit. Try with smaller scope or check connectivity.`,
469
- }],
462
+ content: [
463
+ {
464
+ type: 'text',
465
+ text: `⏱️ Timeout: '${toolName}' exceeded time limit. Try with smaller scope or check connectivity.`,
466
+ },
467
+ ],
470
468
  isError: true,
471
- };
469
+ }
472
470
  }
473
471
 
474
472
  return {
475
- content: [{
476
- type: 'text',
477
- text: `❌ Error in '${toolName}': ${error.message}`,
478
- }],
473
+ content: [
474
+ {
475
+ type: 'text',
476
+ text: `❌ Error in '${toolName}': ${error.message}`,
477
+ },
478
+ ],
479
479
  isError: true,
480
- };
480
+ }
481
481
  }
482
482
 
483
483
  async run() {
484
484
  try {
485
- const transport = new StdioServerTransport();
486
- await this.server.connect(transport);
485
+ const transport = new StdioServerTransport()
486
+ await this.server.connect(transport)
487
487
 
488
488
  // Setup graceful shutdown
489
- let isShuttingDown = false;
489
+ let isShuttingDown = false
490
490
  const gracefulShutdown = async (signal) => {
491
- if (isShuttingDown) return;
492
- isShuttingDown = true;
493
-
491
+ if (isShuttingDown) {
492
+ return
493
+ }
494
+ isShuttingDown = true
495
+
494
496
  try {
495
- console.error(`[MCP] Received ${signal}, shutting down gracefully...`);
496
- await this.server.close();
497
- process.exit(0);
497
+ console.error(`[MCP] Received ${signal}, shutting down gracefully...`)
498
+ await this.server.close()
499
+ process.exit(0)
498
500
  } catch (error) {
499
- console.error('[MCP] Error during shutdown:', error);
500
- process.exit(1);
501
+ console.error('[MCP] Error during shutdown:', error)
502
+ process.exit(1)
501
503
  }
502
- };
504
+ }
503
505
 
504
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
505
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
506
- process.on('SIGQUIT', () => gracefulShutdown('SIGQUIT'));
506
+ process.on('SIGINT', () => gracefulShutdown('SIGINT'))
507
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM'))
508
+ process.on('SIGQUIT', () => gracefulShutdown('SIGQUIT'))
507
509
 
508
510
  // Handle uncaught exceptions
509
511
  process.on('uncaughtException', (error) => {
510
- console.error('[MCP] Uncaught exception:', error);
511
- gracefulShutdown('uncaughtException');
512
- });
512
+ console.error('[MCP] Uncaught exception:', error)
513
+ gracefulShutdown('uncaughtException')
514
+ })
513
515
 
514
516
  process.on('unhandledRejection', (reason, promise) => {
515
- console.error('[MCP] Unhandled rejection at:', promise, 'reason:', reason);
516
- gracefulShutdown('unhandledRejection');
517
- });
517
+ console.error('[MCP] Unhandled rejection at:', promise, 'reason:', reason)
518
+ gracefulShutdown('unhandledRejection')
519
+ })
518
520
 
519
- console.error('[MCP] AI Changelog Generator server running...');
520
-
521
- // Keep process alive
522
- return new Promise(() => {});
521
+ console.error('[MCP] AI Changelog Generator server running...')
523
522
 
523
+ // Keep process alive
524
+ return new Promise(() => {})
524
525
  } catch (error) {
525
- console.error('[MCP] Server failed to start:', error.message);
526
- throw error;
526
+ console.error('[MCP] Server failed to start:', error.message)
527
+ throw error
527
528
  }
528
529
  }
529
530
  }
530
531
 
531
532
  // Start server if called directly
532
533
  if (import.meta.url === `file://${process.argv[1]}`) {
533
- const server = new AIChangelogMCPServer();
534
+ const server = new AIChangelogMCPServer()
534
535
  server.run().catch((error) => {
535
- console.error('MCP Server startup failed:', error);
536
- process.exit(1);
537
- });
536
+ console.error('MCP Server startup failed:', error)
537
+ process.exit(1)
538
+ })
538
539
  }
539
540
 
540
- export default AIChangelogMCPServer;
541
+ export default AIChangelogMCPServer