@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
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* Provides CLI error handling, validation, and user interface utilities
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import fs from 'fs'
|
|
8
|
-
import path from 'path'
|
|
9
|
-
import
|
|
10
|
-
|
|
7
|
+
import fs from 'node:fs'
|
|
8
|
+
import path from 'node:path'
|
|
9
|
+
import process from 'node:process'
|
|
10
|
+
|
|
11
|
+
import colors from '../constants/colors.js'
|
|
12
|
+
import { ConfigError, ErrorContext, GitError, NetworkError } from './error-classes.js'
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Enhanced error handling for CLI applications with context-aware tips
|
|
@@ -16,23 +18,23 @@ import colors from '../constants/colors.js';
|
|
|
16
18
|
* @param {Object} options - Error handling options
|
|
17
19
|
*/
|
|
18
20
|
export function handleCLIError(error, context = 'application', options = {}) {
|
|
19
|
-
const { exitOnError = true, showTips = true, showStack = false } = options
|
|
20
|
-
|
|
21
|
-
console.error(colors.errorMessage(`❌ Failed to ${context}: ${error.message}`))
|
|
22
|
-
|
|
21
|
+
const { exitOnError = true, showTips = true, showStack = false } = options
|
|
22
|
+
|
|
23
|
+
console.error(colors.errorMessage(`❌ Failed to ${context}: ${error.message}`))
|
|
24
|
+
|
|
23
25
|
if (showStack && error.stack) {
|
|
24
|
-
console.error(colors.gray(error.stack))
|
|
26
|
+
console.error(colors.gray(error.stack))
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
|
|
27
29
|
if (showTips) {
|
|
28
|
-
const tips = getContextualTips(error, context)
|
|
30
|
+
const tips = getContextualTips(error, context)
|
|
29
31
|
if (tips.length > 0) {
|
|
30
|
-
tips.forEach(tip => console.error(colors.infoMessage(`💡 Tip: ${tip}`)))
|
|
32
|
+
tips.forEach((tip) => console.error(colors.infoMessage(`💡 Tip: ${tip}`)))
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
|
-
|
|
35
|
+
|
|
34
36
|
if (exitOnError) {
|
|
35
|
-
process.exit(1)
|
|
37
|
+
process.exit(1)
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
|
|
@@ -43,67 +45,72 @@ export function handleCLIError(error, context = 'application', options = {}) {
|
|
|
43
45
|
* @returns {Array} Array of helpful tip strings
|
|
44
46
|
*/
|
|
45
47
|
function getContextualTips(error, context) {
|
|
46
|
-
const tips = []
|
|
47
|
-
const message = error.message.toLowerCase()
|
|
48
|
-
|
|
48
|
+
const tips = []
|
|
49
|
+
const message = error.message.toLowerCase()
|
|
50
|
+
|
|
49
51
|
// Git-related tips
|
|
50
52
|
if (error instanceof GitError || message.includes('git')) {
|
|
51
53
|
if (message.includes('not a git repository')) {
|
|
52
|
-
tips.push(
|
|
53
|
-
tips.push('Run `git init` to initialize a new repository')
|
|
54
|
+
tips.push("Make sure you're in a git repository directory")
|
|
55
|
+
tips.push('Run `git init` to initialize a new repository')
|
|
54
56
|
} else if (message.includes('no commits')) {
|
|
55
|
-
tips.push('Make at least one commit before generating a changelog')
|
|
57
|
+
tips.push('Make at least one commit before generating a changelog')
|
|
56
58
|
} else if (message.includes('remote')) {
|
|
57
|
-
tips.push('Check your git remote configuration with `git remote -v`')
|
|
59
|
+
tips.push('Check your git remote configuration with `git remote -v`')
|
|
58
60
|
} else {
|
|
59
|
-
tips.push('Ensure git is properly installed and configured')
|
|
61
|
+
tips.push('Ensure git is properly installed and configured')
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
|
-
|
|
64
|
+
|
|
63
65
|
// Provider/API related tips
|
|
64
66
|
if (error instanceof ConfigError || message.includes('provider') || message.includes('api key')) {
|
|
65
|
-
tips.push('Configure at least one AI provider in your .env.local file')
|
|
66
|
-
tips.push('Check the documentation for provider-specific setup instructions')
|
|
67
|
-
tips.push('Verify your API keys are valid and have sufficient quota')
|
|
67
|
+
tips.push('Configure at least one AI provider in your .env.local file')
|
|
68
|
+
tips.push('Check the documentation for provider-specific setup instructions')
|
|
69
|
+
tips.push('Verify your API keys are valid and have sufficient quota')
|
|
68
70
|
}
|
|
69
|
-
|
|
71
|
+
|
|
70
72
|
// Network related tips
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
if (
|
|
74
|
+
error instanceof NetworkError ||
|
|
75
|
+
message.includes('enotfound') ||
|
|
76
|
+
message.includes('network') ||
|
|
77
|
+
message.includes('timeout')
|
|
78
|
+
) {
|
|
79
|
+
tips.push('Check your internet connection')
|
|
80
|
+
tips.push('If using a proxy, verify your proxy settings')
|
|
81
|
+
tips.push('Some providers may be temporarily unavailable - try again later')
|
|
75
82
|
}
|
|
76
|
-
|
|
83
|
+
|
|
77
84
|
// Permission related tips
|
|
78
85
|
if (message.includes('permission') || message.includes('eacces')) {
|
|
79
|
-
tips.push('Check file and directory permissions')
|
|
80
|
-
tips.push('Try running with appropriate privileges (but avoid sudo if possible)')
|
|
81
|
-
tips.push('Ensure the current user has write access to the working directory')
|
|
86
|
+
tips.push('Check file and directory permissions')
|
|
87
|
+
tips.push('Try running with appropriate privileges (but avoid sudo if possible)')
|
|
88
|
+
tips.push('Ensure the current user has write access to the working directory')
|
|
82
89
|
}
|
|
83
|
-
|
|
90
|
+
|
|
84
91
|
// File system tips
|
|
85
92
|
if (message.includes('enoent') || message.includes('file not found')) {
|
|
86
|
-
tips.push('Verify the file or directory exists')
|
|
87
|
-
tips.push('Check the file path spelling and case sensitivity')
|
|
93
|
+
tips.push('Verify the file or directory exists')
|
|
94
|
+
tips.push('Check the file path spelling and case sensitivity')
|
|
88
95
|
}
|
|
89
|
-
|
|
96
|
+
|
|
90
97
|
// Memory/resource tips
|
|
91
98
|
if (message.includes('out of memory') || message.includes('heap')) {
|
|
92
|
-
tips.push('Try processing fewer commits at once')
|
|
93
|
-
tips.push('Increase Node.js memory limit with --max-old-space-size')
|
|
99
|
+
tips.push('Try processing fewer commits at once')
|
|
100
|
+
tips.push('Increase Node.js memory limit with --max-old-space-size')
|
|
94
101
|
}
|
|
95
|
-
|
|
102
|
+
|
|
96
103
|
// Context-specific tips
|
|
97
104
|
if (context.includes('changelog')) {
|
|
98
|
-
tips.push('Try using a smaller commit range or batch processing')
|
|
105
|
+
tips.push('Try using a smaller commit range or batch processing')
|
|
99
106
|
}
|
|
100
|
-
|
|
107
|
+
|
|
101
108
|
if (context.includes('mcp')) {
|
|
102
|
-
tips.push('Ensure MCP server dependencies are installed')
|
|
103
|
-
tips.push('Check MCP server configuration and permissions')
|
|
109
|
+
tips.push('Ensure MCP server dependencies are installed')
|
|
110
|
+
tips.push('Check MCP server configuration and permissions')
|
|
104
111
|
}
|
|
105
|
-
|
|
106
|
-
return tips
|
|
112
|
+
|
|
113
|
+
return tips
|
|
107
114
|
}
|
|
108
115
|
|
|
109
116
|
/**
|
|
@@ -112,54 +119,56 @@ function getContextualTips(error, context) {
|
|
|
112
119
|
* @param {Object} options - Handler options
|
|
113
120
|
*/
|
|
114
121
|
export function setupProcessErrorHandlers(appName = 'Application', options = {}) {
|
|
115
|
-
const { gracefulShutdown = true, logErrors = true, showStack = false } = options
|
|
116
|
-
|
|
122
|
+
const { gracefulShutdown = true, logErrors = true, showStack = false } = options
|
|
123
|
+
|
|
117
124
|
process.on('uncaughtException', (error) => {
|
|
118
125
|
if (logErrors) {
|
|
119
|
-
console.error(colors.errorMessage(`💥 Uncaught Exception in ${appName}:`), error.message)
|
|
126
|
+
console.error(colors.errorMessage(`💥 Uncaught Exception in ${appName}:`), error.message)
|
|
120
127
|
if (showStack) {
|
|
121
|
-
console.error(colors.gray('Stack trace:'), error.stack)
|
|
128
|
+
console.error(colors.gray('Stack trace:'), error.stack)
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
|
-
|
|
125
|
-
const
|
|
131
|
+
|
|
132
|
+
const _errorContext = new ErrorContext()
|
|
126
133
|
.add('type', 'uncaughtException')
|
|
127
134
|
.add('appName', appName)
|
|
128
|
-
.build()
|
|
129
|
-
|
|
130
|
-
handleCLIError(error, 'handle uncaught exception', {
|
|
131
|
-
exitOnError: true,
|
|
135
|
+
.build()
|
|
136
|
+
|
|
137
|
+
handleCLIError(error, 'handle uncaught exception', {
|
|
138
|
+
exitOnError: true,
|
|
132
139
|
showTips: true,
|
|
133
|
-
showStack
|
|
134
|
-
})
|
|
135
|
-
})
|
|
140
|
+
showStack,
|
|
141
|
+
})
|
|
142
|
+
})
|
|
136
143
|
|
|
137
144
|
process.on('unhandledRejection', (reason, promise) => {
|
|
138
145
|
if (logErrors) {
|
|
139
|
-
console.error(colors.errorMessage(`💥 Unhandled Rejection in ${appName}:`))
|
|
140
|
-
console.error('Promise:', promise)
|
|
141
|
-
console.error('Reason:', reason)
|
|
146
|
+
console.error(colors.errorMessage(`💥 Unhandled Rejection in ${appName}:`))
|
|
147
|
+
console.error('Promise:', promise)
|
|
148
|
+
console.error('Reason:', reason)
|
|
142
149
|
}
|
|
143
|
-
|
|
144
|
-
const error = reason instanceof Error ? reason : new Error(String(reason))
|
|
145
|
-
handleCLIError(error, 'handle unhandled promise rejection', {
|
|
146
|
-
exitOnError: true,
|
|
150
|
+
|
|
151
|
+
const error = reason instanceof Error ? reason : new Error(String(reason))
|
|
152
|
+
handleCLIError(error, 'handle unhandled promise rejection', {
|
|
153
|
+
exitOnError: true,
|
|
147
154
|
showTips: true,
|
|
148
|
-
showStack
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
155
|
+
showStack,
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
152
159
|
if (gracefulShutdown) {
|
|
153
160
|
// Graceful shutdown handling
|
|
154
161
|
process.on('SIGINT', () => {
|
|
155
|
-
console.log(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
console.log(
|
|
163
|
+
colors.infoMessage(`\n👋 ${appName} interrupted by user. Shutting down gracefully...`)
|
|
164
|
+
)
|
|
165
|
+
process.exit(0)
|
|
166
|
+
})
|
|
167
|
+
|
|
159
168
|
process.on('SIGTERM', () => {
|
|
160
|
-
console.log(colors.infoMessage(`\n👋 ${appName} terminated. Shutting down gracefully...`))
|
|
161
|
-
process.exit(0)
|
|
162
|
-
})
|
|
169
|
+
console.log(colors.infoMessage(`\n👋 ${appName} terminated. Shutting down gracefully...`))
|
|
170
|
+
process.exit(0)
|
|
171
|
+
})
|
|
163
172
|
}
|
|
164
173
|
}
|
|
165
174
|
|
|
@@ -171,99 +180,98 @@ export function setupProcessErrorHandlers(appName = 'Application', options = {})
|
|
|
171
180
|
* @param {Object} options - Application options
|
|
172
181
|
*/
|
|
173
182
|
export async function runCLIApplication(appName, version, initFn, options = {}) {
|
|
174
|
-
const {
|
|
175
|
-
showStartupMessage = true,
|
|
183
|
+
const {
|
|
184
|
+
showStartupMessage = true,
|
|
176
185
|
setupErrorHandlers = true,
|
|
177
186
|
debugMode = process.env.DEBUG === 'true',
|
|
178
187
|
showTips = true,
|
|
179
188
|
validateGit = false,
|
|
180
189
|
requiredEnvVars = [],
|
|
181
|
-
startupTips = []
|
|
182
|
-
} = options
|
|
183
|
-
|
|
190
|
+
startupTips = [],
|
|
191
|
+
} = options
|
|
192
|
+
|
|
184
193
|
if (setupErrorHandlers) {
|
|
185
|
-
setupProcessErrorHandlers(appName, {
|
|
186
|
-
gracefulShutdown: true,
|
|
187
|
-
logErrors: true,
|
|
188
|
-
showStack: debugMode
|
|
189
|
-
})
|
|
194
|
+
setupProcessErrorHandlers(appName, {
|
|
195
|
+
gracefulShutdown: true,
|
|
196
|
+
logErrors: true,
|
|
197
|
+
showStack: debugMode,
|
|
198
|
+
})
|
|
190
199
|
}
|
|
191
|
-
|
|
200
|
+
|
|
192
201
|
if (showStartupMessage) {
|
|
193
|
-
displayStartupMessage(appName, version, { debugMode })
|
|
202
|
+
displayStartupMessage(appName, version, { debugMode })
|
|
194
203
|
}
|
|
195
|
-
|
|
204
|
+
|
|
196
205
|
// Pre-flight checks
|
|
197
206
|
if (validateGit && !validateGitRepository()) {
|
|
198
|
-
console.error(colors.errorMessage('❌ Not in a git repository'))
|
|
199
|
-
console.error(colors.infoMessage('💡 Tip: Navigate to a git repository or run `git init`'))
|
|
200
|
-
process.exit(1)
|
|
207
|
+
console.error(colors.errorMessage('❌ Not in a git repository'))
|
|
208
|
+
console.error(colors.infoMessage('💡 Tip: Navigate to a git repository or run `git init`'))
|
|
209
|
+
process.exit(1)
|
|
201
210
|
}
|
|
202
|
-
|
|
211
|
+
|
|
203
212
|
if (requiredEnvVars.length > 0 && !validateEnvironment(requiredEnvVars)) {
|
|
204
|
-
process.exit(1)
|
|
213
|
+
process.exit(1)
|
|
205
214
|
}
|
|
206
|
-
|
|
215
|
+
|
|
207
216
|
if (showTips && startupTips.length > 0) {
|
|
208
|
-
showStartupTips(appName, startupTips)
|
|
217
|
+
showStartupTips(appName, startupTips)
|
|
209
218
|
}
|
|
210
|
-
|
|
219
|
+
|
|
211
220
|
try {
|
|
212
|
-
await initFn()
|
|
221
|
+
await initFn()
|
|
213
222
|
} catch (error) {
|
|
214
|
-
handleCLIError(error, `start ${appName}`, {
|
|
215
|
-
exitOnError: true,
|
|
223
|
+
handleCLIError(error, `start ${appName}`, {
|
|
224
|
+
exitOnError: true,
|
|
216
225
|
showTips: true,
|
|
217
|
-
showStack: debugMode
|
|
218
|
-
})
|
|
226
|
+
showStack: debugMode,
|
|
227
|
+
})
|
|
219
228
|
}
|
|
220
229
|
}
|
|
221
230
|
|
|
222
231
|
/**
|
|
223
232
|
* Enhanced MCP Server startup wrapper
|
|
224
233
|
* @param {string} serverName - Name of the MCP server
|
|
225
|
-
* @param {string} version - Version string
|
|
234
|
+
* @param {string} version - Version string
|
|
226
235
|
* @param {Function} serverClass - MCP Server class constructor
|
|
227
236
|
* @param {Object} options - Server options
|
|
228
237
|
*/
|
|
229
238
|
export async function runMCPServer(serverName, version, serverClass, options = {}) {
|
|
230
|
-
const {
|
|
239
|
+
const {
|
|
231
240
|
debugMode = process.env.DEBUG === 'true',
|
|
232
241
|
showTools = true,
|
|
233
242
|
tools = [],
|
|
234
243
|
showCapabilities = true,
|
|
235
|
-
capabilities = []
|
|
236
|
-
} = options
|
|
237
|
-
|
|
238
|
-
displayStartupMessage(serverName, version, {
|
|
244
|
+
capabilities = [],
|
|
245
|
+
} = options
|
|
246
|
+
|
|
247
|
+
displayStartupMessage(serverName, version, {
|
|
239
248
|
type: 'MCP Server',
|
|
240
|
-
debugMode
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
console.log(colors.processingMessage('🔌 Starting MCP server...'))
|
|
244
|
-
|
|
249
|
+
debugMode,
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
console.log(colors.processingMessage('🔌 Starting MCP server...'))
|
|
253
|
+
|
|
245
254
|
if (showTools && tools.length > 0) {
|
|
246
|
-
console.log(colors.infoMessage(`🎯 Available tools: ${tools.join(', ')}`))
|
|
255
|
+
console.log(colors.infoMessage(`🎯 Available tools: ${tools.join(', ')}`))
|
|
247
256
|
}
|
|
248
|
-
|
|
257
|
+
|
|
249
258
|
if (showCapabilities && capabilities.length > 0) {
|
|
250
|
-
console.log(colors.infoMessage(`⚡ Capabilities: ${capabilities.join(', ')}`))
|
|
259
|
+
console.log(colors.infoMessage(`⚡ Capabilities: ${capabilities.join(', ')}`))
|
|
251
260
|
}
|
|
252
|
-
|
|
261
|
+
|
|
253
262
|
try {
|
|
254
|
-
console.log(colors.processingMessage('✅ MCP server initializing...'))
|
|
255
|
-
|
|
256
|
-
const server = new serverClass()
|
|
257
|
-
await server.run()
|
|
258
|
-
|
|
259
|
-
console.log(colors.successMessage('🚀 MCP server started successfully'))
|
|
260
|
-
|
|
263
|
+
console.log(colors.processingMessage('✅ MCP server initializing...'))
|
|
264
|
+
|
|
265
|
+
const server = new serverClass()
|
|
266
|
+
await server.run()
|
|
267
|
+
|
|
268
|
+
console.log(colors.successMessage('🚀 MCP server started successfully'))
|
|
261
269
|
} catch (error) {
|
|
262
270
|
handleCLIError(error, 'initialize MCP server', {
|
|
263
271
|
exitOnError: true,
|
|
264
272
|
showTips: true,
|
|
265
|
-
showStack: debugMode
|
|
266
|
-
})
|
|
273
|
+
showStack: debugMode,
|
|
274
|
+
})
|
|
267
275
|
}
|
|
268
276
|
}
|
|
269
277
|
|
|
@@ -274,19 +282,19 @@ export async function runMCPServer(serverName, version, serverClass, options = {
|
|
|
274
282
|
* @param {Object} options - Display options
|
|
275
283
|
*/
|
|
276
284
|
function displayStartupMessage(name, version, options = {}) {
|
|
277
|
-
const { type = 'CLI Tool', debugMode = false } = options
|
|
278
|
-
|
|
279
|
-
console.log(colors.header(`🤖 ${name}`))
|
|
280
|
-
console.log(colors.label(`📦 Version: ${colors.highlight(version)}`))
|
|
281
|
-
console.log(colors.label(`🏷️ Type: ${colors.value(type)}`))
|
|
282
|
-
|
|
285
|
+
const { type = 'CLI Tool', debugMode = false } = options
|
|
286
|
+
|
|
287
|
+
console.log(colors.header(`🤖 ${name}`))
|
|
288
|
+
console.log(colors.label(`📦 Version: ${colors.highlight(version)}`))
|
|
289
|
+
console.log(colors.label(`🏷️ Type: ${colors.value(type)}`))
|
|
290
|
+
|
|
283
291
|
if (debugMode) {
|
|
284
|
-
console.log(colors.warningMessage('🐛 Debug mode enabled'))
|
|
285
|
-
console.log(colors.label(`📁 Working directory: ${colors.path(process.cwd())}`))
|
|
286
|
-
console.log(colors.label(`⚙️ Node.js: ${colors.highlight(process.version)}`))
|
|
287
|
-
console.log(colors.label(`🖥️ Platform: ${colors.value(process.platform)} ${process.arch}`))
|
|
292
|
+
console.log(colors.warningMessage('🐛 Debug mode enabled'))
|
|
293
|
+
console.log(colors.label(`📁 Working directory: ${colors.path(process.cwd())}`))
|
|
294
|
+
console.log(colors.label(`⚙️ Node.js: ${colors.highlight(process.version)}`))
|
|
295
|
+
console.log(colors.label(`🖥️ Platform: ${colors.value(process.platform)} ${process.arch}`))
|
|
288
296
|
}
|
|
289
|
-
console.log('')
|
|
297
|
+
console.log('')
|
|
290
298
|
}
|
|
291
299
|
|
|
292
300
|
/**
|
|
@@ -297,28 +305,28 @@ function displayStartupMessage(name, version, options = {}) {
|
|
|
297
305
|
* @returns {boolean} Whether all required arguments are present
|
|
298
306
|
*/
|
|
299
307
|
export function validateRequiredArgs(requiredArgs, argv, options = {}) {
|
|
300
|
-
const { showUsage = true } = options
|
|
301
|
-
const missing = requiredArgs.filter(arg => !argv[arg])
|
|
302
|
-
|
|
308
|
+
const { showUsage = true } = options
|
|
309
|
+
const missing = requiredArgs.filter((arg) => !argv[arg])
|
|
310
|
+
|
|
303
311
|
if (missing.length > 0) {
|
|
304
|
-
console.error(colors.errorMessage(`❌ Missing required arguments: ${missing.join(', ')}`))
|
|
305
|
-
|
|
312
|
+
console.error(colors.errorMessage(`❌ Missing required arguments: ${missing.join(', ')}`))
|
|
313
|
+
|
|
306
314
|
if (showUsage) {
|
|
307
|
-
console.error(colors.infoMessage('💡 Tip: Use --help to see usage information'))
|
|
308
|
-
|
|
315
|
+
console.error(colors.infoMessage('💡 Tip: Use --help to see usage information'))
|
|
316
|
+
|
|
309
317
|
// Show specific argument descriptions if available
|
|
310
|
-
missing.forEach(arg => {
|
|
311
|
-
const description = getArgumentDescription(arg)
|
|
318
|
+
missing.forEach((arg) => {
|
|
319
|
+
const description = getArgumentDescription(arg)
|
|
312
320
|
if (description) {
|
|
313
|
-
console.error(colors.gray(` --${arg}: ${description}`))
|
|
321
|
+
console.error(colors.gray(` --${arg}: ${description}`))
|
|
314
322
|
}
|
|
315
|
-
})
|
|
323
|
+
})
|
|
316
324
|
}
|
|
317
|
-
|
|
318
|
-
return false
|
|
325
|
+
|
|
326
|
+
return false
|
|
319
327
|
}
|
|
320
|
-
|
|
321
|
-
return true
|
|
328
|
+
|
|
329
|
+
return true
|
|
322
330
|
}
|
|
323
331
|
|
|
324
332
|
/**
|
|
@@ -328,15 +336,15 @@ export function validateRequiredArgs(requiredArgs, argv, options = {}) {
|
|
|
328
336
|
*/
|
|
329
337
|
function getArgumentDescription(arg) {
|
|
330
338
|
const descriptions = {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
339
|
-
return descriptions[arg] || ''
|
|
339
|
+
version: 'Version to use for changelog generation',
|
|
340
|
+
since: 'Git reference to start changelog from',
|
|
341
|
+
provider: 'AI provider to use (openai, anthropic, etc.)',
|
|
342
|
+
model: 'AI model to use for analysis',
|
|
343
|
+
output: 'Output file path for generated changelog',
|
|
344
|
+
format: 'Output format (markdown, json)',
|
|
345
|
+
config: 'Configuration file path',
|
|
346
|
+
}
|
|
347
|
+
return descriptions[arg] || ''
|
|
340
348
|
}
|
|
341
349
|
|
|
342
350
|
/**
|
|
@@ -346,27 +354,31 @@ function getArgumentDescription(arg) {
|
|
|
346
354
|
* @returns {boolean} Whether all required environment variables are set
|
|
347
355
|
*/
|
|
348
356
|
export function validateEnvironment(requiredEnvVars = [], options = {}) {
|
|
349
|
-
const { showExamples = true } = options
|
|
350
|
-
const missing = requiredEnvVars.filter(envVar => !process.env[envVar])
|
|
351
|
-
|
|
357
|
+
const { showExamples = true } = options
|
|
358
|
+
const missing = requiredEnvVars.filter((envVar) => !process.env[envVar])
|
|
359
|
+
|
|
352
360
|
if (missing.length > 0) {
|
|
353
|
-
console.error(
|
|
354
|
-
|
|
355
|
-
|
|
361
|
+
console.error(
|
|
362
|
+
colors.errorMessage(`❌ Missing required environment variables: ${missing.join(', ')}`)
|
|
363
|
+
)
|
|
364
|
+
console.error(
|
|
365
|
+
colors.infoMessage('💡 Tip: Check your .env.local file or environment configuration')
|
|
366
|
+
)
|
|
367
|
+
|
|
356
368
|
if (showExamples) {
|
|
357
|
-
console.error(colors.gray('\nExample .env.local configuration:'))
|
|
358
|
-
missing.forEach(envVar => {
|
|
359
|
-
const example = getEnvVarExample(envVar)
|
|
369
|
+
console.error(colors.gray('\nExample .env.local configuration:'))
|
|
370
|
+
missing.forEach((envVar) => {
|
|
371
|
+
const example = getEnvVarExample(envVar)
|
|
360
372
|
if (example) {
|
|
361
|
-
console.error(colors.gray(`${envVar}=${example}`))
|
|
373
|
+
console.error(colors.gray(`${envVar}=${example}`))
|
|
362
374
|
}
|
|
363
|
-
})
|
|
375
|
+
})
|
|
364
376
|
}
|
|
365
|
-
|
|
366
|
-
return false
|
|
377
|
+
|
|
378
|
+
return false
|
|
367
379
|
}
|
|
368
|
-
|
|
369
|
-
return true
|
|
380
|
+
|
|
381
|
+
return true
|
|
370
382
|
}
|
|
371
383
|
|
|
372
384
|
/**
|
|
@@ -376,16 +388,16 @@ export function validateEnvironment(requiredEnvVars = [], options = {}) {
|
|
|
376
388
|
*/
|
|
377
389
|
function getEnvVarExample(envVar) {
|
|
378
390
|
const examples = {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
}
|
|
388
|
-
return examples[envVar] || 'your-value-here'
|
|
391
|
+
OPENAI_API_KEY: 'sk-...',
|
|
392
|
+
ANTHROPIC_API_KEY: 'sk-ant-...',
|
|
393
|
+
AZURE_OPENAI_API_KEY: 'your-azure-key',
|
|
394
|
+
AZURE_OPENAI_ENDPOINT: 'https://your-resource.openai.azure.com/',
|
|
395
|
+
GOOGLE_AI_API_KEY: 'your-google-ai-key',
|
|
396
|
+
HUGGINGFACE_API_KEY: 'hf_...',
|
|
397
|
+
DATABASE_URL: 'postgresql://user:pass@localhost:5432/db',
|
|
398
|
+
DEBUG: 'true',
|
|
399
|
+
}
|
|
400
|
+
return examples[envVar] || 'your-value-here'
|
|
389
401
|
}
|
|
390
402
|
|
|
391
403
|
/**
|
|
@@ -395,35 +407,34 @@ function getEnvVarExample(envVar) {
|
|
|
395
407
|
* @returns {Object} Validation result with details
|
|
396
408
|
*/
|
|
397
409
|
export function validateGitRepository(pathToCheck = process.cwd(), options = {}) {
|
|
398
|
-
const { checkCommits = false, showDetails = false } = options
|
|
399
|
-
|
|
410
|
+
const { checkCommits = false, showDetails = false } = options
|
|
411
|
+
|
|
400
412
|
try {
|
|
401
|
-
const gitPath = path.join(pathToCheck, '.git')
|
|
402
|
-
const isGitRepo = fs.existsSync(gitPath)
|
|
403
|
-
|
|
413
|
+
const gitPath = path.join(pathToCheck, '.git')
|
|
414
|
+
const isGitRepo = fs.existsSync(gitPath)
|
|
415
|
+
|
|
404
416
|
if (!isGitRepo) {
|
|
405
|
-
return { valid: false, reason: 'not_git_repository' }
|
|
417
|
+
return { valid: false, reason: 'not_git_repository' }
|
|
406
418
|
}
|
|
407
|
-
|
|
408
|
-
const result = { valid: true, path: pathToCheck }
|
|
409
|
-
|
|
419
|
+
|
|
420
|
+
const result = { valid: true, path: pathToCheck }
|
|
421
|
+
|
|
410
422
|
if (checkCommits) {
|
|
411
423
|
// Git validation requires command execution
|
|
412
|
-
result.hasCommits = true
|
|
424
|
+
result.hasCommits = true // Assume true for basic validation
|
|
413
425
|
}
|
|
414
|
-
|
|
426
|
+
|
|
415
427
|
if (showDetails) {
|
|
416
|
-
console.log(colors.successMessage(`✅ Valid git repository: ${pathToCheck}`))
|
|
428
|
+
console.log(colors.successMessage(`✅ Valid git repository: ${pathToCheck}`))
|
|
417
429
|
}
|
|
418
|
-
|
|
419
|
-
return result
|
|
420
|
-
|
|
430
|
+
|
|
431
|
+
return result
|
|
421
432
|
} catch (error) {
|
|
422
|
-
return {
|
|
423
|
-
valid: false,
|
|
424
|
-
reason: 'access_error',
|
|
425
|
-
error: error.message
|
|
426
|
-
}
|
|
433
|
+
return {
|
|
434
|
+
valid: false,
|
|
435
|
+
reason: 'access_error',
|
|
436
|
+
error: error.message,
|
|
437
|
+
}
|
|
427
438
|
}
|
|
428
439
|
}
|
|
429
440
|
|
|
@@ -433,13 +444,15 @@ export function validateGitRepository(pathToCheck = process.cwd(), options = {})
|
|
|
433
444
|
* @param {Array} tips - Array of tip strings to display
|
|
434
445
|
*/
|
|
435
446
|
export function showStartupTips(appName, tips = []) {
|
|
436
|
-
if (tips.length === 0)
|
|
437
|
-
|
|
438
|
-
|
|
447
|
+
if (tips.length === 0) {
|
|
448
|
+
return
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
console.log(colors.header(`💡 ${appName} Tips:`))
|
|
439
452
|
tips.forEach((tip, index) => {
|
|
440
|
-
console.log(colors.infoMessage(` ${index + 1}. ${tip}`))
|
|
441
|
-
})
|
|
442
|
-
console.log('')
|
|
453
|
+
console.log(colors.infoMessage(` ${index + 1}. ${tip}`))
|
|
454
|
+
})
|
|
455
|
+
console.log('')
|
|
443
456
|
}
|
|
444
457
|
|
|
445
458
|
/**
|
|
@@ -449,25 +462,25 @@ export function showStartupTips(appName, tips = []) {
|
|
|
449
462
|
* @param {Object} additional - Additional version info
|
|
450
463
|
*/
|
|
451
464
|
export function displayVersionInfo(name, version, additional = {}) {
|
|
452
|
-
console.log(colors.header(`${name} v${version}`))
|
|
453
|
-
|
|
465
|
+
console.log(colors.header(`${name} v${version}`))
|
|
466
|
+
|
|
454
467
|
if (additional.nodeVersion !== false) {
|
|
455
|
-
console.log(colors.label(`Node.js: ${colors.highlight(process.version)}`))
|
|
468
|
+
console.log(colors.label(`Node.js: ${colors.highlight(process.version)}`))
|
|
456
469
|
}
|
|
457
|
-
|
|
470
|
+
|
|
458
471
|
if (additional.platform !== false) {
|
|
459
|
-
console.log(colors.label(`Platform: ${colors.value(process.platform)} ${process.arch}`))
|
|
472
|
+
console.log(colors.label(`Platform: ${colors.value(process.platform)} ${process.arch}`))
|
|
460
473
|
}
|
|
461
|
-
|
|
474
|
+
|
|
462
475
|
if (additional.gitVersion && additional.gitVersion !== false) {
|
|
463
|
-
console.log(colors.label(`Git: ${colors.highlight(additional.gitVersion || 'Available')}`))
|
|
476
|
+
console.log(colors.label(`Git: ${colors.highlight(additional.gitVersion || 'Available')}`))
|
|
464
477
|
}
|
|
465
|
-
|
|
478
|
+
|
|
466
479
|
Object.entries(additional).forEach(([key, value]) => {
|
|
467
480
|
if (typeof value === 'string' && !['nodeVersion', 'platform', 'gitVersion'].includes(key)) {
|
|
468
|
-
console.log(colors.label(`${key}: ${colors.value(value)}`))
|
|
481
|
+
console.log(colors.label(`${key}: ${colors.value(value)}`))
|
|
469
482
|
}
|
|
470
|
-
})
|
|
483
|
+
})
|
|
471
484
|
}
|
|
472
485
|
|
|
473
486
|
/**
|
|
@@ -480,8 +493,8 @@ export function getDefaultStartupTips() {
|
|
|
480
493
|
'Use --help to see all available commands and options',
|
|
481
494
|
'Run in a git repository with existing commits for best results',
|
|
482
495
|
'Try --analysis-mode detailed for comprehensive changelog generation',
|
|
483
|
-
'Use --interactive for guided changelog creation'
|
|
484
|
-
]
|
|
496
|
+
'Use --interactive for guided changelog creation',
|
|
497
|
+
]
|
|
485
498
|
}
|
|
486
499
|
|
|
487
500
|
/**
|
|
@@ -490,36 +503,31 @@ export function getDefaultStartupTips() {
|
|
|
490
503
|
* @returns {Object} Validation result
|
|
491
504
|
*/
|
|
492
505
|
export function validateCLIPreconditions(requirements = {}) {
|
|
493
|
-
const {
|
|
494
|
-
|
|
495
|
-
envVars = [],
|
|
496
|
-
args = [],
|
|
497
|
-
argv = {}
|
|
498
|
-
} = requirements;
|
|
499
|
-
|
|
506
|
+
const { gitRepository = false, envVars = [], args = [], argv = {} } = requirements
|
|
507
|
+
|
|
500
508
|
const results = {
|
|
501
509
|
valid: true,
|
|
502
510
|
errors: [],
|
|
503
|
-
warnings: []
|
|
504
|
-
}
|
|
505
|
-
|
|
511
|
+
warnings: [],
|
|
512
|
+
}
|
|
513
|
+
|
|
506
514
|
if (gitRepository) {
|
|
507
|
-
const gitResult = validateGitRepository()
|
|
515
|
+
const gitResult = validateGitRepository()
|
|
508
516
|
if (!gitResult.valid) {
|
|
509
|
-
results.valid = false
|
|
510
|
-
results.errors.push('Not in a git repository')
|
|
517
|
+
results.valid = false
|
|
518
|
+
results.errors.push('Not in a git repository')
|
|
511
519
|
}
|
|
512
520
|
}
|
|
513
|
-
|
|
521
|
+
|
|
514
522
|
if (envVars.length > 0 && !validateEnvironment(envVars, { showExamples: false })) {
|
|
515
|
-
results.valid = false
|
|
516
|
-
results.errors.push('Missing required environment variables')
|
|
523
|
+
results.valid = false
|
|
524
|
+
results.errors.push('Missing required environment variables')
|
|
517
525
|
}
|
|
518
|
-
|
|
526
|
+
|
|
519
527
|
if (args.length > 0 && !validateRequiredArgs(args, argv, { showUsage: false })) {
|
|
520
|
-
results.valid = false
|
|
521
|
-
results.errors.push('Missing required arguments')
|
|
528
|
+
results.valid = false
|
|
529
|
+
results.errors.push('Missing required arguments')
|
|
522
530
|
}
|
|
523
|
-
|
|
524
|
-
return results
|
|
525
|
-
}
|
|
531
|
+
|
|
532
|
+
return results
|
|
533
|
+
}
|