@untools/commitgen 0.2.6 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/commands/login.d.ts +1 -0
  2. package/dist/commands/login.js +91 -0
  3. package/dist/commands/login.js.map +1 -0
  4. package/dist/index.js +21 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/providers/commitgen.d.ts +9 -0
  7. package/dist/providers/commitgen.js +77 -0
  8. package/dist/providers/commitgen.js.map +1 -0
  9. package/dist/providers/index.js +3 -11
  10. package/dist/providers/index.js.map +1 -1
  11. package/dist/types.d.ts +8 -1
  12. package/package.json +4 -4
  13. package/README.md +0 -734
  14. package/dist/package.json +0 -70
  15. package/dist/src/commands/configure.d.ts +0 -1
  16. package/dist/src/commands/configure.js +0 -96
  17. package/dist/src/commands/configure.js.map +0 -1
  18. package/dist/src/config.d.ts +0 -15
  19. package/dist/src/config.js +0 -56
  20. package/dist/src/config.js.map +0 -1
  21. package/dist/src/index.d.ts +0 -2
  22. package/dist/src/index.js +0 -649
  23. package/dist/src/index.js.map +0 -1
  24. package/dist/src/providers/base.d.ts +0 -9
  25. package/dist/src/providers/base.js +0 -107
  26. package/dist/src/providers/base.js.map +0 -1
  27. package/dist/src/providers/index.d.ts +0 -4
  28. package/dist/src/providers/index.js +0 -41
  29. package/dist/src/providers/index.js.map +0 -1
  30. package/dist/src/providers/vercel-google.d.ts +0 -10
  31. package/dist/src/providers/vercel-google.js +0 -113
  32. package/dist/src/providers/vercel-google.js.map +0 -1
  33. package/dist/src/types.d.ts +0 -46
  34. package/dist/src/types.js +0 -4
  35. package/dist/src/types.js.map +0 -1
  36. package/dist/src/utils/commit-history.d.ts +0 -35
  37. package/dist/src/utils/commit-history.js +0 -165
  38. package/dist/src/utils/commit-history.js.map +0 -1
  39. package/dist/src/utils/issue-tracker.d.ts +0 -43
  40. package/dist/src/utils/issue-tracker.js +0 -207
  41. package/dist/src/utils/issue-tracker.js.map +0 -1
  42. package/dist/src/utils/loading.d.ts +0 -14
  43. package/dist/src/utils/loading.js +0 -72
  44. package/dist/src/utils/loading.js.map +0 -1
  45. package/dist/src/utils/multi-commit.d.ts +0 -40
  46. package/dist/src/utils/multi-commit.js +0 -274
  47. package/dist/src/utils/multi-commit.js.map +0 -1
package/dist/src/index.js DELETED
@@ -1,649 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- // ./src/index.ts
8
- const child_process_1 = require("child_process");
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const commander_1 = require("commander");
11
- const inquirer_1 = __importDefault(require("inquirer"));
12
- const config_1 = require("./config");
13
- const configure_1 = require("./commands/configure");
14
- const providers_1 = require("./providers");
15
- const commit_history_1 = require("./utils/commit-history");
16
- const multi_commit_1 = require("./utils/multi-commit");
17
- const issue_tracker_1 = require("./utils/issue-tracker");
18
- const loading_1 = require("./utils/loading");
19
- const package_json_1 = __importDefault(require("../package.json"));
20
- const getVersionSimple = () => {
21
- return package_json_1.default.version;
22
- };
23
- // Graceful shutdown handler
24
- process.on("SIGINT", () => {
25
- console.log(chalk_1.default.yellow("\n\nšŸ‘‹ Cancelled by user"));
26
- process.exit(0);
27
- });
28
- process.on("SIGTERM", () => {
29
- console.log(chalk_1.default.yellow("\n\nšŸ‘‹ Cancelled by user"));
30
- process.exit(0);
31
- });
32
- /**
33
- * Wrapper for inquirer prompts that handles SIGINT gracefully
34
- */
35
- async function safePrompt(promptConfig) {
36
- try {
37
- const result = await inquirer_1.default.prompt(promptConfig);
38
- return result;
39
- }
40
- catch (error) {
41
- if (error instanceof Error && error.message.includes("SIGINT")) {
42
- console.log(chalk_1.default.yellow("\n\nšŸ‘‹ Cancelled by user"));
43
- process.exit(0);
44
- }
45
- throw error;
46
- }
47
- }
48
- class CommitGen {
49
- constructor() {
50
- this.historyAnalyzer = new commit_history_1.CommitHistoryAnalyzer();
51
- this.multiCommitAnalyzer = new multi_commit_1.MultiCommitAnalyzer();
52
- this.issueTracker = new issue_tracker_1.IssueTrackerIntegration();
53
- }
54
- exec(cmd) {
55
- try {
56
- return (0, child_process_1.execSync)(cmd, {
57
- encoding: "utf8",
58
- stdio: ["pipe", "pipe", "ignore"],
59
- }).trim();
60
- }
61
- catch (error) {
62
- return "";
63
- }
64
- }
65
- isGitRepo() {
66
- return this.exec("git rev-parse --git-dir") !== "";
67
- }
68
- getStagedChanges() {
69
- return this.exec("git diff --cached --stat");
70
- }
71
- getStagedDiff() {
72
- return this.exec("git diff --cached");
73
- }
74
- getTrackedChanges() {
75
- return this.exec("git diff --stat");
76
- }
77
- analyzeChanges() {
78
- const staged = this.getStagedChanges();
79
- const unstaged = this.getTrackedChanges();
80
- const diff = this.getStagedDiff();
81
- const files = [];
82
- if (staged) {
83
- const lines = staged.split("\n");
84
- lines.forEach((line) => {
85
- const match = line.match(/^\s*(.+?)\s+\|/);
86
- if (match)
87
- files.push(match[1]);
88
- });
89
- }
90
- const additions = (diff.match(/^\+(?!\+)/gm) || []).length;
91
- const deletions = (diff.match(/^-(?!-)/gm) || []).length;
92
- return {
93
- filesChanged: files,
94
- additions,
95
- deletions,
96
- hasStaged: staged !== "",
97
- hasUnstaged: unstaged !== "",
98
- diff,
99
- };
100
- }
101
- formatCommitMessage(msg) {
102
- let result = `${msg.type}`;
103
- if (msg.scope)
104
- result += `(${msg.scope})`;
105
- if (msg.breaking)
106
- result += "!";
107
- result += `: ${msg.subject}`;
108
- if (msg.body)
109
- result += `\n\n${msg.body}`;
110
- if (msg.breaking)
111
- result += `\n\nBREAKING CHANGE: Major version update required`;
112
- return result;
113
- }
114
- displayAnalysis(analysis) {
115
- console.log(chalk_1.default.cyan.bold("\nšŸ“Š Analysis:"));
116
- console.log(chalk_1.default.gray(` Files changed: ${chalk_1.default.white(analysis.filesChanged.length)}`));
117
- console.log(chalk_1.default.gray(` Additions: ${chalk_1.default.green(`+${analysis.additions}`)}`));
118
- console.log(chalk_1.default.gray(` Deletions: ${chalk_1.default.red(`-${analysis.deletions}`)}`));
119
- console.log(chalk_1.default.cyan.bold("\nšŸ“ Changed files:"));
120
- analysis.filesChanged.slice(0, 10).forEach((f) => {
121
- const ext = f.split(".").pop();
122
- const icon = this.getFileIcon(ext || "");
123
- console.log(chalk_1.default.gray(` ${icon} ${f}`));
124
- });
125
- if (analysis.filesChanged.length > 10) {
126
- console.log(chalk_1.default.gray(` ... and ${analysis.filesChanged.length - 10} more files`));
127
- }
128
- }
129
- getFileIcon(ext) {
130
- const icons = {
131
- ts: "šŸ“˜",
132
- js: "šŸ“’",
133
- tsx: "āš›ļø",
134
- jsx: "āš›ļø",
135
- json: "šŸ“‹",
136
- md: "šŸ“",
137
- css: "šŸŽØ",
138
- scss: "šŸŽØ",
139
- html: "🌐",
140
- test: "🧪",
141
- spec: "🧪",
142
- };
143
- return icons[ext] || "šŸ“„";
144
- }
145
- hasEnvironmentApiKey(provider) {
146
- switch (provider) {
147
- case "vercel-google":
148
- return !!process.env.GOOGLE_GENERATIVE_AI_API_KEY;
149
- case "vercel-openai":
150
- return !!process.env.OPENAI_API_KEY;
151
- case "groq":
152
- return !!process.env.GROQ_API_KEY;
153
- case "openai":
154
- return !!process.env.OPENAI_API_KEY;
155
- case "google":
156
- return !!process.env.GOOGLE_GENERATIVE_AI_API_KEY;
157
- default:
158
- return false;
159
- }
160
- }
161
- combineCommitMessages(messages) {
162
- const types = messages.map((m) => m.type);
163
- const typeCount = types.reduce((acc, t) => {
164
- acc[t] = (acc[t] || 0) + 1;
165
- return acc;
166
- }, {});
167
- const mostCommonType = Object.entries(typeCount).sort((a, b) => b[1] - a[1])[0][0];
168
- const scopes = messages.map((m) => m.scope).filter(Boolean);
169
- const uniqueScopes = [...new Set(scopes)];
170
- const scope = uniqueScopes.length > 0 ? uniqueScopes.slice(0, 2).join(", ") : undefined;
171
- const subjects = messages.map((m) => m.subject);
172
- const combinedSubject = subjects.join("; ");
173
- const bodies = messages.map((m) => m.body).filter(Boolean);
174
- const combinedBody = bodies.length > 0 ? bodies.join("\n\n") : undefined;
175
- const hasBreaking = messages.some((m) => m.breaking);
176
- return {
177
- type: mostCommonType,
178
- scope,
179
- subject: combinedSubject,
180
- body: combinedBody,
181
- breaking: hasBreaking,
182
- };
183
- }
184
- async run(options) {
185
- console.log(chalk_1.default.bold.cyan("\nšŸš€ CommitGen") +
186
- chalk_1.default.gray(" - AI-Powered Commit Message Generator\n"));
187
- if (!this.isGitRepo()) {
188
- console.error(chalk_1.default.red("āŒ Error: Not a git repository"));
189
- process.exit(1);
190
- }
191
- const analysis = this.analyzeChanges();
192
- if (!analysis.hasStaged) {
193
- console.log(chalk_1.default.yellow("āš ļø No staged changes found."));
194
- if (analysis.hasUnstaged) {
195
- console.log(chalk_1.default.blue("šŸ’” You have unstaged changes. Stage them with:") +
196
- chalk_1.default.gray(" git add <files>"));
197
- }
198
- process.exit(0);
199
- }
200
- // Check for issue tracking integration
201
- let issueRef = null;
202
- if (options.linkIssues !== false) {
203
- issueRef = this.issueTracker.extractIssueFromBranch();
204
- if (issueRef) {
205
- console.log(chalk_1.default.cyan(`\n${this.issueTracker.getIssueDisplay(issueRef)} detected`));
206
- }
207
- }
208
- // Check if multi-commit mode should be suggested
209
- if (options.multiCommit !== false &&
210
- this.multiCommitAnalyzer.shouldSplit(analysis)) {
211
- const result = await safePrompt([
212
- {
213
- type: "confirm",
214
- name: "useMultiCommit",
215
- message: chalk_1.default.yellow("šŸ”„ Multiple concerns detected. Split into separate commits?"),
216
- default: true,
217
- },
218
- ]);
219
- if (!result)
220
- return;
221
- if (result.useMultiCommit) {
222
- return this.runMultiCommit(analysis, options);
223
- }
224
- }
225
- this.displayAnalysis(analysis);
226
- // Load commit history pattern for personalization
227
- let historyPattern = null;
228
- if (options.learnFromHistory !== false) {
229
- historyPattern = await this.historyAnalyzer.getCommitPattern();
230
- if (historyPattern) {
231
- console.log(chalk_1.default.cyan("\nšŸ“œ Personalizing based on your commit history"));
232
- }
233
- }
234
- let suggestions = [];
235
- let usingFallback = false;
236
- if (options.useAi) {
237
- try {
238
- const configManager = new config_1.ConfigManager();
239
- let providerConfig = configManager.getProviderConfig();
240
- // Override model if specified in options
241
- if (options.model) {
242
- providerConfig = { ...providerConfig, model: options.model };
243
- console.log(chalk_1.default.blue(`šŸŽÆ Using model: ${options.model}`));
244
- }
245
- if (!providerConfig.apiKey &&
246
- !this.hasEnvironmentApiKey(providerConfig.provider)) {
247
- console.log(chalk_1.default.yellow("\nāš ļø API key not found for the selected provider."));
248
- const result = await safePrompt([
249
- {
250
- type: "confirm",
251
- name: "shouldConfigure",
252
- message: "Would you like to configure your API key now?",
253
- default: true,
254
- },
255
- ]);
256
- if (!result)
257
- return;
258
- if (result.shouldConfigure) {
259
- await (0, configure_1.configureCommand)();
260
- providerConfig = configManager.getProviderConfig();
261
- }
262
- else {
263
- console.log(chalk_1.default.gray("Falling back to rule-based suggestions...\n"));
264
- suggestions = this.getFallbackSuggestions(analysis);
265
- usingFallback = true;
266
- }
267
- }
268
- if (!usingFallback) {
269
- const modelDisplay = providerConfig.model || "default";
270
- const provider = (0, providers_1.createProvider)(providerConfig);
271
- suggestions = await (0, loading_1.withLoading)(`Generating commit messages using ${providerConfig.provider} (${modelDisplay})...`, async () => await provider.generateCommitMessage(analysis), "Commit messages generated");
272
- if (!suggestions || suggestions.length === 0) {
273
- throw new Error("No suggestions generated");
274
- }
275
- // Personalize suggestions based on history
276
- if (historyPattern) {
277
- suggestions = suggestions.map((msg) => this.historyAnalyzer.personalizeCommitMessage(msg, historyPattern));
278
- }
279
- // Adjust type based on issue if available
280
- if (issueRef) {
281
- suggestions = suggestions.map((msg) => ({
282
- ...msg,
283
- type: this.issueTracker.suggestTypeFromIssue(issueRef, msg.type),
284
- }));
285
- }
286
- }
287
- }
288
- catch (error) {
289
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
290
- // Check if it's an API overload error
291
- if (errorMessage.includes("overloaded") ||
292
- errorMessage.includes("503")) {
293
- console.warn(chalk_1.default.yellow(`\nāš ļø ${errorMessage}`));
294
- console.log(chalk_1.default.blue("šŸ’” Tip: You can use 'commitgen --no-use-ai' to skip AI generation"));
295
- }
296
- else if (errorMessage.includes("API key")) {
297
- console.warn(chalk_1.default.yellow(`\nāš ļø ${errorMessage}`));
298
- const result = await safePrompt([
299
- {
300
- type: "confirm",
301
- name: "shouldReconfigure",
302
- message: "Would you like to reconfigure your API key?",
303
- default: true,
304
- },
305
- ]);
306
- if (!result)
307
- return;
308
- if (result.shouldReconfigure) {
309
- await (0, configure_1.configureCommand)();
310
- console.log(chalk_1.default.blue("\nšŸ”„ Please run the command again with your new configuration."));
311
- return;
312
- }
313
- }
314
- else {
315
- console.warn(chalk_1.default.yellow(`\nāš ļø AI generation failed: ${errorMessage}`));
316
- }
317
- console.log(chalk_1.default.gray("\nFalling back to rule-based suggestions...\n"));
318
- suggestions = this.getFallbackSuggestions(analysis);
319
- usingFallback = true;
320
- }
321
- }
322
- else {
323
- console.log(chalk_1.default.gray("\nšŸ“ Using rule-based suggestions (AI disabled)\n"));
324
- suggestions = this.getFallbackSuggestions(analysis);
325
- usingFallback = true;
326
- }
327
- await this.commitInteractive(suggestions, analysis, issueRef, options);
328
- }
329
- async runMultiCommit(analysis, options) {
330
- const groups = this.multiCommitAnalyzer.groupFiles(analysis);
331
- console.log(chalk_1.default.cyan.bold(`\nšŸ”„ Splitting into ${groups.length} commits:\n`));
332
- groups.forEach((group, i) => {
333
- console.log(chalk_1.default.gray(`${i + 1}. ${group.reason}`));
334
- console.log(chalk_1.default.gray(` Files: ${group.files.slice(0, 3).join(", ")}${group.files.length > 3 ? "..." : ""}`));
335
- });
336
- const result = await safePrompt([
337
- {
338
- type: "confirm",
339
- name: "proceed",
340
- message: "Proceed with multi-commit?",
341
- default: true,
342
- },
343
- ]);
344
- if (!result)
345
- return;
346
- if (!result.proceed) {
347
- console.log(chalk_1.default.yellow("\nCancelled. Falling back to single commit mode."));
348
- return this.run({ ...options, multiCommit: false });
349
- }
350
- for (let i = 0; i < groups.length; i++) {
351
- const group = groups[i];
352
- console.log(chalk_1.default.cyan.bold(`\nšŸ“ Commit ${i + 1}/${groups.length}: ${group.reason}`));
353
- // Generate suggestions for this group
354
- let suggestions = [group.suggestedMessage];
355
- if (options.useAi) {
356
- try {
357
- const configManager = new config_1.ConfigManager();
358
- let providerConfig = configManager.getProviderConfig();
359
- // Override model if specified
360
- if (options.model) {
361
- providerConfig = { ...providerConfig, model: options.model };
362
- }
363
- if (providerConfig.apiKey ||
364
- this.hasEnvironmentApiKey(providerConfig.provider)) {
365
- const provider = (0, providers_1.createProvider)(providerConfig);
366
- const loader = new loading_1.LoadingIndicator("Generating commit message...");
367
- loader.start();
368
- try {
369
- suggestions = await provider.generateCommitMessage(group.analysis);
370
- loader.succeed("Generated");
371
- }
372
- catch (err) {
373
- loader.stop();
374
- throw err;
375
- }
376
- }
377
- }
378
- catch (error) {
379
- console.log(chalk_1.default.gray("Using suggested message for this commit"));
380
- }
381
- }
382
- await this.commitInteractive(suggestions, group.analysis, null, options, group.files);
383
- }
384
- console.log(chalk_1.default.green.bold("\nāœ… All commits completed!"));
385
- }
386
- async commitInteractive(suggestions, analysis, issueRef, options, specificFiles) {
387
- console.log(chalk_1.default.cyan.bold("šŸ’” Suggested commit messages:\n"));
388
- const choices = suggestions.map((s, i) => {
389
- const formatted = this.formatCommitMessage(s);
390
- const preview = formatted.split("\n")[0];
391
- return {
392
- name: `${chalk_1.default.gray(`${i + 1}.`)} ${preview}`,
393
- value: i,
394
- short: preview,
395
- };
396
- });
397
- choices.push({
398
- name: chalk_1.default.magenta("šŸ”— Combine all suggestions"),
399
- value: -1,
400
- short: "Combined",
401
- });
402
- choices.push({
403
- name: chalk_1.default.gray("āœļø Write custom message"),
404
- value: -2,
405
- short: "Custom message",
406
- });
407
- const result = await safePrompt([
408
- {
409
- type: "list",
410
- name: "selectedIndex",
411
- message: "Choose a commit message:",
412
- choices,
413
- pageSize: 10,
414
- },
415
- ]);
416
- if (!result)
417
- return;
418
- const { selectedIndex } = result;
419
- let commitMessage;
420
- if (selectedIndex === -1) {
421
- const combined = this.combineCommitMessages(suggestions);
422
- const combinedFormatted = this.formatCommitMessage(combined);
423
- console.log(chalk_1.default.cyan("\nšŸ“¦ Combined message:"));
424
- console.log(chalk_1.default.white(combinedFormatted));
425
- const actionResult = await safePrompt([
426
- {
427
- type: "list",
428
- name: "action",
429
- message: "What would you like to do?",
430
- choices: [
431
- { name: "āœ… Use this combined message", value: "use" },
432
- { name: "āœļø Edit this message", value: "edit" },
433
- { name: "šŸ”™ Go back to suggestions", value: "back" },
434
- ],
435
- },
436
- ]);
437
- if (!actionResult)
438
- return;
439
- if (actionResult.action === "back") {
440
- return this.commitInteractive(suggestions, analysis, issueRef, options, specificFiles);
441
- }
442
- else if (actionResult.action === "edit") {
443
- const editResult = await safePrompt([
444
- {
445
- type: "input",
446
- name: "edited",
447
- message: "Edit commit message:",
448
- default: combinedFormatted,
449
- validate: (input) => {
450
- if (!input.trim())
451
- return "Commit message cannot be empty";
452
- return true;
453
- },
454
- },
455
- ]);
456
- if (!editResult)
457
- return;
458
- commitMessage = editResult.edited;
459
- }
460
- else {
461
- commitMessage = combinedFormatted;
462
- }
463
- }
464
- else if (selectedIndex === -2) {
465
- const customResult = await safePrompt([
466
- {
467
- type: "input",
468
- name: "customMessage",
469
- message: "Enter your commit message:",
470
- validate: (input) => {
471
- if (!input.trim())
472
- return "Commit message cannot be empty";
473
- return true;
474
- },
475
- },
476
- ]);
477
- if (!customResult)
478
- return;
479
- commitMessage = customResult.customMessage;
480
- }
481
- else {
482
- let selected = suggestions[selectedIndex];
483
- // Add issue reference if available
484
- if (issueRef && options.linkIssues !== false) {
485
- selected = this.issueTracker.appendIssueToCommit(selected, issueRef);
486
- }
487
- const formatted = this.formatCommitMessage(selected);
488
- const actionResult = await safePrompt([
489
- {
490
- type: "list",
491
- name: "action",
492
- message: "What would you like to do?",
493
- choices: [
494
- { name: "āœ… Use this message", value: "use" },
495
- { name: "āœļø Edit this message", value: "edit" },
496
- { name: "šŸ”™ Choose a different message", value: "back" },
497
- ],
498
- },
499
- ]);
500
- if (!actionResult)
501
- return;
502
- if (actionResult.action === "back") {
503
- return this.commitInteractive(suggestions, analysis, issueRef, options, specificFiles);
504
- }
505
- else if (actionResult.action === "edit") {
506
- const editResult = await safePrompt([
507
- {
508
- type: "input",
509
- name: "edited",
510
- message: "Edit commit message:",
511
- default: formatted,
512
- validate: (input) => {
513
- if (!input.trim())
514
- return "Commit message cannot be empty";
515
- return true;
516
- },
517
- },
518
- ]);
519
- if (!editResult)
520
- return;
521
- commitMessage = editResult.edited;
522
- }
523
- else {
524
- commitMessage = formatted;
525
- }
526
- }
527
- if (!commitMessage.trim()) {
528
- console.log(chalk_1.default.red("\nāŒ Commit cancelled - empty message"));
529
- return;
530
- }
531
- try {
532
- let commitCmd = specificFiles
533
- ? `git commit ${specificFiles
534
- .map((f) => `"${f}"`)
535
- .join(" ")} -m "${commitMessage.replace(/"/g, '\\"')}"`
536
- : `git commit -m "${commitMessage.replace(/"/g, '\\"')}"`;
537
- if (options.noverify) {
538
- commitCmd += " --no-verify";
539
- }
540
- this.exec(commitCmd);
541
- console.log(chalk_1.default.green("\nāœ… Commit successful!"));
542
- if (options.push && !specificFiles) {
543
- console.log(chalk_1.default.blue("\nšŸ“¤ Pushing to remote..."));
544
- const currentBranch = this.exec("git branch --show-current");
545
- this.exec(`git push origin ${currentBranch}`);
546
- console.log(chalk_1.default.green("āœ… Pushed successfully!"));
547
- }
548
- }
549
- catch (error) {
550
- console.error(chalk_1.default.red("āŒ Commit failed:"), error);
551
- process.exit(1);
552
- }
553
- }
554
- getFallbackSuggestions(analysis) {
555
- const { filesChanged, additions, deletions } = analysis;
556
- const suggestions = [];
557
- const hasTests = filesChanged.some((f) => f.includes("test") || f.includes("spec") || f.includes("__tests__"));
558
- const hasDocs = filesChanged.some((f) => f.includes("README") || f.includes(".md"));
559
- const hasConfig = filesChanged.some((f) => f.includes("config") ||
560
- f.includes(".json") ||
561
- f.includes("package.json"));
562
- if (additions > deletions * 2 && additions > 20) {
563
- suggestions.push({
564
- type: "feat",
565
- subject: `add new feature`,
566
- });
567
- }
568
- if (deletions > additions * 2 && deletions > 20) {
569
- suggestions.push({
570
- type: "refactor",
571
- subject: `remove unused code`,
572
- });
573
- }
574
- if (hasTests) {
575
- suggestions.push({
576
- type: "test",
577
- subject: `add tests`,
578
- });
579
- }
580
- if (hasDocs) {
581
- suggestions.push({
582
- type: "docs",
583
- subject: "update documentation",
584
- });
585
- }
586
- if (hasConfig) {
587
- suggestions.push({
588
- type: "chore",
589
- subject: "update configuration",
590
- });
591
- }
592
- if (suggestions.length === 0) {
593
- suggestions.push({
594
- type: "feat",
595
- subject: `add feature`,
596
- }, {
597
- type: "fix",
598
- subject: `fix issue`,
599
- }, {
600
- type: "refactor",
601
- subject: `refactor code`,
602
- });
603
- }
604
- return suggestions.slice(0, 5);
605
- }
606
- }
607
- // CLI setup
608
- const program = new commander_1.Command();
609
- program
610
- .name("commitgen")
611
- .description("AI-powered commit message generator for Git")
612
- .version(getVersionSimple())
613
- .option("-p, --push", "Push changes after committing")
614
- .option("-n, --noverify", "Skip git hooks (--no-verify)")
615
- .option("--use-ai", "Use AI generation (default: enabled)")
616
- .option("--no-use-ai", "Disable AI generation, use rule-based suggestions only")
617
- .option("-m, --multi-commit", "Enable multi-commit mode for atomic commits")
618
- .option("--no-multi-commit", "Disable multi-commit mode")
619
- .option("--no-history", "Disable commit history learning")
620
- .option("--no-issues", "Disable issue tracker integration")
621
- .option("--model <model>", "Specify AI model to use (e.g., gemini-1.5-flash, gemini-2.5-pro)")
622
- .action(async (options) => {
623
- const commitGen = new CommitGen();
624
- // Default useAi to true if not explicitly set
625
- if (options.useAi === undefined) {
626
- options.useAi = true;
627
- }
628
- await commitGen.run(options);
629
- });
630
- program
631
- .command("config")
632
- .description("Configure AI provider and settings")
633
- .action(configure_1.configureCommand);
634
- program
635
- .command("show-config")
636
- .description("Show current configuration")
637
- .action(() => {
638
- const configManager = new config_1.ConfigManager();
639
- const config = configManager.getProviderConfig();
640
- console.log(chalk_1.default.cyan.bold("\nāš™ļø Current Configuration\n"));
641
- console.log(chalk_1.default.gray(`Provider: ${chalk_1.default.white(config.provider)}`));
642
- console.log(chalk_1.default.gray(`Model: ${chalk_1.default.white(config.model || "default")}`));
643
- console.log(chalk_1.default.gray(`API Key: ${config.apiKey ? chalk_1.default.green("configured") : chalk_1.default.red("not set")}`));
644
- if (!config.apiKey) {
645
- console.log(chalk_1.default.yellow("\nšŸ’” Run 'commitgen config' to set up your API key"));
646
- }
647
- });
648
- program.parse();
649
- //# sourceMappingURL=index.js.map