@m3hti/commit-genie 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +430 -0
  3. package/dist/commands/config.d.ts +3 -0
  4. package/dist/commands/config.d.ts.map +1 -0
  5. package/dist/commands/config.js +31 -0
  6. package/dist/commands/config.js.map +1 -0
  7. package/dist/commands/generate.d.ts +10 -0
  8. package/dist/commands/generate.d.ts.map +1 -0
  9. package/dist/commands/generate.js +313 -0
  10. package/dist/commands/generate.js.map +1 -0
  11. package/dist/commands/generate.test.d.ts +2 -0
  12. package/dist/commands/generate.test.d.ts.map +1 -0
  13. package/dist/commands/generate.test.js +168 -0
  14. package/dist/commands/generate.test.js.map +1 -0
  15. package/dist/commands/hook.d.ts +4 -0
  16. package/dist/commands/hook.d.ts.map +1 -0
  17. package/dist/commands/hook.js +62 -0
  18. package/dist/commands/hook.js.map +1 -0
  19. package/dist/commands/stats.d.ts +6 -0
  20. package/dist/commands/stats.d.ts.map +1 -0
  21. package/dist/commands/stats.js +39 -0
  22. package/dist/commands/stats.js.map +1 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +77 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/services/aiService.d.ts +38 -0
  28. package/dist/services/aiService.d.ts.map +1 -0
  29. package/dist/services/aiService.js +187 -0
  30. package/dist/services/aiService.js.map +1 -0
  31. package/dist/services/analyzerService.d.ts +60 -0
  32. package/dist/services/analyzerService.d.ts.map +1 -0
  33. package/dist/services/analyzerService.js +832 -0
  34. package/dist/services/analyzerService.js.map +1 -0
  35. package/dist/services/analyzerService.test.d.ts +2 -0
  36. package/dist/services/analyzerService.test.d.ts.map +1 -0
  37. package/dist/services/analyzerService.test.js +323 -0
  38. package/dist/services/analyzerService.test.js.map +1 -0
  39. package/dist/services/configService.d.ts +25 -0
  40. package/dist/services/configService.d.ts.map +1 -0
  41. package/dist/services/configService.js +207 -0
  42. package/dist/services/configService.js.map +1 -0
  43. package/dist/services/configService.test.d.ts +2 -0
  44. package/dist/services/configService.test.d.ts.map +1 -0
  45. package/dist/services/configService.test.js +165 -0
  46. package/dist/services/configService.test.js.map +1 -0
  47. package/dist/services/gitService.d.ts +44 -0
  48. package/dist/services/gitService.d.ts.map +1 -0
  49. package/dist/services/gitService.js +217 -0
  50. package/dist/services/gitService.js.map +1 -0
  51. package/dist/services/gitService.test.d.ts +2 -0
  52. package/dist/services/gitService.test.d.ts.map +1 -0
  53. package/dist/services/gitService.test.js +140 -0
  54. package/dist/services/gitService.test.js.map +1 -0
  55. package/dist/services/historyService.d.ts +39 -0
  56. package/dist/services/historyService.d.ts.map +1 -0
  57. package/dist/services/historyService.js +195 -0
  58. package/dist/services/historyService.js.map +1 -0
  59. package/dist/services/historyService.test.d.ts +2 -0
  60. package/dist/services/historyService.test.d.ts.map +1 -0
  61. package/dist/services/historyService.test.js +157 -0
  62. package/dist/services/historyService.test.js.map +1 -0
  63. package/dist/services/hookService.d.ts +29 -0
  64. package/dist/services/hookService.d.ts.map +1 -0
  65. package/dist/services/hookService.js +164 -0
  66. package/dist/services/hookService.js.map +1 -0
  67. package/dist/services/statsService.d.ts +28 -0
  68. package/dist/services/statsService.d.ts.map +1 -0
  69. package/dist/services/statsService.js +204 -0
  70. package/dist/services/statsService.js.map +1 -0
  71. package/dist/types/index.d.ts +134 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/index.js +3 -0
  74. package/dist/types/index.js.map +1 -0
  75. package/dist/utils/filePatterns.d.ts +5 -0
  76. package/dist/utils/filePatterns.d.ts.map +1 -0
  77. package/dist/utils/filePatterns.js +77 -0
  78. package/dist/utils/filePatterns.js.map +1 -0
  79. package/dist/utils/filePatterns.test.d.ts +2 -0
  80. package/dist/utils/filePatterns.test.d.ts.map +1 -0
  81. package/dist/utils/filePatterns.test.js +51 -0
  82. package/dist/utils/filePatterns.test.js.map +1 -0
  83. package/dist/utils/prompt.d.ts +4 -0
  84. package/dist/utils/prompt.d.ts.map +1 -0
  85. package/dist/utils/prompt.js +60 -0
  86. package/dist/utils/prompt.js.map +1 -0
  87. package/package.json +47 -0
@@ -0,0 +1,39 @@
1
+ import { TicketInfo, CommitHistoryAnalysis, CommitType } from '../types';
2
+ export declare class HistoryService {
3
+ private static cachedAnalysis;
4
+ private static cacheTimestamp;
5
+ private static CACHE_TTL;
6
+ /**
7
+ * Detect ticket/issue reference from branch name
8
+ */
9
+ static detectTicketFromBranch(): TicketInfo | null;
10
+ /**
11
+ * Analyze commit history to learn project patterns
12
+ */
13
+ static analyzeCommitHistory(): CommitHistoryAnalysis;
14
+ /**
15
+ * Perform the actual analysis on commits
16
+ */
17
+ private static performAnalysis;
18
+ /**
19
+ * Get default analysis when no history is available
20
+ */
21
+ private static getDefaultAnalysis;
22
+ /**
23
+ * Get the most common commit type from history
24
+ */
25
+ static getMostCommonType(): CommitType | null;
26
+ /**
27
+ * Check if project historically uses emojis
28
+ */
29
+ static projectUsesEmojis(): boolean;
30
+ /**
31
+ * Get suggested scope based on history
32
+ */
33
+ static getSuggestedScope(filePaths: string[]): string | undefined;
34
+ /**
35
+ * Clear the cached analysis
36
+ */
37
+ static clearCache(): void;
38
+ }
39
+ //# sourceMappingURL=historyService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyService.d.ts","sourceRoot":"","sources":["../../src/services/historyService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAoB,UAAU,EAAE,MAAM,UAAU,CAAC;AAe3F,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,cAAc,CAAsC;IACnE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAa;IAC1C,OAAO,CAAC,MAAM,CAAC,SAAS,CAAS;IAEjC;;OAEG;IACH,MAAM,CAAC,sBAAsB,IAAI,UAAU,GAAG,IAAI;IA8BlD;;OAEG;IACH,MAAM,CAAC,oBAAoB,IAAI,qBAAqB;IA+BpD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAqE9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAYjC;;OAEG;IACH,MAAM,CAAC,iBAAiB,IAAI,UAAU,GAAG,IAAI;IAU7C;;OAEG;IACH,MAAM,CAAC,iBAAiB,IAAI,OAAO;IAKnC;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS;IAkBjE;;OAEG;IACH,MAAM,CAAC,UAAU,IAAI,IAAI;CAI1B"}
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HistoryService = void 0;
4
+ const gitService_1 = require("./gitService");
5
+ const configService_1 = require("./configService");
6
+ // Common ticket patterns for various issue trackers
7
+ const DEFAULT_TICKET_PATTERNS = [
8
+ /([A-Z]{2,10}-\d+)/g, // JIRA-style: ABC-123, PROJ-1234
9
+ /#(\d+)/g, // GitHub/GitLab: #123
10
+ /([A-Z]{2,10}_\d+)/g, // Underscore style: ABC_123
11
+ ];
12
+ // Common emojis used in commit messages
13
+ const EMOJI_PATTERN = /^[\u{1F300}-\u{1F9FF}]|^[\u{2600}-\u{26FF}]|^[\u{2700}-\u{27BF}]|^:[\w+-]+:/u;
14
+ // Conventional commit pattern
15
+ const CONVENTIONAL_COMMIT_PATTERN = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?!?:/i;
16
+ class HistoryService {
17
+ /**
18
+ * Detect ticket/issue reference from branch name
19
+ */
20
+ static detectTicketFromBranch() {
21
+ const config = configService_1.ConfigService.getConfig();
22
+ const ticketConfig = config.ticketLinking;
23
+ // Check if ticket linking is disabled
24
+ if (ticketConfig?.enabled === false) {
25
+ return null;
26
+ }
27
+ const branch = gitService_1.GitService.getCurrentBranch();
28
+ if (!branch)
29
+ return null;
30
+ // Use custom patterns if provided, otherwise use defaults
31
+ const patterns = ticketConfig?.patterns?.map(p => new RegExp(p, 'g')) || DEFAULT_TICKET_PATTERNS;
32
+ for (const pattern of patterns) {
33
+ pattern.lastIndex = 0; // Reset regex state
34
+ const match = pattern.exec(branch);
35
+ if (match) {
36
+ return {
37
+ id: match[1] || match[0],
38
+ source: 'branch',
39
+ prefix: ticketConfig?.prefix || 'Refs:',
40
+ };
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Analyze commit history to learn project patterns
47
+ */
48
+ static analyzeCommitHistory() {
49
+ const config = configService_1.ConfigService.getConfig();
50
+ const historyConfig = config.learnFromHistory;
51
+ // Check if history learning is disabled
52
+ if (historyConfig?.enabled === false) {
53
+ return this.getDefaultAnalysis();
54
+ }
55
+ // Return cached analysis if still valid
56
+ const now = Date.now();
57
+ if (this.cachedAnalysis && (now - this.cacheTimestamp) < this.CACHE_TTL) {
58
+ return this.cachedAnalysis;
59
+ }
60
+ const commitCount = historyConfig?.commitCount || 50;
61
+ const commits = gitService_1.GitService.getCommitHistory(commitCount);
62
+ if (commits.length === 0) {
63
+ return this.getDefaultAnalysis();
64
+ }
65
+ const analysis = this.performAnalysis(commits);
66
+ // Cache the result
67
+ this.cachedAnalysis = analysis;
68
+ this.cacheTimestamp = now;
69
+ return analysis;
70
+ }
71
+ /**
72
+ * Perform the actual analysis on commits
73
+ */
74
+ static performAnalysis(commits) {
75
+ let emojiCount = 0;
76
+ let conventionalCount = 0;
77
+ let totalLength = 0;
78
+ const scopeCount = {};
79
+ const verbCount = {};
80
+ const emojiFrequency = {};
81
+ const typeFrequency = {};
82
+ for (const commit of commits) {
83
+ const subject = commit.subject;
84
+ totalLength += subject.length;
85
+ // Check for emojis
86
+ const emojiMatch = subject.match(EMOJI_PATTERN);
87
+ if (emojiMatch) {
88
+ emojiCount++;
89
+ const emoji = emojiMatch[0];
90
+ emojiFrequency[emoji] = (emojiFrequency[emoji] || 0) + 1;
91
+ }
92
+ // Check for conventional commits
93
+ const conventionalMatch = subject.match(CONVENTIONAL_COMMIT_PATTERN);
94
+ if (conventionalMatch) {
95
+ conventionalCount++;
96
+ const type = conventionalMatch[1].toLowerCase();
97
+ typeFrequency[type] = (typeFrequency[type] || 0) + 1;
98
+ // Extract scope if present
99
+ if (conventionalMatch[2]) {
100
+ const scope = conventionalMatch[2].replace(/[()]/g, '');
101
+ scopeCount[scope] = (scopeCount[scope] || 0) + 1;
102
+ }
103
+ }
104
+ // Extract common verbs (first word after type or emoji)
105
+ const cleanSubject = subject
106
+ .replace(EMOJI_PATTERN, '')
107
+ .replace(CONVENTIONAL_COMMIT_PATTERN, '')
108
+ .trim();
109
+ const firstWord = cleanSubject.split(/\s+/)[0]?.toLowerCase();
110
+ if (firstWord && firstWord.length > 2 && /^[a-z]+$/.test(firstWord)) {
111
+ verbCount[firstWord] = (verbCount[firstWord] || 0) + 1;
112
+ }
113
+ }
114
+ // Sort and get top items
115
+ const sortedScopes = Object.entries(scopeCount)
116
+ .sort((a, b) => b[1] - a[1])
117
+ .slice(0, 10)
118
+ .map(([scope]) => scope);
119
+ const sortedVerbs = Object.entries(verbCount)
120
+ .sort((a, b) => b[1] - a[1])
121
+ .slice(0, 10)
122
+ .map(([verb]) => verb);
123
+ return {
124
+ usesEmojis: emojiCount > commits.length * 0.3, // 30% threshold
125
+ usesConventionalCommits: conventionalCount > commits.length * 0.5, // 50% threshold
126
+ commonScopes: sortedScopes,
127
+ commonVerbs: sortedVerbs,
128
+ averageLength: Math.round(totalLength / commits.length),
129
+ emojiFrequency,
130
+ typeFrequency,
131
+ };
132
+ }
133
+ /**
134
+ * Get default analysis when no history is available
135
+ */
136
+ static getDefaultAnalysis() {
137
+ return {
138
+ usesEmojis: true, // Default to current behavior
139
+ usesConventionalCommits: true,
140
+ commonScopes: [],
141
+ commonVerbs: ['add', 'update', 'fix', 'remove', 'refactor'],
142
+ averageLength: 50,
143
+ emojiFrequency: {},
144
+ typeFrequency: {},
145
+ };
146
+ }
147
+ /**
148
+ * Get the most common commit type from history
149
+ */
150
+ static getMostCommonType() {
151
+ const analysis = this.analyzeCommitHistory();
152
+ const types = Object.entries(analysis.typeFrequency);
153
+ if (types.length === 0)
154
+ return null;
155
+ types.sort((a, b) => b[1] - a[1]);
156
+ return types[0][0];
157
+ }
158
+ /**
159
+ * Check if project historically uses emojis
160
+ */
161
+ static projectUsesEmojis() {
162
+ const analysis = this.analyzeCommitHistory();
163
+ return analysis.usesEmojis;
164
+ }
165
+ /**
166
+ * Get suggested scope based on history
167
+ */
168
+ static getSuggestedScope(filePaths) {
169
+ const analysis = this.analyzeCommitHistory();
170
+ if (analysis.commonScopes.length === 0)
171
+ return undefined;
172
+ // Try to match file paths with common scopes
173
+ for (const scope of analysis.commonScopes) {
174
+ const scopeLower = scope.toLowerCase();
175
+ for (const filePath of filePaths) {
176
+ if (filePath.toLowerCase().includes(scopeLower)) {
177
+ return scope;
178
+ }
179
+ }
180
+ }
181
+ return undefined;
182
+ }
183
+ /**
184
+ * Clear the cached analysis
185
+ */
186
+ static clearCache() {
187
+ this.cachedAnalysis = null;
188
+ this.cacheTimestamp = 0;
189
+ }
190
+ }
191
+ exports.HistoryService = HistoryService;
192
+ HistoryService.cachedAnalysis = null;
193
+ HistoryService.cacheTimestamp = 0;
194
+ HistoryService.CACHE_TTL = 60000; // 1 minute cache
195
+ //# sourceMappingURL=historyService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyService.js","sourceRoot":"","sources":["../../src/services/historyService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=historyService.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyService.test.d.ts","sourceRoot":"","sources":["../../src/services/historyService.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const historyService_1 = require("./historyService");
4
+ const gitService_1 = require("./gitService");
5
+ const configService_1 = require("./configService");
6
+ // Mock dependencies
7
+ jest.mock('./gitService');
8
+ jest.mock('./configService');
9
+ const mockedGitService = gitService_1.GitService;
10
+ const mockedConfigService = configService_1.ConfigService;
11
+ describe('HistoryService', () => {
12
+ beforeEach(() => {
13
+ jest.clearAllMocks();
14
+ historyService_1.HistoryService.clearCache();
15
+ // Default config mock
16
+ mockedConfigService.getConfig.mockReturnValue({
17
+ scopes: [],
18
+ defaultType: 'feat',
19
+ maxMessageLength: 72,
20
+ });
21
+ });
22
+ describe('detectTicketFromBranch', () => {
23
+ it('should detect JIRA-style tickets from branch name', () => {
24
+ mockedGitService.getCurrentBranch.mockReturnValue('feature/ABC-123-add-login');
25
+ const ticket = historyService_1.HistoryService.detectTicketFromBranch();
26
+ expect(ticket).not.toBeNull();
27
+ expect(ticket?.id).toBe('ABC-123');
28
+ expect(ticket?.source).toBe('branch');
29
+ });
30
+ it('should detect GitHub-style issue numbers from branch name', () => {
31
+ mockedGitService.getCurrentBranch.mockReturnValue('fix/#456-bug-fix');
32
+ const ticket = historyService_1.HistoryService.detectTicketFromBranch();
33
+ expect(ticket).not.toBeNull();
34
+ expect(ticket?.id).toBe('456');
35
+ });
36
+ it('should return null when no ticket found', () => {
37
+ mockedGitService.getCurrentBranch.mockReturnValue('feature/add-new-feature');
38
+ const ticket = historyService_1.HistoryService.detectTicketFromBranch();
39
+ expect(ticket).toBeNull();
40
+ });
41
+ it('should return null when ticket linking is disabled', () => {
42
+ mockedConfigService.getConfig.mockReturnValue({
43
+ scopes: [],
44
+ defaultType: 'feat',
45
+ maxMessageLength: 72,
46
+ ticketLinking: {
47
+ enabled: false,
48
+ },
49
+ });
50
+ mockedGitService.getCurrentBranch.mockReturnValue('feature/ABC-123-add-login');
51
+ const ticket = historyService_1.HistoryService.detectTicketFromBranch();
52
+ expect(ticket).toBeNull();
53
+ });
54
+ it('should use custom patterns when provided', () => {
55
+ mockedConfigService.getConfig.mockReturnValue({
56
+ scopes: [],
57
+ defaultType: 'feat',
58
+ maxMessageLength: 72,
59
+ ticketLinking: {
60
+ enabled: true,
61
+ patterns: ['CUSTOM-(\\d+)'],
62
+ prefix: 'Fixes:',
63
+ },
64
+ });
65
+ mockedGitService.getCurrentBranch.mockReturnValue('feature/CUSTOM-999-task');
66
+ const ticket = historyService_1.HistoryService.detectTicketFromBranch();
67
+ expect(ticket).not.toBeNull();
68
+ expect(ticket?.id).toBe('999');
69
+ expect(ticket?.prefix).toBe('Fixes:');
70
+ });
71
+ });
72
+ describe('analyzeCommitHistory', () => {
73
+ it('should detect emoji usage in history', () => {
74
+ mockedGitService.getCommitHistory.mockReturnValue([
75
+ { hash: '1', subject: '✨ feat: add feature', message: '✨ feat: add feature' },
76
+ { hash: '2', subject: '🐛 fix: fix bug', message: '🐛 fix: fix bug' },
77
+ { hash: '3', subject: '📚 docs: update readme', message: '📚 docs: update readme' },
78
+ ]);
79
+ const analysis = historyService_1.HistoryService.analyzeCommitHistory();
80
+ expect(analysis.usesEmojis).toBe(true);
81
+ });
82
+ it('should detect conventional commits', () => {
83
+ mockedGitService.getCommitHistory.mockReturnValue([
84
+ { hash: '1', subject: 'feat: add feature', message: 'feat: add feature' },
85
+ { hash: '2', subject: 'fix: fix bug', message: 'fix: fix bug' },
86
+ { hash: '3', subject: 'docs: update readme', message: 'docs: update readme' },
87
+ ]);
88
+ const analysis = historyService_1.HistoryService.analyzeCommitHistory();
89
+ expect(analysis.usesConventionalCommits).toBe(true);
90
+ });
91
+ it('should extract common scopes', () => {
92
+ mockedGitService.getCommitHistory.mockReturnValue([
93
+ { hash: '1', subject: 'feat(api): add endpoint', message: 'feat(api): add endpoint' },
94
+ { hash: '2', subject: 'fix(api): fix bug', message: 'fix(api): fix bug' },
95
+ { hash: '3', subject: 'feat(ui): add button', message: 'feat(ui): add button' },
96
+ ]);
97
+ const analysis = historyService_1.HistoryService.analyzeCommitHistory();
98
+ expect(analysis.commonScopes).toContain('api');
99
+ expect(analysis.commonScopes).toContain('ui');
100
+ });
101
+ it('should return default analysis when history is empty', () => {
102
+ mockedGitService.getCommitHistory.mockReturnValue([]);
103
+ const analysis = historyService_1.HistoryService.analyzeCommitHistory();
104
+ expect(analysis.usesEmojis).toBe(true);
105
+ expect(analysis.usesConventionalCommits).toBe(true);
106
+ });
107
+ it('should return default analysis when history learning is disabled', () => {
108
+ mockedConfigService.getConfig.mockReturnValue({
109
+ scopes: [],
110
+ defaultType: 'feat',
111
+ maxMessageLength: 72,
112
+ learnFromHistory: {
113
+ enabled: false,
114
+ },
115
+ });
116
+ const analysis = historyService_1.HistoryService.analyzeCommitHistory();
117
+ expect(analysis.usesEmojis).toBe(true);
118
+ expect(analysis.usesConventionalCommits).toBe(true);
119
+ });
120
+ it('should cache analysis results', () => {
121
+ mockedGitService.getCommitHistory.mockReturnValue([
122
+ { hash: '1', subject: 'feat: add feature', message: 'feat: add feature' },
123
+ ]);
124
+ historyService_1.HistoryService.analyzeCommitHistory();
125
+ historyService_1.HistoryService.analyzeCommitHistory();
126
+ historyService_1.HistoryService.analyzeCommitHistory();
127
+ expect(mockedGitService.getCommitHistory).toHaveBeenCalledTimes(1);
128
+ });
129
+ });
130
+ describe('projectUsesEmojis', () => {
131
+ it('should return true when project uses emojis', () => {
132
+ mockedGitService.getCommitHistory.mockReturnValue([
133
+ { hash: '1', subject: '✨ feat: add feature', message: '✨ feat: add feature' },
134
+ { hash: '2', subject: '🐛 fix: fix bug', message: '🐛 fix: fix bug' },
135
+ ]);
136
+ expect(historyService_1.HistoryService.projectUsesEmojis()).toBe(true);
137
+ });
138
+ });
139
+ describe('getSuggestedScope', () => {
140
+ it('should suggest scope based on file paths matching history', () => {
141
+ mockedGitService.getCommitHistory.mockReturnValue([
142
+ { hash: '1', subject: 'feat(api): add endpoint', message: 'feat(api): add endpoint' },
143
+ { hash: '2', subject: 'feat(api): update endpoint', message: 'feat(api): update endpoint' },
144
+ ]);
145
+ const scope = historyService_1.HistoryService.getSuggestedScope(['src/api/users.ts']);
146
+ expect(scope).toBe('api');
147
+ });
148
+ it('should return undefined when no match found', () => {
149
+ mockedGitService.getCommitHistory.mockReturnValue([
150
+ { hash: '1', subject: 'feat(api): add endpoint', message: 'feat(api): add endpoint' },
151
+ ]);
152
+ const scope = historyService_1.HistoryService.getSuggestedScope(['src/utils/helper.ts']);
153
+ expect(scope).toBeUndefined();
154
+ });
155
+ });
156
+ });
157
+ //# sourceMappingURL=historyService.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"historyService.test.js","sourceRoot":"","sources":["../../src/services/historyService.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export declare class HookService {
2
+ /**
3
+ * Get the path to the git hooks directory
4
+ */
5
+ static getHooksDir(): string;
6
+ /**
7
+ * Get the path to the prepare-commit-msg hook
8
+ */
9
+ static getHookPath(): string;
10
+ /**
11
+ * Check if the hook is already installed
12
+ */
13
+ static isInstalled(): boolean;
14
+ /**
15
+ * Install the prepare-commit-msg hook
16
+ */
17
+ static install(): {
18
+ success: boolean;
19
+ message: string;
20
+ };
21
+ /**
22
+ * Uninstall the prepare-commit-msg hook
23
+ */
24
+ static uninstall(): {
25
+ success: boolean;
26
+ message: string;
27
+ };
28
+ }
29
+ //# sourceMappingURL=hookService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hookService.d.ts","sourceRoot":"","sources":["../../src/services/hookService.ts"],"names":[],"mappings":"AAgCA,qBAAa,WAAW;IACtB;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,MAAM;IAK5B;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,MAAM;IAI5B;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,OAAO;IAS7B;;OAEG;IACH,MAAM,CAAC,OAAO,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAqCvD;;OAEG;IACH,MAAM,CAAC,SAAS,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAoC1D"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HookService = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const gitService_1 = require("./gitService");
40
+ const HOOK_NAME = 'prepare-commit-msg';
41
+ const HOOK_SCRIPT = `#!/bin/sh
42
+ # CommitGenie prepare-commit-msg hook
43
+ # This hook generates a commit message suggestion
44
+
45
+ COMMIT_MSG_FILE=$1
46
+ COMMIT_SOURCE=$2
47
+
48
+ # Only run for regular commits (not merges, squashes, etc.)
49
+ if [ -z "$COMMIT_SOURCE" ]; then
50
+ # Check if commit-genie is available
51
+ if command -v commit-genie &> /dev/null; then
52
+ # Generate message and write to file
53
+ MESSAGE=$(commit-genie --message-only 2>/dev/null)
54
+ if [ -n "$MESSAGE" ]; then
55
+ echo "$MESSAGE" > "$COMMIT_MSG_FILE"
56
+ fi
57
+ elif command -v npx &> /dev/null; then
58
+ # Fallback to npx if commit-genie is not globally installed
59
+ MESSAGE=$(npx --yes commit-genie --message-only 2>/dev/null)
60
+ if [ -n "$MESSAGE" ]; then
61
+ echo "$MESSAGE" > "$COMMIT_MSG_FILE"
62
+ fi
63
+ fi
64
+ fi
65
+ `;
66
+ class HookService {
67
+ /**
68
+ * Get the path to the git hooks directory
69
+ */
70
+ static getHooksDir() {
71
+ const gitDir = gitService_1.GitService.getGitDir();
72
+ return path.join(gitDir, 'hooks');
73
+ }
74
+ /**
75
+ * Get the path to the prepare-commit-msg hook
76
+ */
77
+ static getHookPath() {
78
+ return path.join(this.getHooksDir(), HOOK_NAME);
79
+ }
80
+ /**
81
+ * Check if the hook is already installed
82
+ */
83
+ static isInstalled() {
84
+ const hookPath = this.getHookPath();
85
+ if (!fs.existsSync(hookPath)) {
86
+ return false;
87
+ }
88
+ const content = fs.readFileSync(hookPath, 'utf-8');
89
+ return content.includes('CommitGenie');
90
+ }
91
+ /**
92
+ * Install the prepare-commit-msg hook
93
+ */
94
+ static install() {
95
+ try {
96
+ const hookPath = this.getHookPath();
97
+ const hooksDir = this.getHooksDir();
98
+ // Ensure hooks directory exists
99
+ if (!fs.existsSync(hooksDir)) {
100
+ fs.mkdirSync(hooksDir, { recursive: true });
101
+ }
102
+ // Check if hook already exists
103
+ if (fs.existsSync(hookPath)) {
104
+ const existingContent = fs.readFileSync(hookPath, 'utf-8');
105
+ if (existingContent.includes('CommitGenie')) {
106
+ return { success: true, message: 'Hook is already installed.' };
107
+ }
108
+ // Backup existing hook
109
+ const backupPath = `${hookPath}.backup`;
110
+ fs.copyFileSync(hookPath, backupPath);
111
+ return {
112
+ success: false,
113
+ message: `Existing hook found. Backed up to ${backupPath}. Please manually integrate or remove the existing hook.`,
114
+ };
115
+ }
116
+ // Write the hook
117
+ fs.writeFileSync(hookPath, HOOK_SCRIPT, { mode: 0o755 });
118
+ return { success: true, message: 'Hook installed successfully!' };
119
+ }
120
+ catch (error) {
121
+ return {
122
+ success: false,
123
+ message: `Failed to install hook: ${error instanceof Error ? error.message : error}`,
124
+ };
125
+ }
126
+ }
127
+ /**
128
+ * Uninstall the prepare-commit-msg hook
129
+ */
130
+ static uninstall() {
131
+ try {
132
+ const hookPath = this.getHookPath();
133
+ if (!fs.existsSync(hookPath)) {
134
+ return { success: true, message: 'Hook is not installed.' };
135
+ }
136
+ const content = fs.readFileSync(hookPath, 'utf-8');
137
+ if (!content.includes('CommitGenie')) {
138
+ return {
139
+ success: false,
140
+ message: 'Hook exists but was not installed by CommitGenie. Not removing.',
141
+ };
142
+ }
143
+ fs.unlinkSync(hookPath);
144
+ // Restore backup if exists
145
+ const backupPath = `${hookPath}.backup`;
146
+ if (fs.existsSync(backupPath)) {
147
+ fs.renameSync(backupPath, hookPath);
148
+ return {
149
+ success: true,
150
+ message: 'Hook uninstalled and previous hook restored.',
151
+ };
152
+ }
153
+ return { success: true, message: 'Hook uninstalled successfully!' };
154
+ }
155
+ catch (error) {
156
+ return {
157
+ success: false,
158
+ message: `Failed to uninstall hook: ${error instanceof Error ? error.message : error}`,
159
+ };
160
+ }
161
+ }
162
+ }
163
+ exports.HookService = HookService;
164
+ //# sourceMappingURL=hookService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hookService.js","sourceRoot":"","sources":["../../src/services/hookService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { CommitStats } from '../types';
2
+ export declare class StatsService {
3
+ /**
4
+ * Get commit statistics for the repository
5
+ */
6
+ static getCommitStats(commitCount?: number): CommitStats;
7
+ /**
8
+ * Get commits from git history
9
+ */
10
+ private static getCommits;
11
+ /**
12
+ * Get recent activity for the last 7 days
13
+ */
14
+ private static getRecentActivity;
15
+ /**
16
+ * Get empty stats object
17
+ */
18
+ private static getEmptyStats;
19
+ /**
20
+ * Format stats for display
21
+ */
22
+ static formatStats(stats: CommitStats): string;
23
+ /**
24
+ * Create a visual bar for charts
25
+ */
26
+ private static createBar;
27
+ }
28
+ //# sourceMappingURL=statsService.d.ts.map