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,99 @@
1
+ /**
2
+ * Base error class for Commit CLI
3
+ * Provides consistent error structure with user-friendly messages and suggestions
4
+ */
5
+ class CommitCLIError extends Error {
6
+ suggestion;
7
+ constructor(message, suggestion = null) {
8
+ super(message);
9
+ this.name = this.constructor.name;
10
+ this.suggestion = suggestion;
11
+ Error.captureStackTrace(this, this.constructor);
12
+ }
13
+ }
14
+ /**
15
+ * Git repository related errors
16
+ * Thrown when Git operations fail or repository is invalid
17
+ */
18
+ export class GitRepositoryError extends CommitCLIError {
19
+ constructor(message, suggestion = 'Ensure you are in a valid Git repository or provide a correct path.') {
20
+ super(message, suggestion);
21
+ }
22
+ static noRepositoryFound(path) {
23
+ return new GitRepositoryError(`No Git repository found at: ${path}`, 'Initialize a Git repository with "git init" or provide a valid repository path.');
24
+ }
25
+ static noCommitsFound() {
26
+ return new GitRepositoryError('Repository has no commits yet', 'Create an initial commit with "git add . && git commit -m \'Initial commit\'"');
27
+ }
28
+ static noChanges() {
29
+ return new GitRepositoryError('No changes to commit', 'Make some changes to your files or check "git status" to see the current state.');
30
+ }
31
+ static commitFailed(gitError) {
32
+ return new GitRepositoryError(`Git commit failed: ${gitError}`, 'Check the error message above and resolve any Git issues.');
33
+ }
34
+ static pathNotAccessible(path) {
35
+ return new GitRepositoryError(`Path not accessible: ${path}`, 'Ensure the path exists and you have permission to access it.');
36
+ }
37
+ }
38
+ /**
39
+ * Configuration related errors
40
+ * Thrown when config file operations fail or configuration is invalid
41
+ */
42
+ export class ConfigurationError extends CommitCLIError {
43
+ constructor(message, suggestion = 'Try reconfiguring with the --reconfigure flag.') {
44
+ super(message, suggestion);
45
+ }
46
+ static noApiKey() {
47
+ return new ConfigurationError('No API key configured', 'Run the CLI to set up your Gemini API key, or use --reconfigure to update it.');
48
+ }
49
+ static invalidApiKey() {
50
+ return new ConfigurationError('Invalid API key format', 'Ensure your Gemini API key is correct. Get one at https://makersuite.google.com/app/apikey');
51
+ }
52
+ static configFileCorrupted() {
53
+ return new ConfigurationError('Configuration file is corrupted', 'Delete ~/.commic/config.json and run the CLI again to reconfigure.');
54
+ }
55
+ static configSaveFailed(error) {
56
+ return new ConfigurationError(`Failed to save configuration: ${error.message}`, 'Check file system permissions for ~/.commic/ directory.');
57
+ }
58
+ }
59
+ /**
60
+ * Gemini API related errors
61
+ * Thrown when API requests fail or return invalid responses
62
+ */
63
+ export class APIError extends CommitCLIError {
64
+ constructor(message, suggestion = 'Check your internet connection and try again.') {
65
+ super(message, suggestion);
66
+ }
67
+ static requestFailed(error) {
68
+ return new APIError(`Gemini API request failed: ${error.message}`, 'Verify your API key is valid and you have internet connectivity.');
69
+ }
70
+ static rateLimitExceeded() {
71
+ return new APIError('API rate limit exceeded', 'Wait a few moments before trying again, or check your API quota at https://makersuite.google.com/');
72
+ }
73
+ static invalidResponse() {
74
+ return new APIError('Received invalid response from Gemini API', 'Try again. If the problem persists, the API might be experiencing issues.');
75
+ }
76
+ static authenticationFailed() {
77
+ return new APIError('API authentication failed', 'Your API key may be invalid or expired. Use --reconfigure to update it.');
78
+ }
79
+ static timeout() {
80
+ return new APIError('API request timed out', 'Check your internet connection and try again.');
81
+ }
82
+ }
83
+ /**
84
+ * Commit message validation errors
85
+ * Thrown when generated messages don't meet Conventional Commits specification
86
+ */
87
+ export class ValidationError extends CommitCLIError {
88
+ constructor(message, suggestion = 'This is likely an internal error. Please try again.') {
89
+ super(message, suggestion);
90
+ }
91
+ static invalidConventionalCommit(errors) {
92
+ const errorList = errors.join(', ');
93
+ return new ValidationError(`Generated commit message doesn't meet Conventional Commits spec: ${errorList}`, 'Try generating new suggestions. If this persists, report it as a bug.');
94
+ }
95
+ static noValidSuggestions() {
96
+ return new ValidationError('Could not generate valid commit message suggestions', 'Try again with different changes, or check if your diff is too large.');
97
+ }
98
+ }
99
+ //# sourceMappingURL=CustomErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomErrors.js","sourceRoot":"","sources":["../../src/errors/CustomErrors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import type { GitDiff, GitRepository } from '../types/index.js';
2
+ /**
3
+ * Handles all Git operations including repository discovery, diff retrieval, and commits
4
+ */
5
+ export declare class GitService {
6
+ /**
7
+ * Find Git repository by walking up the directory tree
8
+ * @param startPath Starting path to search from
9
+ * @returns GitRepository with path and root information
10
+ * @throws GitRepositoryError if no repository found or path not accessible
11
+ */
12
+ findRepository(startPath: string): Promise<GitRepository>;
13
+ /**
14
+ * Normalize path by removing trailing slashes and resolving relative paths
15
+ * @param path Path to normalize
16
+ * @returns Normalized path
17
+ */
18
+ private normalizePath;
19
+ /**
20
+ * Check if repository has any commits
21
+ * @param repoPath Path to repository root
22
+ * @returns true if repository has commits, false if empty
23
+ * @throws GitRepositoryError if check fails
24
+ */
25
+ hasCommits(repoPath: string): Promise<boolean>;
26
+ /**
27
+ * Get diff between HEAD and current working state
28
+ * @param repoPath Path to repository root
29
+ * @returns GitDiff with staged, unstaged changes and hasChanges flag
30
+ * @throws GitRepositoryError if diff retrieval fails
31
+ */
32
+ getDiff(repoPath: string): Promise<GitDiff>;
33
+ /**
34
+ * Stage all changes in the repository
35
+ * @param repoPath Path to repository root
36
+ * @throws GitRepositoryError if staging fails
37
+ */
38
+ stageAll(repoPath: string): Promise<void>;
39
+ /**
40
+ * Execute git commit with the provided message
41
+ * @param repoPath Path to repository root
42
+ * @param message Commit message
43
+ * @returns Commit hash
44
+ * @throws GitRepositoryError if commit fails
45
+ */
46
+ commit(repoPath: string, message: string): Promise<string>;
47
+ /**
48
+ * Get current branch name
49
+ * @param repoPath Path to repository root
50
+ * @returns Current branch name
51
+ */
52
+ getCurrentBranch(repoPath: string): Promise<string>;
53
+ /**
54
+ * Get repository name from path
55
+ * @param repoPath Path to repository root
56
+ * @returns Repository name (last directory in path)
57
+ */
58
+ getRepositoryName(repoPath: string): string;
59
+ /**
60
+ * Get diff statistics (files changed, insertions, deletions)
61
+ * @param repoPath Path to repository root
62
+ * @returns Statistics object
63
+ */
64
+ getDiffStats(repoPath: string): Promise<{
65
+ filesChanged: number;
66
+ insertions: number;
67
+ deletions: number;
68
+ }>;
69
+ /**
70
+ * Get remote repository URL
71
+ * @param repoPath Path to repository root
72
+ * @param remoteName Remote name (default: 'origin')
73
+ * @returns Remote URL or null if no remote configured
74
+ */
75
+ getRemoteUrl(repoPath: string, remoteName?: string): Promise<string | null>;
76
+ }
77
+ //# sourceMappingURL=GitService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitService.d.ts","sourceRoot":"","sources":["../../src/git/GitService.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;GAEG;AACH,qBAAa,UAAU;IACrB;;;;;OAKG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAoD/D;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAYrB;;;;;OAKG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWpD;;;;;OAKG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBjD;;;;OAIG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/C;;;;;;OAMG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAchE;;;;OAIG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzD;;;;OAIG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK3C;;;;OAIG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAC5C,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAmBF;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAE,MAAiB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAe5F"}
@@ -0,0 +1,219 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { simpleGit } from 'simple-git';
4
+ import { GitRepositoryError } from '../errors/CustomErrors.js';
5
+ /**
6
+ * Handles all Git operations including repository discovery, diff retrieval, and commits
7
+ */
8
+ export class GitService {
9
+ /**
10
+ * Find Git repository by walking up the directory tree
11
+ * @param startPath Starting path to search from
12
+ * @returns GitRepository with path and root information
13
+ * @throws GitRepositoryError if no repository found or path not accessible
14
+ */
15
+ async findRepository(startPath) {
16
+ try {
17
+ // Normalize and resolve the path
18
+ const normalizedPath = this.normalizePath(startPath);
19
+ const resolvedPath = resolve(normalizedPath);
20
+ // Check if path exists and is accessible
21
+ try {
22
+ await fs.access(resolvedPath);
23
+ }
24
+ catch {
25
+ throw GitRepositoryError.pathNotAccessible(resolvedPath);
26
+ }
27
+ // Walk up directory tree looking for .git folder
28
+ let currentPath = resolvedPath;
29
+ const root = '/';
30
+ while (currentPath !== root) {
31
+ const gitPath = join(currentPath, '.git');
32
+ try {
33
+ const stats = await fs.stat(gitPath);
34
+ if (stats.isDirectory()) {
35
+ // Found .git directory
36
+ return {
37
+ path: resolvedPath,
38
+ rootPath: currentPath,
39
+ };
40
+ }
41
+ }
42
+ catch {
43
+ // .git not found at this level, continue up
44
+ }
45
+ // Move up one directory
46
+ const parentPath = dirname(currentPath);
47
+ if (parentPath === currentPath) {
48
+ // Reached root without finding .git
49
+ break;
50
+ }
51
+ currentPath = parentPath;
52
+ }
53
+ // No .git directory found
54
+ throw GitRepositoryError.noRepositoryFound(resolvedPath);
55
+ }
56
+ catch (error) {
57
+ if (error instanceof GitRepositoryError) {
58
+ throw error;
59
+ }
60
+ throw GitRepositoryError.pathNotAccessible(startPath);
61
+ }
62
+ }
63
+ /**
64
+ * Normalize path by removing trailing slashes and resolving relative paths
65
+ * @param path Path to normalize
66
+ * @returns Normalized path
67
+ */
68
+ normalizePath(path) {
69
+ // Remove trailing slashes
70
+ let normalized = path.replace(/\/+$/, '');
71
+ // Handle empty string (current directory)
72
+ if (normalized === '') {
73
+ normalized = '.';
74
+ }
75
+ return normalized;
76
+ }
77
+ /**
78
+ * Check if repository has any commits
79
+ * @param repoPath Path to repository root
80
+ * @returns true if repository has commits, false if empty
81
+ * @throws GitRepositoryError if check fails
82
+ */
83
+ async hasCommits(repoPath) {
84
+ try {
85
+ const git = simpleGit(repoPath);
86
+ const log = await git.log({ maxCount: 1 });
87
+ return log.total > 0;
88
+ }
89
+ catch (_error) {
90
+ // If git log fails, repository likely has no commits
91
+ return false;
92
+ }
93
+ }
94
+ /**
95
+ * Get diff between HEAD and current working state
96
+ * @param repoPath Path to repository root
97
+ * @returns GitDiff with staged, unstaged changes and hasChanges flag
98
+ * @throws GitRepositoryError if diff retrieval fails
99
+ */
100
+ async getDiff(repoPath) {
101
+ try {
102
+ const git = simpleGit(repoPath);
103
+ // Get staged changes (diff --cached)
104
+ const staged = await git.diff(['--cached']);
105
+ // Get unstaged changes (diff)
106
+ const unstaged = await git.diff();
107
+ const hasChanges = staged.length > 0 || unstaged.length > 0;
108
+ return {
109
+ staged,
110
+ unstaged,
111
+ hasChanges,
112
+ };
113
+ }
114
+ catch (error) {
115
+ throw new GitRepositoryError(`Failed to retrieve Git diff: ${error.message}`, 'Ensure you are in a valid Git repository with proper permissions.');
116
+ }
117
+ }
118
+ /**
119
+ * Stage all changes in the repository
120
+ * @param repoPath Path to repository root
121
+ * @throws GitRepositoryError if staging fails
122
+ */
123
+ async stageAll(repoPath) {
124
+ try {
125
+ const git = simpleGit(repoPath);
126
+ await git.add('.');
127
+ }
128
+ catch (error) {
129
+ throw new GitRepositoryError(`Failed to stage changes: ${error.message}`, 'Check if you have permission to modify the repository.');
130
+ }
131
+ }
132
+ /**
133
+ * Execute git commit with the provided message
134
+ * @param repoPath Path to repository root
135
+ * @param message Commit message
136
+ * @returns Commit hash
137
+ * @throws GitRepositoryError if commit fails
138
+ */
139
+ async commit(repoPath, message) {
140
+ try {
141
+ const git = simpleGit(repoPath);
142
+ const result = await git.commit(message);
143
+ // Extract commit hash from result
144
+ const commitHash = result.commit || 'unknown';
145
+ return commitHash;
146
+ }
147
+ catch (error) {
148
+ throw GitRepositoryError.commitFailed(error.message);
149
+ }
150
+ }
151
+ /**
152
+ * Get current branch name
153
+ * @param repoPath Path to repository root
154
+ * @returns Current branch name
155
+ */
156
+ async getCurrentBranch(repoPath) {
157
+ try {
158
+ const git = simpleGit(repoPath);
159
+ const branch = await git.revparse(['--abbrev-ref', 'HEAD']);
160
+ return branch.trim();
161
+ }
162
+ catch (_error) {
163
+ return 'unknown';
164
+ }
165
+ }
166
+ /**
167
+ * Get repository name from path
168
+ * @param repoPath Path to repository root
169
+ * @returns Repository name (last directory in path)
170
+ */
171
+ getRepositoryName(repoPath) {
172
+ const parts = repoPath.split('/').filter((p) => p.length > 0);
173
+ return parts[parts.length - 1] || 'unknown';
174
+ }
175
+ /**
176
+ * Get diff statistics (files changed, insertions, deletions)
177
+ * @param repoPath Path to repository root
178
+ * @returns Statistics object
179
+ */
180
+ async getDiffStats(repoPath) {
181
+ try {
182
+ const git = simpleGit(repoPath);
183
+ const diffSummary = await git.diffSummary();
184
+ return {
185
+ filesChanged: diffSummary.files.length,
186
+ insertions: diffSummary.insertions,
187
+ deletions: diffSummary.deletions,
188
+ };
189
+ }
190
+ catch (_error) {
191
+ return {
192
+ filesChanged: 0,
193
+ insertions: 0,
194
+ deletions: 0,
195
+ };
196
+ }
197
+ }
198
+ /**
199
+ * Get remote repository URL
200
+ * @param repoPath Path to repository root
201
+ * @param remoteName Remote name (default: 'origin')
202
+ * @returns Remote URL or null if no remote configured
203
+ */
204
+ async getRemoteUrl(repoPath, remoteName = 'origin') {
205
+ try {
206
+ const git = simpleGit(repoPath);
207
+ const remotes = await git.getRemotes(true);
208
+ const remote = remotes.find((r) => r.name === remoteName);
209
+ if (remote?.refs?.fetch) {
210
+ return remote.refs.fetch;
211
+ }
212
+ return null;
213
+ }
214
+ catch (_error) {
215
+ return null;
216
+ }
217
+ }
218
+ }
219
+ //# sourceMappingURL=GitService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitService.js","sourceRoot":"","sources":["../../src/git/GitService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { ConfigManager } from './config/ConfigManager.js';
4
+ import { GitService } from './git/GitService.js';
5
+ import { MainOrchestrator } from './orchestrator/MainOrchestrator.js';
6
+ import { UIManager } from './ui/UIManager.js';
7
+ /**
8
+ * Main entry point for the Commit CLI
9
+ */
10
+ async function main() {
11
+ const program = new Command();
12
+ program
13
+ .name('commic')
14
+ .description('AI-powered Git commit message generator with Conventional Commits support')
15
+ .version('1.0.0')
16
+ .argument('[path]', 'Path to Git repository', '.')
17
+ .option('-r, --reconfigure', 'Reconfigure API key and model settings')
18
+ .action(async (path, options) => {
19
+ try {
20
+ // Create service instances
21
+ const configManager = new ConfigManager();
22
+ const gitService = new GitService();
23
+ const uiManager = new UIManager();
24
+ // Create orchestrator
25
+ const orchestrator = new MainOrchestrator(configManager, gitService, uiManager);
26
+ // Build CLI options
27
+ const cliOptions = {
28
+ path,
29
+ reconfigure: options.reconfigure,
30
+ };
31
+ // Execute workflow
32
+ await orchestrator.execute(cliOptions);
33
+ }
34
+ catch (_error) {
35
+ // Top-level error handler
36
+ // Orchestrator already handles and displays errors
37
+ // This is just to ensure we exit with error code
38
+ process.exit(1);
39
+ }
40
+ });
41
+ await program.parseAsync(process.argv);
42
+ }
43
+ // Run the CLI
44
+ main().catch((error) => {
45
+ console.error('Fatal error:', error.message);
46
+ process.exit(1);
47
+ });
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CAAC,2EAA2E,CAAC;SACxF,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,EAAE,GAAG,CAAC;SACjD,MAAM,CAAC,mBAAmB,EAAE,wCAAwC,CAAC;SACrE,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,OAAkC,EAAE,EAAE;QACjE,IAAI,CAAC;YACH,2BAA2B;YAC3B,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;YAC1C,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;YACpC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;YAElC,sBAAsB;YACtB,MAAM,YAAY,GAAG,IAAI,gBAAgB,CAAC,aAAa,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;YAEhF,oBAAoB;YACpB,MAAM,UAAU,GAAe;gBAC7B,IAAI;gBACJ,WAAW,EAAE,OAAO,CAAC,WAAW;aACjC,CAAC;YAEF,mBAAmB;YACnB,MAAM,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,0BAA0B;YAC1B,mDAAmD;YACnD,iDAAiD;YACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,cAAc;AACd,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,63 @@
1
+ import type { ConfigManager } from '../config/ConfigManager.js';
2
+ import type { GitService } from '../git/GitService.js';
3
+ import type { CLIOptions } from '../types/index.js';
4
+ import type { UIManager } from '../ui/UIManager.js';
5
+ /**
6
+ * Orchestrates the complete workflow of the Commit CLI
7
+ * Coordinates between configuration, Git operations, AI generation, and user interaction
8
+ */
9
+ export declare class MainOrchestrator {
10
+ private readonly configManager;
11
+ private readonly gitService;
12
+ private readonly uiManager;
13
+ constructor(configManager: ConfigManager, gitService: GitService, uiManager: UIManager);
14
+ /**
15
+ * Execute the complete commit workflow
16
+ * @param options CLI options from command line
17
+ */
18
+ execute(options: CLIOptions): Promise<void>;
19
+ /**
20
+ * Handle configuration loading or prompting
21
+ * @param forceReconfigure Force reconfiguration even if config exists
22
+ * @returns Configuration object
23
+ */
24
+ private handleConfiguration;
25
+ /**
26
+ * Find and validate Git repository
27
+ * @param path Path to search for repository
28
+ * @returns Repository information
29
+ */
30
+ private findAndValidateRepository;
31
+ /**
32
+ * Get Git diff and validate changes exist
33
+ * @param repoPath Repository root path
34
+ * @returns Git diff
35
+ */
36
+ private getGitDiff;
37
+ /**
38
+ * Generate commit message suggestions using AI
39
+ * @param config Configuration with API key
40
+ * @param diff Git diff
41
+ * @returns Array of suggestions
42
+ */
43
+ private generateSuggestions;
44
+ /**
45
+ * Stage changes if there are unstaged changes
46
+ * @param repoPath Repository root path
47
+ * @param diff Git diff
48
+ */
49
+ private stageChangesIfNeeded;
50
+ /**
51
+ * Execute Git commit
52
+ * @param repoPath Repository root path
53
+ * @param message Commit message
54
+ * @returns Commit hash
55
+ */
56
+ private executeCommit;
57
+ /**
58
+ * Handle errors with user-friendly messages
59
+ * @param error Error to handle
60
+ */
61
+ private handleError;
62
+ }
63
+ //# sourceMappingURL=MainOrchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MainOrchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrator/MainOrchestrator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAU,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;GAGG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS;IAGvC;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDjD;;;;OAIG;YACW,mBAAmB;IAgCjC;;;;OAIG;YACW,yBAAyB;IAgCvC;;;;OAIG;YACW,UAAU;IA0BxB;;;;;OAKG;YACW,mBAAmB;IAqBjC;;;;OAIG;YACW,oBAAoB;IAelC;;;;;OAKG;YACW,aAAa;IAe3B;;;OAGG;IACH,OAAO,CAAC,WAAW;CAWpB"}