Skip to content

Commit 40deec5

Browse files
authored
Merge pull request #224 from tak-bro/feature/update-error
Feature/update error
2 parents 83cbd4e + a52b935 commit 40deec5

25 files changed

+2021
-368
lines changed

README.md

Lines changed: 146 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -78,25 +78,24 @@ _aicommit2_ automatically generates commit messages using AI. It supports [Git](
7878
- **[Git Hook Integration](#git-hooks)**: Can be used as a prepare-commit-msg hook
7979
- **[Custom Prompt](#custom-prompt-template)**: Supports user-defined system prompt templates
8080

81-
## Supported providers
82-
83-
### Cloud AI Services
84-
85-
- [OpenAI](docs/providers/openai.md)
86-
- [Anthropic Claude](docs/providers/anthropic.md)
87-
- [Gemini](docs/providers/gemini.md)
88-
- [Mistral & Codestral](docs/providers/mistral.md)
89-
- [Cohere](docs/providers/cohere.md)
90-
- [Groq](docs/providers/groq.md)
91-
- [Perplexity](docs/providers/perplexity.md)
92-
- [DeepSeek](docs/providers/deepseek.md)
93-
- [GitHub Models](docs/providers/github-models.md)
94-
- [Amazon Bedrock](docs/providers/bedrock.md)
95-
- [OpenAI API Compatibility](docs/providers/compatible.md)
96-
97-
### Local AI Services
98-
99-
- [Ollama](docs/providers/ollama.md)
81+
## Supported Providers
82+
83+
| Provider | Default Model | Documentation |
84+
|----------|---------------|---------------|
85+
| OpenAI | `gpt-4o-mini` | [Guide](docs/providers/openai.md) |
86+
| Anthropic | `claude-sonnet-4-20250514` | [Guide](docs/providers/anthropic.md) |
87+
| Gemini | `gemini-3-flash-preview` | [Guide](docs/providers/gemini.md) |
88+
| Mistral | `mistral-small-latest` | [Guide](docs/providers/mistral.md) |
89+
| Codestral | `codestral-latest` | [Guide](docs/providers/mistral.md) |
90+
| Cohere | `command-a-03-2025` | [Guide](docs/providers/cohere.md) |
91+
| Groq | `llama-3.3-70b-versatile` | [Guide](docs/providers/groq.md) |
92+
| Perplexity | `sonar` | [Guide](docs/providers/perplexity.md) |
93+
| DeepSeek | `deepseek-chat` | [Guide](docs/providers/deepseek.md) |
94+
| GitHub Models | `gpt-4o-mini` | [Guide](docs/providers/github-models.md) |
95+
| Bedrock | `anthropic.claude-haiku-4-5-20251001-v1:0` | [Guide](docs/providers/bedrock.md) |
96+
| Ollama | *(user configured)* | [Guide](docs/providers/ollama.md) |
97+
98+
> 📘 For OpenAI-compatible APIs, see [Compatibility Guide](docs/providers/compatible.md)
10099
101100
## Setup
102101

@@ -362,48 +361,47 @@ aicommit2 --all # or -a
362361

363362
#### CLI Options
364363

364+
Run `aicommit2 --help` to see all available options grouped by category.
365+
366+
##### Message Options
367+
365368
- `--locale` or `-l`: Locale to use for the generated commit messages (default: **en**)
366-
- `--all` or `-a`: Automatically stage changes in tracked files for the commit (default: **false**)
367-
- `--type` or `-t`: Git commit message format (default: **conventional**). It supports [`conventional`](https://conventionalcommits.org/) and [`gitmoji`](https://gitmoji.dev/)
368-
- `--confirm` or `-y`: Skip confirmation when committing after message generation (default: **false**)
369-
- `--clipboard` or `-c`: Copy the selected message to the clipboard (default: **false**).
370-
- If you give this option, **_aicommit2_ will not commit**.
371-
- `--dry-run` or `-d`: Generate commit message without committing (default: **false**).
372-
- Outputs the generated message without executing a commit.
373-
- Useful for reviewing messages before manual commit (e.g., with GitHub Desktop).
374-
- Can be combined with `--clipboard` to copy the message for use in other tools.
375-
- `--edit` or `-e`: Open the AI-generated commit message in your default editor for modification (default: **false**)
376-
- Opens the message in the editor specified by `$VISUAL`, `$EDITOR`, or platform default
377-
- Works with both Git and Jujutsu repositories
378-
- Allows fine-tuning of AI-generated messages before committing
379369
- `--generate` or `-g`: Number of messages to generate (default: **1**)
380370
- **Warning**: This uses more tokens, meaning it costs more.
381-
- `--exclude` or `-x`: Files to exclude from AI analysis
371+
- `--type` or `-t`: Git commit message format (default: **conventional**). It supports [`conventional`](https://conventionalcommits.org/) and [`gitmoji`](https://gitmoji.dev/)
372+
- `--prompt` or `-p`: Custom prompt to fine-tune the AI generation
382373
- `--include-body` or `-i`: Force include commit body in all generated messages (default: **false**)
383-
- When enabled, all commit messages will include a detailed body section
384-
- Useful for providing more context in commit messages
385-
- `--auto-select` or `-s`: Automatically select the commit message when only one AI model is configured (default: **false**)
386-
- When enabled and only one AI provider is configured, the generated message is automatically selected
387-
- Also skips the confirmation prompt for a seamless experience
388-
- Has no effect when multiple AI providers are configured
389-
- `--disable-lowercase`: Disable automatic lowercase conversion of commit messages (default: **false**)
390-
- Preserves the original casing of commit types and descriptions
391-
- Useful when working with custom commit conventions that require specific casing
392-
- `--hook-mode`: Run as a Git hook, typically used with [`prepare-commit-msg` hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_committing_workflow_hooks) hook (default: **false**)
393-
- This mode is automatically enabled when running through the Git hook system
394-
- See [Git Hooks](#git-hooks) section for more details
395-
- `--pre-commit`: Run in [pre-commit](https://pre-commit.com/) framework mode (default: **false**)
396-
- This option is specifically for use with the pre-commit framework
397-
- See [Integration with pre-commit framework](#integration-with-pre-commit-framework) section for setup instructions
398-
- `--verbose` or `-v`: Enable verbose logging for enhanced debugging output (default: **false**)
399-
- When enabled, shows detailed log messages including readline errors and other diagnostic information
400-
- Useful for troubleshooting issues or understanding the tool's internal operations
401-
- Can also be set via config: `aicommit2 config set logLevel=verbose`
374+
375+
##### Behavior
376+
377+
- `--all` or `-a`: Automatically stage changes in tracked files for the commit (default: **false**)
378+
- `--confirm` or `-y`: Skip confirmation when committing after message generation (default: **false**)
379+
- `--auto-select` or `-s`: Automatically select when only one message is generated (default: **false**)
380+
- `--edit` or `-e`: Open the AI-generated commit message in your default editor (default: **false**)
381+
- `--clipboard` or `-c`: Copy the selected message to the clipboard (default: **false**)
382+
- If you give this option, **_aicommit2_ will not commit**.
383+
- `--dry-run` or `-d`: Generate commit message without committing (default: **false**)
384+
- Useful for reviewing messages before manual commit (e.g., with GitHub Desktop)
402385
- `--output` or `-o`: Output format for non-interactive mode (default: **none**)
403-
- Use `--output json` for JSON Lines format (one JSON object per line)
404-
- Outputs `{"subject":"...","body":"..."}` for each generated message
405-
- Designed for integration with tools like [LazyGit](#lazygit)
406-
- Skips TUI and exits after outputting messages
386+
- Use `--output json` for [LazyGit](#lazygit) integration
387+
388+
##### VCS Selection
389+
390+
- `--git`: Force use Git (overrides auto-detection)
391+
- `--yadm`: Force use YADM (overrides auto-detection)
392+
- `--jj`: Force use Jujutsu (overrides auto-detection)
393+
- `--jj-auto-new`: Run `jj new` after `jj describe` (default: **false**)
394+
395+
##### Hook Integration
396+
397+
- `--hook-mode`: Run as a Git hook with [`prepare-commit-msg`](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_committing_workflow_hooks) (default: **false**)
398+
- `--pre-commit`: Run in [pre-commit](https://pre-commit.com/) framework mode (default: **false**)
399+
400+
##### Formatting & Debug
401+
402+
- `--exclude` or `-x`: Files to exclude from AI analysis
403+
- `--disable-lowercase`: Preserve original casing of commit messages (default: **false**)
404+
- `--verbose` or `-v`: Enable verbose logging for debugging (default: **false**)
407405

408406
Examples:
409407

@@ -424,6 +422,38 @@ aicommit2 -d -c
424422
aicommit2 --verbose # or -v
425423
```
426424

425+
#### Commands
426+
427+
In addition to the main commit message generation, aicommit2 provides several utility commands:
428+
429+
| Command | Description |
430+
|---------|-------------|
431+
| `aicommit2 config` | Manage configuration (get, set, list, del) |
432+
| `aicommit2 doctor` | Check health status of AI providers |
433+
| `aicommit2 stats` | View usage statistics and performance metrics |
434+
| `aicommit2 hook` | Install/uninstall Git prepare-commit-msg hook |
435+
| `aicommit2 log` | Manage log files |
436+
| `aicommit2 github-login` | Login to GitHub for GitHub Models access |
437+
438+
```bash
439+
# Configuration management
440+
aicommit2 config set OPENAI.key=<your-key>
441+
aicommit2 config get OPENAI
442+
aicommit2 config list
443+
444+
# Health check
445+
aicommit2 doctor
446+
447+
# Statistics
448+
aicommit2 stats
449+
aicommit2 stats -d 7 # Last 7 days
450+
aicommit2 stats clear # Clear all stats
451+
452+
# Git hook
453+
aicommit2 hook install
454+
aicommit2 hook uninstall
455+
```
456+
427457
## Integrations
428458

429459
### LazyGit
@@ -600,6 +630,65 @@ aicommit2 hook uninstall
600630

601631
Or manually delete the `.git/hooks/prepare-commit-msg` file.
602632

633+
### Health Check
634+
635+
Use the `doctor` command to check the status of your configured AI providers:
636+
637+
```bash
638+
aicommit2 doctor
639+
```
640+
641+
Example output:
642+
643+
```
644+
🩺 AICommit2 Health Check
645+
646+
Providers:
647+
✅ OPENAI API key configured
648+
✅ OLLAMA Running (Host: http://localhost:11434)
649+
⏭️ ANTHROPIC Not configured
650+
⚠️ GEMINI API key configured
651+
652+
Summary: 2 healthy, 0 error, 1 warning, 1 skipped
653+
```
654+
655+
Status icons:
656+
- ✅ **Healthy**: Provider is properly configured
657+
- ⚠️ **Warning**: Provider has issues (e.g., Ollama not running)
658+
- ❌ **Error**: Provider configuration has errors
659+
- ⏭️ **Skipped**: Provider is not configured
660+
661+
### Statistics
662+
663+
Use the `stats` command to view AI request statistics and performance metrics:
664+
665+
```bash
666+
aicommit2 stats
667+
```
668+
669+
Example output:
670+
671+
```
672+
📊 AICommit2 Statistics
673+
Period: 2/10/2026 - 3/10/2026
674+
675+
Overview:
676+
Total requests: 126
677+
Success rate: 97.6%
678+
Avg response time: 2.1s
679+
680+
Provider Usage:
681+
OPENAI ████████████████████ 78 (62%) 2.2s 100%
682+
ANTHROPIC ██████████░░░░░░░░░░ 30 (24%) 2.5s 93%
683+
GEMINI ████░░░░░░░░░░░░░░░░ 18 (14%) 1.6s 100%
684+
```
685+
686+
Options:
687+
- `aicommit2 stats -d 7` - Show statistics for the last 7 days
688+
- `aicommit2 stats clear` - Clear all statistics
689+
690+
Statistics are stored locally at `~/.config/aicommit2/stats.json`. Use `aicommit2 stats clear` to reset.
691+
603692
## Configuration
604693

605694
aicommit2 supports configuration via command-line arguments, environment variables, and a configuration file. Settings are resolved in the following order of precedence:
@@ -744,7 +833,7 @@ aicommit2 config set \
744833
maxTokens=1024 \
745834
temperature=0.7 \
746835
OPENAI.key="sk-..." OPENAI.model="gpt-4o-mini" OPENAI.temperature=0.5 \
747-
ANTHROPIC.key="sk-..." ANTHROPIC.model="claude-3-5-haiku-20241022" ANTHROPIC.maxTokens=2000 \
836+
ANTHROPIC.key="sk-..." ANTHROPIC.model="claude-sonnet-4-20250514" ANTHROPIC.maxTokens=2000 \
748837
MISTRAL.key="your-key" MISTRAL.model="mistral-small-latest" \
749838
OLLAMA.model="llama3.2" OLLAMA.numCtx=4096 OLLAMA.watchMode=true
750839
```

src/cli.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import { cli } from 'cleye';
33
import pkg from '../package.json';
44
import aicommit2 from './commands/aicommit2.js';
55
import configCommand from './commands/config.js';
6+
import { doctorCommand } from './commands/doctor.js';
67
import githubLoginCommand from './commands/github-login.js';
78
import hookCommand, { isCalledFromGitHook } from './commands/hook.js';
89
import logCommand from './commands/log.js';
910
import preCommitHook from './commands/pre-commit-hook.js';
1011
import prepareCommitMessageHook from './commands/prepare-commit-msg-hook.js';
12+
import { statsCommand } from './commands/stats.js';
1113
import watchGit from './commands/watch-git.js';
1214
import { RawConfig, getConfig } from './utils/config.js';
15+
import { renderGroupedHelp } from './utils/help-renderer.js';
1316
import { initializeLogger, logger } from './utils/logger.js';
1417

1518
const rawArgv = process.argv.slice(2);
@@ -144,10 +147,11 @@ cli(
144147
},
145148
},
146149

147-
commands: [configCommand, githubLoginCommand, hookCommand, logCommand],
150+
commands: [configCommand, doctorCommand, githubLoginCommand, hookCommand, logCommand, statsCommand],
148151

149152
help: {
150153
description,
154+
render: renderGroupedHelp,
151155
},
152156

153157
ignoreArgv: type => type === 'unknown-flag' || type === 'argument',

src/commands/aicommit2.ts

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import {
1818
commitMsgLoader,
1919
emptyCodeReview,
2020
} from '../managers/reactive-prompt.manager.js';
21-
import { ModelName, RawConfig, getConfig } from '../utils/config.js';
21+
import { ModelName, RawConfig, applyDisableLowerCaseToConfig, applyIncludeBodyToConfig, getConfig } from '../utils/config.js';
22+
import { ErrorCode, ErrorMessages } from '../utils/error-messages.js';
2223
import { KnownError, handleCliError } from '../utils/error.js';
2324
import { validateSystemPrompt } from '../utils/prompt.js';
2425
import { CommitOptions, assertGitRepo, getBranchName, getStagedDiff, getVCSName, commitChanges as vcsCommitChanges } from '../utils/vcs.js';
@@ -90,19 +91,11 @@ export default async (
9091

9192
const shouldIncludeBody = includeBody === true || config.includeBody === true;
9293
if (shouldIncludeBody) {
93-
Object.keys(config).forEach(key => {
94-
if (typeof config[key] === 'object' && config[key] !== null && 'includeBody' in config[key]) {
95-
(config[key] as any).includeBody = true;
96-
}
97-
});
94+
applyIncludeBodyToConfig(config);
9895
}
9996

10097
if (disableLowerCase) {
101-
Object.keys(config).forEach(key => {
102-
if (typeof config[key] === 'object' && config[key] !== null && 'disableLowerCase' in config[key]) {
103-
(config[key] as any).disableLowerCase = true;
104-
}
105-
});
98+
applyDisableLowerCaseToConfig(config);
10699
}
107100

108101
await validateSystemPrompt(config);
@@ -118,22 +111,9 @@ export default async (
118111

119112
if (!staged) {
120113
const vcsName = await getVCSName();
121-
let errorMessage = 'No staged changes found.';
122-
123-
if (vcsName === 'yadm') {
124-
errorMessage += '\n\nStage your changes with: yadm add <file>';
125-
errorMessage += '\nOr stage tracked file modifications: aicommit2 --all';
126-
errorMessage += '\n\nNote: The --all flag only stages already-tracked files (YADM best practice).';
127-
errorMessage += '\nTo track new dotfiles, explicitly add them first: yadm add <file>';
128-
} else if (vcsName === 'git') {
129-
errorMessage += '\n\nStage your changes with: git add <file>';
130-
errorMessage += '\nOr automatically stage all changes: aicommit2 --all';
131-
} else if (vcsName === 'jujutsu') {
132-
errorMessage += '\n\nJujutsu automatically tracks all changes in the working copy.';
133-
errorMessage += '\nMake some changes to your files and try again.';
134-
}
135-
136-
throw new KnownError(errorMessage);
114+
throw new KnownError(ErrorMessages.noStagedChanges(vcsName), {
115+
code: ErrorCode.NO_STAGED_CHANGES,
116+
});
137117
}
138118

139119
if (!isJsonMode) {
@@ -142,7 +122,9 @@ export default async (
142122

143123
const availableAIs = getAvailableAIs(config, 'commit');
144124
if (availableAIs.length === 0) {
145-
throw new KnownError('Please set at least one API key via the `aicommit2 config set` command');
125+
throw new KnownError(ErrorMessages.noApiKeysConfigured(), {
126+
code: ErrorCode.MISSING_API_KEY,
127+
});
146128
}
147129

148130
const branchName = await getBranchName();
@@ -170,7 +152,9 @@ export default async (
170152
selectedCommitMessage = await openEditor(selectedCommitMessage);
171153

172154
if (!selectedCommitMessage.trim()) {
173-
throw new KnownError('Commit message cannot be empty');
155+
throw new KnownError(ErrorMessages.emptyCommitMessage(), {
156+
code: ErrorCode.EMPTY_COMMIT_MESSAGE,
157+
});
174158
}
175159

176160
consoleManager.printSuccess('Commit message edited successfully!');

0 commit comments

Comments
 (0)