@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
|
@@ -1,191 +1,297 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import {
|
|
1
|
+
import { access } from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
|
|
5
|
+
import { hideBin } from 'yargs/helpers'
|
|
6
|
+
import yargs from 'yargs/yargs'
|
|
7
|
+
|
|
8
|
+
import { ApplicationService } from '../../application/services/application.service.js'
|
|
9
|
+
import colors from '../../shared/constants/colors.js'
|
|
10
|
+
import { handleCLIError, setupProcessErrorHandlers } from '../../shared/utils/cli-entry-utils.js'
|
|
11
|
+
import { EnhancedConsole } from '../../shared/utils/cli-ui.js'
|
|
12
|
+
import { formatDuration, promptForConfig } from '../../shared/utils/utils.js'
|
|
9
13
|
|
|
10
14
|
export class CLIController {
|
|
11
15
|
constructor() {
|
|
12
|
-
this.commands = new Map()
|
|
13
|
-
this.appService = null
|
|
14
|
-
this.startTime = Date.now()
|
|
16
|
+
this.commands = new Map()
|
|
17
|
+
this.appService = null
|
|
18
|
+
this.startTime = Date.now()
|
|
15
19
|
|
|
16
20
|
// Setup enhanced error handling
|
|
17
21
|
setupProcessErrorHandlers('AI Changelog Generator', {
|
|
18
22
|
gracefulShutdown: true,
|
|
19
23
|
logErrors: true,
|
|
20
|
-
showStack: process.env.DEBUG === 'true'
|
|
21
|
-
})
|
|
24
|
+
showStack: process.env.DEBUG === 'true',
|
|
25
|
+
})
|
|
22
26
|
|
|
23
|
-
this.registerCommands()
|
|
27
|
+
this.registerCommands()
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
registerCommands() {
|
|
27
31
|
// Register all available commands
|
|
28
|
-
this.commands.set('default', new DefaultCommand())
|
|
29
|
-
this.commands.set('init', new InitCommand())
|
|
30
|
-
this.commands.set('validate', new ValidateCommand())
|
|
31
|
-
this.commands.set('analyze', new AnalyzeCommand())
|
|
32
|
-
this.commands.set('analyze-commits', new AnalyzeCommitsCommand())
|
|
33
|
-
this.commands.set('git-info', new GitInfoCommand())
|
|
34
|
-
this.commands.set('health', new HealthCommand())
|
|
35
|
-
this.commands.set('branches', new BranchesCommand())
|
|
36
|
-
this.commands.set('comprehensive', new ComprehensiveCommand())
|
|
37
|
-
this.commands.set('untracked', new UntrackedCommand())
|
|
38
|
-
this.commands.set('working-dir', new WorkingDirCommand())
|
|
39
|
-
this.commands.set('from-commits', new FromCommitsCommand())
|
|
40
|
-
this.commands.set('commit-message', new CommitMessageCommand())
|
|
41
|
-
this.commands.set('
|
|
32
|
+
this.commands.set('default', new DefaultCommand())
|
|
33
|
+
this.commands.set('init', new InitCommand())
|
|
34
|
+
this.commands.set('validate', new ValidateCommand())
|
|
35
|
+
this.commands.set('analyze', new AnalyzeCommand())
|
|
36
|
+
this.commands.set('analyze-commits', new AnalyzeCommitsCommand())
|
|
37
|
+
this.commands.set('git-info', new GitInfoCommand())
|
|
38
|
+
this.commands.set('health', new HealthCommand())
|
|
39
|
+
this.commands.set('branches', new BranchesCommand())
|
|
40
|
+
this.commands.set('comprehensive', new ComprehensiveCommand())
|
|
41
|
+
this.commands.set('untracked', new UntrackedCommand())
|
|
42
|
+
this.commands.set('working-dir', new WorkingDirCommand())
|
|
43
|
+
this.commands.set('from-commits', new FromCommitsCommand())
|
|
44
|
+
this.commands.set('commit-message', new CommitMessageCommand())
|
|
45
|
+
this.commands.set('commit', new CommitCommand())
|
|
46
|
+
this.commands.set('providers', new ProvidersCommand())
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
async runCLI() {
|
|
45
50
|
try {
|
|
46
51
|
// Ensure config exists
|
|
47
|
-
await this.ensureConfig()
|
|
52
|
+
await this.ensureConfig()
|
|
48
53
|
|
|
49
|
-
const argv = await this.setupYargs()
|
|
54
|
+
const argv = await this.setupYargs()
|
|
50
55
|
|
|
51
56
|
// Initialize application service with CLI options
|
|
52
57
|
this.appService = new ApplicationService({
|
|
53
58
|
dryRun: argv.dryRun,
|
|
54
59
|
noColor: argv.noColor,
|
|
55
|
-
silent: argv.silent
|
|
56
|
-
})
|
|
60
|
+
silent: argv.silent,
|
|
61
|
+
})
|
|
57
62
|
|
|
58
63
|
// Execute command
|
|
59
|
-
const commandName = argv._[0] || 'default'
|
|
60
|
-
const command = this.commands.get(commandName)
|
|
64
|
+
const commandName = argv._[0] || 'default'
|
|
65
|
+
const command = this.commands.get(commandName)
|
|
61
66
|
|
|
62
67
|
if (!command) {
|
|
63
|
-
throw new Error(`Unknown command: ${commandName}`)
|
|
68
|
+
throw new Error(`Unknown command: ${commandName}`)
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
await command.execute(argv, this.appService)
|
|
71
|
+
await command.execute(argv, this.appService)
|
|
67
72
|
|
|
68
73
|
// Show completion metrics
|
|
69
|
-
await this.showMetrics()
|
|
70
|
-
|
|
74
|
+
await this.showMetrics()
|
|
71
75
|
} catch (error) {
|
|
72
76
|
handleCLIError(error, 'run CLI application', {
|
|
73
77
|
exitOnError: false,
|
|
74
78
|
showTips: true,
|
|
75
|
-
showStack: process.env.DEBUG === 'true'
|
|
76
|
-
})
|
|
77
|
-
process.exitCode = 1
|
|
79
|
+
showStack: process.env.DEBUG === 'true',
|
|
80
|
+
})
|
|
81
|
+
process.exitCode = 1
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
async ensureConfig() {
|
|
82
|
-
const configPath = path.join(process.cwd(), '.env.local')
|
|
86
|
+
const configPath = path.join(process.cwd(), '.env.local')
|
|
83
87
|
try {
|
|
84
|
-
await access(configPath)
|
|
88
|
+
await access(configPath)
|
|
85
89
|
} catch {
|
|
86
|
-
await promptForConfig()
|
|
90
|
+
await promptForConfig()
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
setupYargs() {
|
|
91
|
-
return
|
|
92
|
-
.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
95
|
+
return (
|
|
96
|
+
yargs(hideBin(process.argv))
|
|
97
|
+
.scriptName('ai-changelog')
|
|
98
|
+
.usage(
|
|
99
|
+
`${colors.header('AI Changelog Generator')} - ${colors.secondary('Automatically generate changelogs from your git commits using AI.')}\n\n${colors.header('Usage:')} $0 [command] [options]`
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
// Default command
|
|
103
|
+
.command('$0', 'Generate a changelog from git commits (default command).', (yargs) => {
|
|
104
|
+
yargs
|
|
105
|
+
.option('interactive', {
|
|
106
|
+
alias: 'i',
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
description: 'Choose commits interactively.',
|
|
109
|
+
})
|
|
110
|
+
.option('release-version', {
|
|
111
|
+
alias: 'v',
|
|
112
|
+
type: 'string',
|
|
113
|
+
description: 'Set the release version (e.g., 1.2.3).',
|
|
114
|
+
})
|
|
115
|
+
.option('since', {
|
|
116
|
+
alias: 's',
|
|
117
|
+
type: 'string',
|
|
118
|
+
description: 'Generate changelog since a specific git ref (tag/commit).',
|
|
119
|
+
})
|
|
120
|
+
.option('model', {
|
|
121
|
+
alias: 'm',
|
|
122
|
+
type: 'string',
|
|
123
|
+
description: 'Override the default model.',
|
|
124
|
+
})
|
|
125
|
+
.option('detailed', { type: 'boolean', description: 'Use detailed analysis mode.' })
|
|
126
|
+
.option('enterprise', { type: 'boolean', description: 'Use enterprise analysis mode.' })
|
|
127
|
+
.option('dry-run', {
|
|
128
|
+
type: 'boolean',
|
|
129
|
+
description: 'Preview changelog without writing to file.',
|
|
130
|
+
})
|
|
131
|
+
.option('no-attribution', {
|
|
132
|
+
type: 'boolean',
|
|
133
|
+
description: 'Disable the attribution footer.',
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
// Analysis commands
|
|
138
|
+
.command('init', 'Run interactive setup to configure the tool.')
|
|
139
|
+
.command('validate', 'Validate your configuration and connectivity.')
|
|
140
|
+
.command(
|
|
141
|
+
'analyze',
|
|
142
|
+
'Analyze current working directory changes.',
|
|
143
|
+
this.createStandardOptions
|
|
144
|
+
)
|
|
145
|
+
.command(
|
|
146
|
+
'analyze-commits <limit>',
|
|
147
|
+
'Analyze recent commits with detailed information.',
|
|
148
|
+
(yargs) => {
|
|
149
|
+
this.createStandardOptions(yargs).positional('limit', {
|
|
150
|
+
type: 'number',
|
|
151
|
+
default: 10,
|
|
152
|
+
description: 'Number of commits to analyze',
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
.command(
|
|
157
|
+
'git-info',
|
|
158
|
+
'Display comprehensive repository information and statistics.',
|
|
159
|
+
this.createStandardOptions
|
|
160
|
+
)
|
|
161
|
+
.command(
|
|
162
|
+
'health',
|
|
163
|
+
'Assess repository health and commit quality.',
|
|
164
|
+
this.createStandardOptions
|
|
165
|
+
)
|
|
166
|
+
.command(
|
|
167
|
+
'branches',
|
|
168
|
+
'Analyze all branches and unmerged commits.',
|
|
169
|
+
this.createStandardOptions
|
|
170
|
+
)
|
|
171
|
+
.command(
|
|
172
|
+
'comprehensive',
|
|
173
|
+
'Comprehensive analysis including dangling commits.',
|
|
174
|
+
this.createStandardOptions
|
|
175
|
+
)
|
|
176
|
+
.command('untracked', 'Include untracked files analysis.', this.createStandardOptions)
|
|
177
|
+
.command(
|
|
178
|
+
'working-dir',
|
|
179
|
+
'Generate changelog from working directory changes.',
|
|
180
|
+
this.createStandardOptions
|
|
181
|
+
)
|
|
182
|
+
.command(
|
|
183
|
+
'from-commits <commits...>',
|
|
184
|
+
'Generate changelog from specific commit hashes.',
|
|
185
|
+
(yargs) => {
|
|
186
|
+
yargs.positional('commits', { describe: 'Commit hashes to analyze', type: 'string' })
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
// Utility commands
|
|
191
|
+
.command('commit-message', 'Generate a commit message for current changes.')
|
|
192
|
+
.command('commit', 'Interactive commit workflow with AI-generated messages.', (yargs) => {
|
|
193
|
+
yargs
|
|
194
|
+
.option('interactive', {
|
|
195
|
+
alias: 'i',
|
|
196
|
+
type: 'boolean',
|
|
197
|
+
default: true,
|
|
198
|
+
description: 'Use interactive staging (default).',
|
|
199
|
+
})
|
|
200
|
+
.option('all', {
|
|
201
|
+
alias: 'a',
|
|
202
|
+
type: 'boolean',
|
|
203
|
+
description: 'Automatically stage all changes.',
|
|
204
|
+
})
|
|
205
|
+
.option('message', {
|
|
206
|
+
alias: 'm',
|
|
207
|
+
type: 'string',
|
|
208
|
+
description: 'Use provided commit message (skip AI generation).',
|
|
209
|
+
})
|
|
210
|
+
.option('dry-run', {
|
|
211
|
+
type: 'boolean',
|
|
212
|
+
description: 'Preview commit message without committing.',
|
|
213
|
+
})
|
|
214
|
+
.option('editor', {
|
|
215
|
+
alias: 'e',
|
|
216
|
+
type: 'boolean',
|
|
217
|
+
description: 'Open editor to review/edit commit message.',
|
|
218
|
+
})
|
|
219
|
+
.option('model', { type: 'string', description: 'Override the default AI model.' })
|
|
220
|
+
})
|
|
221
|
+
.command('providers', 'Manage AI providers.', (yargs) => {
|
|
222
|
+
yargs
|
|
223
|
+
.command('list', 'List available providers.')
|
|
224
|
+
.command('switch <provider>', 'Switch to a different provider.')
|
|
225
|
+
.command('configure [provider]', 'Configure AI provider settings.')
|
|
226
|
+
.command('validate [provider]', 'Validate provider models and capabilities.')
|
|
227
|
+
.demandCommand(1, 'Please specify a provider subcommand.')
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
// Global options
|
|
231
|
+
.option('no-color', { type: 'boolean', description: 'Disable colored output.' })
|
|
232
|
+
.option('silent', { type: 'boolean', description: 'Suppress non-essential output.' })
|
|
233
|
+
.help('h')
|
|
234
|
+
.alias('h', 'help')
|
|
235
|
+
.epilogue(
|
|
236
|
+
`For more information, visit ${colors.highlight('https://github.com/entro314-labs/ai-changelog-generator')}`
|
|
237
|
+
)
|
|
238
|
+
.demandCommand(0)
|
|
239
|
+
.strict()
|
|
240
|
+
.parse()
|
|
241
|
+
)
|
|
146
242
|
}
|
|
147
243
|
|
|
148
244
|
createStandardOptions(yargs) {
|
|
149
245
|
return yargs
|
|
150
|
-
.option('format', {
|
|
246
|
+
.option('format', {
|
|
247
|
+
alias: 'f',
|
|
248
|
+
type: 'string',
|
|
249
|
+
choices: ['markdown', 'json'],
|
|
250
|
+
default: 'markdown',
|
|
251
|
+
description: 'Output format',
|
|
252
|
+
})
|
|
151
253
|
.option('output', { alias: 'o', type: 'string', description: 'Output file path' })
|
|
152
254
|
.option('since', { type: 'string', description: 'Analyze changes since this git ref' })
|
|
153
255
|
.option('silent', { type: 'boolean', description: 'Suppress non-essential output' })
|
|
154
256
|
.option('dry-run', { type: 'boolean', description: 'Preview without writing files' })
|
|
155
257
|
.option('detailed', { type: 'boolean', description: 'Use detailed analysis mode' })
|
|
156
258
|
.option('enterprise', { type: 'boolean', description: 'Use enterprise analysis mode' })
|
|
157
|
-
.option('model', { alias: 'm', type: 'string', description: 'Override the default model' })
|
|
259
|
+
.option('model', { alias: 'm', type: 'string', description: 'Override the default model' })
|
|
158
260
|
}
|
|
159
261
|
|
|
160
262
|
async showMetrics() {
|
|
161
|
-
if (!this.appService || this.appService.options.silent)
|
|
263
|
+
if (!this.appService || this.appService.options.silent) {
|
|
264
|
+
return
|
|
265
|
+
}
|
|
162
266
|
|
|
163
|
-
const endTime = Date.now()
|
|
164
|
-
const metrics = this.appService.getMetrics()
|
|
267
|
+
const endTime = Date.now()
|
|
268
|
+
const metrics = this.appService.getMetrics()
|
|
165
269
|
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
270
|
+
const summaryData = {
|
|
271
|
+
'Total time': formatDuration(endTime - this.startTime),
|
|
272
|
+
'Commits processed': metrics.commitsProcessed || 0,
|
|
273
|
+
}
|
|
170
274
|
|
|
171
275
|
if (metrics.apiCalls > 0) {
|
|
172
|
-
|
|
173
|
-
|
|
276
|
+
summaryData['AI calls'] = metrics.apiCalls
|
|
277
|
+
summaryData['Total tokens'] = (metrics.totalTokens || 0).toLocaleString()
|
|
174
278
|
}
|
|
175
279
|
|
|
176
280
|
if (metrics.errors > 0) {
|
|
177
|
-
|
|
178
|
-
summaryLines.push(colors.error(`❌ Errors: ${metrics.errors}`));
|
|
281
|
+
summaryData.Errors = colors.error(`${metrics.errors}`)
|
|
179
282
|
}
|
|
180
283
|
|
|
181
|
-
|
|
284
|
+
EnhancedConsole.box('📊 Session Summary', colors.formatMetrics(summaryData), {
|
|
285
|
+
borderStyle: 'rounded',
|
|
286
|
+
borderColor: 'info',
|
|
287
|
+
})
|
|
182
288
|
}
|
|
183
289
|
}
|
|
184
290
|
|
|
185
291
|
// Base command class
|
|
186
292
|
class BaseCommand {
|
|
187
|
-
async execute(
|
|
188
|
-
throw new Error('Command execute method not implemented')
|
|
293
|
+
async execute(_argv, _appService) {
|
|
294
|
+
throw new Error('Command execute method not implemented')
|
|
189
295
|
}
|
|
190
296
|
|
|
191
297
|
processStandardFlags(argv, appService) {
|
|
@@ -193,58 +299,64 @@ class BaseCommand {
|
|
|
193
299
|
format: argv.format || 'markdown',
|
|
194
300
|
output: argv.output,
|
|
195
301
|
since: argv.since,
|
|
196
|
-
silent: argv.silent
|
|
197
|
-
dryRun: argv.dryRun
|
|
198
|
-
}
|
|
302
|
+
silent: argv.silent,
|
|
303
|
+
dryRun: argv.dryRun,
|
|
304
|
+
}
|
|
199
305
|
|
|
200
306
|
// Apply analysis mode
|
|
201
|
-
if (argv.detailed)
|
|
202
|
-
|
|
203
|
-
|
|
307
|
+
if (argv.detailed) {
|
|
308
|
+
appService.setAnalysisMode('detailed')
|
|
309
|
+
}
|
|
310
|
+
if (argv.enterprise) {
|
|
311
|
+
appService.setAnalysisMode('enterprise')
|
|
312
|
+
}
|
|
313
|
+
if (argv.model) {
|
|
314
|
+
appService.setModelOverride(argv.model)
|
|
315
|
+
}
|
|
204
316
|
|
|
205
|
-
return config
|
|
317
|
+
return config
|
|
206
318
|
}
|
|
207
319
|
}
|
|
208
320
|
|
|
209
321
|
// Command implementations
|
|
210
322
|
class DefaultCommand extends BaseCommand {
|
|
211
323
|
async execute(argv, appService) {
|
|
212
|
-
const
|
|
324
|
+
const _config = this.processStandardFlags(argv, appService)
|
|
213
325
|
|
|
214
326
|
if (argv.interactive) {
|
|
215
|
-
await appService.runInteractive()
|
|
327
|
+
await appService.runInteractive()
|
|
216
328
|
} else {
|
|
217
329
|
await appService.generateChangelog({
|
|
218
330
|
version: argv.releaseVersion,
|
|
219
|
-
since: argv.since
|
|
220
|
-
})
|
|
331
|
+
since: argv.since,
|
|
332
|
+
})
|
|
221
333
|
}
|
|
222
334
|
}
|
|
223
335
|
}
|
|
224
336
|
|
|
225
337
|
class InitCommand extends BaseCommand {
|
|
226
|
-
async execute(
|
|
227
|
-
await promptForConfig()
|
|
338
|
+
async execute(_argv, _appService) {
|
|
339
|
+
await promptForConfig()
|
|
228
340
|
}
|
|
229
341
|
}
|
|
230
342
|
|
|
231
343
|
class ValidateCommand extends BaseCommand {
|
|
232
|
-
async execute(
|
|
233
|
-
const validation = await appService.validateConfiguration()
|
|
344
|
+
async execute(_argv, appService) {
|
|
345
|
+
const validation = await appService.validateConfiguration()
|
|
234
346
|
|
|
235
347
|
if (validation.valid) {
|
|
236
|
-
console.log(colors.successMessage('✅ Configuration is valid'))
|
|
348
|
+
console.log(colors.successMessage('✅ Configuration is valid'))
|
|
237
349
|
} else {
|
|
238
|
-
console.log(colors.errorMessage('❌ Configuration has issues:'))
|
|
239
|
-
validation.issues.forEach(issue => {
|
|
240
|
-
console.log(` - ${issue}`)
|
|
241
|
-
})
|
|
350
|
+
console.log(colors.errorMessage('❌ Configuration has issues:'))
|
|
351
|
+
validation.issues.forEach((issue) => {
|
|
352
|
+
console.log(` - ${issue}`)
|
|
353
|
+
})
|
|
242
354
|
|
|
243
355
|
if (validation.recommendations.length > 0) {
|
|
244
|
-
console.log(colors.infoMessage('\n💡 Recommendations:'))
|
|
245
|
-
validation.recommendations.forEach(rec => {
|
|
246
|
-
console.log(` - ${rec}`)
|
|
247
|
-
})
|
|
356
|
+
console.log(colors.infoMessage('\n💡 Recommendations:'))
|
|
357
|
+
validation.recommendations.forEach((rec) => {
|
|
358
|
+
console.log(` - ${rec}`)
|
|
359
|
+
})
|
|
248
360
|
}
|
|
249
361
|
}
|
|
250
362
|
}
|
|
@@ -252,266 +364,322 @@ class ValidateCommand extends BaseCommand {
|
|
|
252
364
|
|
|
253
365
|
class AnalyzeCommand extends BaseCommand {
|
|
254
366
|
async execute(argv, appService) {
|
|
255
|
-
const
|
|
256
|
-
await appService.analyzeCurrentChanges()
|
|
367
|
+
const _config = this.processStandardFlags(argv, appService)
|
|
368
|
+
await appService.analyzeCurrentChanges()
|
|
257
369
|
}
|
|
258
370
|
}
|
|
259
371
|
|
|
260
372
|
class AnalyzeCommitsCommand extends BaseCommand {
|
|
261
373
|
async execute(argv, appService) {
|
|
262
|
-
const
|
|
263
|
-
await appService.analyzeRecentCommits(argv.limit || 10)
|
|
374
|
+
const _config = this.processStandardFlags(argv, appService)
|
|
375
|
+
await appService.analyzeRecentCommits(argv.limit || 10)
|
|
264
376
|
}
|
|
265
377
|
}
|
|
266
378
|
|
|
267
379
|
class GitInfoCommand extends BaseCommand {
|
|
268
380
|
async execute(argv, appService) {
|
|
269
|
-
const config = this.processStandardFlags(argv, appService)
|
|
270
|
-
await appService.analyzeRepository({ type: 'git-info', ...config })
|
|
381
|
+
const config = this.processStandardFlags(argv, appService)
|
|
382
|
+
await appService.analyzeRepository({ type: 'git-info', ...config })
|
|
271
383
|
}
|
|
272
384
|
}
|
|
273
385
|
|
|
274
386
|
class HealthCommand extends BaseCommand {
|
|
275
387
|
async execute(argv, appService) {
|
|
276
|
-
const config = this.processStandardFlags(argv, appService)
|
|
277
|
-
await appService.assessHealth(config)
|
|
388
|
+
const config = this.processStandardFlags(argv, appService)
|
|
389
|
+
await appService.assessHealth(config)
|
|
278
390
|
}
|
|
279
391
|
}
|
|
280
392
|
|
|
281
393
|
class BranchesCommand extends BaseCommand {
|
|
282
394
|
async execute(argv, appService) {
|
|
283
|
-
const config = this.processStandardFlags(argv, appService)
|
|
284
|
-
await appService.analyzeRepository({ type: 'branches', ...config })
|
|
395
|
+
const config = this.processStandardFlags(argv, appService)
|
|
396
|
+
await appService.analyzeRepository({ type: 'branches', ...config })
|
|
285
397
|
}
|
|
286
398
|
}
|
|
287
399
|
|
|
288
400
|
class ComprehensiveCommand extends BaseCommand {
|
|
289
401
|
async execute(argv, appService) {
|
|
290
|
-
const config = this.processStandardFlags(argv, appService)
|
|
291
|
-
await appService.analyzeRepository({ type: 'comprehensive', ...config })
|
|
402
|
+
const config = this.processStandardFlags(argv, appService)
|
|
403
|
+
await appService.analyzeRepository({ type: 'comprehensive', ...config })
|
|
292
404
|
}
|
|
293
405
|
}
|
|
294
406
|
|
|
295
407
|
class UntrackedCommand extends BaseCommand {
|
|
296
408
|
async execute(argv, appService) {
|
|
297
|
-
const config = this.processStandardFlags(argv, appService)
|
|
298
|
-
await appService.analyzeRepository({ type: 'untracked', ...config })
|
|
409
|
+
const config = this.processStandardFlags(argv, appService)
|
|
410
|
+
await appService.analyzeRepository({ type: 'untracked', ...config })
|
|
299
411
|
}
|
|
300
412
|
}
|
|
301
413
|
|
|
302
414
|
class WorkingDirCommand extends BaseCommand {
|
|
303
415
|
async execute(argv, appService) {
|
|
304
|
-
const
|
|
305
|
-
await appService.generateChangelogFromChanges(argv.releaseVersion)
|
|
416
|
+
const _config = this.processStandardFlags(argv, appService)
|
|
417
|
+
await appService.generateChangelogFromChanges(argv.releaseVersion)
|
|
306
418
|
}
|
|
307
419
|
}
|
|
308
420
|
|
|
309
421
|
class FromCommitsCommand extends BaseCommand {
|
|
310
422
|
async execute(argv, appService) {
|
|
311
|
-
const
|
|
423
|
+
const _config = this.processStandardFlags(argv, appService)
|
|
312
424
|
// Implementation would generate changelog from specific commits
|
|
313
|
-
console.log(colors.infoMessage(`Generating changelog from commits: ${argv.commits.join(', ')}`))
|
|
425
|
+
console.log(colors.infoMessage(`Generating changelog from commits: ${argv.commits.join(', ')}`))
|
|
314
426
|
}
|
|
315
427
|
}
|
|
316
428
|
|
|
317
429
|
class CommitMessageCommand extends BaseCommand {
|
|
318
|
-
async execute(
|
|
319
|
-
console.log(
|
|
430
|
+
async execute(_argv, appService) {
|
|
431
|
+
console.log(
|
|
432
|
+
colors.processingMessage('🤖 Analyzing current changes for commit message suggestions...')
|
|
433
|
+
)
|
|
320
434
|
|
|
321
435
|
try {
|
|
322
|
-
const result = await appService.generateCommitMessage()
|
|
436
|
+
const result = await appService.generateCommitMessage()
|
|
323
437
|
|
|
324
|
-
if (result
|
|
325
|
-
console.log(colors.successMessage('\n✅ Generated commit message suggestions:'))
|
|
438
|
+
if (result?.suggestions && result.suggestions.length > 0) {
|
|
439
|
+
console.log(colors.successMessage('\n✅ Generated commit message suggestions:'))
|
|
326
440
|
result.suggestions.forEach((suggestion, index) => {
|
|
327
|
-
console.log(`${colors.number(index + 1)}. ${colors.highlight(suggestion)}`)
|
|
328
|
-
})
|
|
441
|
+
console.log(`${colors.number(index + 1)}. ${colors.highlight(suggestion)}`)
|
|
442
|
+
})
|
|
329
443
|
|
|
330
444
|
if (result.context) {
|
|
331
|
-
console.log(colors.dim(`\nContext: ${result.context}`))
|
|
445
|
+
console.log(colors.dim(`\nContext: ${result.context}`))
|
|
332
446
|
}
|
|
333
447
|
} else {
|
|
334
|
-
console.log(colors.warningMessage('No commit message suggestions could be generated.'))
|
|
335
|
-
console.log(colors.infoMessage('Make sure you have uncommitted changes.'))
|
|
448
|
+
console.log(colors.warningMessage('No commit message suggestions could be generated.'))
|
|
449
|
+
console.log(colors.infoMessage('Make sure you have uncommitted changes.'))
|
|
336
450
|
}
|
|
337
451
|
} catch (error) {
|
|
338
|
-
console.error(colors.errorMessage(`Error generating commit message: ${error.message}`))
|
|
452
|
+
console.error(colors.errorMessage(`Error generating commit message: ${error.message}`))
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
class CommitCommand extends BaseCommand {
|
|
458
|
+
async execute(argv, appService) {
|
|
459
|
+
console.log(colors.processingMessage('🚀 Starting interactive commit workflow...'))
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
// Process flags and model override
|
|
463
|
+
if (argv.model) {
|
|
464
|
+
appService.setModelOverride(argv.model)
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Execute the commit workflow
|
|
468
|
+
const result = await appService.executeCommitWorkflow({
|
|
469
|
+
interactive: argv.interactive !== false, // Default to true unless explicitly false
|
|
470
|
+
stageAll: argv.all,
|
|
471
|
+
customMessage: argv.message,
|
|
472
|
+
dryRun: argv.dryRun,
|
|
473
|
+
useEditor: argv.editor,
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
if (result?.success) {
|
|
477
|
+
if (argv.dryRun) {
|
|
478
|
+
console.log(colors.successMessage('✅ Commit workflow completed (dry-run mode)'))
|
|
479
|
+
console.log(colors.highlight(`Proposed commit message:\n${result.commitMessage}`))
|
|
480
|
+
} else {
|
|
481
|
+
console.log(colors.successMessage('✅ Changes committed successfully!'))
|
|
482
|
+
console.log(colors.highlight(`Commit: ${result.commitHash}`))
|
|
483
|
+
console.log(colors.dim(`Message: ${result.commitMessage}`))
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
console.log(colors.warningMessage('Commit workflow cancelled or no changes to commit.'))
|
|
487
|
+
}
|
|
488
|
+
} catch (error) {
|
|
489
|
+
console.error(colors.errorMessage(`Commit workflow failed: ${error.message}`))
|
|
490
|
+
|
|
491
|
+
// Provide helpful suggestions based on error type
|
|
492
|
+
if (error.message.includes('No changes')) {
|
|
493
|
+
console.log(
|
|
494
|
+
colors.infoMessage('💡 Try making some changes first, then run the commit command.')
|
|
495
|
+
)
|
|
496
|
+
} else if (error.message.includes('git')) {
|
|
497
|
+
console.log(
|
|
498
|
+
colors.infoMessage(
|
|
499
|
+
'💡 Make sure you are in a git repository and git is properly configured.'
|
|
500
|
+
)
|
|
501
|
+
)
|
|
502
|
+
}
|
|
339
503
|
}
|
|
340
504
|
}
|
|
341
505
|
}
|
|
342
506
|
|
|
343
507
|
class ProvidersCommand extends BaseCommand {
|
|
344
508
|
async execute(argv, appService) {
|
|
345
|
-
const subcommand = argv._[1]
|
|
509
|
+
const subcommand = argv._[1]
|
|
346
510
|
|
|
347
511
|
switch (subcommand) {
|
|
348
512
|
case 'list':
|
|
349
|
-
await this.listProviders(appService)
|
|
350
|
-
break
|
|
513
|
+
await this.listProviders(appService)
|
|
514
|
+
break
|
|
351
515
|
case 'switch':
|
|
352
|
-
await this.switchProvider(appService, argv.provider)
|
|
353
|
-
break
|
|
516
|
+
await this.switchProvider(appService, argv.provider)
|
|
517
|
+
break
|
|
354
518
|
case 'configure':
|
|
355
|
-
await this.configureProvider(appService, argv.provider)
|
|
356
|
-
break
|
|
519
|
+
await this.configureProvider(appService, argv.provider)
|
|
520
|
+
break
|
|
357
521
|
case 'validate':
|
|
358
|
-
await this.validateProvider(appService, argv.provider)
|
|
359
|
-
break
|
|
522
|
+
await this.validateProvider(appService, argv.provider)
|
|
523
|
+
break
|
|
360
524
|
default:
|
|
361
|
-
console.log(colors.errorMessage('Unknown provider subcommand'))
|
|
362
|
-
console.log(colors.infoMessage('Available subcommands: list, switch, configure, validate'))
|
|
525
|
+
console.log(colors.errorMessage('Unknown provider subcommand'))
|
|
526
|
+
console.log(colors.infoMessage('Available subcommands: list, switch, configure, validate'))
|
|
363
527
|
}
|
|
364
528
|
}
|
|
365
529
|
|
|
366
530
|
async listProviders(appService) {
|
|
367
531
|
try {
|
|
368
|
-
const providers = await appService.listProviders()
|
|
532
|
+
const providers = await appService.listProviders()
|
|
369
533
|
|
|
370
|
-
console.log(colors.header('\n🤖 Available AI Providers:'))
|
|
534
|
+
console.log(colors.header('\n🤖 Available AI Providers:'))
|
|
371
535
|
|
|
372
|
-
providers.forEach(provider => {
|
|
373
|
-
const status = provider.available ? '✅ Available' : '⚠️ Needs configuration'
|
|
374
|
-
const activeIndicator = provider.active ? ' 🎯 (Active)' : ''
|
|
536
|
+
providers.forEach((provider) => {
|
|
537
|
+
const status = provider.available ? '✅ Available' : '⚠️ Needs configuration'
|
|
538
|
+
const activeIndicator = provider.active ? ' 🎯 (Active)' : ''
|
|
375
539
|
|
|
376
|
-
console.log(` ${colors.highlight(provider.name)} - ${status}${activeIndicator}`)
|
|
540
|
+
console.log(` ${colors.highlight(provider.name)} - ${status}${activeIndicator}`)
|
|
377
541
|
|
|
378
542
|
if (provider.capabilities && Object.keys(provider.capabilities).length > 0) {
|
|
379
543
|
const caps = Object.entries(provider.capabilities)
|
|
380
|
-
.filter(([
|
|
544
|
+
.filter(([_key, value]) => value === true)
|
|
381
545
|
.map(([key]) => key)
|
|
382
|
-
.join(', ')
|
|
546
|
+
.join(', ')
|
|
383
547
|
if (caps) {
|
|
384
|
-
console.log(` ${colors.dim(`Capabilities: ${caps}`)}`)
|
|
548
|
+
console.log(` ${colors.dim(`Capabilities: ${caps}`)}`)
|
|
385
549
|
}
|
|
386
550
|
}
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
console.log(colors.dim('\nUse "ai-changelog providers configure <provider>" to set up a provider'));
|
|
551
|
+
})
|
|
390
552
|
|
|
553
|
+
console.log(
|
|
554
|
+
colors.dim('\nUse "ai-changelog providers configure <provider>" to set up a provider')
|
|
555
|
+
)
|
|
391
556
|
} catch (error) {
|
|
392
|
-
console.error(colors.errorMessage(`Error listing providers: ${error.message}`))
|
|
557
|
+
console.error(colors.errorMessage(`Error listing providers: ${error.message}`))
|
|
393
558
|
}
|
|
394
559
|
}
|
|
395
560
|
|
|
396
561
|
async switchProvider(appService, providerName) {
|
|
397
562
|
if (!providerName) {
|
|
398
|
-
console.log(colors.errorMessage('Please specify a provider name'))
|
|
399
|
-
console.log(colors.infoMessage('Usage: ai-changelog providers switch <provider>'))
|
|
400
|
-
return
|
|
563
|
+
console.log(colors.errorMessage('Please specify a provider name'))
|
|
564
|
+
console.log(colors.infoMessage('Usage: ai-changelog providers switch <provider>'))
|
|
565
|
+
return
|
|
401
566
|
}
|
|
402
567
|
|
|
403
568
|
try {
|
|
404
|
-
const result = await appService.switchProvider(providerName)
|
|
569
|
+
const result = await appService.switchProvider(providerName)
|
|
405
570
|
|
|
406
571
|
if (result.success) {
|
|
407
|
-
console.log(colors.successMessage(`✅ Switched to ${providerName} provider`))
|
|
572
|
+
console.log(colors.successMessage(`✅ Switched to ${providerName} provider`))
|
|
408
573
|
} else {
|
|
409
|
-
console.log(colors.errorMessage(`❌ Failed to switch provider: ${result.error}`))
|
|
410
|
-
console.log(
|
|
574
|
+
console.log(colors.errorMessage(`❌ Failed to switch provider: ${result.error}`))
|
|
575
|
+
console.log(
|
|
576
|
+
colors.infoMessage('Use "ai-changelog providers list" to see available providers')
|
|
577
|
+
)
|
|
411
578
|
}
|
|
412
579
|
} catch (error) {
|
|
413
|
-
console.error(colors.errorMessage(`Error switching provider: ${error.message}`))
|
|
580
|
+
console.error(colors.errorMessage(`Error switching provider: ${error.message}`))
|
|
414
581
|
}
|
|
415
582
|
}
|
|
416
583
|
|
|
417
584
|
async configureProvider(appService, providerName) {
|
|
418
|
-
const { select } = await import('@clack/prompts')
|
|
585
|
+
const { select } = await import('@clack/prompts')
|
|
419
586
|
|
|
420
587
|
try {
|
|
421
588
|
// If no provider specified, let user choose
|
|
422
589
|
if (!providerName) {
|
|
423
|
-
const providers = await appService.listProviders()
|
|
590
|
+
const providers = await appService.listProviders()
|
|
424
591
|
|
|
425
|
-
const choices = providers.map(p => ({
|
|
592
|
+
const choices = providers.map((p) => ({
|
|
426
593
|
value: p.name,
|
|
427
|
-
label: `${p.name} ${p.available ? '✅' : '⚠️ (needs configuration)'}
|
|
428
|
-
}))
|
|
594
|
+
label: `${p.name} ${p.available ? '✅' : '⚠️ (needs configuration)'}`,
|
|
595
|
+
}))
|
|
429
596
|
|
|
430
597
|
providerName = await select({
|
|
431
598
|
message: 'Select provider to configure:',
|
|
432
|
-
options: choices
|
|
433
|
-
})
|
|
599
|
+
options: choices,
|
|
600
|
+
})
|
|
434
601
|
}
|
|
435
602
|
|
|
436
|
-
console.log(colors.header(`\n🔧 Configuring ${providerName.toUpperCase()} Provider`))
|
|
437
|
-
console.log(colors.infoMessage('Please add the following to your .env.local file:\n'))
|
|
603
|
+
console.log(colors.header(`\n🔧 Configuring ${providerName.toUpperCase()} Provider`))
|
|
604
|
+
console.log(colors.infoMessage('Please add the following to your .env.local file:\n'))
|
|
438
605
|
|
|
439
606
|
switch (providerName.toLowerCase()) {
|
|
440
607
|
case 'openai':
|
|
441
|
-
console.log(colors.code('OPENAI_API_KEY=your_openai_api_key_here'))
|
|
442
|
-
console.log(colors.dim('Get your API key from: https://platform.openai.com/api-keys'))
|
|
443
|
-
break
|
|
608
|
+
console.log(colors.code('OPENAI_API_KEY=your_openai_api_key_here'))
|
|
609
|
+
console.log(colors.dim('Get your API key from: https://platform.openai.com/api-keys'))
|
|
610
|
+
break
|
|
444
611
|
|
|
445
612
|
case 'anthropic':
|
|
446
|
-
console.log(colors.code('ANTHROPIC_API_KEY=your_anthropic_api_key_here'))
|
|
447
|
-
console.log(colors.dim('Get your API key from: https://console.anthropic.com/'))
|
|
448
|
-
break
|
|
613
|
+
console.log(colors.code('ANTHROPIC_API_KEY=your_anthropic_api_key_here'))
|
|
614
|
+
console.log(colors.dim('Get your API key from: https://console.anthropic.com/'))
|
|
615
|
+
break
|
|
449
616
|
|
|
450
617
|
case 'azure':
|
|
451
|
-
console.log(colors.code('AZURE_OPENAI_API_KEY=your_azure_api_key_here'))
|
|
452
|
-
console.log(colors.code('AZURE_OPENAI_ENDPOINT=your_azure_endpoint_here'))
|
|
453
|
-
console.log(colors.dim('Get from your Azure OpenAI resource in Azure portal'))
|
|
454
|
-
break
|
|
618
|
+
console.log(colors.code('AZURE_OPENAI_API_KEY=your_azure_api_key_here'))
|
|
619
|
+
console.log(colors.code('AZURE_OPENAI_ENDPOINT=your_azure_endpoint_here'))
|
|
620
|
+
console.log(colors.dim('Get from your Azure OpenAI resource in Azure portal'))
|
|
621
|
+
break
|
|
455
622
|
|
|
456
623
|
case 'google':
|
|
457
|
-
console.log(colors.code('GOOGLE_API_KEY=your_google_api_key_here'))
|
|
458
|
-
console.log(colors.dim('Get your API key from: https://aistudio.google.com/app/apikey'))
|
|
459
|
-
break
|
|
624
|
+
console.log(colors.code('GOOGLE_API_KEY=your_google_api_key_here'))
|
|
625
|
+
console.log(colors.dim('Get your API key from: https://aistudio.google.com/app/apikey'))
|
|
626
|
+
break
|
|
460
627
|
|
|
461
628
|
case 'ollama':
|
|
462
|
-
console.log(colors.code('OLLAMA_HOST=http://localhost:11434'))
|
|
463
|
-
console.log(colors.dim('Make sure Ollama is running: ollama serve'))
|
|
464
|
-
break
|
|
629
|
+
console.log(colors.code('OLLAMA_HOST=http://localhost:11434'))
|
|
630
|
+
console.log(colors.dim('Make sure Ollama is running: ollama serve'))
|
|
631
|
+
break
|
|
465
632
|
|
|
466
633
|
default:
|
|
467
|
-
console.log(colors.code(`${providerName.toUpperCase()}_API_KEY=your_api_key_here`))
|
|
634
|
+
console.log(colors.code(`${providerName.toUpperCase()}_API_KEY=your_api_key_here`))
|
|
468
635
|
}
|
|
469
636
|
|
|
470
|
-
console.log(colors.infoMessage('\nAfter adding the configuration, run:'))
|
|
471
|
-
console.log(colors.highlight(`ai-changelog providers validate ${providerName}`))
|
|
472
|
-
|
|
637
|
+
console.log(colors.infoMessage('\nAfter adding the configuration, run:'))
|
|
638
|
+
console.log(colors.highlight(`ai-changelog providers validate ${providerName}`))
|
|
473
639
|
} catch (error) {
|
|
474
|
-
console.error(colors.errorMessage(`Error configuring provider: ${error.message}`))
|
|
640
|
+
console.error(colors.errorMessage(`Error configuring provider: ${error.message}`))
|
|
475
641
|
}
|
|
476
642
|
}
|
|
477
643
|
|
|
478
644
|
async validateProvider(appService, providerName) {
|
|
479
645
|
try {
|
|
480
646
|
if (!providerName) {
|
|
481
|
-
console.log(colors.processingMessage('🔍 Validating all configured providers...'))
|
|
482
|
-
const result = await appService.validateAllProviders()
|
|
647
|
+
console.log(colors.processingMessage('🔍 Validating all configured providers...'))
|
|
648
|
+
const result = await appService.validateAllProviders()
|
|
483
649
|
|
|
484
|
-
console.log(colors.header('\n📊 Provider Validation Results:'))
|
|
650
|
+
console.log(colors.header('\n📊 Provider Validation Results:'))
|
|
485
651
|
|
|
486
652
|
Object.entries(result).forEach(([name, validation]) => {
|
|
487
|
-
const status = validation.success ? '✅ Valid' : '❌ Invalid'
|
|
488
|
-
console.log(` ${colors.highlight(name)}: ${status}`)
|
|
653
|
+
const status = validation.success ? '✅ Valid' : '❌ Invalid'
|
|
654
|
+
console.log(` ${colors.highlight(name)}: ${status}`)
|
|
489
655
|
|
|
490
656
|
if (!validation.success) {
|
|
491
|
-
console.log(` ${colors.errorMessage(validation.error)}`)
|
|
657
|
+
console.log(` ${colors.errorMessage(validation.error)}`)
|
|
492
658
|
}
|
|
493
|
-
})
|
|
494
|
-
|
|
659
|
+
})
|
|
495
660
|
} else {
|
|
496
|
-
console.log(colors.processingMessage(`🔍 Validating ${providerName} provider...`))
|
|
497
|
-
const result = await appService.validateProvider(providerName)
|
|
661
|
+
console.log(colors.processingMessage(`🔍 Validating ${providerName} provider...`))
|
|
662
|
+
const result = await appService.validateProvider(providerName)
|
|
498
663
|
|
|
499
664
|
if (result.success) {
|
|
500
|
-
console.log(colors.successMessage(`✅ ${providerName} provider is configured correctly`))
|
|
665
|
+
console.log(colors.successMessage(`✅ ${providerName} provider is configured correctly`))
|
|
501
666
|
if (result.model) {
|
|
502
|
-
console.log(colors.dim(` Default model: ${result.model}`))
|
|
667
|
+
console.log(colors.dim(` Default model: ${result.model}`))
|
|
503
668
|
}
|
|
504
669
|
} else {
|
|
505
|
-
console.log(colors.errorMessage(`❌ ${providerName} validation failed: ${result.error}`))
|
|
506
|
-
console.log(
|
|
670
|
+
console.log(colors.errorMessage(`❌ ${providerName} validation failed: ${result.error}`))
|
|
671
|
+
console.log(
|
|
672
|
+
colors.infoMessage(
|
|
673
|
+
`Use "ai-changelog providers configure ${providerName}" for setup instructions`
|
|
674
|
+
)
|
|
675
|
+
)
|
|
507
676
|
}
|
|
508
677
|
}
|
|
509
|
-
|
|
510
678
|
} catch (error) {
|
|
511
|
-
console.error(colors.errorMessage(`Error validating provider: ${error.message}`))
|
|
679
|
+
console.error(colors.errorMessage(`Error validating provider: ${error.message}`))
|
|
512
680
|
}
|
|
513
681
|
}
|
|
514
682
|
}
|
|
515
683
|
|
|
516
684
|
// Export the controller
|
|
517
|
-
export default CLIController
|
|
685
|
+
export default CLIController
|