commitect 1.0.3 → 1.1.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.
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- const VERSION = '1.0.3';
2
+ const VERSION = '1.1.0';
3
3
  const GITHUB_REPO = 'https://github.com/Mohammed-3tef/CommiTect_CLI';
4
4
  const ISSUES_URL = GITHUB_REPO + '/issues';
5
5
  export function helpCommand() {
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ const program = new Command();
10
10
  program
11
11
  .name('commitect')
12
12
  .description('Zero-config Git Commit Assistant')
13
- .version('1.0.3');
13
+ .version('1.1.0');
14
14
  program
15
15
  .command('analyze')
16
16
  .description('Analyze changes and suggest a commit message')
@@ -2,5 +2,10 @@ export interface CommitSuggestion {
2
2
  intent: string;
3
3
  message: string;
4
4
  }
5
- export declare function generateCommitMessage(diff: string): Promise<CommitSuggestion>;
5
+ interface ChangeSummary {
6
+ total?: number;
7
+ renamed?: number;
8
+ }
9
+ export declare function generateCommitMessage(diff: string, summary?: ChangeSummary): Promise<CommitSuggestion>;
10
+ export {};
6
11
  //# sourceMappingURL=llm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAsFnF"}
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAyBD,UAAU,aAAa;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAsF5G"}
@@ -2,7 +2,7 @@ import axios from 'axios';
2
2
  import crypto from 'crypto';
3
3
  import { commitCache } from '../utils/cache.js';
4
4
  const API_ENDPOINT = 'http://commitintentdetector.runasp.net/api/Commit/analyze';
5
- export async function generateCommitMessage(diff) {
5
+ export async function generateCommitMessage(diff, summary) {
6
6
  const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
7
7
  // Check cache first
8
8
  const cached = commitCache.get(diffHash);
@@ -68,7 +68,7 @@ export async function generateCommitMessage(diff) {
68
68
  }
69
69
  }
70
70
  console.warn('⚠ AI service unavailable, using fallback commit message.');
71
- return generateFallbackCommit(diff);
71
+ return generateFallbackCommit(diff, summary);
72
72
  }
73
73
  function parseResponse(response) {
74
74
  const lines = response.trim().split('\n');
@@ -90,37 +90,183 @@ function parseResponse(response) {
90
90
  }
91
91
  return { intent, message };
92
92
  }
93
- function generateFallbackCommit(diff) {
94
- const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
95
- const lowerDiff = diff.toLowerCase();
96
- let intent;
97
- let message;
98
- if (/(fix|bug|error|issue|crash|fault)/i.test(lowerDiff)) {
99
- intent = 'Bug Fix';
100
- message = 'fix reported issue';
101
- }
102
- else if (/(add|create|implement|introduce|new)/i.test(lowerDiff)) {
103
- intent = 'Feature';
104
- message = 'add new functionality';
105
- }
106
- else if (/(refactor|cleanup|restructure|optimize)/i.test(lowerDiff)) {
107
- intent = 'Refactor';
108
- message = 'refactor code structure';
93
+ function extractFilesFromDiff(diff) {
94
+ const files = new Set();
95
+ const regex = /^diff --git a\/(.+?) b\/(.+)$/gm;
96
+ let match;
97
+ while ((match = regex.exec(diff))) {
98
+ files.add(match[2]);
109
99
  }
110
- else if (/(doc|readme|comment)/i.test(lowerDiff)) {
111
- intent = 'Docs';
112
- message = 'update documentation';
113
- }
114
- else if (/(test|spec|coverage)/i.test(lowerDiff)) {
115
- intent = 'Test';
116
- message = 'update tests';
117
- }
118
- else {
119
- intent = 'Chore';
120
- message = 'update project files';
100
+ return [...files];
101
+ }
102
+ function isTrivialWhitespace(lines) {
103
+ return lines.every(l => /^[+-]\s*$/.test(l) ||
104
+ /^[+-]\s*[{}();,]*\s*$/.test(l));
105
+ }
106
+ /**
107
+ * Analyze the diff content for patterns
108
+ * @param diff - The git diff string
109
+ * @param summary - Optional summary with file change counts
110
+ * @returns Analysis results with detected patterns
111
+ */
112
+ function analyzeDiff(diff, summary = {}) {
113
+ const lines = diff.split('\n');
114
+ const lowerDiff = diff.toLowerCase();
115
+ const files = extractFilesFromDiff(diff);
116
+ const addedLines = lines.filter(l => l.startsWith('+') && !l.startsWith('+++'));
117
+ const removedLines = lines.filter(l => l.startsWith('-') && !l.startsWith('---'));
118
+ const additions = addedLines.length;
119
+ const deletions = removedLines.length;
120
+ const matchesAny = (patterns, text) => patterns.some(p => p.test(text));
121
+ const patterns = {
122
+ bugFix: [/\b(fix(e[ds])?|bug|error|issue|crash|incorrect|fault)\b/i],
123
+ testFix: [/\b(fix|repair|correct).*(test|spec)\b/i],
124
+ refactor: [/\b(refactor|cleanup|simplify|restructure|reorganize)\b/i],
125
+ style: [/\b(format|lint|prettier|indent)\b/i]
126
+ };
127
+ const hasDocsChange = files.some(f => /\.(md|rst|txt)$/i.test(f) || /readme/i.test(f));
128
+ const hasTestChange = files.some(f => /(__tests__|\.test\.|\.spec\.)/i.test(f));
129
+ const hasConfigChange = files.some(f => /\.(json|ya?ml|env|toml)$/i.test(f));
130
+ const hasDependencyChange = files.some(f => /(package(-lock)?\.json|requirements\.txt|go\.mod|pom\.xml)/i.test(f));
131
+ const hasNewFunction = addedLines.some(l => /^\+\s*(export\s+)?(async\s+)?function\s+\w+/.test(l) ||
132
+ /^\+\s*(export\s+)?const\s+\w+\s*=\s*(async\s*)?\(/.test(l));
133
+ const hasNewClass = addedLines.some(l => /^\+\s*(export\s+)?class\s+\w+/.test(l));
134
+ const hasNewEndpoint = addedLines.some(l => /\b(app|router)\.(get|post|put|delete|patch)\b/i.test(l)) ||
135
+ /^\+\s*@(Get|Post|Put|Delete|Patch)\b/m.test(diff);
136
+ const hasNewComponent = files.some(f => /\.(jsx|tsx)$/i.test(f)) &&
137
+ addedLines.some(l => /^\+\s*(export\s+)?(function|const)\s+[A-Z]\w*/.test(l));
138
+ const hasWhitespaceOnly = additions + deletions > 0 &&
139
+ isTrivialWhitespace([...addedLines, ...removedLines]);
140
+ return {
141
+ hasBugFix: matchesAny(patterns.bugFix, diff),
142
+ hasTestFix: hasTestChange && matchesAny(patterns.testFix, diff),
143
+ hasNewFunction,
144
+ hasNewClass,
145
+ hasNewEndpoint,
146
+ hasNewComponent,
147
+ hasRefactor: matchesAny(patterns.refactor, diff),
148
+ hasRename: (summary.renamed ?? 0) > 0,
149
+ hasMovedCode: (summary.renamed ?? 0) > 0 && additions > 0 && deletions > 0,
150
+ hasDocsChange,
151
+ hasCommentChange: addedLines.some(l => /^\+\s*(\/\/|\/\*|\*)/.test(l)),
152
+ hasTestChange,
153
+ hasDeletions: deletions > 0,
154
+ hasStyleChange: matchesAny(patterns.style, diff),
155
+ hasWhitespaceOnly,
156
+ hasConfigChange,
157
+ hasDependencyChange,
158
+ additions,
159
+ deletions,
160
+ hasChanges: additions + deletions > 0
161
+ };
162
+ }
163
+ /**
164
+ * Determine the commit intent type based on analysis
165
+ * @param analysis - Analysis results from analyzeDiff
166
+ * @param summary - Changes summary
167
+ * @returns The intent type string
168
+ */
169
+ function determineIntent(analysis, summary = {}) {
170
+ if (!analysis.hasChanges)
171
+ return 'Chore';
172
+ if (analysis.hasBugFix || analysis.hasTestFix)
173
+ return 'Bug Fix';
174
+ if (analysis.hasTestChange && !analysis.hasBugFix)
175
+ return 'Test';
176
+ if (analysis.hasDocsChange)
177
+ return 'Documentation';
178
+ if (analysis.hasRefactor ||
179
+ analysis.hasMovedCode ||
180
+ (analysis.deletions > analysis.additions * 2))
181
+ return 'Refactor';
182
+ if (analysis.hasNewFunction ||
183
+ analysis.hasNewClass ||
184
+ analysis.hasNewComponent ||
185
+ analysis.hasNewEndpoint)
186
+ return 'Feature';
187
+ if (analysis.hasDependencyChange || analysis.hasConfigChange)
188
+ return 'Chore';
189
+ if (analysis.hasStyleChange || analysis.hasWhitespaceOnly)
190
+ return 'Style';
191
+ return 'Update';
192
+ }
193
+ /**
194
+ * Generate a descriptive commit message based on analysis
195
+ * @param analysis - Analysis results from analyzeDiff
196
+ * @param intent - The determined intent type
197
+ * @returns A commit message string
198
+ */
199
+ function generateMessage(analysis, intent, summary = {}) {
200
+ const fileCount = summary.total;
201
+ const hasFileCount = typeof fileCount === 'number' && fileCount > 0;
202
+ const fileWord = fileCount === 1 ? 'file' : 'files';
203
+ switch (intent) {
204
+ case 'Bug Fix':
205
+ return analysis.hasTestFix
206
+ ? hasFileCount
207
+ ? `fix failing tests in ${fileCount} ${fileWord}`
208
+ : 'fix failing tests'
209
+ : hasFileCount
210
+ ? `fix issues in ${fileCount} ${fileWord}`
211
+ : 'fix issues';
212
+ case 'Feature':
213
+ if (analysis.hasNewEndpoint)
214
+ return 'add new API endpoints';
215
+ if (analysis.hasNewComponent)
216
+ return 'add new components';
217
+ if (analysis.hasNewClass || analysis.hasNewFunction)
218
+ return hasFileCount
219
+ ? `add new functionality to ${fileCount} ${fileWord}`
220
+ : 'add new functionality';
221
+ return hasFileCount
222
+ ? `implement new features in ${fileCount} ${fileWord}`
223
+ : 'implement new features';
224
+ case 'Refactor':
225
+ if (analysis.hasMovedCode)
226
+ return hasFileCount
227
+ ? `restructure code in ${fileCount} ${fileWord}`
228
+ : 'restructure code';
229
+ if (analysis.deletions > analysis.additions * 2)
230
+ return hasFileCount
231
+ ? `remove unused code from ${fileCount} ${fileWord}`
232
+ : 'remove unused code';
233
+ return hasFileCount
234
+ ? `refactor code in ${fileCount} ${fileWord}`
235
+ : 'refactor code';
236
+ case 'Test':
237
+ return hasFileCount
238
+ ? `add/update tests in ${fileCount} ${fileWord}`
239
+ : 'add/update tests';
240
+ case 'Chore':
241
+ if (analysis.hasDependencyChange)
242
+ return 'update dependencies';
243
+ if (analysis.hasConfigChange)
244
+ return 'update configuration files';
245
+ return 'update project configuration';
246
+ case 'Style':
247
+ return hasFileCount
248
+ ? `format and style ${fileCount} ${fileWord}`
249
+ : 'format and style code';
250
+ case 'Documentation':
251
+ return hasFileCount
252
+ ? fileCount === 1
253
+ ? 'update documentation'
254
+ : `update documentation in ${fileCount} ${fileWord}`
255
+ : 'update documentation';
256
+ default:
257
+ return hasFileCount
258
+ ? `update ${fileCount} ${fileWord}`
259
+ : 'update code';
121
260
  }
261
+ }
262
+ function generateFallbackCommit(diff, summary) {
263
+ const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
264
+ const analysis = analyzeDiff(diff, summary);
265
+ const intent = determineIntent(analysis, summary);
266
+ const message = generateMessage(analysis, intent, summary);
267
+ const result = { intent, message };
122
268
  commitCache.set(diffHash, intent, message);
123
- return { intent, message };
269
+ return result;
124
270
  }
125
271
  function sleep(ms) {
126
272
  return new Promise(resolve => setTimeout(resolve, ms));
@@ -1 +1 @@
1
- {"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commitect",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Zero-config Git Commit Assistant CLI",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
Binary file
@@ -1,6 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
 
3
- const VERSION = '1.0.3';
3
+ const VERSION = '1.1.0';
4
4
  const GITHUB_REPO = 'https://github.com/Mohammed-3tef/CommiTect_CLI';
5
5
  const ISSUES_URL = GITHUB_REPO + '/issues';
6
6
 
package/src/index.ts CHANGED
@@ -12,7 +12,7 @@ const program = new Command();
12
12
  program
13
13
  .name('commitect')
14
14
  .description('Zero-config Git Commit Assistant')
15
- .version('1.0.3');
15
+ .version('1.1.0');
16
16
 
17
17
  program
18
18
  .command('analyze')
@@ -7,9 +7,37 @@ export interface CommitSuggestion {
7
7
  message: string;
8
8
  }
9
9
 
10
+ interface DiffAnalysis {
11
+ hasBugFix: boolean;
12
+ hasTestFix: boolean;
13
+ hasNewFunction: boolean;
14
+ hasNewClass: boolean;
15
+ hasNewEndpoint: boolean;
16
+ hasNewComponent: boolean;
17
+ hasRefactor: boolean;
18
+ hasRename: boolean;
19
+ hasMovedCode: boolean;
20
+ hasDocsChange: boolean;
21
+ hasCommentChange: boolean;
22
+ hasTestChange: boolean;
23
+ hasDeletions: boolean;
24
+ hasStyleChange: boolean;
25
+ hasWhitespaceOnly: boolean;
26
+ hasConfigChange: boolean;
27
+ hasDependencyChange: boolean;
28
+ additions: number;
29
+ deletions: number;
30
+ hasChanges: boolean;
31
+ }
32
+
33
+ interface ChangeSummary {
34
+ total?: number;
35
+ renamed?: number;
36
+ }
37
+
10
38
  const API_ENDPOINT = 'http://commitintentdetector.runasp.net/api/Commit/analyze';
11
39
 
12
- export async function generateCommitMessage(diff: string): Promise<CommitSuggestion> {
40
+ export async function generateCommitMessage(diff: string, summary?: ChangeSummary): Promise<CommitSuggestion> {
13
41
  const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
14
42
 
15
43
  // Check cache first
@@ -94,7 +122,7 @@ export async function generateCommitMessage(diff: string): Promise<CommitSuggest
94
122
  }
95
123
 
96
124
  console.warn('⚠ AI service unavailable, using fallback commit message.');
97
- return generateFallbackCommit(diff);
125
+ return generateFallbackCommit(diff, summary);
98
126
  }
99
127
 
100
128
  function parseResponse(response: string): CommitSuggestion {
@@ -122,42 +150,245 @@ function parseResponse(response: string): CommitSuggestion {
122
150
  return { intent, message };
123
151
  }
124
152
 
125
- function generateFallbackCommit(diff: string): CommitSuggestion {
126
- const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
153
+ function extractFilesFromDiff(diff: string): string[] {
154
+ const files = new Set<string>();
155
+ const regex = /^diff --git a\/(.+?) b\/(.+)$/gm;
156
+ let match;
157
+ while ((match = regex.exec(diff))) {
158
+ files.add(match[2]);
159
+ }
160
+ return [...files];
161
+ }
162
+
163
+ function isTrivialWhitespace(lines: string[]): boolean {
164
+ return lines.every(l =>
165
+ /^[+-]\s*$/.test(l) ||
166
+ /^[+-]\s*[{}();,]*\s*$/.test(l)
167
+ );
168
+ }
169
+
170
+ /**
171
+ * Analyze the diff content for patterns
172
+ * @param diff - The git diff string
173
+ * @param summary - Optional summary with file change counts
174
+ * @returns Analysis results with detected patterns
175
+ */
176
+ function analyzeDiff(diff: string, summary: ChangeSummary = {}): DiffAnalysis {
177
+ const lines = diff.split('\n');
127
178
  const lowerDiff = diff.toLowerCase();
179
+ const files = extractFilesFromDiff(diff);
180
+
181
+ const addedLines = lines.filter(l => l.startsWith('+') && !l.startsWith('+++'));
182
+ const removedLines = lines.filter(l => l.startsWith('-') && !l.startsWith('---'));
183
+
184
+ const additions = addedLines.length;
185
+ const deletions = removedLines.length;
186
+
187
+ const matchesAny = (patterns: RegExp[], text: string): boolean =>
188
+ patterns.some(p => p.test(text));
189
+
190
+ const patterns = {
191
+ bugFix: [/\b(fix(e[ds])?|bug|error|issue|crash|incorrect|fault)\b/i],
192
+ testFix: [/\b(fix|repair|correct).*(test|spec)\b/i],
193
+ refactor: [/\b(refactor|cleanup|simplify|restructure|reorganize)\b/i],
194
+ style: [/\b(format|lint|prettier|indent)\b/i]
195
+ };
196
+
197
+ const hasDocsChange = files.some(f =>
198
+ /\.(md|rst|txt)$/i.test(f) || /readme/i.test(f)
199
+ );
200
+
201
+ const hasTestChange = files.some(f =>
202
+ /(__tests__|\.test\.|\.spec\.)/i.test(f)
203
+ );
204
+
205
+ const hasConfigChange = files.some(f =>
206
+ /\.(json|ya?ml|env|toml)$/i.test(f)
207
+ );
208
+
209
+ const hasDependencyChange = files.some(f =>
210
+ /(package(-lock)?\.json|requirements\.txt|go\.mod|pom\.xml)/i.test(f)
211
+ );
212
+
213
+ const hasNewFunction =
214
+ addedLines.some(l =>
215
+ /^\+\s*(export\s+)?(async\s+)?function\s+\w+/.test(l) ||
216
+ /^\+\s*(export\s+)?const\s+\w+\s*=\s*(async\s*)?\(/.test(l)
217
+ );
218
+
219
+ const hasNewClass =
220
+ addedLines.some(l =>
221
+ /^\+\s*(export\s+)?class\s+\w+/.test(l)
222
+ );
223
+
224
+ const hasNewEndpoint =
225
+ addedLines.some(l =>
226
+ /\b(app|router)\.(get|post|put|delete|patch)\b/i.test(l)
227
+ ) ||
228
+ /^\+\s*@(Get|Post|Put|Delete|Patch)\b/m.test(diff);
229
+
230
+ const hasNewComponent =
231
+ files.some(f => /\.(jsx|tsx)$/i.test(f)) &&
232
+ addedLines.some(l =>
233
+ /^\+\s*(export\s+)?(function|const)\s+[A-Z]\w*/.test(l)
234
+ );
235
+
236
+ const hasWhitespaceOnly =
237
+ additions + deletions > 0 &&
238
+ isTrivialWhitespace([...addedLines, ...removedLines]);
239
+
240
+ return {
241
+ hasBugFix: matchesAny(patterns.bugFix, diff),
242
+ hasTestFix: hasTestChange && matchesAny(patterns.testFix, diff),
243
+
244
+ hasNewFunction,
245
+ hasNewClass,
246
+ hasNewEndpoint,
247
+ hasNewComponent,
248
+
249
+ hasRefactor: matchesAny(patterns.refactor, diff),
250
+
251
+ hasRename: (summary.renamed ?? 0) > 0,
252
+ hasMovedCode: (summary.renamed ?? 0) > 0 && additions > 0 && deletions > 0,
128
253
 
129
- let intent: CommitSuggestion['intent'];
130
- let message: string;
131
-
132
- if (/(fix|bug|error|issue|crash|fault)/i.test(lowerDiff)) {
133
- intent = 'Bug Fix';
134
- message = 'fix reported issue';
135
- }
136
- else if (/(add|create|implement|introduce|new)/i.test(lowerDiff)) {
137
- intent = 'Feature';
138
- message = 'add new functionality';
139
- }
140
- else if (/(refactor|cleanup|restructure|optimize)/i.test(lowerDiff)) {
141
- intent = 'Refactor';
142
- message = 'refactor code structure';
143
- }
144
- else if (/(doc|readme|comment)/i.test(lowerDiff)) {
145
- intent = 'Docs';
146
- message = 'update documentation';
147
- }
148
- else if (/(test|spec|coverage)/i.test(lowerDiff)) {
149
- intent = 'Test';
150
- message = 'update tests';
151
- }
152
- else {
153
- intent = 'Chore';
154
- message = 'update project files';
254
+ hasDocsChange,
255
+ hasCommentChange: addedLines.some(l => /^\+\s*(\/\/|\/\*|\*)/.test(l)),
256
+ hasTestChange,
257
+
258
+ hasDeletions: deletions > 0,
259
+ hasStyleChange: matchesAny(patterns.style, diff),
260
+
261
+ hasWhitespaceOnly,
262
+ hasConfigChange,
263
+ hasDependencyChange,
264
+
265
+ additions,
266
+ deletions,
267
+ hasChanges: additions + deletions > 0
268
+ };
269
+ }
270
+
271
+ /**
272
+ * Determine the commit intent type based on analysis
273
+ * @param analysis - Analysis results from analyzeDiff
274
+ * @param summary - Changes summary
275
+ * @returns The intent type string
276
+ */
277
+ function determineIntent(analysis: DiffAnalysis, summary: ChangeSummary = {}): string {
278
+ if (!analysis.hasChanges) return 'Chore';
279
+
280
+ if (analysis.hasBugFix || analysis.hasTestFix) return 'Bug Fix';
281
+ if (analysis.hasTestChange && !analysis.hasBugFix) return 'Test';
282
+ if (analysis.hasDocsChange) return 'Documentation';
283
+
284
+ if (
285
+ analysis.hasRefactor ||
286
+ analysis.hasMovedCode ||
287
+ (analysis.deletions > analysis.additions * 2)
288
+ )
289
+ return 'Refactor';
290
+
291
+ if (
292
+ analysis.hasNewFunction ||
293
+ analysis.hasNewClass ||
294
+ analysis.hasNewComponent ||
295
+ analysis.hasNewEndpoint
296
+ )
297
+ return 'Feature';
298
+
299
+ if (analysis.hasDependencyChange || analysis.hasConfigChange) return 'Chore';
300
+ if (analysis.hasStyleChange || analysis.hasWhitespaceOnly) return 'Style';
301
+
302
+ return 'Update';
303
+ }
304
+
305
+ /**
306
+ * Generate a descriptive commit message based on analysis
307
+ * @param analysis - Analysis results from analyzeDiff
308
+ * @param intent - The determined intent type
309
+ * @returns A commit message string
310
+ */
311
+ function generateMessage(analysis: DiffAnalysis, intent: string, summary: ChangeSummary = {}): string {
312
+ const fileCount = summary.total;
313
+ const hasFileCount = typeof fileCount === 'number' && fileCount > 0;
314
+ const fileWord = fileCount === 1 ? 'file' : 'files';
315
+
316
+ switch (intent) {
317
+ case 'Bug Fix':
318
+ return analysis.hasTestFix
319
+ ? hasFileCount
320
+ ? `fix failing tests in ${fileCount} ${fileWord}`
321
+ : 'fix failing tests'
322
+ : hasFileCount
323
+ ? `fix issues in ${fileCount} ${fileWord}`
324
+ : 'fix issues';
325
+
326
+ case 'Feature':
327
+ if (analysis.hasNewEndpoint) return 'add new API endpoints';
328
+ if (analysis.hasNewComponent) return 'add new components';
329
+ if (analysis.hasNewClass || analysis.hasNewFunction)
330
+ return hasFileCount
331
+ ? `add new functionality to ${fileCount} ${fileWord}`
332
+ : 'add new functionality';
333
+ return hasFileCount
334
+ ? `implement new features in ${fileCount} ${fileWord}`
335
+ : 'implement new features';
336
+
337
+ case 'Refactor':
338
+ if (analysis.hasMovedCode)
339
+ return hasFileCount
340
+ ? `restructure code in ${fileCount} ${fileWord}`
341
+ : 'restructure code';
342
+ if (analysis.deletions > analysis.additions * 2)
343
+ return hasFileCount
344
+ ? `remove unused code from ${fileCount} ${fileWord}`
345
+ : 'remove unused code';
346
+ return hasFileCount
347
+ ? `refactor code in ${fileCount} ${fileWord}`
348
+ : 'refactor code';
349
+
350
+ case 'Test':
351
+ return hasFileCount
352
+ ? `add/update tests in ${fileCount} ${fileWord}`
353
+ : 'add/update tests';
354
+
355
+ case 'Chore':
356
+ if (analysis.hasDependencyChange) return 'update dependencies';
357
+ if (analysis.hasConfigChange) return 'update configuration files';
358
+ return 'update project configuration';
359
+
360
+ case 'Style':
361
+ return hasFileCount
362
+ ? `format and style ${fileCount} ${fileWord}`
363
+ : 'format and style code';
364
+
365
+ case 'Documentation':
366
+ return hasFileCount
367
+ ? fileCount === 1
368
+ ? 'update documentation'
369
+ : `update documentation in ${fileCount} ${fileWord}`
370
+ : 'update documentation';
371
+
372
+ default:
373
+ return hasFileCount
374
+ ? `update ${fileCount} ${fileWord}`
375
+ : 'update code';
155
376
  }
377
+ }
156
378
 
379
+ function generateFallbackCommit(diff: string, summary?: ChangeSummary): CommitSuggestion {
380
+ const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
381
+
382
+ const analysis = analyzeDiff(diff, summary);
383
+ const intent = determineIntent(analysis, summary);
384
+ const message = generateMessage(analysis, intent, summary);
385
+
386
+ const result = { intent, message };
157
387
  commitCache.set(diffHash, intent, message);
158
- return { intent, message };
388
+
389
+ return result;
159
390
  }
160
391
 
161
392
  function sleep(ms: number): Promise<void> {
162
393
  return new Promise(resolve => setTimeout(resolve, ms));
163
- }
394
+ }