@entro314labs/ai-changelog-generator 3.0.5 ā 3.1.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/CHANGELOG.md +92 -0
- package/README.md +22 -0
- package/package.json +10 -10
- package/src/application/orchestrators/changelog.orchestrator.js +469 -0
- package/src/application/services/application.service.js +13 -0
- package/src/infrastructure/cli/cli.controller.js +52 -0
- package/src/infrastructure/interactive/interactive-staging.service.js +313 -0
- package/src/infrastructure/validation/commit-message-validation.service.js +458 -0
- package/src/shared/constants/colors.js +28 -6
- package/src/shared/utils/utils.js +352 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,98 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.1.1] - 2025-08-01 ([480d3bc...a55fbc9](https://github.com/entro314-labs/AI-changelog-generator/compare/480d3bc9ac50fb983ddcf856aa99f9cc05cfc601...a55fbc98c36bd95d44d1582ed290b432e696058a))
|
|
9
|
+
|
|
10
|
+
### š Release Summary
|
|
11
|
+
Release 3.1.1 includes 10 commits (3 chore, 2 feature, 2 fix, 2 refactor, 1 docs). Complexity: low. Affected areas: configuration, documentation, source, other, assets.
|
|
12
|
+
|
|
13
|
+
**Business Impact**: minor
|
|
14
|
+
**Complexity**: low
|
|
15
|
+
|
|
16
|
+
## Changes
|
|
17
|
+
|
|
18
|
+
### š§ Maintenance
|
|
19
|
+
|
|
20
|
+
- **Update package.json**: The package version was incremented from 3.0.4 to 3.0.5 in package.json. No functional or dependency changes were made. ([641ad94](https://github.com/entro314-labs/AI-changelog-generator/commit/641ad94a5907d587f4427d1bfab195f7590a20a6))
|
|
21
|
+
- **Update package.json**: The version field in package.json was incremented from 3.0.3 to 3.0.4. No functionality, dependencies, or APIs were changed. ([787425e](https://github.com/entro314-labs/AI-changelog-generator/commit/787425e6f9b8524a3a2ee894ee201fcf29fc2e44))
|
|
22
|
+
|
|
23
|
+
### š Documentation
|
|
24
|
+
|
|
25
|
+
- **minor updates**: A comprehensive new setup guide was added, while several older, more detailed documentation files were removed for clarity and maintainability. Minor updates were made to documentation references and copyright information. ([28c0949](https://github.com/entro314-labs/AI-changelog-generator/commit/28c0949bcf455be78efae9162a4463bfc54afe3e))
|
|
26
|
+
|
|
27
|
+
### š Bug Fixes
|
|
28
|
+
|
|
29
|
+
- **fix: add publishConfig for public access**: Added a publishConfig section to package.json to specify public access for npm publishing. No application logic or user-facing functionality was changed. ([0f78591](https://github.com/entro314-labs/AI-changelog-generator/commit/0f7859165c80f29383afe6d02f88999664c29459))
|
|
30
|
+
- **fix: remove prepublishOnly hook with missing test-runner**: The 'prepublishOnly' npm script, which referenced a non-existent test runner, was removed from package.json. This prevents publishing errors caused by the missing script. ([0e7d691](https://github.com/entro314-labs/AI-changelog-generator/commit/0e7d691da1da409e57cabf77baf55f92b2d47d41))
|
|
31
|
+
- **fix: remove missing validate:mcp script from prepublishOnly**: Removed the call to the non-existent 'validate:mcp' script from the 'prepublishOnly' lifecycle step in package.json. Only 'test:comprehensive' now runs before publishing. ([215c644](https://github.com/entro314-labs/AI-changelog-generator/commit/215c6440005607ed56684e8d7906be5fe252e6fc))
|
|
32
|
+
|
|
33
|
+
### ā»ļø Refactoring
|
|
34
|
+
|
|
35
|
+
- **minor naming changes**: Internal code references to utility functions were updated to use a new file naming convention, changing imports from 'consolidated-utils.js' to 'utils.js' across multiple modules. No new features, APIs, or behavioral changes were introduced. ([3b99ef2](https://github.com/entro314-labs/AI-changelog-generator/commit/3b99ef20c6c3d39c5c1d7c0ea0ed8a84da07de34))
|
|
36
|
+
- **minor naming updates**: This update removes sample DXT extension files and documentation, and restructures the MCP server entry point for clarity and maintainability. Internal naming and initialization logic were adjusted, but no APIs or user commands were added or removed. ([480d3bc](https://github.com/entro314-labs/AI-changelog-generator/commit/480d3bc9ac50fb983ddcf856aa99f9cc05cfc601))
|
|
37
|
+
|
|
38
|
+
### š§ Working Directory Changes
|
|
39
|
+
|
|
40
|
+
- (feature) Expanded color constants in colors.js - Added new color entries including 'dracula', 'draculaDark', 'draculaLight', 'draculaYellow', 'draculaCyan', 'draculaOrange', 'draculaPink', 'draculaPurple', 'draculaRed', 'draculaGreen', and 'draculaBackground' to the exported COLORS object.
|
|
41
|
+
|
|
42
|
+
- (docs) Added changelog for version 3.1.0 - Created CHANGELOG-3.1.0.md with 50 lines detailing changes for version 3.1.0 dated 2025-08-01.
|
|
43
|
+
|
|
44
|
+
- (other) Added demo tape and video files - Created demo-basic.tape, demo-features.tape, demo-interactive.tape, demo-quick-real.tape, demo-quick.tape, demo-simple.tape, and demo.tape with various demo scripts; added demo.mp4 and demo-interactive.mp4 video files.
|
|
45
|
+
|
|
46
|
+
- (assets) Added demo GIF assets - Created demo-interactive-optimized.gif and demo-quick-real.gif with image data; added empty demo-interactive.gif, demo-optimized.gif, and demo-simple.gif files.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
*Generated using [ai-changelog-generator](https://github.com/entro314-labs/AI-changelog-generator) - AI-powered changelog generation for Git repositories*
|
|
51
|
+
|
|
52
|
+
## [3.1.0] - 2025-08-01 ([480d3bc...a55fbc9](https://github.com/entro314-labs/AI-changelog-generator/compare/480d3bc9ac50fb983ddcf856aa99f9cc05cfc601...a55fbc98c36bd95d44d1582ed290b432e696058a))
|
|
53
|
+
|
|
54
|
+
### š Release Summary
|
|
55
|
+
Release 3.1.0 includes 10 commits (3 chore, 2 feature, 2 fix, 2 refactor, 1 docs). Complexity: low. Affected areas: configuration, documentation, source, other, assets.
|
|
56
|
+
|
|
57
|
+
**Business Impact**: minor
|
|
58
|
+
**Complexity**: low
|
|
59
|
+
|
|
60
|
+
## Changes
|
|
61
|
+
|
|
62
|
+
### š§ Maintenance
|
|
63
|
+
|
|
64
|
+
- **Update package.json**: The package.json file version was updated from 3.0.4 to 3.0.5. No functionality, dependencies, or configuration were changed. ([641ad94](https://github.com/entro314-labs/AI-changelog-generator/commit/641ad94a5907d587f4427d1bfab195f7590a20a6))
|
|
65
|
+
- **Update package.json**: The package version was updated from 3.0.3 to 3.0.4 in package.json. No code, features, or dependencies were changed. ([787425e](https://github.com/entro314-labs/AI-changelog-generator/commit/787425e6f9b8524a3a2ee894ee201fcf29fc2e44))
|
|
66
|
+
|
|
67
|
+
### š Documentation
|
|
68
|
+
|
|
69
|
+
- **minor updates**: A new comprehensive 'AI Provider Setup Guide' was added, consolidating and simplifying provider configuration instructions; several outdated or redundant documentation files were removed, and the .gitignore was updated to exclude these files. No application code or user-facing features were changed. ([28c0949](https://github.com/entro314-labs/AI-changelog-generator/commit/28c0949bcf455be78efae9162a4463bfc54afe3e))
|
|
70
|
+
|
|
71
|
+
### š Bug Fixes
|
|
72
|
+
|
|
73
|
+
- **fix: add publishConfig for public access**: Added a publishConfig section with 'access: public' to package.json, ensuring the package is published with public visibility. No application code or runtime behavior was changed. ([0f78591](https://github.com/entro314-labs/AI-changelog-generator/commit/0f7859165c80f29383afe6d02f88999664c29459))
|
|
74
|
+
- **fix: remove prepublishOnly hook with missing test-runner**: The 'prepublishOnly' npm script, which referenced a non-existent 'test:comprehensive' command, was removed from package.json. This prevents npm publish operations from being blocked by missing scripts. ([0e7d691](https://github.com/entro314-labs/AI-changelog-generator/commit/0e7d691da1da409e57cabf77baf55f92b2d47d41))
|
|
75
|
+
- **fix: remove missing validate:mcp script from prepublishOnly**: The prepublishOnly script no longer tries to run the removed validate:mcp command, which previously caused errors if the script was absent. Only the comprehensive test suite is now run before publishing. ([215c644](https://github.com/entro314-labs/AI-changelog-generator/commit/215c6440005607ed56684e8d7906be5fe252e6fc))
|
|
76
|
+
|
|
77
|
+
### ā»ļø Refactoring
|
|
78
|
+
|
|
79
|
+
- **minor naming changes**: The update consolidates utility imports by renaming and redirecting them from 'consolidated-utils.js' to 'utils.js' across core modules and provider integrations. No APIs, commands, or outputs were changed; only internal code references were updated for consistency. ([3b99ef2](https://github.com/entro314-labs/AI-changelog-generator/commit/3b99ef20c6c3d39c5c1d7c0ea0ed8a84da07de34))
|
|
80
|
+
- š„ **minor naming updates**: This update removes all sample DXT extension packages, documentation, and related files, and restructures the MCP server entry point and supporting utilities for improved clarity and maintainability. No new tools or APIs were introduced, and no user-facing commands or behaviors were modified. ([480d3bc](https://github.com/entro314-labs/AI-changelog-generator/commit/480d3bc9ac50fb983ddcf856aa99f9cc05cfc601))
|
|
81
|
+
|
|
82
|
+
### š§ Working Directory Changes
|
|
83
|
+
|
|
84
|
+
- (feature) Added demo-optimized.gif asset - Created new empty file demo-optimized.gif in assets.
|
|
85
|
+
|
|
86
|
+
- (feature) Added demo-simple.gif asset - Created new empty file demo-simple.gif in assets.
|
|
87
|
+
|
|
88
|
+
- (feature) Added demo-quick.tape script - Created new file demo-quick.tape with 70 lines, including commands for outputting demo-quick.gif, setting font size, width, height, theme, typing speed, and various typing and enter actions.
|
|
89
|
+
|
|
90
|
+
- (feature) Added demo-simple.tape script - Created new file demo-simple.tape with 24 lines, including commands for outputting demo-simple.gif, setting font size, width, height, theme, typing speed, and typing a demo title.
|
|
91
|
+
|
|
92
|
+
- (feature) Added demo.mp4 media file - Created new file demo.mp4 with 3243 lines of binary content.
|
|
93
|
+
|
|
94
|
+
- (feature) Added demo.tape script - Created new file demo.tape with 129 lines, including documentation comments and commands for outputting GIF and MP4 files, setting font size, width, height, theme, typing speed, and various typing and enter actions.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
*Generated using [ai-changelog-generator](https://github.com/entro314-labs/AI-changelog-generator) - AI-powered changelog generation for Git repositories*
|
|
99
|
+
|
|
8
100
|
## [3.0.3]
|
|
9
101
|
|
|
10
102
|
### š§ **Maintenance & Bug Fixes**
|
package/README.md
CHANGED
|
@@ -148,6 +148,27 @@ ai-changelog --help
|
|
|
148
148
|
|
|
149
149
|
That's it! Your AI-powered changelog is ready to generate.
|
|
150
150
|
|
|
151
|
+
## Demo
|
|
152
|
+
|
|
153
|
+
### Interactive Mode
|
|
154
|
+
See the tool in action with our interactive mode demo:
|
|
155
|
+
|
|
156
|
+

|
|
157
|
+
|
|
158
|
+
*Interactive mode with guided setup and provider selection*
|
|
159
|
+
|
|
160
|
+
### Quick Generation
|
|
161
|
+
Watch how fast you can generate professional changelogs:
|
|
162
|
+
|
|
163
|
+

|
|
164
|
+
|
|
165
|
+
*Generate changelogs from recent commits in seconds*
|
|
166
|
+
|
|
167
|
+
### Video Walkthrough
|
|
168
|
+
For a complete walkthrough of features and capabilities:
|
|
169
|
+
|
|
170
|
+
[šŗ Watch Full Demo Video](docs/media/demo-interactive.mp4)
|
|
171
|
+
|
|
151
172
|
## How It Works
|
|
152
173
|
|
|
153
174
|
1. **Code Analysis**: Analyzes actual git diffs and file changes using advanced AI models
|
|
@@ -326,6 +347,7 @@ ai-changelog health --detailed
|
|
|
326
347
|
- **[Configuration Reference](./docs/configuration.md)** - All YAML and environment options
|
|
327
348
|
- **[MCP Integration](./docs/mcp-integration.md)** - Claude Desktop and MCP server setup
|
|
328
349
|
- **[API Reference](./docs/api-reference.md)** - All commands, options, and programmatic usage
|
|
350
|
+
- **[Demo Media](./docs/media/)** - Interactive demos, GIFs, and video walkthroughs
|
|
329
351
|
|
|
330
352
|
## Contributing
|
|
331
353
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entro314labs/ai-changelog-generator",
|
|
3
3
|
"displayName": "AI Changelog Generator",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.1.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",
|
|
@@ -21,28 +21,28 @@
|
|
|
21
21
|
"CHANGELOG.md"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@anthropic-ai/sdk": "^0.
|
|
25
|
-
"@aws-sdk/client-bedrock-runtime": "^3.
|
|
26
|
-
"@azure/identity": "^4.
|
|
24
|
+
"@anthropic-ai/sdk": "^0.58.0",
|
|
25
|
+
"@aws-sdk/client-bedrock-runtime": "^3.861.0",
|
|
26
|
+
"@azure/identity": "^4.11.1",
|
|
27
27
|
"@clack/prompts": "^0.11.0",
|
|
28
28
|
"@google/genai": "^1.12.0",
|
|
29
29
|
"@google/generative-ai": "^0.24.1",
|
|
30
30
|
"@huggingface/hub": "^2.4.0",
|
|
31
31
|
"@huggingface/inference": "^4.6.1",
|
|
32
32
|
"@lmstudio/sdk": "^1.4.0",
|
|
33
|
-
"@modelcontextprotocol/sdk": "^1.17.
|
|
34
|
-
"@modelcontextprotocol/server-filesystem": "2025.7.
|
|
35
|
-
"chalk": "^5.
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.17.1",
|
|
34
|
+
"@modelcontextprotocol/server-filesystem": "2025.7.29",
|
|
35
|
+
"chalk": "^5.5.0",
|
|
36
36
|
"dotenv": "^17.2.1",
|
|
37
|
-
"google-auth-library": "^10.2.
|
|
37
|
+
"google-auth-library": "^10.2.1",
|
|
38
38
|
"js-yaml": "^4.1.0",
|
|
39
39
|
"ollama": "^0.5.16",
|
|
40
|
-
"openai": "^5.
|
|
40
|
+
"openai": "^5.12.0",
|
|
41
41
|
"yargs": "^18.0.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@anthropic-ai/dxt": "^0.2.6",
|
|
45
|
-
"@types/node": "22.
|
|
45
|
+
"@types/node": "22.17.1"
|
|
46
46
|
},
|
|
47
47
|
"keywords": [
|
|
48
48
|
"changelog",
|
|
@@ -4,6 +4,8 @@ import { ChangelogService } from '../../domains/changelog/changelog.service.js';
|
|
|
4
4
|
import { AnalysisEngine } from '../../domains/analysis/analysis.engine.js';
|
|
5
5
|
import { ProviderManagerService } from '../../infrastructure/providers/provider-manager.service.js';
|
|
6
6
|
import { InteractiveWorkflowService } from '../../infrastructure/interactive/interactive-workflow.service.js';
|
|
7
|
+
import { InteractiveStagingService } from '../../infrastructure/interactive/interactive-staging.service.js';
|
|
8
|
+
import { CommitMessageValidationService } from '../../infrastructure/validation/commit-message-validation.service.js';
|
|
7
9
|
import colors from '../../shared/constants/colors.js';
|
|
8
10
|
|
|
9
11
|
export class ChangelogOrchestrator {
|
|
@@ -54,6 +56,8 @@ export class ChangelogOrchestrator {
|
|
|
54
56
|
this.analysisEngine = new AnalysisEngine(this.gitService, this.aiAnalysisService);
|
|
55
57
|
this.changelogService = new ChangelogService(this.gitService, this.aiAnalysisService, this.analysisEngine, this.configManager);
|
|
56
58
|
this.interactiveService = new InteractiveWorkflowService(this.gitService, this.aiAnalysisService, this.changelogService);
|
|
59
|
+
this.stagingService = new InteractiveStagingService(this.gitManager);
|
|
60
|
+
this.validationService = new CommitMessageValidationService(this.configManager);
|
|
57
61
|
|
|
58
62
|
// Only log if not in MCP server mode
|
|
59
63
|
if (!process.env.MCP_SERVER_MODE) {
|
|
@@ -727,4 +731,469 @@ export class ChangelogOrchestrator {
|
|
|
727
731
|
this.aiAnalysisService.resetMetrics();
|
|
728
732
|
}
|
|
729
733
|
}
|
|
734
|
+
|
|
735
|
+
// Interactive commit workflow
|
|
736
|
+
async executeCommitWorkflow(options = {}) {
|
|
737
|
+
await this.ensureInitialized();
|
|
738
|
+
|
|
739
|
+
console.log(colors.header('š Interactive Commit Workflow'));
|
|
740
|
+
|
|
741
|
+
try {
|
|
742
|
+
// Step 1: Show current git status
|
|
743
|
+
const statusResult = await this.stagingService.showGitStatus();
|
|
744
|
+
|
|
745
|
+
// Check if we have any changes at all
|
|
746
|
+
const totalChanges = statusResult.staged.length + statusResult.unstaged.length + statusResult.untracked.length;
|
|
747
|
+
if (totalChanges === 0) {
|
|
748
|
+
console.log(colors.infoMessage('⨠Working directory clean - no changes to commit.'));
|
|
749
|
+
return { success: false, message: 'No changes to commit' };
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Step 2: Handle staging based on options
|
|
753
|
+
let stagedFiles = [];
|
|
754
|
+
|
|
755
|
+
if (options.stageAll) {
|
|
756
|
+
// Auto-stage all changes
|
|
757
|
+
console.log(colors.processingMessage('š¦ Staging all changes...'));
|
|
758
|
+
await this.stagingService.stageAllChanges();
|
|
759
|
+
stagedFiles = [...statusResult.unstaged, ...statusResult.untracked];
|
|
760
|
+
} else if (options.interactive && (statusResult.unstaged.length > 0 || statusResult.untracked.length > 0)) {
|
|
761
|
+
// Interactive staging
|
|
762
|
+
console.log(colors.infoMessage('\nšÆ Interactive staging mode'));
|
|
763
|
+
stagedFiles = await this.stagingService.selectFilesToStage();
|
|
764
|
+
|
|
765
|
+
if (stagedFiles.length === 0 && statusResult.staged.length === 0) {
|
|
766
|
+
console.log(colors.warningMessage('No files staged for commit.'));
|
|
767
|
+
return { success: false, message: 'No files staged' };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Step 3: Verify we have staged changes
|
|
772
|
+
if (!this.stagingService.hasStagedChanges()) {
|
|
773
|
+
console.log(colors.warningMessage('No staged changes found for commit.'));
|
|
774
|
+
|
|
775
|
+
if (statusResult.unstaged.length > 0 || statusResult.untracked.length > 0) {
|
|
776
|
+
console.log(colors.infoMessage('š” Use --all flag to stage all changes, or run interactively to select files.'));
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
return { success: false, message: 'No staged changes' };
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Step 4: Get final staged changes for analysis
|
|
783
|
+
const finalStatus = this.stagingService.getDetailedStatus();
|
|
784
|
+
console.log(colors.successMessage(`\nā
Ready to commit ${finalStatus.staged.length} staged file(s)`));
|
|
785
|
+
|
|
786
|
+
// Step 5: Branch Intelligence Analysis
|
|
787
|
+
const { analyzeBranchIntelligence, getSuggestedCommitType, generateCommitContextFromBranch } = await import('../../shared/utils/utils.js');
|
|
788
|
+
|
|
789
|
+
const branchAnalysis = analyzeBranchIntelligence();
|
|
790
|
+
const suggestedType = getSuggestedCommitType(branchAnalysis, finalStatus.staged);
|
|
791
|
+
const branchContext = generateCommitContextFromBranch(branchAnalysis, finalStatus.staged);
|
|
792
|
+
|
|
793
|
+
// Display branch intelligence findings
|
|
794
|
+
if (branchAnalysis.confidence > 20) {
|
|
795
|
+
console.log(colors.infoMessage('\nš§ Branch Intelligence:'));
|
|
796
|
+
console.log(colors.secondary(` Branch: ${branchAnalysis.branch}`));
|
|
797
|
+
|
|
798
|
+
if (branchAnalysis.type) {
|
|
799
|
+
console.log(colors.success(` š·ļø Detected type: ${branchAnalysis.type} (${branchAnalysis.confidence}% confidence)`));
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
if (branchAnalysis.ticket) {
|
|
803
|
+
console.log(colors.highlight(` š« Related ticket: ${branchAnalysis.ticket}`));
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (branchAnalysis.description) {
|
|
807
|
+
console.log(colors.dim(` š Description: ${branchAnalysis.description}`));
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
console.log(colors.dim(` š Patterns: ${branchAnalysis.patterns.join(', ')}`));
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Display suggested commit type
|
|
814
|
+
console.log(colors.infoMessage(`\nš” Suggested commit type: ${colors.highlight(suggestedType.type)} (from ${suggestedType.source}, ${suggestedType.confidence}% confidence)`));
|
|
815
|
+
|
|
816
|
+
// Step 6: Generate enhanced commit message
|
|
817
|
+
let commitMessage;
|
|
818
|
+
|
|
819
|
+
if (options.customMessage) {
|
|
820
|
+
commitMessage = options.customMessage;
|
|
821
|
+
} else {
|
|
822
|
+
// Generate AI-enhanced commit message with branch context
|
|
823
|
+
commitMessage = this.generateBranchAwareCommitMessage(branchAnalysis, suggestedType, finalStatus.staged);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Step 7: Validate commit message
|
|
827
|
+
console.log(colors.processingMessage('\nš Validating commit message...'));
|
|
828
|
+
|
|
829
|
+
const validationContext = {
|
|
830
|
+
branchAnalysis,
|
|
831
|
+
stagedFiles: finalStatus.staged,
|
|
832
|
+
suggestedType
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
const validationResult = await this.validationService.validateCommitMessage(commitMessage, validationContext);
|
|
836
|
+
|
|
837
|
+
// Display validation results
|
|
838
|
+
const isValid = this.validationService.displayValidationResults(validationResult);
|
|
839
|
+
|
|
840
|
+
// Step 8: Interactive improvement if needed
|
|
841
|
+
if (!isValid || validationResult.warnings.length > 0) {
|
|
842
|
+
const { confirm } = await import('@clack/prompts');
|
|
843
|
+
|
|
844
|
+
const shouldImprove = await confirm({
|
|
845
|
+
message: 'Would you like to improve the commit message?',
|
|
846
|
+
initialValue: !isValid
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
if (shouldImprove) {
|
|
850
|
+
commitMessage = await this.handleCommitMessageImprovement(commitMessage, validationResult, validationContext);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
if (options.dryRun) {
|
|
855
|
+
console.log(colors.infoMessage('\nš Dry-run mode - showing what would be committed:'));
|
|
856
|
+
console.log(colors.highlight(`Commit message:\n${commitMessage}`));
|
|
857
|
+
return {
|
|
858
|
+
success: true,
|
|
859
|
+
commitMessage,
|
|
860
|
+
stagedFiles: finalStatus.staged.length,
|
|
861
|
+
dryRun: true
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Step 6: Development phase notice
|
|
866
|
+
console.log(colors.warningMessage('\nā ļø Commit execution is in development phase.'));
|
|
867
|
+
console.log(colors.infoMessage('Current capabilities:'));
|
|
868
|
+
console.log(colors.success(' ⢠Git status analysis ā
'));
|
|
869
|
+
console.log(colors.success(' ⢠Interactive staging ā
'));
|
|
870
|
+
console.log(colors.dim(' ⢠AI commit message generation (coming soon) ā³'));
|
|
871
|
+
console.log(colors.dim(' ⢠Git commit execution (coming soon) ā³'));
|
|
872
|
+
|
|
873
|
+
console.log(colors.infoMessage('\nš” Files are staged and ready for commit!'));
|
|
874
|
+
console.log(colors.infoMessage('š” Use "git commit" manually or wait for the next phase.'));
|
|
875
|
+
|
|
876
|
+
return {
|
|
877
|
+
success: true,
|
|
878
|
+
commitMessage,
|
|
879
|
+
stagedFiles: finalStatus.staged.length,
|
|
880
|
+
phase: 'staging-complete'
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
} catch (error) {
|
|
884
|
+
console.error(colors.errorMessage(`Commit workflow error: ${error.message}`));
|
|
885
|
+
throw error;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Generate branch-aware commit message using AI and branch intelligence
|
|
891
|
+
*/
|
|
892
|
+
generateBranchAwareCommitMessage(branchAnalysis, suggestedType, stagedFiles) {
|
|
893
|
+
const type = suggestedType.type;
|
|
894
|
+
|
|
895
|
+
// Build description based on branch intelligence
|
|
896
|
+
let description = 'implement changes';
|
|
897
|
+
|
|
898
|
+
if (branchAnalysis.description && branchAnalysis.confidence > 40) {
|
|
899
|
+
description = branchAnalysis.description;
|
|
900
|
+
} else {
|
|
901
|
+
// Generate description from file changes
|
|
902
|
+
const fileTypes = new Set();
|
|
903
|
+
stagedFiles.forEach(file => {
|
|
904
|
+
const path = file.path;
|
|
905
|
+
if (path.includes('service')) fileTypes.add('services');
|
|
906
|
+
if (path.includes('component')) fileTypes.add('components');
|
|
907
|
+
if (path.includes('utils')) fileTypes.add('utilities');
|
|
908
|
+
if (path.includes('config')) fileTypes.add('configuration');
|
|
909
|
+
if (path.includes('test')) fileTypes.add('tests');
|
|
910
|
+
if (path.includes('doc')) fileTypes.add('documentation');
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
if (fileTypes.size > 0) {
|
|
914
|
+
description = `update ${Array.from(fileTypes).join(', ')}`;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// Build commit message
|
|
919
|
+
let commitMessage = `${type}: ${description}`;
|
|
920
|
+
|
|
921
|
+
// Add body with details
|
|
922
|
+
const bodyLines = [];
|
|
923
|
+
|
|
924
|
+
if (branchAnalysis.ticket) {
|
|
925
|
+
bodyLines.push(`Related to: ${branchAnalysis.ticket}`);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Add file summary
|
|
929
|
+
const addedFiles = stagedFiles.filter(f => f.status === 'A').length;
|
|
930
|
+
const modifiedFiles = stagedFiles.filter(f => f.status === 'M').length;
|
|
931
|
+
const deletedFiles = stagedFiles.filter(f => f.status === 'D').length;
|
|
932
|
+
|
|
933
|
+
const changes = [];
|
|
934
|
+
if (addedFiles > 0) changes.push(`${addedFiles} added`);
|
|
935
|
+
if (modifiedFiles > 0) changes.push(`${modifiedFiles} modified`);
|
|
936
|
+
if (deletedFiles > 0) changes.push(`${deletedFiles} deleted`);
|
|
937
|
+
|
|
938
|
+
if (changes.length > 0) {
|
|
939
|
+
bodyLines.push(`Files: ${changes.join(', ')}`);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// Add branch context
|
|
943
|
+
if (branchAnalysis.confidence > 60) {
|
|
944
|
+
bodyLines.push(`Branch: ${branchAnalysis.branch} (${branchAnalysis.confidence}% confidence)`);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (bodyLines.length > 0) {
|
|
948
|
+
commitMessage += '\n\n' + bodyLines.join('\n');
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
return commitMessage;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Handle interactive commit message improvement
|
|
956
|
+
*/
|
|
957
|
+
async handleCommitMessageImprovement(originalMessage, validationResult, context) {
|
|
958
|
+
const { select, text, confirm } = await import('@clack/prompts');
|
|
959
|
+
|
|
960
|
+
console.log(colors.infoMessage('\nš§ Commit Message Improvement'));
|
|
961
|
+
|
|
962
|
+
// Try automatic improvement first
|
|
963
|
+
const improvementResult = await this.validationService.improveCommitMessage(originalMessage, context);
|
|
964
|
+
|
|
965
|
+
const options = [
|
|
966
|
+
{
|
|
967
|
+
value: 'auto',
|
|
968
|
+
label: 'š¤ Use automatically improved version',
|
|
969
|
+
hint: improvementResult.improved ? 'AI-suggested improvements applied' : 'Minor fixes applied'
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
value: 'manual',
|
|
973
|
+
label: 'āļø Edit manually',
|
|
974
|
+
hint: 'Customize the commit message yourself'
|
|
975
|
+
}
|
|
976
|
+
];
|
|
977
|
+
|
|
978
|
+
// Add AI suggestions if available
|
|
979
|
+
if (this.aiAnalysisService.hasAI) {
|
|
980
|
+
options.unshift({
|
|
981
|
+
value: 'ai',
|
|
982
|
+
label: 'š§ Generate AI suggestions',
|
|
983
|
+
hint: 'Get AI-powered commit message alternatives'
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const choice = await select({
|
|
988
|
+
message: 'How would you like to improve the commit message?',
|
|
989
|
+
options
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
switch (choice) {
|
|
993
|
+
case 'ai':
|
|
994
|
+
return await this.generateAICommitSuggestions(originalMessage, context, validationResult);
|
|
995
|
+
|
|
996
|
+
case 'auto':
|
|
997
|
+
console.log(colors.successMessage(`\nā
Using improved message:`));
|
|
998
|
+
console.log(colors.highlight(improvementResult.message));
|
|
999
|
+
return improvementResult.message;
|
|
1000
|
+
|
|
1001
|
+
case 'manual':
|
|
1002
|
+
return await this.handleManualCommitEdit(originalMessage, validationResult);
|
|
1003
|
+
|
|
1004
|
+
default:
|
|
1005
|
+
return originalMessage;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* Generate AI-powered commit message suggestions
|
|
1011
|
+
*/
|
|
1012
|
+
async generateAICommitSuggestions(originalMessage, context, validationResult) {
|
|
1013
|
+
const { select } = await import('@clack/prompts');
|
|
1014
|
+
|
|
1015
|
+
console.log(colors.processingMessage('š¤ Generating AI suggestions...'));
|
|
1016
|
+
|
|
1017
|
+
try {
|
|
1018
|
+
// Build comprehensive context for AI
|
|
1019
|
+
const branchInfo = context.branchAnalysis?.confidence > 30
|
|
1020
|
+
? `Branch: ${context.branchAnalysis.branch} (${context.branchAnalysis.type || 'unknown'} type)`
|
|
1021
|
+
: '';
|
|
1022
|
+
|
|
1023
|
+
const fileChanges = context.stagedFiles.map(f => `${f.status} ${f.path}`).join('\n');
|
|
1024
|
+
|
|
1025
|
+
const validationIssues = [
|
|
1026
|
+
...validationResult.errors,
|
|
1027
|
+
...validationResult.warnings
|
|
1028
|
+
].join('\n');
|
|
1029
|
+
|
|
1030
|
+
const prompt = `Improve this commit message based on the validation feedback and context:
|
|
1031
|
+
|
|
1032
|
+
Original message: "${originalMessage}"
|
|
1033
|
+
|
|
1034
|
+
Validation issues:
|
|
1035
|
+
${validationIssues}
|
|
1036
|
+
|
|
1037
|
+
File changes:
|
|
1038
|
+
${fileChanges}
|
|
1039
|
+
|
|
1040
|
+
${branchInfo}
|
|
1041
|
+
|
|
1042
|
+
Requirements:
|
|
1043
|
+
- Follow conventional commit format
|
|
1044
|
+
- Address all validation issues
|
|
1045
|
+
- Keep subject under 72 characters
|
|
1046
|
+
- Use imperative mood
|
|
1047
|
+
- Be specific and descriptive
|
|
1048
|
+
|
|
1049
|
+
Provide 3 improved alternatives.`;
|
|
1050
|
+
|
|
1051
|
+
const response = await this.aiAnalysisService.aiProvider.generateCompletion([{
|
|
1052
|
+
role: 'user',
|
|
1053
|
+
content: prompt
|
|
1054
|
+
}], { max_tokens: 300 });
|
|
1055
|
+
|
|
1056
|
+
const suggestions = this.parseAICommitSuggestions(response.content);
|
|
1057
|
+
|
|
1058
|
+
if (suggestions.length === 0) {
|
|
1059
|
+
console.log(colors.warningMessage('No AI suggestions generated, falling back to manual edit.'));
|
|
1060
|
+
return await this.handleManualCommitEdit(originalMessage, validationResult);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// Present suggestions to user
|
|
1064
|
+
const choices = suggestions.map((suggestion, index) => ({
|
|
1065
|
+
value: suggestion,
|
|
1066
|
+
label: `${index + 1}. ${suggestion.split('\n')[0]}`, // First line only
|
|
1067
|
+
hint: suggestion.includes('\n') ? 'Has body content' : 'Subject only'
|
|
1068
|
+
}));
|
|
1069
|
+
|
|
1070
|
+
choices.push({
|
|
1071
|
+
value: 'MANUAL',
|
|
1072
|
+
label: 'āļø Edit manually instead',
|
|
1073
|
+
hint: 'Write your own commit message'
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
const selectedMessage = await select({
|
|
1077
|
+
message: 'Choose an AI-generated commit message:',
|
|
1078
|
+
options: choices
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
if (selectedMessage === 'MANUAL') {
|
|
1082
|
+
return await this.handleManualCommitEdit(originalMessage, validationResult);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
console.log(colors.successMessage('\nā
Selected AI suggestion:'));
|
|
1086
|
+
console.log(colors.highlight(selectedMessage));
|
|
1087
|
+
return selectedMessage;
|
|
1088
|
+
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
console.error(colors.errorMessage(`AI suggestion failed: ${error.message}`));
|
|
1091
|
+
return await this.handleManualCommitEdit(originalMessage, validationResult);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Handle manual commit message editing
|
|
1097
|
+
*/
|
|
1098
|
+
async handleManualCommitEdit(originalMessage, validationResult) {
|
|
1099
|
+
const { text, confirm } = await import('@clack/prompts');
|
|
1100
|
+
|
|
1101
|
+
console.log(colors.infoMessage('\nāļø Manual Edit Mode'));
|
|
1102
|
+
console.log(colors.dim('Validation issues to address:'));
|
|
1103
|
+
|
|
1104
|
+
validationResult.errors.forEach(error => {
|
|
1105
|
+
console.log(colors.error(` ⢠${error}`));
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
validationResult.warnings.forEach(warning => {
|
|
1109
|
+
console.log(colors.warning(` ⢠${warning}`));
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
if (validationResult.suggestions.length > 0) {
|
|
1113
|
+
console.log(colors.dim('\nSuggestions:'));
|
|
1114
|
+
validationResult.suggestions.forEach(suggestion => {
|
|
1115
|
+
console.log(colors.dim(` ⢠${suggestion}`));
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
let improvedMessage;
|
|
1120
|
+
let isValid = false;
|
|
1121
|
+
let attempts = 0;
|
|
1122
|
+
const maxAttempts = 3;
|
|
1123
|
+
|
|
1124
|
+
while (!isValid && attempts < maxAttempts) {
|
|
1125
|
+
improvedMessage = await text({
|
|
1126
|
+
message: 'Enter improved commit message:',
|
|
1127
|
+
placeholder: originalMessage,
|
|
1128
|
+
defaultValue: attempts === 0 ? originalMessage : undefined,
|
|
1129
|
+
validate: (input) => {
|
|
1130
|
+
if (!input || input.trim().length === 0) {
|
|
1131
|
+
return 'Commit message cannot be empty';
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
// Validate the improved message
|
|
1137
|
+
const newValidation = await this.validationService.validateCommitMessage(improvedMessage, {
|
|
1138
|
+
branchAnalysis: validationResult.parsed?.branchAnalysis
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
if (newValidation.valid) {
|
|
1142
|
+
isValid = true;
|
|
1143
|
+
console.log(colors.successMessage('ā
Validation passed!'));
|
|
1144
|
+
} else {
|
|
1145
|
+
attempts++;
|
|
1146
|
+
console.log(colors.warningMessage(`\nā ļø Validation failed (attempt ${attempts}/${maxAttempts}):`));
|
|
1147
|
+
this.validationService.displayValidationResults(newValidation);
|
|
1148
|
+
|
|
1149
|
+
if (attempts < maxAttempts) {
|
|
1150
|
+
const tryAgain = await confirm({
|
|
1151
|
+
message: 'Try again with improvements?',
|
|
1152
|
+
initialValue: true
|
|
1153
|
+
});
|
|
1154
|
+
|
|
1155
|
+
if (!tryAgain) {
|
|
1156
|
+
break;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
return improvedMessage || originalMessage;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Parse AI-generated commit suggestions
|
|
1167
|
+
*/
|
|
1168
|
+
parseAICommitSuggestions(content) {
|
|
1169
|
+
const suggestions = [];
|
|
1170
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
1171
|
+
|
|
1172
|
+
let currentSuggestion = '';
|
|
1173
|
+
for (const line of lines) {
|
|
1174
|
+
const trimmed = line.trim();
|
|
1175
|
+
|
|
1176
|
+
// Check if it's a new suggestion (starts with number, bullet, or looks like commit format)
|
|
1177
|
+
if (trimmed.match(/^(\d+[\.\)]|\*|-|ā¢)|^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.*?\))?:/)) {
|
|
1178
|
+
if (currentSuggestion) {
|
|
1179
|
+
suggestions.push(currentSuggestion.trim());
|
|
1180
|
+
}
|
|
1181
|
+
// Clean up the line (remove numbering/bullets)
|
|
1182
|
+
currentSuggestion = trimmed.replace(/^(\d+[\.\)]|\*|-|ā¢)\s*/, '');
|
|
1183
|
+
} else if (currentSuggestion && trimmed.length > 0) {
|
|
1184
|
+
// Add to current suggestion (body content)
|
|
1185
|
+
currentSuggestion += '\n' + trimmed;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// Add the last suggestion
|
|
1190
|
+
if (currentSuggestion) {
|
|
1191
|
+
suggestions.push(currentSuggestion.trim());
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// Filter valid suggestions
|
|
1195
|
+
return suggestions
|
|
1196
|
+
.filter(s => s.length > 10 && s.includes(':'))
|
|
1197
|
+
.slice(0, 3); // Limit to 3 suggestions
|
|
1198
|
+
}
|
|
730
1199
|
}
|