@entro314labs/ai-changelog-generator 3.7.1 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/ai-changelog.js +5 -1
- package/package.json +12 -9
- package/src/application/orchestrators/changelog.orchestrator.js +16 -10
- package/src/application/services/application.service.js +36 -20
- package/src/domains/analysis/analysis.engine.js +26 -22
- package/src/domains/changelog/changelog.service.js +66 -8
- package/src/domains/git/git-manager.js +15 -7
- package/src/domains/git/git.service.js +36 -13
- package/src/infrastructure/cli/cli.controller.js +61 -42
- package/src/infrastructure/config/configuration.manager.js +6 -4
- package/src/infrastructure/interactive/interactive-workflow.service.js +119 -12
- package/src/infrastructure/mcp/mcp-server.service.js +13 -10
- package/src/infrastructure/providers/core/base-provider.js +2 -1
- package/src/infrastructure/providers/utils/model-config.js +3 -1
- package/src/infrastructure/validation/commit-message-validation.service.js +1 -1
- package/src/shared/constants/colors.js +2 -1
- package/src/shared/utils/cli-entry-utils.js +3 -1
- package/src/shared/utils/cli-ui.js +17 -14
- package/src/shared/utils/diff-processor.js +3 -13
- package/src/shared/utils/json-utils.js +6 -2
- package/src/shared/utils/utils.js +22 -10
package/bin/ai-changelog.js
CHANGED
|
@@ -9,7 +9,11 @@ import { CLIController } from '../src/infrastructure/cli/cli.controller.js'
|
|
|
9
9
|
|
|
10
10
|
// Run the CLI with new refactored architecture using proper CLI controller
|
|
11
11
|
const cliController = new CLIController()
|
|
12
|
-
cliController.runCLI().
|
|
12
|
+
cliController.runCLI().then(() => {
|
|
13
|
+
if (process.exitCode !== undefined) {
|
|
14
|
+
process.exit(process.exitCode)
|
|
15
|
+
}
|
|
16
|
+
}).catch((error) => {
|
|
13
17
|
console.error('❌ CLI Error:', error.message)
|
|
14
18
|
if (process.env.DEBUG) {
|
|
15
19
|
console.error(error.stack)
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entro314labs/ai-changelog-generator",
|
|
3
3
|
"displayName": "AI Changelog Generator",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.8.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "AI-powered changelog generator with MCP server support - works with most providers, online and local models",
|
|
7
7
|
"main": "src/ai-changelog-generator.js",
|
|
8
8
|
"types": "types/index.d.ts",
|
|
9
|
+
"workspaces": [
|
|
10
|
+
"vscode-extension"
|
|
11
|
+
],
|
|
9
12
|
"bin": {
|
|
10
13
|
"ai-changelog": "./bin/ai-changelog.js",
|
|
11
14
|
"ai-changelog-mcp": "./bin/ai-changelog-mcp.js"
|
|
@@ -23,15 +26,15 @@
|
|
|
23
26
|
],
|
|
24
27
|
"dependencies": {
|
|
25
28
|
"@anthropic-ai/sdk": "^0.71.2",
|
|
26
|
-
"@aws-sdk/client-bedrock-runtime": "^3.
|
|
29
|
+
"@aws-sdk/client-bedrock-runtime": "^3.966.0",
|
|
27
30
|
"@azure/identity": "^4.13.0",
|
|
28
31
|
"@clack/prompts": "^0.11.0",
|
|
29
|
-
"@google/genai": "^1.
|
|
32
|
+
"@google/genai": "^1.35.0",
|
|
30
33
|
"@google/generative-ai": "^0.24.1",
|
|
31
34
|
"@huggingface/hub": "^2.7.1",
|
|
32
35
|
"@huggingface/inference": "^4.13.5",
|
|
33
36
|
"@lmstudio/sdk": "^1.5.0",
|
|
34
|
-
"@modelcontextprotocol/sdk": "^1.25.
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
35
38
|
"@modelcontextprotocol/server-filesystem": "2025.12.18",
|
|
36
39
|
"boxen": "^8.0.1",
|
|
37
40
|
"chalk": "^5.6.2",
|
|
@@ -42,13 +45,13 @@
|
|
|
42
45
|
"gradient-string": "^3.0.0",
|
|
43
46
|
"js-yaml": "^4.1.1",
|
|
44
47
|
"ollama": "^0.6.3",
|
|
45
|
-
"openai": "^6.
|
|
48
|
+
"openai": "^6.16.0",
|
|
46
49
|
"ora": "^9.0.0",
|
|
47
50
|
"yargs": "^18.0.0"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
53
|
"@anthropic-ai/mcpb": "^2.1.2",
|
|
51
|
-
"@types/node": "25.0.
|
|
54
|
+
"@types/node": "25.0.5",
|
|
52
55
|
"@vitest/browser": "latest",
|
|
53
56
|
"@vitest/coverage-v8": "latest",
|
|
54
57
|
"@vitest/ui": "latest",
|
|
@@ -96,7 +99,7 @@
|
|
|
96
99
|
},
|
|
97
100
|
"engines": {
|
|
98
101
|
"node": ">=22.21.1",
|
|
99
|
-
"pnpm": ">=10.
|
|
102
|
+
"pnpm": ">=10.27.0"
|
|
100
103
|
},
|
|
101
104
|
"funding": {
|
|
102
105
|
"type": "github",
|
|
@@ -108,8 +111,8 @@
|
|
|
108
111
|
}
|
|
109
112
|
},
|
|
110
113
|
"volta": {
|
|
111
|
-
"node": "22.
|
|
112
|
-
"pnpm": "10.
|
|
114
|
+
"node": "22.21.1",
|
|
115
|
+
"pnpm": "10.27.0"
|
|
113
116
|
},
|
|
114
117
|
"scripts": {
|
|
115
118
|
"start": "node bin/ai-changelog.js",
|
|
@@ -61,7 +61,12 @@ export class ChangelogOrchestrator {
|
|
|
61
61
|
this.aiProvider = this.providerManager.getActiveProvider()
|
|
62
62
|
|
|
63
63
|
// Create proper implementations using the new classes
|
|
64
|
-
|
|
64
|
+
// Pass cwd/repositoryPath to GitManager so it runs commands in correct directory
|
|
65
|
+
const gitOptions = {}
|
|
66
|
+
if (this.options.cwd || this.options.repositoryPath) {
|
|
67
|
+
gitOptions.cwd = this.options.cwd || this.options.repositoryPath
|
|
68
|
+
}
|
|
69
|
+
this.gitManager = new GitManager(gitOptions)
|
|
65
70
|
this.tagger = new CommitTagger()
|
|
66
71
|
this.promptEngine = await this.createPromptEngine()
|
|
67
72
|
|
|
@@ -178,7 +183,11 @@ export class ChangelogOrchestrator {
|
|
|
178
183
|
if (toTag) {
|
|
179
184
|
effectiveUntil = toTag
|
|
180
185
|
}
|
|
181
|
-
console.log(
|
|
186
|
+
console.log(
|
|
187
|
+
colors.infoMessage(
|
|
188
|
+
`📦 Generating changelog between tags: ${fromTag} → ${toTag || 'HEAD'}`
|
|
189
|
+
)
|
|
190
|
+
)
|
|
182
191
|
}
|
|
183
192
|
|
|
184
193
|
// Display author filter if specified
|
|
@@ -194,7 +203,11 @@ export class ChangelogOrchestrator {
|
|
|
194
203
|
}
|
|
195
204
|
|
|
196
205
|
// Generate changelog using the service
|
|
197
|
-
const result = await this.changelogService.generateChangelog(
|
|
206
|
+
const result = await this.changelogService.generateChangelog(
|
|
207
|
+
version,
|
|
208
|
+
effectiveSince,
|
|
209
|
+
mergedOptions
|
|
210
|
+
)
|
|
198
211
|
|
|
199
212
|
if (!result) {
|
|
200
213
|
console.log(colors.warningMessage('No changelog generated'))
|
|
@@ -883,13 +896,6 @@ export class ChangelogOrchestrator {
|
|
|
883
896
|
filesStaged: true,
|
|
884
897
|
}
|
|
885
898
|
}
|
|
886
|
-
|
|
887
|
-
return {
|
|
888
|
-
success: true,
|
|
889
|
-
commitMessage,
|
|
890
|
-
stagedFiles: finalStatus.staged.length,
|
|
891
|
-
phase: 'staging-complete',
|
|
892
|
-
}
|
|
893
899
|
} catch (error) {
|
|
894
900
|
console.error(colors.errorMessage(`Commit workflow error: ${error.message}`))
|
|
895
901
|
throw error
|
|
@@ -7,49 +7,65 @@ import { ChangelogOrchestrator } from '../orchestrators/changelog.orchestrator.j
|
|
|
7
7
|
export class ApplicationService {
|
|
8
8
|
constructor(options = {}) {
|
|
9
9
|
this.options = options
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
// Normalize repositoryPath option (can be cwd or repositoryPath)
|
|
12
|
+
const repositoryPath = options.repositoryPath || options.cwd
|
|
13
|
+
if (repositoryPath) {
|
|
14
|
+
this.options.repositoryPath = repositoryPath
|
|
15
|
+
this.options.cwd = repositoryPath
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
this.configManager = new ConfigurationManager(options.configPath)
|
|
19
|
+
this.orchestrator = new ChangelogOrchestrator(this.configManager, this.options)
|
|
12
20
|
this.initialized = false
|
|
21
|
+
this.initializationError = null
|
|
13
22
|
|
|
14
23
|
// Apply options
|
|
15
24
|
if (options.noColor || process.env.NO_COLOR) {
|
|
16
25
|
colors.disable()
|
|
17
26
|
}
|
|
18
27
|
|
|
19
|
-
//
|
|
20
|
-
this.initializeAsync()
|
|
28
|
+
// Start initialization (don't await here to keep constructor sync)
|
|
29
|
+
this.initializationPromise = this.initializeAsync()
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
async initializeAsync() {
|
|
24
33
|
try {
|
|
25
|
-
// Wait for orchestrator services to be ready
|
|
26
|
-
|
|
34
|
+
// Wait for orchestrator services to be ready with timeout
|
|
35
|
+
const timeoutPromise = new Promise((_, reject) =>
|
|
36
|
+
setTimeout(() => reject(new Error('Initialization timeout after 10 seconds')), 10000)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
await Promise.race([
|
|
40
|
+
this.orchestrator.ensureInitialized(),
|
|
41
|
+
timeoutPromise
|
|
42
|
+
])
|
|
43
|
+
|
|
27
44
|
this.initialized = true
|
|
28
45
|
} catch (error) {
|
|
46
|
+
this.initializationError = error
|
|
29
47
|
console.error(
|
|
30
48
|
colors.errorMessage('Application service initialization failed:'),
|
|
31
49
|
error.message
|
|
32
50
|
)
|
|
51
|
+
// Don't throw - allow graceful degradation
|
|
33
52
|
}
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
async ensureInitialized() {
|
|
37
|
-
if (
|
|
38
|
-
|
|
56
|
+
if (this.initialized) {
|
|
57
|
+
return
|
|
39
58
|
}
|
|
40
|
-
}
|
|
41
59
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
})
|
|
52
|
-
} catch (error) {
|
|
60
|
+
if (this.initializationError) {
|
|
61
|
+
throw new Error(`Service not initialized: ${this.initializationError.message}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Wait for initialization to complete
|
|
65
|
+
await this.initializationPromise
|
|
66
|
+
|
|
67
|
+
if (this.initializationError) {
|
|
68
|
+
throw new Error(`Service initialization failed: ${this.initializationError.message}`)
|
|
53
69
|
console.error(colors.errorMessage('Application service error:'), error.message)
|
|
54
70
|
throw error
|
|
55
71
|
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
getWorkingDirectoryChanges,
|
|
14
14
|
performSemanticAnalysis,
|
|
15
15
|
} from '../../shared/utils/utils.js'
|
|
16
|
+
import { EnhancedConsole } from '../../shared/utils/cli-ui.js'
|
|
16
17
|
|
|
17
18
|
export class AnalysisEngine {
|
|
18
19
|
constructor(gitService, aiAnalysisService, gitManager = null) {
|
|
@@ -51,16 +52,17 @@ export class AnalysisEngine {
|
|
|
51
52
|
let enhancedChanges = []
|
|
52
53
|
|
|
53
54
|
try {
|
|
54
|
-
|
|
55
|
+
// Get cwd from git manager if available
|
|
56
|
+
const cwd = this.gitService?.gitManager?.options?.cwd
|
|
57
|
+
console.log(`[AnalysisEngine] analyzeCurrentChanges called with cwd: ${cwd || 'undefined'}`)
|
|
58
|
+
const changes = getWorkingDirectoryChanges(cwd)
|
|
55
59
|
|
|
56
60
|
if (changes.length === 0) {
|
|
57
|
-
|
|
61
|
+
EnhancedConsole.info('No changes detected in working directory.')
|
|
58
62
|
return { changes: [], analysis: null }
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
colors.processingMessage(`Analyzing ${changes.length} working directory changes...`)
|
|
63
|
-
)
|
|
65
|
+
EnhancedConsole.processing(`Analyzing ${changes.length} working directory changes...`)
|
|
64
66
|
|
|
65
67
|
// Enhanced file analysis with actual diff content
|
|
66
68
|
enhancedChanges = []
|
|
@@ -102,9 +104,10 @@ export class AnalysisEngine {
|
|
|
102
104
|
semanticChanges: { changeType: 'unknown', patterns: [], frameworks: [] },
|
|
103
105
|
functionalImpact: { scope: 'local', severity: 'low' },
|
|
104
106
|
})
|
|
107
|
+
|
|
105
108
|
}
|
|
106
109
|
} catch (error) {
|
|
107
|
-
|
|
110
|
+
EnhancedConsole.error(`Error processing change ${i}:`, change, error.message)
|
|
108
111
|
enhancedChanges.push({
|
|
109
112
|
...change,
|
|
110
113
|
category: 'other',
|
|
@@ -130,7 +133,7 @@ export class AnalysisEngine {
|
|
|
130
133
|
'working-directory'
|
|
131
134
|
)
|
|
132
135
|
} catch (error) {
|
|
133
|
-
|
|
136
|
+
EnhancedConsole.error('Error in AI analysis:', error.message)
|
|
134
137
|
aiAnalysis = null
|
|
135
138
|
}
|
|
136
139
|
}
|
|
@@ -140,7 +143,7 @@ export class AnalysisEngine {
|
|
|
140
143
|
try {
|
|
141
144
|
ruleBasedAnalysis = this.analyzeChangesRuleBased(enhancedChanges)
|
|
142
145
|
} catch (error) {
|
|
143
|
-
|
|
146
|
+
EnhancedConsole.error('Error in rule-based analysis:', error.message)
|
|
144
147
|
ruleBasedAnalysis = {
|
|
145
148
|
summary: 'Analysis failed',
|
|
146
149
|
category: 'other',
|
|
@@ -154,7 +157,7 @@ export class AnalysisEngine {
|
|
|
154
157
|
try {
|
|
155
158
|
finalAnalysis = this.combineAnalyses(aiAnalysis, ruleBasedAnalysis)
|
|
156
159
|
} catch (error) {
|
|
157
|
-
|
|
160
|
+
EnhancedConsole.error('Error combining analyses:', error.message)
|
|
158
161
|
finalAnalysis = {
|
|
159
162
|
summary: `${enhancedChanges.length} working directory changes detected`,
|
|
160
163
|
category: 'working-directory',
|
|
@@ -169,7 +172,7 @@ export class AnalysisEngine {
|
|
|
169
172
|
summary: generateAnalysisSummary(enhancedChanges, finalAnalysis),
|
|
170
173
|
}
|
|
171
174
|
} catch (error) {
|
|
172
|
-
|
|
175
|
+
EnhancedConsole.error('Error analyzing current changes:', error.message)
|
|
173
176
|
// Return enhanced changes if they were created before the error
|
|
174
177
|
return {
|
|
175
178
|
changes: enhancedChanges,
|
|
@@ -189,13 +192,13 @@ export class AnalysisEngine {
|
|
|
189
192
|
|
|
190
193
|
async analyzeRecentCommits(limit = 10, _config = {}) {
|
|
191
194
|
try {
|
|
192
|
-
|
|
195
|
+
EnhancedConsole.processing(`Analyzing recent ${limit} commits...`)
|
|
193
196
|
|
|
194
197
|
const commits = await this.gitService.getCommitsSince(null)
|
|
195
198
|
const recentCommits = commits.slice(0, limit)
|
|
196
199
|
|
|
197
200
|
if (recentCommits.length === 0) {
|
|
198
|
-
|
|
201
|
+
EnhancedConsole.info('No recent commits found.')
|
|
199
202
|
return { commits: [], analysis: null }
|
|
200
203
|
}
|
|
201
204
|
|
|
@@ -219,7 +222,7 @@ export class AnalysisEngine {
|
|
|
219
222
|
summary: this.generateCommitsSummary(analyzedCommits, overallAnalysis),
|
|
220
223
|
}
|
|
221
224
|
} catch (error) {
|
|
222
|
-
|
|
225
|
+
EnhancedConsole.error('Error analyzing recent commits:', error.message)
|
|
223
226
|
return { commits: [], analysis: null, error: error.message }
|
|
224
227
|
}
|
|
225
228
|
}
|
|
@@ -259,11 +262,9 @@ export class AnalysisEngine {
|
|
|
259
262
|
},
|
|
260
263
|
}
|
|
261
264
|
} catch (error) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
error.message
|
|
266
|
-
)
|
|
265
|
+
EnhancedConsole.warn(
|
|
266
|
+
`Failed to enhance analysis for commit ${commitAnalysis.hash}:`,
|
|
267
|
+
error.message
|
|
267
268
|
)
|
|
268
269
|
return commitAnalysis
|
|
269
270
|
}
|
|
@@ -552,8 +553,9 @@ export class AnalysisEngine {
|
|
|
552
553
|
totalCommits: commits.length,
|
|
553
554
|
suggestions,
|
|
554
555
|
}
|
|
556
|
+
|
|
555
557
|
} catch (error) {
|
|
556
|
-
|
|
558
|
+
EnhancedConsole.warn(`Commit pattern analysis failed: ${error.message}`)
|
|
557
559
|
return {
|
|
558
560
|
patterns: [],
|
|
559
561
|
compliance: 0,
|
|
@@ -621,8 +623,9 @@ export class AnalysisEngine {
|
|
|
621
623
|
totalChanges: changes.length,
|
|
622
624
|
details: `Detected ${detectedTypes.size} change types from ${changes.length} changes`,
|
|
623
625
|
}
|
|
626
|
+
|
|
624
627
|
} catch (error) {
|
|
625
|
-
|
|
628
|
+
EnhancedConsole.warn(`Change type detection failed: ${error.message}`)
|
|
626
629
|
return {
|
|
627
630
|
types: [],
|
|
628
631
|
confidence: 'low',
|
|
@@ -706,8 +709,9 @@ export class AnalysisEngine {
|
|
|
706
709
|
recommendations,
|
|
707
710
|
filesAnalyzed: files.length,
|
|
708
711
|
}
|
|
712
|
+
|
|
709
713
|
} catch (error) {
|
|
710
|
-
|
|
714
|
+
EnhancedConsole.warn(`Code quality assessment failed: ${error.message}`)
|
|
711
715
|
return {
|
|
712
716
|
score: 0,
|
|
713
717
|
issues: [`Assessment failed: ${error.message}`],
|
|
@@ -775,7 +779,7 @@ export class AnalysisEngine {
|
|
|
775
779
|
|
|
776
780
|
return dependencies
|
|
777
781
|
} catch (error) {
|
|
778
|
-
|
|
782
|
+
EnhancedConsole.warn(`Dependency analysis failed: ${error.message}`)
|
|
779
783
|
return {
|
|
780
784
|
added: [],
|
|
781
785
|
removed: [],
|
|
@@ -1805,11 +1805,12 @@ export class ChangelogService {
|
|
|
1805
1805
|
]
|
|
1806
1806
|
|
|
1807
1807
|
patterns.forEach((pattern) => {
|
|
1808
|
-
let match
|
|
1809
|
-
while (
|
|
1808
|
+
let match = pattern.exec(content)
|
|
1809
|
+
while (match !== null) {
|
|
1810
1810
|
if (match[1] && !functions.includes(match[1])) {
|
|
1811
1811
|
functions.push(match[1])
|
|
1812
1812
|
}
|
|
1813
|
+
match = pattern.exec(content)
|
|
1813
1814
|
}
|
|
1814
1815
|
})
|
|
1815
1816
|
|
|
@@ -2186,7 +2187,7 @@ export class ChangelogService {
|
|
|
2186
2187
|
|
|
2187
2188
|
// Add context information for detailed modes
|
|
2188
2189
|
if (options.analysisMode === 'detailed' || options.analysisMode === 'enterprise') {
|
|
2189
|
-
changelog += this.generateContextSection(result.
|
|
2190
|
+
changelog += this.generateContextSection(result.summary)
|
|
2190
2191
|
}
|
|
2191
2192
|
|
|
2192
2193
|
return {
|
|
@@ -2209,6 +2210,8 @@ export class ChangelogService {
|
|
|
2209
2210
|
// Enhanced analysis of changes with diff content for AI analysis
|
|
2210
2211
|
const enhancedChanges = await this.enhanceChangesWithDiff(rawChanges)
|
|
2211
2212
|
const changesSummary = summarizeFileChanges(enhancedChanges)
|
|
2213
|
+
|
|
2214
|
+
console.log('DEBUG generateComprehensiveWorkspaceChangelog changesSummary:', JSON.stringify(changesSummary))
|
|
2212
2215
|
|
|
2213
2216
|
// Use DiffProcessor for intelligent processing
|
|
2214
2217
|
const analysisMode = options.analysisMode || 'standard'
|
|
@@ -2244,6 +2247,9 @@ export class ChangelogService {
|
|
|
2244
2247
|
}
|
|
2245
2248
|
|
|
2246
2249
|
async generateCommitStyleWorkingDirectoryEntries(options = {}) {
|
|
2250
|
+
console.log('DEBUG: generateCommitStyleWorkingDirectoryEntries called')
|
|
2251
|
+
console.log('DEBUG: summarizeFileChanges type:', typeof summarizeFileChanges)
|
|
2252
|
+
|
|
2247
2253
|
// Use provided working directory analysis or get current changes
|
|
2248
2254
|
let rawChanges
|
|
2249
2255
|
if (options.workingDirAnalysis?.changes) {
|
|
@@ -2260,6 +2266,9 @@ export class ChangelogService {
|
|
|
2260
2266
|
// Enhanced analysis of changes with diff content for AI analysis
|
|
2261
2267
|
const enhancedChanges = await this.enhanceChangesWithDiff(rawChanges)
|
|
2262
2268
|
const changesSummary = summarizeFileChanges(enhancedChanges)
|
|
2269
|
+
|
|
2270
|
+
console.log('DEBUG: enhancedChanges length:', enhancedChanges.length)
|
|
2271
|
+
console.log('DEBUG: changesSummary:', changesSummary)
|
|
2263
2272
|
|
|
2264
2273
|
// Use DiffProcessor for intelligent diff processing
|
|
2265
2274
|
const analysisMode =
|
|
@@ -2272,6 +2281,10 @@ export class ChangelogService {
|
|
|
2272
2281
|
|
|
2273
2282
|
const processedResult = diffProcessor.processFiles(enhancedChanges)
|
|
2274
2283
|
const { processedFiles, patterns } = processedResult
|
|
2284
|
+
|
|
2285
|
+
console.log('DEBUG: changesSummary type:', typeof changesSummary)
|
|
2286
|
+
console.log('DEBUG: changesSummary:', JSON.stringify(changesSummary))
|
|
2287
|
+
console.log('DEBUG: processedResult:', JSON.stringify(processedResult))
|
|
2275
2288
|
|
|
2276
2289
|
// Build pattern summary if patterns were detected
|
|
2277
2290
|
const patternSummary =
|
|
@@ -2507,6 +2520,8 @@ Generate one entry per file or logical change group. Only describe what you can
|
|
|
2507
2520
|
}
|
|
2508
2521
|
|
|
2509
2522
|
async generateAIChangelogContentFromChanges(changes, changesSummary, analysisMode = 'standard') {
|
|
2523
|
+
console.log('DEBUG generateAIChangelogContentFromChanges changesSummary:', JSON.stringify(changesSummary))
|
|
2524
|
+
|
|
2510
2525
|
if (!this.aiAnalysisService.hasAI) {
|
|
2511
2526
|
console.log(colors.infoMessage('AI not available, using rule-based analysis...'))
|
|
2512
2527
|
return this.generateBasicChangelogContentFromChanges(changes, changesSummary)
|
|
@@ -2548,6 +2563,7 @@ Generate one entry per file or logical change group. Only describe what you can
|
|
|
2548
2563
|
.join('\n')
|
|
2549
2564
|
|
|
2550
2565
|
// Build comprehensive prompt with processed changes
|
|
2566
|
+
console.log('DEBUG before prompt, changesSummary:', changesSummary ? 'defined' : 'undefined', 'totalFiles:', changesSummary?.totalFiles)
|
|
2551
2567
|
const prompt = `Generate a comprehensive AI changelog for the following working directory changes:
|
|
2552
2568
|
|
|
2553
2569
|
**Analysis Mode**: ${analysisMode}
|
|
@@ -2727,13 +2743,55 @@ ONLY describe what you can literally see in the diff content. Do not invent conn
|
|
|
2727
2743
|
}
|
|
2728
2744
|
|
|
2729
2745
|
generateContextSection(context) {
|
|
2746
|
+
if (!context) {
|
|
2747
|
+
return ''
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2730
2750
|
let section = '## Context Analysis\n\n'
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2751
|
+
|
|
2752
|
+
// Handle totalFiles from either structure
|
|
2753
|
+
if (context.totalFiles !== undefined) {
|
|
2754
|
+
section += `- **Total Files:** ${context.totalFiles}\n`
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
// Handle categories from summarizeFileChanges structure
|
|
2758
|
+
if (context.categories && typeof context.categories === 'object') {
|
|
2759
|
+
const categoryNames = Object.keys(context.categories)
|
|
2760
|
+
if (categoryNames.length > 0) {
|
|
2761
|
+
section += `- **Affected Areas:** ${categoryNames.join(', ')}\n`
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
// Handle stats if available
|
|
2766
|
+
if (context.stats) {
|
|
2767
|
+
const statParts = []
|
|
2768
|
+
if (context.stats.added > 0) statParts.push(`${context.stats.added} added`)
|
|
2769
|
+
if (context.stats.modified > 0) statParts.push(`${context.stats.modified} modified`)
|
|
2770
|
+
if (context.stats.deleted > 0) statParts.push(`${context.stats.deleted} deleted`)
|
|
2771
|
+
if (statParts.length > 0) {
|
|
2772
|
+
section += `- **Changes:** ${statParts.join(', ')}\n`
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
// Handle languages if available
|
|
2777
|
+
if (context.languages && Array.isArray(context.languages) && context.languages.length > 0) {
|
|
2778
|
+
section += `- **Languages:** ${context.languages.join(', ')}\n`
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
// Legacy properties for backward compatibility
|
|
2782
|
+
if (context.primaryCategory) {
|
|
2783
|
+
section += `- **Primary Category:** ${context.primaryCategory}\n`
|
|
2784
|
+
}
|
|
2785
|
+
if (context.riskLevel) {
|
|
2786
|
+
section += `- **Risk Level:** ${context.riskLevel}\n`
|
|
2787
|
+
}
|
|
2788
|
+
if (context.complexity) {
|
|
2789
|
+
section += `- **Complexity:** ${context.complexity}\n`
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
section += '\n'
|
|
2735
2793
|
|
|
2736
|
-
if (context.recommendations.length > 0) {
|
|
2794
|
+
if (context.recommendations && Array.isArray(context.recommendations) && context.recommendations.length > 0) {
|
|
2737
2795
|
section += '### Recommendations\n\n'
|
|
2738
2796
|
context.recommendations.forEach((rec) => {
|
|
2739
2797
|
section += `- ${rec}\n`
|
|
@@ -14,6 +14,7 @@ export class GitManager {
|
|
|
14
14
|
encoding: 'utf8',
|
|
15
15
|
timeout: 30000,
|
|
16
16
|
stdio: 'pipe',
|
|
17
|
+
cwd: undefined, // Will use process.cwd() if not specified
|
|
17
18
|
...options,
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -56,11 +57,18 @@ export class GitManager {
|
|
|
56
57
|
*/
|
|
57
58
|
execGit(command) {
|
|
58
59
|
try {
|
|
59
|
-
|
|
60
|
+
const execOptions = {
|
|
60
61
|
encoding: this.options.encoding,
|
|
61
62
|
stdio: this.options.stdio,
|
|
62
63
|
timeout: this.options.timeout,
|
|
63
|
-
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Add cwd if specified
|
|
67
|
+
if (this.options.cwd) {
|
|
68
|
+
execOptions.cwd = this.options.cwd
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return execSync(command, execOptions)
|
|
64
72
|
} catch (error) {
|
|
65
73
|
throw this._createGitError(command, error)
|
|
66
74
|
}
|
|
@@ -239,9 +247,7 @@ export class GitManager {
|
|
|
239
247
|
*/
|
|
240
248
|
getCommitsByAuthor(author, limit = 50) {
|
|
241
249
|
try {
|
|
242
|
-
const output = this.execGitSafe(
|
|
243
|
-
`git log --author="${author}" --oneline -n ${limit}`
|
|
244
|
-
)
|
|
250
|
+
const output = this.execGitSafe(`git log --author="${author}" --oneline -n ${limit}`)
|
|
245
251
|
return output
|
|
246
252
|
.split('\n')
|
|
247
253
|
.filter((line) => line.trim())
|
|
@@ -341,7 +347,9 @@ export class GitManager {
|
|
|
341
347
|
.filter(Boolean)
|
|
342
348
|
|
|
343
349
|
// Get summary stats
|
|
344
|
-
const summaryMatch = statOutput.match(
|
|
350
|
+
const summaryMatch = statOutput.match(
|
|
351
|
+
/(\d+) files? changed(?:, (\d+) insertions?)?(?:, (\d+) deletions?)?/
|
|
352
|
+
)
|
|
345
353
|
|
|
346
354
|
return {
|
|
347
355
|
ref: stashRef,
|
|
@@ -351,7 +359,7 @@ export class GitManager {
|
|
|
351
359
|
stats: {
|
|
352
360
|
filesChanged: summaryMatch ? parseInt(summaryMatch[1], 10) : files.length,
|
|
353
361
|
insertions: summaryMatch && summaryMatch[2] ? parseInt(summaryMatch[2], 10) : 0,
|
|
354
|
-
deletions: summaryMatch
|
|
362
|
+
deletions: summaryMatch?.[3] ? parseInt(summaryMatch[3], 10) : 0,
|
|
355
363
|
},
|
|
356
364
|
}
|
|
357
365
|
} catch {
|