commic 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.
- package/.husky/pre-commit +2 -0
- package/README.md +306 -0
- package/biome.json +50 -0
- package/dist/ai/AIService.d.ts +51 -0
- package/dist/ai/AIService.d.ts.map +1 -0
- package/dist/ai/AIService.js +351 -0
- package/dist/ai/AIService.js.map +1 -0
- package/dist/config/ConfigManager.d.ts +49 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +124 -0
- package/dist/config/ConfigManager.js.map +1 -0
- package/dist/errors/CustomErrors.d.ts +54 -0
- package/dist/errors/CustomErrors.d.ts.map +1 -0
- package/dist/errors/CustomErrors.js +99 -0
- package/dist/errors/CustomErrors.js.map +1 -0
- package/dist/git/GitService.d.ts +77 -0
- package/dist/git/GitService.d.ts.map +1 -0
- package/dist/git/GitService.js +219 -0
- package/dist/git/GitService.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator/MainOrchestrator.d.ts +63 -0
- package/dist/orchestrator/MainOrchestrator.d.ts.map +1 -0
- package/dist/orchestrator/MainOrchestrator.js +225 -0
- package/dist/orchestrator/MainOrchestrator.js.map +1 -0
- package/dist/types/index.d.ts +55 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/UIManager.d.ts +118 -0
- package/dist/ui/UIManager.d.ts.map +1 -0
- package/dist/ui/UIManager.js +369 -0
- package/dist/ui/UIManager.js.map +1 -0
- package/dist/validation/ConventionalCommitsValidator.d.ts +33 -0
- package/dist/validation/ConventionalCommitsValidator.d.ts.map +1 -0
- package/dist/validation/ConventionalCommitsValidator.js +114 -0
- package/dist/validation/ConventionalCommitsValidator.js.map +1 -0
- package/package.json +49 -0
- package/src/ai/AIService.ts +413 -0
- package/src/config/ConfigManager.ts +141 -0
- package/src/errors/CustomErrors.ts +176 -0
- package/src/git/GitService.ts +246 -0
- package/src/index.ts +55 -0
- package/src/orchestrator/MainOrchestrator.ts +263 -0
- package/src/types/index.ts +60 -0
- package/src/ui/UIManager.ts +420 -0
- package/src/validation/ConventionalCommitsValidator.ts +139 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import boxen from 'boxen';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
/**
|
|
6
|
+
* Manages terminal UI rendering and visual feedback
|
|
7
|
+
* Provides consistent, colorful interface with emojis and loading indicators
|
|
8
|
+
*/
|
|
9
|
+
export class UIManager {
|
|
10
|
+
colors = {
|
|
11
|
+
primary: chalk.cyan,
|
|
12
|
+
success: chalk.green,
|
|
13
|
+
error: chalk.red,
|
|
14
|
+
warning: chalk.yellow,
|
|
15
|
+
info: chalk.blue,
|
|
16
|
+
muted: chalk.gray,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Display welcome message with branding
|
|
20
|
+
*/
|
|
21
|
+
showWelcome() {
|
|
22
|
+
const welcomeText = chalk.bold.cyan('Commic') +
|
|
23
|
+
'\n' +
|
|
24
|
+
chalk.gray('AI-powered commit messages with Conventional Commits') +
|
|
25
|
+
'\n\n' +
|
|
26
|
+
this.colors.muted('✨ Features:') +
|
|
27
|
+
'\n' +
|
|
28
|
+
' • ' +
|
|
29
|
+
this.colors.primary('Automated commit message generation') +
|
|
30
|
+
'\n' +
|
|
31
|
+
' • ' +
|
|
32
|
+
this.colors.primary('Conventional Commits specification') +
|
|
33
|
+
'\n' +
|
|
34
|
+
' • ' +
|
|
35
|
+
this.colors.primary('Multiple AI-generated suggestions') +
|
|
36
|
+
'\n' +
|
|
37
|
+
' • ' +
|
|
38
|
+
this.colors.primary('Smart diff analysis') +
|
|
39
|
+
'\n\n' +
|
|
40
|
+
this.colors.muted('📋 How it works:') +
|
|
41
|
+
'\n' +
|
|
42
|
+
' 1. Analyzes your Git changes' +
|
|
43
|
+
'\n' +
|
|
44
|
+
' 2. Generates commit message suggestions' +
|
|
45
|
+
'\n' +
|
|
46
|
+
' 3. Lets you choose the best one' +
|
|
47
|
+
'\n' +
|
|
48
|
+
' 4. Creates the commit automatically';
|
|
49
|
+
console.log('\n' +
|
|
50
|
+
boxen(welcomeText, {
|
|
51
|
+
padding: 1,
|
|
52
|
+
margin: 1,
|
|
53
|
+
borderStyle: 'round',
|
|
54
|
+
borderColor: 'cyan',
|
|
55
|
+
}) +
|
|
56
|
+
'\n');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Display success message with checkmark emoji
|
|
60
|
+
* @param message Success message to display
|
|
61
|
+
*/
|
|
62
|
+
showSuccess(message) {
|
|
63
|
+
console.log(`\n${this.colors.success(`✨ ${message}`)}\n\n`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Display error message with cross emoji
|
|
67
|
+
* @param message Error message to display
|
|
68
|
+
* @param details Optional detailed error information
|
|
69
|
+
*/
|
|
70
|
+
showError(message, details) {
|
|
71
|
+
console.log(`\n${this.colors.error(`❌ Error: ${message}`)}`);
|
|
72
|
+
if (details) {
|
|
73
|
+
console.log(this.colors.muted(` ${details}`));
|
|
74
|
+
}
|
|
75
|
+
console.log('\n');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Display error with suggestion
|
|
79
|
+
* @param message Error message
|
|
80
|
+
* @param suggestion Actionable suggestion for user
|
|
81
|
+
*/
|
|
82
|
+
showErrorWithSuggestion(message, suggestion) {
|
|
83
|
+
console.log(`\n${this.colors.error(`❌ Error: ${message}`)}`);
|
|
84
|
+
console.log(`${this.colors.info(`💡 Suggestion: ${suggestion}`)}\n\n`);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Display informational message with bulb emoji
|
|
88
|
+
* @param message Info message to display
|
|
89
|
+
*/
|
|
90
|
+
showInfo(message) {
|
|
91
|
+
console.log(`\n${this.colors.info(`💡 ${message}`)}\n\n`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Display warning message
|
|
95
|
+
* @param message Warning message to display
|
|
96
|
+
*/
|
|
97
|
+
showWarning(message) {
|
|
98
|
+
console.log(`\n${this.colors.warning(`⚠️ ${message}`)}\n\n`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Apply muted (gray) color to text
|
|
102
|
+
* @param text Text to color
|
|
103
|
+
* @returns Colored text string
|
|
104
|
+
*/
|
|
105
|
+
muted(text) {
|
|
106
|
+
return this.colors.muted(text);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create and start a loading spinner
|
|
110
|
+
* @param message Loading message to display
|
|
111
|
+
* @returns Ora spinner instance
|
|
112
|
+
*/
|
|
113
|
+
showLoading(message) {
|
|
114
|
+
return ora({
|
|
115
|
+
text: message,
|
|
116
|
+
color: 'cyan',
|
|
117
|
+
spinner: 'dots',
|
|
118
|
+
}).start();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Display a section header
|
|
122
|
+
* @param title Section title
|
|
123
|
+
*/
|
|
124
|
+
showSectionHeader(title) {
|
|
125
|
+
console.log(`\n${this.colors.primary.bold(title)}`);
|
|
126
|
+
console.log(this.colors.muted('─'.repeat(Math.max(title.length, 50))));
|
|
127
|
+
console.log();
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Display formatted commit message preview
|
|
131
|
+
* @param message Commit message to preview
|
|
132
|
+
* @param index Optional index number
|
|
133
|
+
*/
|
|
134
|
+
showCommitPreview(message, index) {
|
|
135
|
+
const prefix = index !== undefined ? `${index + 1}. ` : ' ';
|
|
136
|
+
const lines = message.split('\n');
|
|
137
|
+
console.log(this.colors.muted(prefix) + this.colors.primary(lines[0]));
|
|
138
|
+
if (lines.length > 1) {
|
|
139
|
+
lines.slice(1).forEach((line) => {
|
|
140
|
+
if (line.trim()) {
|
|
141
|
+
console.log(this.colors.muted(` ${line}`));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
console.log();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Clear the console
|
|
149
|
+
*/
|
|
150
|
+
clear() {
|
|
151
|
+
console.clear();
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Display a blank line
|
|
155
|
+
*/
|
|
156
|
+
newLine() {
|
|
157
|
+
console.log();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Display repository information banner
|
|
161
|
+
* @param repoName Repository name
|
|
162
|
+
* @param branch Current branch
|
|
163
|
+
* @param repoPath Repository path
|
|
164
|
+
* @param remoteUrl Optional remote repository URL
|
|
165
|
+
*/
|
|
166
|
+
showRepositoryInfo(repoName, branch, repoPath, remoteUrl) {
|
|
167
|
+
console.log();
|
|
168
|
+
console.log(this.colors.primary.bold('📦 Repository Information'));
|
|
169
|
+
console.log(this.colors.muted('─'.repeat(50)));
|
|
170
|
+
console.log();
|
|
171
|
+
console.log(` ${this.colors.primary('📁 Repository: ')}${chalk.bold.white(repoName)}`);
|
|
172
|
+
console.log(` ${this.colors.primary('🌿 Branch: ')}${chalk.bold.green(branch)}`);
|
|
173
|
+
if (remoteUrl) {
|
|
174
|
+
console.log(` ${this.colors.primary('🔗 Remote: ')}${this.colors.muted(remoteUrl)}`);
|
|
175
|
+
}
|
|
176
|
+
console.log(` ${this.colors.muted('📍 Path: ')}${this.colors.muted(repoPath)}`);
|
|
177
|
+
console.log();
|
|
178
|
+
console.log(this.colors.muted('─'.repeat(50)));
|
|
179
|
+
console.log();
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Display change statistics
|
|
183
|
+
* @param stats Statistics object with files, insertions, deletions
|
|
184
|
+
*/
|
|
185
|
+
showChangeStats(stats) {
|
|
186
|
+
const { filesChanged, insertions, deletions } = stats;
|
|
187
|
+
console.log();
|
|
188
|
+
console.log(this.colors.primary.bold('📊 Changes Summary'));
|
|
189
|
+
console.log(this.colors.muted('─'.repeat(50)));
|
|
190
|
+
console.log();
|
|
191
|
+
const fileText = filesChanged === 1 ? 'file' : 'files';
|
|
192
|
+
console.log(` ${chalk.bold.white(filesChanged)} ${fileText} changed`);
|
|
193
|
+
if (insertions > 0) {
|
|
194
|
+
console.log(` ${chalk.bold.green(`+${insertions}`)} insertions`);
|
|
195
|
+
}
|
|
196
|
+
if (deletions > 0) {
|
|
197
|
+
console.log(` ${chalk.bold.red(`-${deletions}`)} deletions`);
|
|
198
|
+
}
|
|
199
|
+
const totalChanges = insertions + deletions;
|
|
200
|
+
if (totalChanges > 0) {
|
|
201
|
+
console.log(` ${chalk.bold.cyan(`Total: ${totalChanges} lines`)} changed`);
|
|
202
|
+
}
|
|
203
|
+
console.log();
|
|
204
|
+
console.log(this.colors.muted('─'.repeat(50)));
|
|
205
|
+
console.log();
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Display AI generation info
|
|
209
|
+
* @param model Model name being used
|
|
210
|
+
* @param suggestionCount Number of suggestions generated
|
|
211
|
+
*/
|
|
212
|
+
showAIGenerationInfo(model, suggestionCount) {
|
|
213
|
+
console.log(this.colors.muted(` 🤖 Model: ${chalk.cyan.bold(model)}`));
|
|
214
|
+
console.log(this.colors.muted(` 📝 Generating ${chalk.cyan.bold(suggestionCount)} commit message suggestions...`));
|
|
215
|
+
console.log();
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Prompt user for API key
|
|
219
|
+
* @returns Entered API key
|
|
220
|
+
*/
|
|
221
|
+
async promptForApiKey() {
|
|
222
|
+
const answer = await inquirer.prompt([
|
|
223
|
+
{
|
|
224
|
+
type: 'password',
|
|
225
|
+
name: 'apiKey',
|
|
226
|
+
message: 'Enter your Gemini API key:',
|
|
227
|
+
mask: '*',
|
|
228
|
+
validate: (input) => {
|
|
229
|
+
if (!input || input.trim().length === 0) {
|
|
230
|
+
return 'API key cannot be empty';
|
|
231
|
+
}
|
|
232
|
+
if (input.length < 20) {
|
|
233
|
+
return 'API key seems too short. Please check and try again.';
|
|
234
|
+
}
|
|
235
|
+
return true;
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
]);
|
|
239
|
+
return answer.apiKey.trim();
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Prompt user to select a Gemini model
|
|
243
|
+
* @param models Available model options
|
|
244
|
+
* @returns Selected model
|
|
245
|
+
*/
|
|
246
|
+
async promptForModel(models) {
|
|
247
|
+
const answer = await inquirer.prompt([
|
|
248
|
+
{
|
|
249
|
+
type: 'list',
|
|
250
|
+
name: 'model',
|
|
251
|
+
message: 'Select Gemini model:',
|
|
252
|
+
choices: models.map((model) => {
|
|
253
|
+
if (model === 'gemini-2.5-flash') {
|
|
254
|
+
return {
|
|
255
|
+
name: `${model} ${chalk.gray('(stable)')}`,
|
|
256
|
+
value: model,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
else if (model === 'gemini-flash-latest') {
|
|
260
|
+
return {
|
|
261
|
+
name: `${model} ${chalk.gray('(always latest, recommended)')}`,
|
|
262
|
+
value: model,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
name: model,
|
|
267
|
+
value: model,
|
|
268
|
+
};
|
|
269
|
+
}),
|
|
270
|
+
default: 'gemini-flash-latest',
|
|
271
|
+
},
|
|
272
|
+
]);
|
|
273
|
+
return answer.model;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Prompt user to select a commit message from suggestions
|
|
277
|
+
* @param suggestions Array of commit message suggestions
|
|
278
|
+
* @returns Index of selected suggestion, or -1 if cancelled
|
|
279
|
+
*/
|
|
280
|
+
async promptForCommitSelection(suggestions) {
|
|
281
|
+
this.showSectionHeader('📝 Select a commit message');
|
|
282
|
+
this.newLine();
|
|
283
|
+
// Show all suggestions with more detail
|
|
284
|
+
console.log(this.colors.muted('Available suggestions:'));
|
|
285
|
+
console.log();
|
|
286
|
+
suggestions.forEach((suggestion, index) => {
|
|
287
|
+
const lines = suggestion.message.split('\n');
|
|
288
|
+
const firstLine = lines[0];
|
|
289
|
+
const hasBody = lines.length > 1;
|
|
290
|
+
console.log(` ${this.colors.primary.bold(`${index + 1}.`)} ${this.colors.primary(firstLine)}`);
|
|
291
|
+
if (hasBody) {
|
|
292
|
+
lines.slice(1).forEach((line) => {
|
|
293
|
+
if (line.trim()) {
|
|
294
|
+
console.log(this.colors.muted(` ${line}`));
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
console.log();
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
console.log();
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
console.log();
|
|
304
|
+
const choices = suggestions.map((suggestion, index) => {
|
|
305
|
+
const lines = suggestion.message.split('\n');
|
|
306
|
+
const firstLine = lines[0];
|
|
307
|
+
const hasBody = lines.length > 1;
|
|
308
|
+
return {
|
|
309
|
+
name: hasBody ? `${firstLine} ${chalk.gray('(multi-line)')}` : firstLine,
|
|
310
|
+
value: index,
|
|
311
|
+
short: firstLine,
|
|
312
|
+
};
|
|
313
|
+
});
|
|
314
|
+
// Add cancel option
|
|
315
|
+
choices.push({
|
|
316
|
+
name: chalk.red("✖ Cancel (don't commit)"),
|
|
317
|
+
value: -1,
|
|
318
|
+
short: 'Cancelled',
|
|
319
|
+
});
|
|
320
|
+
const answer = await inquirer.prompt([
|
|
321
|
+
{
|
|
322
|
+
type: 'list',
|
|
323
|
+
name: 'selection',
|
|
324
|
+
message: 'Choose a commit message:',
|
|
325
|
+
choices,
|
|
326
|
+
pageSize: 10,
|
|
327
|
+
loop: false,
|
|
328
|
+
},
|
|
329
|
+
]);
|
|
330
|
+
// Show preview of selected message if not cancelled
|
|
331
|
+
if (answer.selection !== -1) {
|
|
332
|
+
this.newLine();
|
|
333
|
+
this.showSectionHeader('✅ Selected commit message');
|
|
334
|
+
console.log();
|
|
335
|
+
console.log(this.colors.muted('─'.repeat(50)));
|
|
336
|
+
console.log();
|
|
337
|
+
const messageLines = suggestions[answer.selection].message.split('\n');
|
|
338
|
+
messageLines.forEach((line) => {
|
|
339
|
+
if (line.trim()) {
|
|
340
|
+
console.log(` ${this.colors.primary(line)}`);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
console.log();
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
console.log();
|
|
347
|
+
console.log(this.colors.muted('─'.repeat(50)));
|
|
348
|
+
console.log();
|
|
349
|
+
}
|
|
350
|
+
return answer.selection;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Prompt for confirmation
|
|
354
|
+
* @param message Confirmation message
|
|
355
|
+
* @returns true if confirmed, false otherwise
|
|
356
|
+
*/
|
|
357
|
+
async promptForConfirmation(message) {
|
|
358
|
+
const answer = await inquirer.prompt([
|
|
359
|
+
{
|
|
360
|
+
type: 'confirm',
|
|
361
|
+
name: 'confirmed',
|
|
362
|
+
message,
|
|
363
|
+
default: true,
|
|
364
|
+
},
|
|
365
|
+
]);
|
|
366
|
+
return answer.confirmed;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=UIManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UIManager.js","sourceRoot":"","sources":["../../src/ui/UIManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ParsedCommitMessage, ValidationResult } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates commit messages against the Conventional Commits specification
|
|
4
|
+
* https://www.conventionalcommits.org/en/v1.0.0/
|
|
5
|
+
*/
|
|
6
|
+
export declare class ConventionalCommitsValidator {
|
|
7
|
+
private static readonly VALID_TYPES;
|
|
8
|
+
private static readonly COMMIT_PATTERN;
|
|
9
|
+
/**
|
|
10
|
+
* Get list of valid commit types
|
|
11
|
+
* @returns Array of valid type strings
|
|
12
|
+
*/
|
|
13
|
+
static getValidTypes(): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Validate a commit message against Conventional Commits spec
|
|
16
|
+
* @param message Commit message to validate
|
|
17
|
+
* @returns ValidationResult with valid flag and any errors
|
|
18
|
+
*/
|
|
19
|
+
static validate(message: string): ValidationResult;
|
|
20
|
+
/**
|
|
21
|
+
* Parse a commit message into its components
|
|
22
|
+
* @param message Commit message to parse
|
|
23
|
+
* @returns Parsed commit message structure
|
|
24
|
+
*/
|
|
25
|
+
static parseCommitMessage(message: string): ParsedCommitMessage | null;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a message is single-line (no body)
|
|
28
|
+
* @param message Commit message to check
|
|
29
|
+
* @returns true if single-line, false if multi-line
|
|
30
|
+
*/
|
|
31
|
+
static isSingleLine(message: string): boolean;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=ConventionalCommitsValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConventionalCommitsValidator.d.ts","sourceRoot":"","sources":["../../src/validation/ConventionalCommitsValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;;GAGG;AACH,qBAAa,4BAA4B;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAWjC;IAIF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAyC;IAE/E;;;OAGG;IACH,MAAM,CAAC,aAAa,IAAI,MAAM,EAAE;IAIhC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB;IA6DlD;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI;IA0BtE;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;CAI9C"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates commit messages against the Conventional Commits specification
|
|
3
|
+
* https://www.conventionalcommits.org/en/v1.0.0/
|
|
4
|
+
*/
|
|
5
|
+
export class ConventionalCommitsValidator {
|
|
6
|
+
static VALID_TYPES = [
|
|
7
|
+
'feat',
|
|
8
|
+
'fix',
|
|
9
|
+
'docs',
|
|
10
|
+
'style',
|
|
11
|
+
'refactor',
|
|
12
|
+
'test',
|
|
13
|
+
'chore',
|
|
14
|
+
'perf',
|
|
15
|
+
'ci',
|
|
16
|
+
'build',
|
|
17
|
+
];
|
|
18
|
+
// Regex pattern for Conventional Commits format
|
|
19
|
+
// Matches: type(scope)?: description or type(scope)?!: description
|
|
20
|
+
static COMMIT_PATTERN = /^(\w+)(\([a-z0-9-]+\))?(!)?:\s(.+)$/;
|
|
21
|
+
/**
|
|
22
|
+
* Get list of valid commit types
|
|
23
|
+
* @returns Array of valid type strings
|
|
24
|
+
*/
|
|
25
|
+
static getValidTypes() {
|
|
26
|
+
return [...ConventionalCommitsValidator.VALID_TYPES];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate a commit message against Conventional Commits spec
|
|
30
|
+
* @param message Commit message to validate
|
|
31
|
+
* @returns ValidationResult with valid flag and any errors
|
|
32
|
+
*/
|
|
33
|
+
static validate(message) {
|
|
34
|
+
const errors = [];
|
|
35
|
+
if (!message || message.trim().length === 0) {
|
|
36
|
+
errors.push('Commit message cannot be empty');
|
|
37
|
+
return { valid: false, errors };
|
|
38
|
+
}
|
|
39
|
+
// Split into lines to check subject and body separately
|
|
40
|
+
const lines = message.split('\n');
|
|
41
|
+
const subject = lines[0];
|
|
42
|
+
// Validate subject line format
|
|
43
|
+
const match = subject.match(ConventionalCommitsValidator.COMMIT_PATTERN);
|
|
44
|
+
if (!match) {
|
|
45
|
+
errors.push('Subject line must follow format: type(scope)?: description');
|
|
46
|
+
return { valid: false, errors };
|
|
47
|
+
}
|
|
48
|
+
const [, type, , breaking, description] = match;
|
|
49
|
+
// Validate type
|
|
50
|
+
if (!ConventionalCommitsValidator.VALID_TYPES.includes(type)) {
|
|
51
|
+
errors.push(`Invalid type "${type}". Must be one of: ${ConventionalCommitsValidator.VALID_TYPES.join(', ')}`);
|
|
52
|
+
}
|
|
53
|
+
// Validate description
|
|
54
|
+
if (!description || description.trim().length === 0) {
|
|
55
|
+
errors.push('Description cannot be empty');
|
|
56
|
+
}
|
|
57
|
+
// Check description starts with lowercase (Conventional Commits convention)
|
|
58
|
+
if (description && /^[A-Z]/.test(description)) {
|
|
59
|
+
errors.push('Description should start with lowercase letter');
|
|
60
|
+
}
|
|
61
|
+
// Validate subject line length (recommended max 72 characters)
|
|
62
|
+
if (subject.length > 72) {
|
|
63
|
+
errors.push('Subject line should be 72 characters or less');
|
|
64
|
+
}
|
|
65
|
+
// If multi-line, validate blank line between subject and body
|
|
66
|
+
if (lines.length > 1 && lines[1].trim() !== '') {
|
|
67
|
+
errors.push('There should be a blank line between subject and body');
|
|
68
|
+
}
|
|
69
|
+
// Check for breaking change notation
|
|
70
|
+
if (breaking === '!' || message.includes('BREAKING CHANGE:')) {
|
|
71
|
+
// This is valid - breaking changes are properly marked
|
|
72
|
+
// No error to add
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
valid: errors.length === 0,
|
|
76
|
+
errors,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Parse a commit message into its components
|
|
81
|
+
* @param message Commit message to parse
|
|
82
|
+
* @returns Parsed commit message structure
|
|
83
|
+
*/
|
|
84
|
+
static parseCommitMessage(message) {
|
|
85
|
+
const lines = message.split('\n');
|
|
86
|
+
const subject = lines[0];
|
|
87
|
+
const match = subject.match(ConventionalCommitsValidator.COMMIT_PATTERN);
|
|
88
|
+
if (!match) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const [, type, scopeWithParens, breaking, description] = match;
|
|
92
|
+
// Extract scope without parentheses
|
|
93
|
+
const scope = scopeWithParens ? scopeWithParens.slice(1, -1) : undefined;
|
|
94
|
+
// Extract body (everything after the blank line)
|
|
95
|
+
const body = lines.length > 2 ? lines.slice(2).join('\n').trim() : undefined;
|
|
96
|
+
return {
|
|
97
|
+
type,
|
|
98
|
+
scope,
|
|
99
|
+
breaking: breaking === '!' || message.includes('BREAKING CHANGE:'),
|
|
100
|
+
description,
|
|
101
|
+
body,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if a message is single-line (no body)
|
|
106
|
+
* @param message Commit message to check
|
|
107
|
+
* @returns true if single-line, false if multi-line
|
|
108
|
+
*/
|
|
109
|
+
static isSingleLine(message) {
|
|
110
|
+
const lines = message.split('\n').filter((line) => line.trim().length > 0);
|
|
111
|
+
return lines.length === 1;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=ConventionalCommitsValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConventionalCommitsValidator.js","sourceRoot":"","sources":["../../src/validation/ConventionalCommitsValidator.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,4BAA4B;IAC/B,MAAM,CAAU,WAAW,GAAG;QACpC,MAAM;QACN,KAAK;QACL,MAAM;QACN,OAAO;QACP,UAAU;QACV,MAAM;QACN,OAAO;QACP,MAAM;QACN,IAAI;QACJ,OAAO;KACR,CAAC;IAEF,gDAAgD;IAChD,mEAAmE;IAC3D,MAAM,CAAU,cAAc,GAAG,qCAAqC,CAAC;IAE/E;;;OAGG;IACH,MAAM,CAAC,aAAa;QAClB,OAAO,CAAC,GAAG,4BAA4B,CAAC,WAAW,CAAC,CAAC;IACvD,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAe;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;YAC9C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAClC,CAAC;QAED,wDAAwD;QACxD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEzB,+BAA+B;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,cAAc,CAAC,CAAC;QAEzE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YAC1E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAClC,CAAC;QAED,MAAM,CAAC,EAAE,IAAI,EAAE,AAAD,EAAG,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC;QAEhD,gBAAgB;QAChB,IAAI,CAAC,4BAA4B,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7D,MAAM,CAAC,IAAI,CACT,iBAAiB,IAAI,sBAAsB,4BAA4B,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACjG,CAAC;QACJ,CAAC;QAED,uBAAuB;QACvB,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC7C,CAAC;QAED,4EAA4E;QAC5E,IAAI,WAAW,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9C,MAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;QAChE,CAAC;QAED,+DAA+D;QAC/D,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;QAC9D,CAAC;QAED,8DAA8D;QAC9D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;QACvE,CAAC;QAED,qCAAqC;QACrC,IAAI,QAAQ,KAAK,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC7D,uDAAuD;YACvD,kBAAkB;QACpB,CAAC;QAED,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;YAC1B,MAAM;SACP,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAe;QACvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,cAAc,CAAC,CAAC;QAEzE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC;QAE/D,oCAAoC;QACpC,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEzE,iDAAiD;QACjD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAE7E,OAAO;YACL,IAAI;YACJ,KAAK;YACL,QAAQ,EAAE,QAAQ,KAAK,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YAClE,WAAW;YACX,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,OAAe;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC3E,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IAC5B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "commic",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI-powered Git commit message generator with Conventional Commits support",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"commic": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "npm run build && node dist/index.js",
|
|
13
|
+
"dev": "tsx src/index.ts",
|
|
14
|
+
"prepare": "husky",
|
|
15
|
+
"lint": "biome check .",
|
|
16
|
+
"lint:fix": "biome check --write --unsafe .",
|
|
17
|
+
"format": "biome format --write ."
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"git",
|
|
21
|
+
"commit",
|
|
22
|
+
"ai",
|
|
23
|
+
"gemini",
|
|
24
|
+
"conventional-commits",
|
|
25
|
+
"cli"
|
|
26
|
+
],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@google/generative-ai": "^0.21.0",
|
|
31
|
+
"boxen": "^8.0.1",
|
|
32
|
+
"chalk": "^5.4.1",
|
|
33
|
+
"commander": "^12.1.0",
|
|
34
|
+
"inquirer": "^12.2.0",
|
|
35
|
+
"ora": "^8.1.1",
|
|
36
|
+
"simple-git": "^3.27.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@biomejs/biome": "^2.3.11",
|
|
40
|
+
"@types/inquirer": "^9.0.7",
|
|
41
|
+
"@types/node": "^22.10.5",
|
|
42
|
+
"husky": "^9.1.7",
|
|
43
|
+
"tsx": "^4.19.2",
|
|
44
|
+
"typescript": "^5.7.3"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|