@untools/commitgen 0.2.4 → 0.2.6

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 (37) hide show
  1. package/dist/index.js +5 -7
  2. package/dist/index.js.map +1 -1
  3. package/dist/package.json +70 -0
  4. package/dist/src/commands/configure.d.ts +1 -0
  5. package/dist/src/commands/configure.js +96 -0
  6. package/dist/src/commands/configure.js.map +1 -0
  7. package/dist/src/config.d.ts +15 -0
  8. package/dist/src/config.js +56 -0
  9. package/dist/src/config.js.map +1 -0
  10. package/dist/src/index.d.ts +2 -0
  11. package/dist/src/index.js +649 -0
  12. package/dist/src/index.js.map +1 -0
  13. package/dist/src/providers/base.d.ts +9 -0
  14. package/dist/src/providers/base.js +107 -0
  15. package/dist/src/providers/base.js.map +1 -0
  16. package/dist/src/providers/index.d.ts +4 -0
  17. package/dist/src/providers/index.js +41 -0
  18. package/dist/src/providers/index.js.map +1 -0
  19. package/dist/src/providers/vercel-google.d.ts +10 -0
  20. package/dist/src/providers/vercel-google.js +113 -0
  21. package/dist/src/providers/vercel-google.js.map +1 -0
  22. package/dist/src/types.d.ts +46 -0
  23. package/dist/src/types.js +4 -0
  24. package/dist/src/types.js.map +1 -0
  25. package/dist/src/utils/commit-history.d.ts +35 -0
  26. package/dist/src/utils/commit-history.js +165 -0
  27. package/dist/src/utils/commit-history.js.map +1 -0
  28. package/dist/src/utils/issue-tracker.d.ts +43 -0
  29. package/dist/src/utils/issue-tracker.js +207 -0
  30. package/dist/src/utils/issue-tracker.js.map +1 -0
  31. package/dist/src/utils/loading.d.ts +14 -0
  32. package/dist/src/utils/loading.js +72 -0
  33. package/dist/src/utils/loading.js.map +1 -0
  34. package/dist/src/utils/multi-commit.d.ts +40 -0
  35. package/dist/src/utils/multi-commit.js +274 -0
  36. package/dist/src/utils/multi-commit.js.map +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1,43 @@
1
+ import { CommitMessage } from "../types";
2
+ export interface IssueReference {
3
+ platform: "jira" | "github" | "linear" | "gitlab" | "unknown";
4
+ issueKey: string;
5
+ issueType?: string;
6
+ branchName: string;
7
+ }
8
+ export declare class IssueTrackerIntegration {
9
+ private cache;
10
+ private exec;
11
+ /**
12
+ * Extract issue reference from current branch
13
+ */
14
+ extractIssueFromBranch(): IssueReference | null;
15
+ /**
16
+ * Parse issue reference from branch name
17
+ */
18
+ private parseIssueFromBranch;
19
+ /**
20
+ * Infer issue type from branch name
21
+ */
22
+ private inferIssueType;
23
+ /**
24
+ * Check if repository is GitLab
25
+ */
26
+ private isGitLabRepo;
27
+ /**
28
+ * Append issue reference to commit message
29
+ */
30
+ appendIssueToCommit(message: CommitMessage, issue: IssueReference): CommitMessage;
31
+ /**
32
+ * Suggest commit type based on issue type
33
+ */
34
+ suggestTypeFromIssue(issue: IssueReference, defaultType: string): string;
35
+ /**
36
+ * Get display string for issue
37
+ */
38
+ getIssueDisplay(issue: IssueReference): string;
39
+ /**
40
+ * Clear cache (useful for testing or branch switches)
41
+ */
42
+ clearCache(): void;
43
+ }
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ // ./src/utils/issue-tracker.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.IssueTrackerIntegration = void 0;
5
+ const child_process_1 = require("child_process");
6
+ class IssueTrackerIntegration {
7
+ constructor() {
8
+ this.cache = null;
9
+ }
10
+ exec(cmd) {
11
+ try {
12
+ return (0, child_process_1.execSync)(cmd, {
13
+ encoding: "utf8",
14
+ stdio: ["pipe", "pipe", "ignore"],
15
+ }).trim();
16
+ }
17
+ catch (_a) {
18
+ return "";
19
+ }
20
+ }
21
+ /**
22
+ * Extract issue reference from current branch
23
+ */
24
+ extractIssueFromBranch() {
25
+ // Check cache first
26
+ if (this.cache)
27
+ return this.cache;
28
+ const branchName = this.exec("git branch --show-current");
29
+ if (!branchName)
30
+ return null;
31
+ const issue = this.parseIssueFromBranch(branchName);
32
+ // Cache the result
33
+ this.cache = issue;
34
+ return issue;
35
+ }
36
+ /**
37
+ * Parse issue reference from branch name
38
+ */
39
+ parseIssueFromBranch(branchName) {
40
+ // Jira pattern: PROJ-123 or feature/PROJ-123-description
41
+ const jiraMatch = branchName.match(/([A-Z]{2,10}-\d+)/);
42
+ if (jiraMatch) {
43
+ return {
44
+ platform: "jira",
45
+ issueKey: jiraMatch[1],
46
+ branchName,
47
+ issueType: this.inferIssueType(branchName),
48
+ };
49
+ }
50
+ // GitHub issue pattern: #123 or issue-123 or 123-description
51
+ const githubMatch = branchName.match(/(?:issue[/-]|#)?(\d+)(?:[/-]|$)/i);
52
+ if (githubMatch) {
53
+ return {
54
+ platform: "github",
55
+ issueKey: `#${githubMatch[1]}`,
56
+ branchName,
57
+ issueType: this.inferIssueType(branchName),
58
+ };
59
+ }
60
+ // Linear pattern: TEAM-123 or team/TEAM-123-description
61
+ const linearMatch = branchName.match(/([A-Z]{2,5}-\d+)/);
62
+ if (linearMatch) {
63
+ return {
64
+ platform: "linear",
65
+ issueKey: linearMatch[1],
66
+ branchName,
67
+ issueType: this.inferIssueType(branchName),
68
+ };
69
+ }
70
+ // GitLab issue pattern: similar to GitHub
71
+ const gitlabMatch = branchName.match(/(?:issue[/-]|#)?(\d+)(?:[/-]|$)/i);
72
+ if (gitlabMatch && this.isGitLabRepo()) {
73
+ return {
74
+ platform: "gitlab",
75
+ issueKey: `#${gitlabMatch[1]}`,
76
+ branchName,
77
+ issueType: this.inferIssueType(branchName),
78
+ };
79
+ }
80
+ return null;
81
+ }
82
+ /**
83
+ * Infer issue type from branch name
84
+ */
85
+ inferIssueType(branchName) {
86
+ const lower = branchName.toLowerCase();
87
+ if (lower.startsWith("feature/") || lower.includes("/feature/")) {
88
+ return "feature";
89
+ }
90
+ if (lower.startsWith("fix/") ||
91
+ lower.startsWith("bugfix/") ||
92
+ lower.includes("/fix/")) {
93
+ return "fix";
94
+ }
95
+ if (lower.startsWith("hotfix/") || lower.includes("/hotfix/")) {
96
+ return "hotfix";
97
+ }
98
+ if (lower.startsWith("refactor/") || lower.includes("/refactor/")) {
99
+ return "refactor";
100
+ }
101
+ if (lower.startsWith("docs/") || lower.includes("/docs/")) {
102
+ return "docs";
103
+ }
104
+ if (lower.startsWith("test/") || lower.includes("/test/")) {
105
+ return "test";
106
+ }
107
+ if (lower.startsWith("chore/") || lower.includes("/chore/")) {
108
+ return "chore";
109
+ }
110
+ return undefined;
111
+ }
112
+ /**
113
+ * Check if repository is GitLab
114
+ */
115
+ isGitLabRepo() {
116
+ const remote = this.exec("git config --get remote.origin.url");
117
+ return remote.includes("gitlab");
118
+ }
119
+ /**
120
+ * Append issue reference to commit message
121
+ */
122
+ appendIssueToCommit(message, issue) {
123
+ const enhanced = { ...message };
124
+ // Add issue reference based on platform conventions
125
+ switch (issue.platform) {
126
+ case "jira":
127
+ // Jira: Add to subject if not already there
128
+ if (!enhanced.subject.includes(issue.issueKey)) {
129
+ enhanced.subject = `${enhanced.subject} [${issue.issueKey}]`;
130
+ }
131
+ // Also add to footer
132
+ if (enhanced.body) {
133
+ enhanced.body += `\n\nJira: ${issue.issueKey}`;
134
+ }
135
+ else {
136
+ enhanced.body = `Jira: ${issue.issueKey}`;
137
+ }
138
+ break;
139
+ case "github":
140
+ // GitHub: Add to footer for auto-linking
141
+ if (enhanced.body) {
142
+ enhanced.body += `\n\nCloses ${issue.issueKey}`;
143
+ }
144
+ else {
145
+ enhanced.body = `Closes ${issue.issueKey}`;
146
+ }
147
+ break;
148
+ case "linear":
149
+ // Linear: Add to subject
150
+ if (!enhanced.subject.includes(issue.issueKey)) {
151
+ enhanced.subject = `${enhanced.subject} [${issue.issueKey}]`;
152
+ }
153
+ break;
154
+ case "gitlab":
155
+ // GitLab: Add to footer for auto-linking
156
+ if (enhanced.body) {
157
+ enhanced.body += `\n\nCloses ${issue.issueKey}`;
158
+ }
159
+ else {
160
+ enhanced.body = `Closes ${issue.issueKey}`;
161
+ }
162
+ break;
163
+ }
164
+ return enhanced;
165
+ }
166
+ /**
167
+ * Suggest commit type based on issue type
168
+ */
169
+ suggestTypeFromIssue(issue, defaultType) {
170
+ if (!issue.issueType)
171
+ return defaultType;
172
+ const typeMap = {
173
+ feature: "feat",
174
+ fix: "fix",
175
+ bugfix: "fix",
176
+ hotfix: "fix",
177
+ refactor: "refactor",
178
+ docs: "docs",
179
+ test: "test",
180
+ chore: "chore",
181
+ };
182
+ return typeMap[issue.issueType] || defaultType;
183
+ }
184
+ /**
185
+ * Get display string for issue
186
+ */
187
+ getIssueDisplay(issue) {
188
+ const platformEmoji = {
189
+ jira: "🎫",
190
+ github: "🐙",
191
+ linear: "📐",
192
+ gitlab: "🦊",
193
+ unknown: "🔗",
194
+ };
195
+ const emoji = platformEmoji[issue.platform] || "🔗";
196
+ const platform = issue.platform.charAt(0).toUpperCase() + issue.platform.slice(1);
197
+ return `${emoji} ${platform}: ${issue.issueKey}`;
198
+ }
199
+ /**
200
+ * Clear cache (useful for testing or branch switches)
201
+ */
202
+ clearCache() {
203
+ this.cache = null;
204
+ }
205
+ }
206
+ exports.IssueTrackerIntegration = IssueTrackerIntegration;
207
+ //# sourceMappingURL=issue-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-tracker.js","sourceRoot":"","sources":["../../../src/utils/issue-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export declare class LoadingIndicator {
2
+ private frames;
3
+ private currentFrame;
4
+ private interval;
5
+ private message;
6
+ constructor(message?: string);
7
+ start(): void;
8
+ updateMessage(message: string): void;
9
+ stop(finalMessage?: string): void;
10
+ succeed(message: string): void;
11
+ fail(message: string): void;
12
+ warn(message: string): void;
13
+ }
14
+ export declare function withLoading<T>(message: string, operation: () => Promise<T>, successMessage?: string): Promise<T>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LoadingIndicator = void 0;
7
+ exports.withLoading = withLoading;
8
+ // ./src/utils/loading.ts
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ class LoadingIndicator {
11
+ constructor(message = "Loading...") {
12
+ this.frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
13
+ this.currentFrame = 0;
14
+ this.interval = null;
15
+ this.message = message;
16
+ }
17
+ start() {
18
+ // Hide cursor
19
+ process.stdout.write("\x1B[?25l");
20
+ this.interval = setInterval(() => {
21
+ const frame = this.frames[this.currentFrame];
22
+ process.stdout.write(`\r${chalk_1.default.cyan(frame)} ${chalk_1.default.gray(this.message)}`);
23
+ this.currentFrame = (this.currentFrame + 1) % this.frames.length;
24
+ }, 80);
25
+ }
26
+ updateMessage(message) {
27
+ this.message = message;
28
+ }
29
+ stop(finalMessage) {
30
+ if (this.interval) {
31
+ clearInterval(this.interval);
32
+ this.interval = null;
33
+ }
34
+ // Clear the line
35
+ process.stdout.write("\r\x1B[K");
36
+ // Show cursor
37
+ process.stdout.write("\x1B[?25h");
38
+ if (finalMessage) {
39
+ console.log(finalMessage);
40
+ }
41
+ }
42
+ succeed(message) {
43
+ this.stop(chalk_1.default.green(`✓ ${message}`));
44
+ }
45
+ fail(message) {
46
+ this.stop(chalk_1.default.red(`✗ ${message}`));
47
+ }
48
+ warn(message) {
49
+ this.stop(chalk_1.default.yellow(`⚠ ${message}`));
50
+ }
51
+ }
52
+ exports.LoadingIndicator = LoadingIndicator;
53
+ // Utility function for wrapping async operations with loading indicator
54
+ async function withLoading(message, operation, successMessage) {
55
+ const loader = new LoadingIndicator(message);
56
+ loader.start();
57
+ try {
58
+ const result = await operation();
59
+ if (successMessage) {
60
+ loader.succeed(successMessage);
61
+ }
62
+ else {
63
+ loader.stop();
64
+ }
65
+ return result;
66
+ }
67
+ catch (error) {
68
+ loader.stop();
69
+ throw error;
70
+ }
71
+ }
72
+ //# sourceMappingURL=loading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loading.js","sourceRoot":"","sources":["../../../src/utils/loading.ts"],"names":[],"mappings":";;;;;;AA6DA,kCAoBC;AAjFD,yBAAyB;AACzB,kDAA0B;AAE1B,MAAa,gBAAgB;IAM3B,YAAY,UAAkB,YAAY;QALlC,WAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC5D,iBAAY,GAAG,CAAC,CAAC;QACjB,aAAQ,GAA0B,IAAI,CAAC;QAI7C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK;QACH,cAAc;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAElC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,KAAK,eAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,eAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CACrD,CAAC;YACF,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACnE,CAAC,EAAE,EAAE,CAAC,CAAC;IACT,CAAC;IAED,aAAa,CAAC,OAAe;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,YAAqB;QACxB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;QAED,iBAAiB;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAEjC,cAAc;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAElC,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,CAAC,OAAe;QACrB,IAAI,CAAC,IAAI,CAAC,eAAK,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,IAAI,CAAC,eAAK,CAAC,MAAM,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;CACF;AAvDD,4CAuDC;AAED,wEAAwE;AACjE,KAAK,UAAU,WAAW,CAC/B,OAAe,EACf,SAA2B,EAC3B,cAAuB;IAEvB,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,EAAE,CAAC;IAEf,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { CommitMessage, GitAnalysis } from "../types";
2
+ export interface CommitGroup {
3
+ files: string[];
4
+ analysis: GitAnalysis;
5
+ suggestedMessage: CommitMessage;
6
+ reason: string;
7
+ }
8
+ export declare class MultiCommitAnalyzer {
9
+ private exec;
10
+ /**
11
+ * Analyze if changes should be split into multiple commits
12
+ */
13
+ shouldSplit(analysis: GitAnalysis): boolean;
14
+ /**
15
+ * Identify distinct concerns in changed files
16
+ */
17
+ private identifyConcerns;
18
+ /**
19
+ * Group files into logical commits
20
+ */
21
+ groupFiles(analysis: GitAnalysis): CommitGroup[];
22
+ /**
23
+ * Create analysis for a specific file group
24
+ */
25
+ private createGroupAnalysis;
26
+ /**
27
+ * Suggest commit message for a group
28
+ */
29
+ private suggestMessageForGroup;
30
+ private inferScopeFromFiles;
31
+ /**
32
+ * Get human-readable reason for grouping
33
+ */
34
+ private getGroupReason;
35
+ /**
36
+ * Sort groups in logical commit order
37
+ */
38
+ private sortCommitGroups;
39
+ private getGroupKey;
40
+ }
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ // ./src/utils/multi-commit.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.MultiCommitAnalyzer = void 0;
5
+ const child_process_1 = require("child_process");
6
+ class MultiCommitAnalyzer {
7
+ exec(cmd) {
8
+ try {
9
+ return (0, child_process_1.execSync)(cmd, {
10
+ encoding: "utf8",
11
+ stdio: ["pipe", "pipe", "ignore"],
12
+ }).trim();
13
+ }
14
+ catch (_a) {
15
+ return "";
16
+ }
17
+ }
18
+ /**
19
+ * Analyze if changes should be split into multiple commits
20
+ */
21
+ shouldSplit(analysis) {
22
+ const { filesChanged } = analysis;
23
+ // Don't split if only a few files
24
+ if (filesChanged.length < 4)
25
+ return false;
26
+ // Check for mixed concerns
27
+ const concerns = this.identifyConcerns(filesChanged);
28
+ // Split if we have 2+ distinct concerns
29
+ return concerns.size >= 2;
30
+ }
31
+ /**
32
+ * Identify distinct concerns in changed files
33
+ */
34
+ identifyConcerns(files) {
35
+ const concerns = new Set();
36
+ for (const file of files) {
37
+ if (file.includes("test") ||
38
+ file.includes("spec") ||
39
+ file.includes("__tests__")) {
40
+ concerns.add("tests");
41
+ }
42
+ else if (file.includes("README") || file.endsWith(".md")) {
43
+ concerns.add("docs");
44
+ }
45
+ else if (file.includes("package.json") ||
46
+ file.includes("tsconfig") ||
47
+ file.includes(".config")) {
48
+ concerns.add("config");
49
+ }
50
+ else if (file.includes("component") || file.includes("Component")) {
51
+ concerns.add("components");
52
+ }
53
+ else if (file.includes("util") || file.includes("helper")) {
54
+ concerns.add("utils");
55
+ }
56
+ else if (file.includes("api") || file.includes("endpoint")) {
57
+ concerns.add("api");
58
+ }
59
+ else if (file.includes("style") ||
60
+ file.endsWith(".css") ||
61
+ file.endsWith(".scss")) {
62
+ concerns.add("styles");
63
+ }
64
+ else if (file.includes("type") || file.includes("interface")) {
65
+ concerns.add("types");
66
+ }
67
+ else {
68
+ concerns.add("feature");
69
+ }
70
+ }
71
+ return concerns;
72
+ }
73
+ /**
74
+ * Group files into logical commits
75
+ */
76
+ groupFiles(analysis) {
77
+ const { filesChanged } = analysis;
78
+ const groups = new Map();
79
+ // Priority order for grouping
80
+ const priorities = [
81
+ {
82
+ key: "config",
83
+ pattern: (f) => f.includes("package.json") ||
84
+ f.includes("tsconfig") ||
85
+ f.includes(".config"),
86
+ },
87
+ {
88
+ key: "types",
89
+ pattern: (f) => f.includes("type") || f.includes("interface"),
90
+ },
91
+ {
92
+ key: "tests",
93
+ pattern: (f) => f.includes("test") || f.includes("spec") || f.includes("__tests__"),
94
+ },
95
+ {
96
+ key: "docs",
97
+ pattern: (f) => f.includes("README") || f.endsWith(".md"),
98
+ },
99
+ {
100
+ key: "styles",
101
+ pattern: (f) => f.includes("style") || f.endsWith(".css") || f.endsWith(".scss"),
102
+ },
103
+ {
104
+ key: "components",
105
+ pattern: (f) => f.includes("component") || f.includes("Component"),
106
+ },
107
+ {
108
+ key: "api",
109
+ pattern: (f) => f.includes("api") || f.includes("endpoint"),
110
+ },
111
+ {
112
+ key: "utils",
113
+ pattern: (f) => f.includes("util") || f.includes("helper"),
114
+ },
115
+ ];
116
+ // Group files by concern
117
+ const ungrouped = [];
118
+ for (const file of filesChanged) {
119
+ let grouped = false;
120
+ for (const { key, pattern } of priorities) {
121
+ if (pattern(file)) {
122
+ if (!groups.has(key)) {
123
+ groups.set(key, []);
124
+ }
125
+ groups.get(key).push(file);
126
+ grouped = true;
127
+ break;
128
+ }
129
+ }
130
+ if (!grouped) {
131
+ ungrouped.push(file);
132
+ }
133
+ }
134
+ // Group remaining files by directory
135
+ if (ungrouped.length > 0) {
136
+ const dirGroups = new Map();
137
+ for (const file of ungrouped) {
138
+ const dir = file.split("/")[0] || "root";
139
+ if (!dirGroups.has(dir)) {
140
+ dirGroups.set(dir, []);
141
+ }
142
+ dirGroups.get(dir).push(file);
143
+ }
144
+ dirGroups.forEach((files, dir) => {
145
+ groups.set(`feature-${dir}`, files);
146
+ });
147
+ }
148
+ // Convert to CommitGroup array
149
+ const commitGroups = [];
150
+ for (const [key, files] of groups.entries()) {
151
+ if (files.length === 0)
152
+ continue;
153
+ const groupAnalysis = this.createGroupAnalysis(files, analysis);
154
+ const suggestedMessage = this.suggestMessageForGroup(key, files);
155
+ const reason = this.getGroupReason(key, files);
156
+ commitGroups.push({
157
+ files,
158
+ analysis: groupAnalysis,
159
+ suggestedMessage,
160
+ reason,
161
+ });
162
+ }
163
+ // Sort by logical commit order
164
+ return this.sortCommitGroups(commitGroups);
165
+ }
166
+ /**
167
+ * Create analysis for a specific file group
168
+ */
169
+ createGroupAnalysis(files, fullAnalysis) {
170
+ // Get diff for specific files
171
+ const filesStr = files.map((f) => `"${f}"`).join(" ");
172
+ const diff = this.exec(`git diff --cached -- ${filesStr}`);
173
+ const additions = (diff.match(/^\+(?!\+)/gm) || []).length;
174
+ const deletions = (diff.match(/^-(?!-)/gm) || []).length;
175
+ return {
176
+ filesChanged: files,
177
+ additions,
178
+ deletions,
179
+ hasStaged: true,
180
+ hasUnstaged: fullAnalysis.hasUnstaged,
181
+ diff,
182
+ };
183
+ }
184
+ /**
185
+ * Suggest commit message for a group
186
+ */
187
+ suggestMessageForGroup(key, files) {
188
+ const typeMap = {
189
+ config: { type: "chore", subject: "update configuration" },
190
+ types: { type: "feat", subject: "update type definitions" },
191
+ tests: { type: "test", subject: "add/update tests" },
192
+ docs: { type: "docs", subject: "update documentation" },
193
+ styles: { type: "style", subject: "update styles" },
194
+ components: { type: "feat", subject: "update components" },
195
+ api: { type: "feat", subject: "update API endpoints" },
196
+ utils: { type: "feat", subject: "update utility functions" },
197
+ };
198
+ const suggestion = typeMap[key] || {
199
+ type: "feat",
200
+ subject: "update files",
201
+ };
202
+ // Infer scope from files
203
+ const scope = this.inferScopeFromFiles(files);
204
+ return {
205
+ type: suggestion.type,
206
+ scope,
207
+ subject: suggestion.subject,
208
+ };
209
+ }
210
+ inferScopeFromFiles(files) {
211
+ if (files.length === 0)
212
+ return undefined;
213
+ const dirs = files
214
+ .map((f) => f.split("/")[0])
215
+ .filter((d) => d && !d.startsWith("."));
216
+ if (dirs.length === 0)
217
+ return undefined;
218
+ const dirCount = dirs.reduce((acc, d) => {
219
+ acc[d] = (acc[d] || 0) + 1;
220
+ return acc;
221
+ }, {});
222
+ const mostCommon = Object.entries(dirCount).sort((a, b) => b[1] - a[1])[0];
223
+ return mostCommon[1] >= files.length * 0.6 ? mostCommon[0] : undefined;
224
+ }
225
+ /**
226
+ * Get human-readable reason for grouping
227
+ */
228
+ getGroupReason(key, files) {
229
+ const reasonMap = {
230
+ config: "Configuration changes",
231
+ types: "Type definition updates",
232
+ tests: "Test additions/updates",
233
+ docs: "Documentation updates",
234
+ styles: "Styling changes",
235
+ components: "Component updates",
236
+ api: "API changes",
237
+ utils: "Utility function updates",
238
+ };
239
+ return reasonMap[key] || `${files.length} related files`;
240
+ }
241
+ /**
242
+ * Sort groups in logical commit order
243
+ */
244
+ sortCommitGroups(groups) {
245
+ const order = [
246
+ "types",
247
+ "config",
248
+ "api",
249
+ "components",
250
+ "utils",
251
+ "styles",
252
+ "tests",
253
+ "docs",
254
+ ];
255
+ return groups.sort((a, b) => {
256
+ const aKey = this.getGroupKey(a);
257
+ const bKey = this.getGroupKey(b);
258
+ const aIndex = order.indexOf(aKey);
259
+ const bIndex = order.indexOf(bKey);
260
+ if (aIndex === -1 && bIndex === -1)
261
+ return 0;
262
+ if (aIndex === -1)
263
+ return 1;
264
+ if (bIndex === -1)
265
+ return -1;
266
+ return aIndex - bIndex;
267
+ });
268
+ }
269
+ getGroupKey(group) {
270
+ return group.reason.toLowerCase().split(" ")[0];
271
+ }
272
+ }
273
+ exports.MultiCommitAnalyzer = MultiCommitAnalyzer;
274
+ //# sourceMappingURL=multi-commit.js.map