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.
Files changed (50) hide show
  1. package/.husky/pre-commit +2 -0
  2. package/README.md +306 -0
  3. package/biome.json +50 -0
  4. package/dist/ai/AIService.d.ts +51 -0
  5. package/dist/ai/AIService.d.ts.map +1 -0
  6. package/dist/ai/AIService.js +351 -0
  7. package/dist/ai/AIService.js.map +1 -0
  8. package/dist/config/ConfigManager.d.ts +49 -0
  9. package/dist/config/ConfigManager.d.ts.map +1 -0
  10. package/dist/config/ConfigManager.js +124 -0
  11. package/dist/config/ConfigManager.js.map +1 -0
  12. package/dist/errors/CustomErrors.d.ts +54 -0
  13. package/dist/errors/CustomErrors.d.ts.map +1 -0
  14. package/dist/errors/CustomErrors.js +99 -0
  15. package/dist/errors/CustomErrors.js.map +1 -0
  16. package/dist/git/GitService.d.ts +77 -0
  17. package/dist/git/GitService.d.ts.map +1 -0
  18. package/dist/git/GitService.js +219 -0
  19. package/dist/git/GitService.js.map +1 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +48 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/orchestrator/MainOrchestrator.d.ts +63 -0
  25. package/dist/orchestrator/MainOrchestrator.d.ts.map +1 -0
  26. package/dist/orchestrator/MainOrchestrator.js +225 -0
  27. package/dist/orchestrator/MainOrchestrator.js.map +1 -0
  28. package/dist/types/index.d.ts +55 -0
  29. package/dist/types/index.d.ts.map +1 -0
  30. package/dist/types/index.js +2 -0
  31. package/dist/types/index.js.map +1 -0
  32. package/dist/ui/UIManager.d.ts +118 -0
  33. package/dist/ui/UIManager.d.ts.map +1 -0
  34. package/dist/ui/UIManager.js +369 -0
  35. package/dist/ui/UIManager.js.map +1 -0
  36. package/dist/validation/ConventionalCommitsValidator.d.ts +33 -0
  37. package/dist/validation/ConventionalCommitsValidator.d.ts.map +1 -0
  38. package/dist/validation/ConventionalCommitsValidator.js +114 -0
  39. package/dist/validation/ConventionalCommitsValidator.js.map +1 -0
  40. package/package.json +49 -0
  41. package/src/ai/AIService.ts +413 -0
  42. package/src/config/ConfigManager.ts +141 -0
  43. package/src/errors/CustomErrors.ts +176 -0
  44. package/src/git/GitService.ts +246 -0
  45. package/src/index.ts +55 -0
  46. package/src/orchestrator/MainOrchestrator.ts +263 -0
  47. package/src/types/index.ts +60 -0
  48. package/src/ui/UIManager.ts +420 -0
  49. package/src/validation/ConventionalCommitsValidator.ts +139 -0
  50. package/tsconfig.json +24 -0
@@ -0,0 +1,351 @@
1
+ import { GoogleGenerativeAI } from '@google/generative-ai';
2
+ import { APIError, ValidationError } from '../errors/CustomErrors.js';
3
+ import { ConventionalCommitsValidator } from '../validation/ConventionalCommitsValidator.js';
4
+ /**
5
+ * Handles AI-powered commit message generation using Google's Gemini API
6
+ */
7
+ export class AIService {
8
+ genAI;
9
+ model;
10
+ constructor(apiKey, modelName) {
11
+ this.genAI = new GoogleGenerativeAI(apiKey);
12
+ this.model = this.genAI.getGenerativeModel({ model: modelName });
13
+ }
14
+ /**
15
+ * Build prompt for Gemini API to generate commit messages
16
+ * @param diff Git diff information
17
+ * @param count Number of suggestions to generate (3-5)
18
+ * @returns Formatted prompt string
19
+ */
20
+ buildPrompt(diff, count) {
21
+ // Combine staged and unstaged diffs
22
+ const combinedDiff = [diff.staged, diff.unstaged].filter((d) => d.length > 0).join('\n\n');
23
+ // Truncate diff if too large (Gemini input token limit: 1,048,576 tokens)
24
+ // Using ~800K characters (approx 200K-266K tokens) leaves plenty of room for prompt
25
+ // 1 token ≈ 3-4 characters on average, so 800K chars ≈ 200K-266K tokens
26
+ const maxDiffLength = 800000;
27
+ const truncatedDiff = combinedDiff.length > maxDiffLength
28
+ ? combinedDiff.substring(0, maxDiffLength) +
29
+ '\n\n[... diff truncated due to size limit ...]'
30
+ : combinedDiff;
31
+ return `You are an expert Git commit message writer. Analyze the ENTIRE Git diff below and generate ${count} commit messages that summarize ALL changes together. Each commit message should cover the complete set of changes, not individual features.
32
+
33
+ IMPORTANT:
34
+ - Analyze ALL changes in the diff as a single commit
35
+ - Each suggested message should describe the complete set of changes
36
+ - Do NOT create separate messages for different parts of the diff
37
+ - Consider all file changes, additions, deletions, and modifications together
38
+ - Provide different perspectives/styles for the SAME set of changes
39
+
40
+ CRITICAL RULES:
41
+ 1. Format: type(scope)?: description
42
+ 2. Valid types: feat, fix, docs, style, refactor, test, chore, perf, ci, build
43
+ 3. Use imperative mood (add, fix, update - NOT added, fixed, updated)
44
+ 4. Description starts with lowercase
45
+ 5. Single-line messages: max 72 chars, no body
46
+ 6. Multi-line messages: blank line between subject and body
47
+ 7. At least 2 messages should be single-line
48
+ 8. Each message must summarize ALL changes in the diff
49
+
50
+ OUTPUT FORMAT:
51
+ Separate each commit message with exactly "---" on its own line.
52
+ Return ONLY the messages, no explanations or numbering.
53
+
54
+ EXAMPLES (each covers all changes):
55
+ feat(auth): add JWT validation and user login flow
56
+ ---
57
+ fix: resolve authentication issues and update error handling
58
+ ---
59
+ refactor(auth): improve JWT implementation and error messages
60
+
61
+ Update token validation logic and add comprehensive error handling
62
+ ---
63
+ feat: implement user authentication system
64
+
65
+ Add JWT token validation, login endpoints, and error handling
66
+
67
+ GIT DIFF:
68
+ ${truncatedDiff}
69
+
70
+ Generate ${count} commit messages that each describe ALL the changes above:`;
71
+ }
72
+ /**
73
+ * Parse API response into CommitSuggestion array
74
+ * Tries multiple parsing strategies for robustness
75
+ * @param response Raw response text from API
76
+ * @returns Array of commit suggestions
77
+ */
78
+ parseResponse(response) {
79
+ if (!response || response.trim().length === 0) {
80
+ return [];
81
+ }
82
+ let messages = [];
83
+ // Strategy 1: Split by "---" on its own line
84
+ const tripleDashPattern = /\n---\n/g;
85
+ if (tripleDashPattern.test(response)) {
86
+ messages = response
87
+ .split(tripleDashPattern)
88
+ .map((msg) => msg.trim())
89
+ .filter((msg) => msg.length > 0);
90
+ }
91
+ // Strategy 2: Split by "---" anywhere
92
+ if (messages.length === 0 || messages.length === 1) {
93
+ messages = response
94
+ .split('---')
95
+ .map((msg) => msg.trim())
96
+ .filter((msg) => msg.length > 0);
97
+ }
98
+ // Strategy 3: Split by numbered items (1., 2., etc.)
99
+ if (messages.length === 0 || messages.length === 1) {
100
+ const numberedPattern = /^\d+\.\s+/gm;
101
+ if (numberedPattern.test(response)) {
102
+ messages = response
103
+ .split(numberedPattern)
104
+ .map((msg) => msg.trim())
105
+ .filter((msg) => msg.length > 0 && !/^\d+\./.test(msg));
106
+ }
107
+ }
108
+ // Strategy 4: Split by double newlines (common for multi-line messages)
109
+ if (messages.length === 0 || messages.length === 1) {
110
+ const doubleNewlinePattern = /\n\n+/;
111
+ if (doubleNewlinePattern.test(response)) {
112
+ const parts = response.split(doubleNewlinePattern);
113
+ // Filter out parts that look like commit messages (start with type:)
114
+ messages = parts
115
+ .map((msg) => msg.trim())
116
+ .filter((msg) => {
117
+ const trimmed = msg.trim();
118
+ return (trimmed.length > 0 &&
119
+ /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build)(\([^)]+\))?(!)?:\s/.test(trimmed));
120
+ });
121
+ }
122
+ }
123
+ // Strategy 5: Try to extract commit messages by pattern matching
124
+ if (messages.length === 0) {
125
+ const commitPattern = /(feat|fix|docs|style|refactor|test|chore|perf|ci|build)(\([^)]+\))?(!)?:\s[^\n]+(?:\n(?!---|\d+\.)[^\n]+)*/g;
126
+ const matches = response.match(commitPattern);
127
+ if (matches) {
128
+ messages = matches.map((msg) => msg.trim());
129
+ }
130
+ }
131
+ // If still no messages, try to extract any line starting with a valid type
132
+ if (messages.length === 0) {
133
+ const lines = response.split('\n');
134
+ const validTypeLines = [];
135
+ let currentMessage = '';
136
+ for (const line of lines) {
137
+ const trimmed = line.trim();
138
+ if (/^(feat|fix|docs|style|refactor|test|chore|perf|ci|build)(\([^)]+\))?(!)?:\s/.test(trimmed)) {
139
+ if (currentMessage) {
140
+ validTypeLines.push(currentMessage.trim());
141
+ }
142
+ currentMessage = trimmed;
143
+ }
144
+ else if (currentMessage && trimmed.length > 0) {
145
+ currentMessage += `\n${trimmed}`;
146
+ }
147
+ else if (currentMessage && trimmed.length === 0) {
148
+ // Blank line - continue building message
149
+ currentMessage += '\n';
150
+ }
151
+ }
152
+ if (currentMessage) {
153
+ validTypeLines.push(currentMessage.trim());
154
+ }
155
+ messages = validTypeLines;
156
+ }
157
+ // Clean up messages - remove any that are clearly not commit messages
158
+ messages = messages
159
+ .map((msg) => {
160
+ // Remove common prefixes AI might add
161
+ return msg
162
+ .replace(/^(Here are|Here's|Generated|Commit messages?):?\s*/i, '')
163
+ .replace(/^[-*•]\s*/, '')
164
+ .trim();
165
+ })
166
+ .filter((msg) => {
167
+ // Must start with a valid commit type
168
+ return (msg.length > 0 &&
169
+ /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build)(\([^)]+\))?(!)?:\s/.test(msg));
170
+ });
171
+ return messages.map((message) => ({
172
+ message: message.trim(),
173
+ type: ConventionalCommitsValidator.isSingleLine(message) ? 'single-line' : 'multi-line',
174
+ }));
175
+ }
176
+ /**
177
+ * Filter and validate suggestions, returning only valid ones
178
+ * @param suggestions Array of suggestions to validate
179
+ * @returns Array of valid suggestions
180
+ */
181
+ filterValidSuggestions(suggestions) {
182
+ const validSuggestions = [];
183
+ for (const suggestion of suggestions) {
184
+ const validation = ConventionalCommitsValidator.validate(suggestion.message);
185
+ if (validation.valid) {
186
+ validSuggestions.push(suggestion);
187
+ }
188
+ }
189
+ return validSuggestions;
190
+ }
191
+ /**
192
+ * Check if suggestions meet minimum requirements
193
+ * @param suggestions Array of suggestions to check
194
+ * @returns true if meets minimum requirements
195
+ */
196
+ meetsMinimumRequirements(suggestions) {
197
+ // Need at least 2 valid suggestions
198
+ if (suggestions.length < 2) {
199
+ return false;
200
+ }
201
+ // At least 1 should be single-line (relaxed from 2)
202
+ const singleLineCount = suggestions.filter((s) => s.type === 'single-line').length;
203
+ if (singleLineCount < 1) {
204
+ return false;
205
+ }
206
+ return true;
207
+ }
208
+ /**
209
+ * Generate commit message suggestions using Gemini API
210
+ * @param diff Git diff information
211
+ * @param count Number of suggestions to generate (3-5)
212
+ * @returns Array of validated commit suggestions
213
+ * @throws APIError if API request fails
214
+ * @throws ValidationError if no valid suggestions generated
215
+ */
216
+ async generateCommitMessages(diff, count = 4) {
217
+ // Ensure count is within bounds
218
+ const requestCount = Math.max(3, Math.min(5, count));
219
+ let attempts = 0;
220
+ const maxAttempts = 3;
221
+ let bestSuggestions = [];
222
+ while (attempts < maxAttempts) {
223
+ attempts++;
224
+ try {
225
+ // Build prompt
226
+ const prompt = this.buildPrompt(diff, requestCount);
227
+ // Call Gemini API with timeout
228
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), 30000));
229
+ const result = await Promise.race([this.model.generateContent(prompt), timeoutPromise]);
230
+ const response = result.response;
231
+ const text = response.text();
232
+ if (!text || text.trim().length === 0) {
233
+ continue;
234
+ }
235
+ // Parse response
236
+ const parsedSuggestions = this.parseResponse(text);
237
+ if (parsedSuggestions.length === 0) {
238
+ continue;
239
+ }
240
+ // Filter valid suggestions
241
+ const validSuggestions = this.filterValidSuggestions(parsedSuggestions);
242
+ // If we have valid suggestions, check if they meet requirements
243
+ if (validSuggestions.length > 0) {
244
+ // If we meet minimum requirements, return them
245
+ if (this.meetsMinimumRequirements(validSuggestions)) {
246
+ // Limit to requested count, prioritizing single-line messages
247
+ const sorted = validSuggestions.sort((a, b) => {
248
+ if (a.type === 'single-line' && b.type !== 'single-line')
249
+ return -1;
250
+ if (a.type !== 'single-line' && b.type === 'single-line')
251
+ return 1;
252
+ return 0;
253
+ });
254
+ return sorted.slice(0, requestCount);
255
+ }
256
+ // Store best suggestions so far
257
+ if (validSuggestions.length > bestSuggestions.length) {
258
+ bestSuggestions = validSuggestions;
259
+ }
260
+ }
261
+ // If we have some valid suggestions but not enough, try to generate more
262
+ if (validSuggestions.length > 0 && validSuggestions.length < 2 && attempts < maxAttempts) {
263
+ // Request more messages in next attempt
264
+ continue;
265
+ }
266
+ // If we have at least 2 valid suggestions, return them even if not perfect
267
+ if (validSuggestions.length >= 2) {
268
+ return validSuggestions.slice(0, requestCount);
269
+ }
270
+ }
271
+ catch (error) {
272
+ const errorMessage = error.message.toLowerCase();
273
+ // Handle specific API errors that shouldn't be retried
274
+ if (errorMessage.includes('rate limit') || errorMessage.includes('quota')) {
275
+ throw APIError.rateLimitExceeded();
276
+ }
277
+ if (errorMessage.includes('api key') ||
278
+ errorMessage.includes('auth') ||
279
+ errorMessage.includes('permission')) {
280
+ throw APIError.authenticationFailed();
281
+ }
282
+ if (errorMessage.includes('timeout') || errorMessage.includes('request timeout')) {
283
+ if (attempts >= maxAttempts) {
284
+ throw APIError.timeout();
285
+ }
286
+ // Continue to retry on timeout
287
+ continue;
288
+ }
289
+ // For other errors, continue retrying
290
+ if (attempts < maxAttempts) {
291
+ }
292
+ }
293
+ }
294
+ // If we have some valid suggestions, return them as fallback
295
+ if (bestSuggestions.length >= 1) {
296
+ return bestSuggestions.slice(0, requestCount);
297
+ }
298
+ // Last resort: try to generate a simple fallback message
299
+ if (bestSuggestions.length === 0) {
300
+ const fallbackMessage = this.generateFallbackMessage(diff);
301
+ if (fallbackMessage) {
302
+ return [
303
+ {
304
+ message: fallbackMessage,
305
+ type: 'single-line',
306
+ },
307
+ ];
308
+ }
309
+ }
310
+ // If all else fails, throw error with helpful message
311
+ throw ValidationError.noValidSuggestions();
312
+ }
313
+ /**
314
+ * Generate a simple fallback commit message when AI fails
315
+ * @param diff Git diff information
316
+ * @returns Simple commit message or null
317
+ */
318
+ generateFallbackMessage(diff) {
319
+ const combinedDiff = `${diff.staged}\n${diff.unstaged}`.toLowerCase();
320
+ // Simple heuristics to determine commit type
321
+ let type = 'chore';
322
+ if (combinedDiff.includes('fix') ||
323
+ combinedDiff.includes('bug') ||
324
+ combinedDiff.includes('error')) {
325
+ type = 'fix';
326
+ }
327
+ else if (combinedDiff.includes('feat') ||
328
+ combinedDiff.includes('add') ||
329
+ combinedDiff.includes('new')) {
330
+ type = 'feat';
331
+ }
332
+ else if (combinedDiff.includes('doc') || combinedDiff.includes('readme')) {
333
+ type = 'docs';
334
+ }
335
+ else if (combinedDiff.includes('refactor')) {
336
+ type = 'refactor';
337
+ }
338
+ // Try to extract a simple description
339
+ const lines = combinedDiff.split('\n').slice(0, 5);
340
+ const fileChanges = lines.filter((l) => l.startsWith('+++') || l.startsWith('---'));
341
+ if (fileChanges.length > 0) {
342
+ const firstFile = fileChanges[0]
343
+ .replace(/^[+-]{3}\s+/, '')
344
+ .split('/')
345
+ .pop() || 'files';
346
+ return `${type}: update ${firstFile}`;
347
+ }
348
+ return `${type}: update code`;
349
+ }
350
+ }
351
+ //# sourceMappingURL=AIService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AIService.js","sourceRoot":"","sources":["../../src/ai/AIService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { Config } from '../types/index.js';
2
+ import type { UIManager } from '../ui/UIManager.js';
3
+ /**
4
+ * Manages persistent configuration for the Commit CLI
5
+ * Handles loading, saving, and validation of API key and model preferences
6
+ */
7
+ export declare class ConfigManager {
8
+ private readonly configPath;
9
+ private readonly configDir;
10
+ private static readonly CONFIG_VERSION;
11
+ constructor(configPath?: string);
12
+ /**
13
+ * Load configuration from disk
14
+ * @returns Config object or null if not found
15
+ * @throws ConfigurationError if config file is corrupted
16
+ */
17
+ load(): Promise<Config | null>;
18
+ /**
19
+ * Save configuration to disk
20
+ * Creates config directory if it doesn't exist
21
+ * @param config Configuration to save
22
+ * @throws ConfigurationError if save fails
23
+ */
24
+ save(config: Config): Promise<void>;
25
+ /**
26
+ * Check if configuration file exists
27
+ * @returns true if config exists, false otherwise
28
+ */
29
+ exists(): Promise<boolean>;
30
+ /**
31
+ * Get the configuration file path
32
+ * @returns Absolute path to config file
33
+ */
34
+ getConfigPath(): string;
35
+ /**
36
+ * Validate API key format
37
+ * Basic validation - checks if it looks like a Gemini API key
38
+ * @param apiKey API key to validate
39
+ * @returns true if valid format
40
+ */
41
+ static validateApiKeyFormat(apiKey: string): boolean;
42
+ /**
43
+ * Prompt user for configuration (API key and model)
44
+ * @param ui UIManager instance for prompts
45
+ * @returns New configuration object
46
+ */
47
+ promptForConfig(ui: UIManager): Promise<Config>;
48
+ }
49
+ //# sourceMappingURL=ConfigManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigManager.d.ts","sourceRoot":"","sources":["../../src/config/ConfigManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAW;gBAErC,UAAU,CAAC,EAAE,MAAM;IAK/B;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA6BpC;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBzC;;;OAGG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShC;;;OAGG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;;OAKG;IACH,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAMpD;;;;OAIG;IACG,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;CAuBtD"}
@@ -0,0 +1,124 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ import { ConfigurationError } from '../errors/CustomErrors.js';
5
+ /**
6
+ * Manages persistent configuration for the Commit CLI
7
+ * Handles loading, saving, and validation of API key and model preferences
8
+ */
9
+ export class ConfigManager {
10
+ configPath;
11
+ configDir;
12
+ static CONFIG_VERSION = '1.0.0';
13
+ constructor(configPath) {
14
+ this.configPath = configPath || join(homedir(), '.commic', 'config.json');
15
+ this.configDir = dirname(this.configPath);
16
+ }
17
+ /**
18
+ * Load configuration from disk
19
+ * @returns Config object or null if not found
20
+ * @throws ConfigurationError if config file is corrupted
21
+ */
22
+ async load() {
23
+ try {
24
+ const configData = await fs.readFile(this.configPath, 'utf-8');
25
+ const config = JSON.parse(configData);
26
+ // Validate config structure
27
+ if (!config.apiKey || !config.model) {
28
+ throw ConfigurationError.configFileCorrupted();
29
+ }
30
+ return config;
31
+ }
32
+ catch (error) {
33
+ if (error.code === 'ENOENT') {
34
+ // Config file doesn't exist yet - this is fine on first run
35
+ return null;
36
+ }
37
+ if (error instanceof SyntaxError) {
38
+ throw ConfigurationError.configFileCorrupted();
39
+ }
40
+ if (error instanceof ConfigurationError) {
41
+ throw error;
42
+ }
43
+ throw ConfigurationError.configSaveFailed(error);
44
+ }
45
+ }
46
+ /**
47
+ * Save configuration to disk
48
+ * Creates config directory if it doesn't exist
49
+ * @param config Configuration to save
50
+ * @throws ConfigurationError if save fails
51
+ */
52
+ async save(config) {
53
+ try {
54
+ // Ensure config directory exists
55
+ await fs.mkdir(this.configDir, { recursive: true });
56
+ // Add version to config
57
+ const configWithVersion = {
58
+ ...config,
59
+ version: ConfigManager.CONFIG_VERSION,
60
+ };
61
+ // Write config file with pretty formatting
62
+ await fs.writeFile(this.configPath, JSON.stringify(configWithVersion, null, 2), 'utf-8');
63
+ }
64
+ catch (error) {
65
+ throw ConfigurationError.configSaveFailed(error);
66
+ }
67
+ }
68
+ /**
69
+ * Check if configuration file exists
70
+ * @returns true if config exists, false otherwise
71
+ */
72
+ async exists() {
73
+ try {
74
+ await fs.access(this.configPath);
75
+ return true;
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ }
81
+ /**
82
+ * Get the configuration file path
83
+ * @returns Absolute path to config file
84
+ */
85
+ getConfigPath() {
86
+ return this.configPath;
87
+ }
88
+ /**
89
+ * Validate API key format
90
+ * Basic validation - checks if it looks like a Gemini API key
91
+ * @param apiKey API key to validate
92
+ * @returns true if valid format
93
+ */
94
+ static validateApiKeyFormat(apiKey) {
95
+ // Gemini API keys typically start with "AIza" and are around 39 characters
96
+ // This is a basic check - actual validation happens when making API calls
97
+ return apiKey.length > 20 && apiKey.trim() === apiKey;
98
+ }
99
+ /**
100
+ * Prompt user for configuration (API key and model)
101
+ * @param ui UIManager instance for prompts
102
+ * @returns New configuration object
103
+ */
104
+ async promptForConfig(ui) {
105
+ ui.showSectionHeader('🔧 Configuration Setup');
106
+ ui.showInfo('Get your free API key at: https://aistudio.google.com/app/api-keys');
107
+ ui.newLine();
108
+ // Prompt for API key
109
+ const apiKey = await ui.promptForApiKey();
110
+ // Validate API key format
111
+ if (!ConfigManager.validateApiKeyFormat(apiKey)) {
112
+ throw ConfigurationError.invalidApiKey();
113
+ }
114
+ // Prompt for model selection
115
+ const availableModels = ['gemini-2.5-flash', 'gemini-flash-latest'];
116
+ const model = await ui.promptForModel(availableModels);
117
+ return {
118
+ apiKey,
119
+ model,
120
+ version: ConfigManager.CONFIG_VERSION,
121
+ };
122
+ }
123
+ }
124
+ //# sourceMappingURL=ConfigManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigManager.js","sourceRoot":"","sources":["../../src/config/ConfigManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Base error class for Commit CLI
3
+ * Provides consistent error structure with user-friendly messages and suggestions
4
+ */
5
+ declare class CommitCLIError extends Error {
6
+ readonly suggestion: string | null;
7
+ constructor(message: string, suggestion?: string | null);
8
+ }
9
+ /**
10
+ * Git repository related errors
11
+ * Thrown when Git operations fail or repository is invalid
12
+ */
13
+ export declare class GitRepositoryError extends CommitCLIError {
14
+ constructor(message: string, suggestion?: string);
15
+ static noRepositoryFound(path: string): GitRepositoryError;
16
+ static noCommitsFound(): GitRepositoryError;
17
+ static noChanges(): GitRepositoryError;
18
+ static commitFailed(gitError: string): GitRepositoryError;
19
+ static pathNotAccessible(path: string): GitRepositoryError;
20
+ }
21
+ /**
22
+ * Configuration related errors
23
+ * Thrown when config file operations fail or configuration is invalid
24
+ */
25
+ export declare class ConfigurationError extends CommitCLIError {
26
+ constructor(message: string, suggestion?: string);
27
+ static noApiKey(): ConfigurationError;
28
+ static invalidApiKey(): ConfigurationError;
29
+ static configFileCorrupted(): ConfigurationError;
30
+ static configSaveFailed(error: Error): ConfigurationError;
31
+ }
32
+ /**
33
+ * Gemini API related errors
34
+ * Thrown when API requests fail or return invalid responses
35
+ */
36
+ export declare class APIError extends CommitCLIError {
37
+ constructor(message: string, suggestion?: string);
38
+ static requestFailed(error: Error): APIError;
39
+ static rateLimitExceeded(): APIError;
40
+ static invalidResponse(): APIError;
41
+ static authenticationFailed(): APIError;
42
+ static timeout(): APIError;
43
+ }
44
+ /**
45
+ * Commit message validation errors
46
+ * Thrown when generated messages don't meet Conventional Commits specification
47
+ */
48
+ export declare class ValidationError extends CommitCLIError {
49
+ constructor(message: string, suggestion?: string);
50
+ static invalidConventionalCommit(errors: string[]): ValidationError;
51
+ static noValidSuggestions(): ValidationError;
52
+ }
53
+ export {};
54
+ //# sourceMappingURL=CustomErrors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomErrors.d.ts","sourceRoot":"","sources":["../../src/errors/CustomErrors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAM,cAAe,SAAQ,KAAK;IAChC,SAAgB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;gBAE9B,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,GAAG,IAAW;CAM9D;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,cAAc;gBAElD,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAA8E;IAK5F,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAO1D,MAAM,CAAC,cAAc,IAAI,kBAAkB;IAO3C,MAAM,CAAC,SAAS,IAAI,kBAAkB;IAOtC,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAOzD,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB;CAM3D;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,cAAc;gBAElD,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAAyD;IAKvE,MAAM,CAAC,QAAQ,IAAI,kBAAkB;IAOrC,MAAM,CAAC,aAAa,IAAI,kBAAkB;IAO1C,MAAM,CAAC,mBAAmB,IAAI,kBAAkB;IAOhD,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;CAM1D;AAED;;;GAGG;AACH,qBAAa,QAAS,SAAQ,cAAc;gBAExC,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAAwD;IAKtE,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ;IAO5C,MAAM,CAAC,iBAAiB,IAAI,QAAQ;IAOpC,MAAM,CAAC,eAAe,IAAI,QAAQ;IAOlC,MAAM,CAAC,oBAAoB,IAAI,QAAQ;IAOvC,MAAM,CAAC,OAAO,IAAI,QAAQ;CAG3B;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,cAAc;gBAE/C,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAA8D;IAK5E,MAAM,CAAC,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe;IAQnE,MAAM,CAAC,kBAAkB,IAAI,eAAe;CAM7C"}