@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
@@ -4,23 +4,23 @@
4
4
  * Based on the original lib-old/utils/error-handler.js
5
5
  */
6
6
 
7
- import JsonUtils from './json-utils.js';
7
+ import JsonUtils from './json-utils.js'
8
8
 
9
9
  /**
10
10
  * Base error class for domain-specific errors
11
11
  */
12
12
  export class AIChangelogError extends Error {
13
13
  constructor(message, type, context = {}, originalError = null) {
14
- super(message);
15
- this.name = this.constructor.name;
16
- this.type = type;
17
- this.context = context;
18
- this.originalError = originalError;
19
- this.timestamp = new Date().toISOString();
20
-
14
+ super(message)
15
+ this.name = this.constructor.name
16
+ this.type = type
17
+ this.context = context
18
+ this.originalError = originalError
19
+ this.timestamp = new Date().toISOString()
20
+
21
21
  // Capture stack trace
22
22
  if (Error.captureStackTrace) {
23
- Error.captureStackTrace(this, this.constructor);
23
+ Error.captureStackTrace(this, this.constructor)
24
24
  }
25
25
  }
26
26
 
@@ -32,23 +32,25 @@ export class AIChangelogError extends Error {
32
32
  context: this.context,
33
33
  timestamp: this.timestamp,
34
34
  stack: this.stack,
35
- originalError: this.originalError ? {
36
- name: this.originalError.name,
37
- message: this.originalError.message,
38
- stack: this.originalError.stack
39
- } : null
40
- };
35
+ originalError: this.originalError
36
+ ? {
37
+ name: this.originalError.name,
38
+ message: this.originalError.message,
39
+ stack: this.originalError.stack,
40
+ }
41
+ : null,
42
+ }
41
43
  }
42
44
 
43
45
  toString() {
44
- let str = `${this.name}: ${this.message}`;
46
+ let str = `${this.name}: ${this.message}`
45
47
  if (Object.keys(this.context).length > 0) {
46
- str += `\nContext: ${JsonUtils.stringifyCompact(this.context)}`;
48
+ str += `\nContext: ${JsonUtils.stringifyCompact(this.context)}`
47
49
  }
48
50
  if (this.originalError) {
49
- str += `\nCaused by: ${this.originalError.name}: ${this.originalError.message}`;
51
+ str += `\nCaused by: ${this.originalError.name}: ${this.originalError.message}`
50
52
  }
51
- return str;
53
+ return str
52
54
  }
53
55
  }
54
56
 
@@ -57,8 +59,8 @@ export class AIChangelogError extends Error {
57
59
  */
58
60
  export class GitError extends AIChangelogError {
59
61
  constructor(message, command, originalError = null, context = {}) {
60
- super(message, 'git', { command, ...context }, originalError);
61
- this.command = command;
62
+ super(message, 'git', { command, ...context }, originalError)
63
+ this.command = command
62
64
  }
63
65
 
64
66
  static fromCommandFailure(command, exitCode, stdout, stderr, originalError = null) {
@@ -66,41 +68,36 @@ export class GitError extends AIChangelogError {
66
68
  command,
67
69
  exitCode,
68
70
  stdout: stdout?.trim(),
69
- stderr: stderr?.trim()
70
- };
71
-
72
- let message = `Git command failed: ${command}`;
73
- if (exitCode) message += ` (exit code: ${exitCode})`;
74
- if (stderr) message += `\nError: ${stderr}`;
75
-
76
- return new GitError(message, command, originalError, context);
71
+ stderr: stderr?.trim(),
72
+ }
73
+
74
+ let message = `Git command failed: ${command}`
75
+ if (exitCode) {
76
+ message += ` (exit code: ${exitCode})`
77
+ }
78
+ if (stderr) {
79
+ message += `\nError: ${stderr}`
80
+ }
81
+
82
+ return new GitError(message, command, originalError, context)
77
83
  }
78
84
 
79
85
  static repositoryNotFound(path) {
80
- return new GitError(
81
- `Git repository not found at path: ${path}`,
82
- 'init',
83
- null,
84
- { path, reason: 'repository_not_found' }
85
- );
86
+ return new GitError(`Git repository not found at path: ${path}`, 'init', null, {
87
+ path,
88
+ reason: 'repository_not_found',
89
+ })
86
90
  }
87
91
 
88
92
  static invalidReference(ref, reason = 'unknown') {
89
- return new GitError(
90
- `Invalid git reference: ${ref}`,
91
- 'show',
92
- null,
93
- { ref, reason }
94
- );
93
+ return new GitError(`Invalid git reference: ${ref}`, 'show', null, { ref, reason })
95
94
  }
96
95
 
97
96
  static workingDirectoryDirty(files = []) {
98
- return new GitError(
99
- 'Working directory has uncommitted changes',
100
- 'status',
101
- null,
102
- { dirtyFiles: files, reason: 'working_directory_dirty' }
103
- );
97
+ return new GitError('Working directory has uncommitted changes', 'status', null, {
98
+ dirtyFiles: files,
99
+ reason: 'working_directory_dirty',
100
+ })
104
101
  }
105
102
  }
106
103
 
@@ -109,17 +106,15 @@ export class GitError extends AIChangelogError {
109
106
  */
110
107
  export class ConfigError extends AIChangelogError {
111
108
  constructor(message, configKey, originalError = null, context = {}) {
112
- super(message, 'config', { configKey, ...context }, originalError);
113
- this.configKey = configKey;
109
+ super(message, 'config', { configKey, ...context }, originalError)
110
+ this.configKey = configKey
114
111
  }
115
112
 
116
113
  static missingRequired(configKey, source = 'configuration') {
117
- return new ConfigError(
118
- `Required configuration missing: ${configKey}`,
119
- configKey,
120
- null,
121
- { source, reason: 'missing_required' }
122
- );
114
+ return new ConfigError(`Required configuration missing: ${configKey}`, configKey, null, {
115
+ source,
116
+ reason: 'missing_required',
117
+ })
123
118
  }
124
119
 
125
120
  static invalidValue(configKey, value, expectedType, source = 'configuration') {
@@ -128,16 +123,14 @@ export class ConfigError extends AIChangelogError {
128
123
  configKey,
129
124
  null,
130
125
  { value, expectedType, actualType: typeof value, source, reason: 'invalid_type' }
131
- );
126
+ )
132
127
  }
133
128
 
134
129
  static fileNotFound(configPath) {
135
- return new ConfigError(
136
- `Configuration file not found: ${configPath}`,
137
- 'file',
138
- null,
139
- { configPath, reason: 'file_not_found' }
140
- );
130
+ return new ConfigError(`Configuration file not found: ${configPath}`, 'file', null, {
131
+ configPath,
132
+ reason: 'file_not_found',
133
+ })
141
134
  }
142
135
 
143
136
  static parseError(configPath, originalError) {
@@ -146,7 +139,7 @@ export class ConfigError extends AIChangelogError {
146
139
  'file',
147
140
  originalError,
148
141
  { configPath, reason: 'parse_error' }
149
- );
142
+ )
150
143
  }
151
144
 
152
145
  static providerNotConfigured(providerName) {
@@ -155,7 +148,7 @@ export class ConfigError extends AIChangelogError {
155
148
  `providers.${providerName}`,
156
149
  null,
157
150
  { providerName, reason: 'provider_not_configured' }
158
- );
151
+ )
159
152
  }
160
153
  }
161
154
 
@@ -164,19 +157,15 @@ export class ConfigError extends AIChangelogError {
164
157
  */
165
158
  export class ValidationError extends AIChangelogError {
166
159
  constructor(message, field, value, originalError = null, context = {}) {
167
- super(message, 'validation', { field, value, ...context }, originalError);
168
- this.field = field;
169
- this.value = value;
160
+ super(message, 'validation', { field, value, ...context }, originalError)
161
+ this.field = field
162
+ this.value = value
170
163
  }
171
164
 
172
165
  static required(field) {
173
- return new ValidationError(
174
- `Field '${field}' is required`,
175
- field,
176
- undefined,
177
- null,
178
- { reason: 'required_field' }
179
- );
166
+ return new ValidationError(`Field '${field}' is required`, field, undefined, null, {
167
+ reason: 'required_field',
168
+ })
180
169
  }
181
170
 
182
171
  static invalidType(field, value, expectedType) {
@@ -186,7 +175,7 @@ export class ValidationError extends AIChangelogError {
186
175
  value,
187
176
  null,
188
177
  { expectedType, actualType: typeof value, reason: 'invalid_type' }
189
- );
178
+ )
190
179
  }
191
180
 
192
181
  static outOfRange(field, value, min, max) {
@@ -196,30 +185,27 @@ export class ValidationError extends AIChangelogError {
196
185
  value,
197
186
  null,
198
187
  { min, max, reason: 'out_of_range' }
199
- );
188
+ )
200
189
  }
201
190
 
202
191
  static invalidFormat(field, value, format, example = null) {
203
- let message = `Field '${field}' has invalid format: expected ${format}`;
204
- if (example) message += ` (example: ${example})`;
205
-
206
- return new ValidationError(
207
- message,
208
- field,
209
- value,
210
- null,
211
- { format, example, reason: 'invalid_format' }
212
- );
192
+ let message = `Field '${field}' has invalid format: expected ${format}`
193
+ if (example) {
194
+ message += ` (example: ${example})`
195
+ }
196
+
197
+ return new ValidationError(message, field, value, null, {
198
+ format,
199
+ example,
200
+ reason: 'invalid_format',
201
+ })
213
202
  }
214
203
 
215
204
  static custom(field, value, message, context = {}) {
216
- return new ValidationError(
217
- message,
218
- field,
219
- value,
220
- null,
221
- { ...context, reason: 'custom_validation' }
222
- );
205
+ return new ValidationError(message, field, value, null, {
206
+ ...context,
207
+ reason: 'custom_validation',
208
+ })
223
209
  }
224
210
  }
225
211
 
@@ -228,9 +214,9 @@ export class ValidationError extends AIChangelogError {
228
214
  */
229
215
  export class ProviderError extends AIChangelogError {
230
216
  constructor(message, providerName, methodName, originalError = null, context = {}) {
231
- super(message, 'provider', { providerName, methodName, ...context }, originalError);
232
- this.providerName = providerName;
233
- this.methodName = methodName;
217
+ super(message, 'provider', { providerName, methodName, ...context }, originalError)
218
+ this.providerName = providerName
219
+ this.methodName = methodName
234
220
  }
235
221
 
236
222
  static notAvailable(providerName, reason = 'unknown') {
@@ -240,7 +226,7 @@ export class ProviderError extends AIChangelogError {
240
226
  'availability',
241
227
  null,
242
228
  { reason }
243
- );
229
+ )
244
230
  }
245
231
 
246
232
  static authenticationFailed(providerName, details = {}) {
@@ -250,7 +236,7 @@ export class ProviderError extends AIChangelogError {
250
236
  'authenticate',
251
237
  null,
252
238
  { ...details, reason: 'authentication_failed' }
253
- );
239
+ )
254
240
  }
255
241
 
256
242
  static rateLimitExceeded(providerName, retryAfter = null) {
@@ -260,7 +246,7 @@ export class ProviderError extends AIChangelogError {
260
246
  'request',
261
247
  null,
262
248
  { retryAfter, reason: 'rate_limit_exceeded' }
263
- );
249
+ )
264
250
  }
265
251
 
266
252
  static apiError(providerName, methodName, statusCode, response, originalError = null) {
@@ -270,7 +256,7 @@ export class ProviderError extends AIChangelogError {
270
256
  methodName,
271
257
  originalError,
272
258
  { statusCode, response, reason: 'api_error' }
273
- );
259
+ )
274
260
  }
275
261
 
276
262
  static invalidResponse(providerName, methodName, response, expectedFormat) {
@@ -280,7 +266,7 @@ export class ProviderError extends AIChangelogError {
280
266
  methodName,
281
267
  null,
282
268
  { response, expectedFormat, reason: 'invalid_response' }
283
- );
269
+ )
284
270
  }
285
271
  }
286
272
 
@@ -289,9 +275,9 @@ export class ProviderError extends AIChangelogError {
289
275
  */
290
276
  export class AbstractMethodError extends AIChangelogError {
291
277
  constructor(message, className, methodName, context = {}) {
292
- super(message, 'abstract', { className, methodName, ...context });
293
- this.className = className;
294
- this.methodName = methodName;
278
+ super(message, 'abstract', { className, methodName, ...context })
279
+ this.className = className
280
+ this.methodName = methodName
295
281
  }
296
282
 
297
283
  static notImplemented(className, methodName) {
@@ -300,7 +286,7 @@ export class AbstractMethodError extends AIChangelogError {
300
286
  className,
301
287
  methodName,
302
288
  { reason: 'not_implemented' }
303
- );
289
+ )
304
290
  }
305
291
  }
306
292
 
@@ -309,19 +295,15 @@ export class AbstractMethodError extends AIChangelogError {
309
295
  */
310
296
  export class FileSystemError extends AIChangelogError {
311
297
  constructor(message, operation, path, originalError = null, context = {}) {
312
- super(message, 'filesystem', { operation, path, ...context }, originalError);
313
- this.operation = operation;
314
- this.path = path;
298
+ super(message, 'filesystem', { operation, path, ...context }, originalError)
299
+ this.operation = operation
300
+ this.path = path
315
301
  }
316
302
 
317
303
  static fileNotFound(path) {
318
- return new FileSystemError(
319
- `File not found: ${path}`,
320
- 'read',
321
- path,
322
- null,
323
- { reason: 'file_not_found' }
324
- );
304
+ return new FileSystemError(`File not found: ${path}`, 'read', path, null, {
305
+ reason: 'file_not_found',
306
+ })
325
307
  }
326
308
 
327
309
  static permissionDenied(operation, path) {
@@ -331,17 +313,13 @@ export class FileSystemError extends AIChangelogError {
331
313
  path,
332
314
  null,
333
315
  { reason: 'permission_denied' }
334
- );
316
+ )
335
317
  }
336
318
 
337
319
  static directoryNotFound(path) {
338
- return new FileSystemError(
339
- `Directory not found: ${path}`,
340
- 'access',
341
- path,
342
- null,
343
- { reason: 'directory_not_found' }
344
- );
320
+ return new FileSystemError(`Directory not found: ${path}`, 'access', path, null, {
321
+ reason: 'directory_not_found',
322
+ })
345
323
  }
346
324
  }
347
325
 
@@ -350,39 +328,30 @@ export class FileSystemError extends AIChangelogError {
350
328
  */
351
329
  export class NetworkError extends AIChangelogError {
352
330
  constructor(message, url, operation, originalError = null, context = {}) {
353
- super(message, 'network', { url, operation, ...context }, originalError);
354
- this.url = url;
355
- this.operation = operation;
331
+ super(message, 'network', { url, operation, ...context }, originalError)
332
+ this.url = url
333
+ this.operation = operation
356
334
  }
357
335
 
358
336
  static connectionFailed(url, originalError = null) {
359
- return new NetworkError(
360
- `Failed to connect to ${url}`,
361
- url,
362
- 'connect',
363
- originalError,
364
- { reason: 'connection_failed' }
365
- );
337
+ return new NetworkError(`Failed to connect to ${url}`, url, 'connect', originalError, {
338
+ reason: 'connection_failed',
339
+ })
366
340
  }
367
341
 
368
342
  static timeout(url, timeoutMs) {
369
- return new NetworkError(
370
- `Request timeout after ${timeoutMs}ms: ${url}`,
371
- url,
372
- 'request',
373
- null,
374
- { timeoutMs, reason: 'timeout' }
375
- );
343
+ return new NetworkError(`Request timeout after ${timeoutMs}ms: ${url}`, url, 'request', null, {
344
+ timeoutMs,
345
+ reason: 'timeout',
346
+ })
376
347
  }
377
348
 
378
349
  static httpError(url, statusCode, statusText) {
379
- return new NetworkError(
380
- `HTTP ${statusCode} ${statusText}: ${url}`,
381
- url,
382
- 'request',
383
- null,
384
- { statusCode, statusText, reason: 'http_error' }
385
- );
350
+ return new NetworkError(`HTTP ${statusCode} ${statusText}: ${url}`, url, 'request', null, {
351
+ statusCode,
352
+ statusText,
353
+ reason: 'http_error',
354
+ })
386
355
  }
387
356
  }
388
357
 
@@ -391,33 +360,33 @@ export class NetworkError extends AIChangelogError {
391
360
  */
392
361
  export class ErrorContext {
393
362
  constructor() {
394
- this.data = {};
363
+ this.data = {}
395
364
  }
396
365
 
397
366
  add(key, value) {
398
- this.data[key] = value;
399
- return this;
367
+ this.data[key] = value
368
+ return this
400
369
  }
401
370
 
402
371
  addGitInfo(command, exitCode, stdout, stderr) {
403
- return this.add('git', { command, exitCode, stdout, stderr });
372
+ return this.add('git', { command, exitCode, stdout, stderr })
404
373
  }
405
374
 
406
375
  addProviderInfo(name, model, endpoint) {
407
- return this.add('provider', { name, model, endpoint });
376
+ return this.add('provider', { name, model, endpoint })
408
377
  }
409
378
 
410
379
  addFileInfo(path, size, mtime) {
411
- return this.add('file', { path, size, mtime });
380
+ return this.add('file', { path, size, mtime })
412
381
  }
413
382
 
414
383
  addUserInfo(action, timestamp = new Date().toISOString()) {
415
- return this.add('user', { action, timestamp });
384
+ return this.add('user', { action, timestamp })
416
385
  }
417
386
 
418
387
  build() {
419
- return { ...this.data };
388
+ return { ...this.data }
420
389
  }
421
390
  }
422
391
 
423
- // All error classes are exported individually with their class declarations above
392
+ // All error classes are exported individually with their class declarations above