git-cai-cli 0.8.1__tar.gz → 0.9.0__tar.gz

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 (86) hide show
  1. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.pylintrc +2 -2
  2. {git_cai_cli-0.8.1/src/git_cai_cli.egg-info → git_cai_cli-0.9.0}/PKG-INFO +12 -2
  3. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/README.md +11 -1
  4. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/docs/git-cai.txt +50 -1
  5. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/docs/man/git-cai.1 +76 -3
  6. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/pyproject.toml +3 -0
  7. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/_version.py +3 -3
  8. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/cli/cli.py +29 -1
  9. git_cai_cli-0.9.0/src/git_cai_cli/cli/helptext.py +45 -0
  10. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/cli/modes.py +17 -0
  11. git_cai_cli-0.9.0/src/git_cai_cli/core/completion.py +186 -0
  12. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/config.py +80 -7
  13. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/llm.py +118 -29
  14. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/options.py +17 -8
  15. git_cai_cli-0.9.0/src/git_cai_cli/core/prompts_fallback.py +26 -0
  16. git_cai_cli-0.9.0/src/git_cai_cli/core/spinner.py +53 -0
  17. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/squash.py +36 -4
  18. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/validate.py +2 -0
  19. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/main.py +32 -8
  20. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0/src/git_cai_cli.egg-info}/PKG-INFO +12 -2
  21. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli.egg-info/SOURCES.txt +6 -0
  22. git_cai_cli-0.9.0/tests/unit/test_cli.py +180 -0
  23. git_cai_cli-0.9.0/tests/unit/test_completion.py +229 -0
  24. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_config.py +67 -0
  25. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_llm.py +209 -0
  26. git_cai_cli-0.9.0/tests/unit/test_main.py +113 -0
  27. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_modes.py +123 -0
  28. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_prompt_loading.py +19 -17
  29. git_cai_cli-0.9.0/tests/unit/test_spinner.py +91 -0
  30. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_validate.py +79 -0
  31. git_cai_cli-0.8.1/src/git_cai_cli/cli/helptext.py +0 -41
  32. git_cai_cli-0.8.1/tests/unit/test_cli.py +0 -54
  33. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.caiignore +0 -0
  34. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.gitattributes +0 -0
  35. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/cd/.SRCINFO +0 -0
  36. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/cd/PKGBUILD +0 -0
  37. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/ci/_version.py +0 -0
  38. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/ci/cai_config.ci.yml +0 -0
  39. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/ci/tokens.ci.yml +0 -0
  40. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/workflows/python-tests.yml +0 -0
  41. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/workflows/release.yml +0 -0
  42. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.github/workflows/release_aur.yml +0 -0
  43. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.gitignore +0 -0
  44. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.bandit.yml +0 -0
  45. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.checkov.yml +0 -0
  46. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.flake8 +0 -0
  47. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.ls-lint.yml +0 -0
  48. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.markdown-link-check.json +0 -0
  49. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.markdownlint.json +0 -0
  50. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.proselintrc +0 -0
  51. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/.yamllint.yml +0 -0
  52. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/check_git_branch_name.sh +0 -0
  53. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/lychee.toml +0 -0
  54. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.linters/pyrightconfig.json +0 -0
  55. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.markdownlintignore +0 -0
  56. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.mega-linter.yml +0 -0
  57. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.semgrepignore +0 -0
  58. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/.trivyignore +0 -0
  59. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/LICENSE +0 -0
  60. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/Makefile +0 -0
  61. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/setup.cfg +0 -0
  62. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/__init__.py +0 -0
  63. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/cli/__init__.py +0 -0
  64. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/__init__.py +0 -0
  65. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/editors.py +0 -0
  66. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/gitutils.py +0 -0
  67. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/core/languages.py +0 -0
  68. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/defaults/__init__.py +0 -0
  69. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/defaults/commit_prompt.md +0 -0
  70. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli/defaults/squash_prompt.md +0 -0
  71. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli.egg-info/dependency_links.txt +0 -0
  72. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli.egg-info/entry_points.txt +0 -0
  73. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli.egg-info/requires.txt +0 -0
  74. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/src/git_cai_cli.egg-info/top_level.txt +0 -0
  75. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/conftest.py +0 -0
  76. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/integration/test_cli_integration.py +0 -0
  77. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/integration/test_config_integration.py +0 -0
  78. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/integration/test_gitutils_integration.py +0 -0
  79. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/integration/test_modes_integration.py +0 -0
  80. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/integration/test_options_integration.py +0 -0
  81. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/integration/test_squash_integration.py +0 -0
  82. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_gitutils.py +0 -0
  83. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_helptext.py +0 -0
  84. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_options.py +0 -0
  85. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/tests/unit/test_squash.py +0 -0
  86. {git_cai_cli-0.8.1 → git_cai_cli-0.9.0}/uv.lock +0 -0
@@ -68,8 +68,8 @@ check-protected-access-in-special-methods=no
68
68
  [DESIGN]
69
69
  max-args=15 # Max arguments per function
70
70
  max-attributes=7 # Max attributes per class
71
- max-branches=20 # Max branches per function
72
- max-locals=30 # Max locals per function
71
+ max-branches=30 # Max branches per function
72
+ max-locals=50 # Max locals per function
73
73
  max-returns=10 # Max return statements per function
74
74
  max-statements=100 # Max total statements per function
75
75
  max-public-methods=20 # Max public methods per class
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-cai-cli
3
- Version: 0.8.1
3
+ Version: 0.9.0
4
4
  Summary: Use LLM to create git commit messages
5
5
  Author-email: Thorsten Foltz <thorsten.foltz@live.com>
6
6
  License-Expression: MIT
@@ -75,9 +75,13 @@ Currently supported providers:
75
75
  - Generates meaningful, context-aware commit messages using an LLM
76
76
  - Seamless integration with Git
77
77
  - Supports multiple LLM providers and models
78
+ - Override provider and model per invocation (`-P`, `-m`)
78
79
  - Global configuration with per-repository overrides
79
80
  - Repository-specific language, style, and model selection
80
81
  - Optional commit squashing with automatic summary generation
82
+ - Token usage logging for API calls
83
+ - Generation time measurement (`-t`)
84
+ - Shell completion for bash, zsh, and fish (`-i`)
81
85
 
82
86
  ---
83
87
 
@@ -210,6 +214,8 @@ git cai -g
210
214
  - `load_tokens_from` – path to the file where API tokens are stored
211
215
  - `prompt_file` - path to the file where the prompt for the commit is stored
212
216
  - `squash_prompt_file` - path to the file where the prompt for the squash is stored
217
+ - `token_logging` – log token usage after each LLM call (default: `true` for new installs)
218
+ - `measure_time` – log generation time (default: `false`)
213
219
 
214
220
  ---
215
221
 
@@ -217,14 +223,18 @@ git cai -g
217
223
 
218
224
  In addition to `git cai`, the following options are available:
219
225
 
220
- - `-h` `--help` – show help and available commands
221
226
  - `-a`, `--all` – stage all tracked modified and deleted files
222
227
  - `-c`, `--crazy` – Trust the LLM and commit without checking
223
228
  - `-d`, `--debug` – enable debug logging
224
229
  - `-g`, `--generate-config` – generate the default `cai_config.yml` in the current directory
230
+ - `-h`, `--help` – show help and available commands
231
+ - `-i`, `--install-completion` – install shell completion for bash, zsh, or fish
225
232
  - `-l`, `--list` – list available languages, styles, and supported editors
233
+ - `-m`, `--model` – override the model for this invocation (requires `-P`)
226
234
  - `-p`, `--generate-prompts` – generate default `commit_prompt.md` and `squash_prompt.md` in the current directory (for customization)
235
+ - `-P`, `--provider` – override the LLM provider for this invocation
227
236
  - `-s`, `--squash` – squash commits on the current branch and summarize them
237
+ - `-t`, `--time` – measure and log commit message generation time
228
238
  - `-u`, `--update` – check for updates
229
239
  - `-v`, `--version` – show the installed version
230
240
 
@@ -46,9 +46,13 @@ Currently supported providers:
46
46
  - Generates meaningful, context-aware commit messages using an LLM
47
47
  - Seamless integration with Git
48
48
  - Supports multiple LLM providers and models
49
+ - Override provider and model per invocation (`-P`, `-m`)
49
50
  - Global configuration with per-repository overrides
50
51
  - Repository-specific language, style, and model selection
51
52
  - Optional commit squashing with automatic summary generation
53
+ - Token usage logging for API calls
54
+ - Generation time measurement (`-t`)
55
+ - Shell completion for bash, zsh, and fish (`-i`)
52
56
 
53
57
  ---
54
58
 
@@ -181,6 +185,8 @@ git cai -g
181
185
  - `load_tokens_from` – path to the file where API tokens are stored
182
186
  - `prompt_file` - path to the file where the prompt for the commit is stored
183
187
  - `squash_prompt_file` - path to the file where the prompt for the squash is stored
188
+ - `token_logging` – log token usage after each LLM call (default: `true` for new installs)
189
+ - `measure_time` – log generation time (default: `false`)
184
190
 
185
191
  ---
186
192
 
@@ -188,14 +194,18 @@ git cai -g
188
194
 
189
195
  In addition to `git cai`, the following options are available:
190
196
 
191
- - `-h` `--help` – show help and available commands
192
197
  - `-a`, `--all` – stage all tracked modified and deleted files
193
198
  - `-c`, `--crazy` – Trust the LLM and commit without checking
194
199
  - `-d`, `--debug` – enable debug logging
195
200
  - `-g`, `--generate-config` – generate the default `cai_config.yml` in the current directory
201
+ - `-h`, `--help` – show help and available commands
202
+ - `-i`, `--install-completion` – install shell completion for bash, zsh, or fish
196
203
  - `-l`, `--list` – list available languages, styles, and supported editors
204
+ - `-m`, `--model` – override the model for this invocation (requires `-P`)
197
205
  - `-p`, `--generate-prompts` – generate default `commit_prompt.md` and `squash_prompt.md` in the current directory (for customization)
206
+ - `-P`, `--provider` – override the LLM provider for this invocation
198
207
  - `-s`, `--squash` – squash commits on the current branch and summarize them
208
+ - `-t`, `--time` – measure and log commit message generation time
199
209
  - `-u`, `--update` – check for updates
200
210
  - `-v`, `--version` – show the installed version
201
211
 
@@ -11,8 +11,11 @@ SYNOPSIS
11
11
  --------
12
12
  [verse]
13
13
  `git cai` [-a | --all] [-c | --crazy] [-d | --debug] [-g | --generate-config]
14
+ [-i | --install-completion]
14
15
  [-l [editor|language|style] | --list [editor|language|style]]
15
- [-p | --generate-prompts] [-s | --squash] [-u | --update] [-v | --version]
16
+ [-m MODEL | --model MODEL] [-p | --generate-prompts]
17
+ [-P PROVIDER | --provider PROVIDER]
18
+ [-s | --squash] [-t | --time] [-u | --update] [-v | --version]
16
19
 
17
20
 
18
21
  DESCRIPTION
@@ -73,16 +76,38 @@ Enable debug logging.
73
76
  -g, --generate-config::
74
77
  Generate default cai_config.yml in the current directory.
75
78
 
79
+ -i, --install-completion::
80
+ Install shell completion for `git cai`. Supports bash, zsh, and fish.
81
+ After installation, restart your terminal or source your shell configuration.
82
+ Completions include all flags and provider names for `--provider`.
83
+
76
84
  -l, --list::
77
85
  List information. Provide one of `editor`, `language`, or `style` as the next argument.
78
86
 
87
+ -m, --model MODEL::
88
+ Override the model for this invocation. Must be used together with `--provider`.
89
+ The model name is passed directly to the provider's API.
90
+ Example: `git cai -P openai -m gpt-4o`
91
+
79
92
  -p, --generate-prompts::
80
93
  Generate default commit_prompt.md and squash_prompt.md in the current directory.
81
94
  Use these as a starting point for custom prompts.
82
95
 
96
+ -P, --provider PROVIDER::
97
+ Override the LLM provider for this invocation. The model from the configuration
98
+ for that provider is used unless `--model` is also specified.
99
+ Available providers: `anthropic`, `deepseek`, `gemini`, `groq`,
100
+ `mistral`, `ollama`, `openai`, `xai`.
101
+ Example: `git cai -P anthropic`
102
+
83
103
  -s, --squash::
84
104
  Squash commits on the current branch and summarize them.
85
105
 
106
+ -t, --time::
107
+ Measure and log the time taken to generate the commit message.
108
+ Can also be permanently enabled via `measure_time: true` in
109
+ `cai_config.yml`.
110
+
86
111
  -u, --update::
87
112
  Check for updates.
88
113
 
@@ -193,6 +218,30 @@ git cai -l language
193
218
  git cai -l editor
194
219
  ----
195
220
 
221
+ Override the provider for a single invocation:
222
+
223
+ ----
224
+ git cai -P anthropic
225
+ ----
226
+
227
+ Override both provider and model:
228
+
229
+ ----
230
+ git cai -P openai -m gpt-4o
231
+ ----
232
+
233
+ Measure generation time:
234
+
235
+ ----
236
+ git cai -t
237
+ ----
238
+
239
+ Install shell completion:
240
+
241
+ ----
242
+ git cai -i
243
+ ----
244
+
196
245
  SEE ALSO
197
246
  --------
198
247
  git(1)
@@ -2,12 +2,12 @@
2
2
  .\" Title: git-cai
3
3
  .\" Author: Thorsten Foltz
4
4
  .\" Generator: Asciidoctor 2.0.26
5
- .\" Date: 2026-02-14
5
+ .\" Date: 2026-03-16
6
6
  .\" Manual: \ \&
7
7
  .\" Source: \ \&
8
8
  .\" Language: English
9
9
  .\"
10
- .TH "GIT\-CAI" "1" "2026-02-14" "\ \&" "\ \&"
10
+ .TH "GIT\-CAI" "1" "2026-03-16" "\ \&" "\ \&"
11
11
  .ie \n(.g .ds Aq \(aq
12
12
  .el .ds Aq '
13
13
  .ss \n[.ss] 0
@@ -33,8 +33,11 @@ git-cai \- AI\-powered commit message generator
33
33
  .sp
34
34
  .nf
35
35
  \f(CRgit cai\fP [\-a | \-\-all] [\-c | \-\-crazy] [\-d | \-\-debug] [\-g | \-\-generate\-config]
36
+ [\-i | \-\-install\-completion]
36
37
  [\-l [editor|language|style] | \-\-list [editor|language|style]]
37
- [\-p | \-\-generate\-prompts] [\-s | \-\-squash] [\-u | \-\-update] [\-v | \-\-version]
38
+ [\-m MODEL | \-\-model MODEL] [\-p | \-\-generate\-prompts]
39
+ [\-P PROVIDER | \-\-provider PROVIDER]
40
+ [\-s | \-\-squash] [\-t | \-\-time] [\-u | \-\-update] [\-v | \-\-version]
38
41
  .fi
39
42
  .br
40
43
  .SH "DESCRIPTION"
@@ -199,22 +202,52 @@ Enable debug logging.
199
202
  Generate default cai_config.yml in the current directory.
200
203
  .RE
201
204
  .sp
205
+ \-i, \-\-install\-completion
206
+ .RS 4
207
+ Install shell completion for \f(CRgit cai\fP. Supports bash, zsh, and fish.
208
+ After installation, restart your terminal or source your shell configuration.
209
+ Completions include all flags and provider names for \f(CR\-\-provider\fP.
210
+ .RE
211
+ .sp
202
212
  \-l, \-\-list
203
213
  .RS 4
204
214
  List information. Provide one of \f(CReditor\fP, \f(CRlanguage\fP, or \f(CRstyle\fP as the next argument.
205
215
  .RE
206
216
  .sp
217
+ \-m, \-\-model MODEL
218
+ .RS 4
219
+ Override the model for this invocation. Must be used together with \f(CR\-\-provider\fP.
220
+ The model name is passed directly to the provider\(cqs API.
221
+ Example: \f(CRgit cai \-P openai \-m gpt\-4o\fP
222
+ .RE
223
+ .sp
207
224
  \-p, \-\-generate\-prompts
208
225
  .RS 4
209
226
  Generate default commit_prompt.md and squash_prompt.md in the current directory.
210
227
  Use these as a starting point for custom prompts.
211
228
  .RE
212
229
  .sp
230
+ \-P, \-\-provider PROVIDER
231
+ .RS 4
232
+ Override the LLM provider for this invocation. The model from the configuration
233
+ for that provider is used unless \f(CR\-\-model\fP is also specified.
234
+ Available providers: \f(CRanthropic\fP, \f(CRdeepseek\fP, \f(CRgemini\fP, \f(CRgroq\fP,
235
+ \f(CRmistral\fP, \f(CRollama\fP, \f(CRopenai\fP, \f(CRxai\fP.
236
+ Example: \f(CRgit cai \-P anthropic\fP
237
+ .RE
238
+ .sp
213
239
  \-s, \-\-squash
214
240
  .RS 4
215
241
  Squash commits on the current branch and summarize them.
216
242
  .RE
217
243
  .sp
244
+ \-t, \-\-time
245
+ .RS 4
246
+ Measure and log the time taken to generate the commit message.
247
+ Can also be permanently enabled via \f(CRmeasure_time: true\fP in
248
+ \f(CRcai_config.yml\fP.
249
+ .RE
250
+ .sp
218
251
  \-u, \-\-update
219
252
  .RS 4
220
253
  Check for updates.
@@ -413,6 +446,46 @@ git cai \-l editor
413
446
  .fam
414
447
  .fi
415
448
  .if n .RE
449
+ .sp
450
+ Override the provider for a single invocation:
451
+ .sp
452
+ .if n .RS 4
453
+ .nf
454
+ .fam C
455
+ git cai \-P anthropic
456
+ .fam
457
+ .fi
458
+ .if n .RE
459
+ .sp
460
+ Override both provider and model:
461
+ .sp
462
+ .if n .RS 4
463
+ .nf
464
+ .fam C
465
+ git cai \-P openai \-m gpt\-4o
466
+ .fam
467
+ .fi
468
+ .if n .RE
469
+ .sp
470
+ Measure generation time:
471
+ .sp
472
+ .if n .RS 4
473
+ .nf
474
+ .fam C
475
+ git cai \-t
476
+ .fam
477
+ .fi
478
+ .if n .RE
479
+ .sp
480
+ Install shell completion:
481
+ .sp
482
+ .if n .RS 4
483
+ .nf
484
+ .fam C
485
+ git cai \-i
486
+ .fam
487
+ .fi
488
+ .if n .RE
416
489
  .SH "SEE ALSO"
417
490
  .sp
418
491
  git(1)
@@ -47,6 +47,9 @@ git_cai_cli = ["defaults/*.md"]
47
47
  [tool.setuptools.data-files]
48
48
  "share/man/man1" = ["docs/man/git-cai.1"]
49
49
 
50
+ [tool.pytest.ini_options]
51
+ testpaths = ["tests"]
52
+
50
53
  [tool.setuptools_scm]
51
54
  version_scheme = "guess-next-dev"
52
55
  local_scheme = "no-local-version"
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.8.1'
32
- __version_tuple__ = version_tuple = (0, 8, 1)
31
+ __version__ = version = '0.9.0'
32
+ __version_tuple__ = version_tuple = (0, 9, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g1830345d9'
34
+ __commit_id__ = commit_id = 'g836915852'
@@ -7,7 +7,7 @@ from git_cai_cli.cli.helptext import print_help_and_exit
7
7
  from git_cai_cli.cli.modes import resolve_mode, validate_options
8
8
  from git_cai_cli.main import run
9
9
 
10
- app = typer.Typer(add_completion=True, help=None, no_args_is_help=False)
10
+ app = typer.Typer(add_completion=False, help=None, no_args_is_help=False)
11
11
 
12
12
 
13
13
  @app.callback(invoke_without_command=True)
@@ -18,6 +18,13 @@ def callback(
18
18
  help_flag: bool = typer.Option(
19
19
  False, "-h", "--help", help="Show help", is_eager=True
20
20
  ),
21
+ install_completion: bool = typer.Option(
22
+ False,
23
+ "--install-completion",
24
+ "-i",
25
+ help="Install shell completion for git-cai",
26
+ is_eager=True,
27
+ ),
21
28
  crazy: bool = typer.Option(
22
29
  False, "-c", "--crazy", help="Commit immediately without opening editor"
23
30
  ),
@@ -49,6 +56,15 @@ def callback(
49
56
  False, "--squash", "-s", help="Squash commits on this branch"
50
57
  ),
51
58
  update: bool = typer.Option(False, "--update", "-u", help="Check for updates"),
59
+ provider: str = typer.Option(
60
+ None, "--provider", "-P", help="Override LLM provider for this invocation"
61
+ ),
62
+ model: str = typer.Option(
63
+ None, "--model", "-m", help="Override model (requires --provider)"
64
+ ),
65
+ time_flag: bool = typer.Option(
66
+ False, "--time", "-t", help="Measure and log generation time"
67
+ ),
52
68
  ):
53
69
  """
54
70
  CLI entry point for git-cai-cli.
@@ -62,6 +78,12 @@ def callback(
62
78
  typer.echo(f"cai version: {__version__}")
63
79
  raise typer.Exit()
64
80
 
81
+ if install_completion:
82
+ from git_cai_cli.core.completion import install_completion as do_install
83
+
84
+ do_install()
85
+ raise typer.Exit()
86
+
65
87
  mode = resolve_mode(list_flag=list_flag, squash=squash, update=update)
66
88
 
67
89
  validate_options(
@@ -70,6 +92,9 @@ def callback(
70
92
  enable_debug=enable_debug,
71
93
  help_flag=help_flag,
72
94
  version_flag=version,
95
+ provider_override=provider,
96
+ model_override=model,
97
+ time_flag=time_flag,
73
98
  )
74
99
 
75
100
  if generate_config:
@@ -108,6 +133,9 @@ def callback(
108
133
  list_arg=list_arg,
109
134
  stage_tracked=stage_tracked,
110
135
  crazy=crazy,
136
+ provider_override=provider,
137
+ model_override=model,
138
+ time_flag=time_flag,
111
139
  )
112
140
 
113
141
 
@@ -0,0 +1,45 @@
1
+ """
2
+ Help text for git-cai-cli.
3
+ """
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+
9
+ HOME = Path.home()
10
+
11
+ HELP_TEXT = f"""
12
+ Git CAI - AI-powered commit message generator
13
+
14
+ Usage:
15
+ git cai Generate commit message from staged changes
16
+
17
+ Flags:
18
+ -a, --all Stage all modified and deleted files that are already tracked by Git
19
+ -c, --crazy Commit immediately without opening editor (trust LLM output)
20
+ -d, --debug Enable debug logging
21
+ -g, --generate-config Generate default cai_config.yml in the current directory
22
+ -h, --help Show this help message or opens manual
23
+ -i, --install-completion Install shell completion for git-cai
24
+ -l, --list List information about available languages, styles, and editors
25
+ -m, --model NAME Override model for this invocation (requires --provider)
26
+ -p, --generate-prompts Generate default commit_prompt.md and squash_prompt.md
27
+ -P, --provider NAME Override LLM provider for this invocation
28
+ -s, --squash Squash commits on this branch and summarize them
29
+ -t, --time Measure and log commit message generation time
30
+ -u, --update Check for updates
31
+ -v, --version Show installed version
32
+
33
+ Configuration:
34
+ Tokens are loaded from {HOME}/.config/cai/tokens.yml
35
+ Reset to default config by deleting {HOME}/.config/cai/cai_config.yml
36
+ and executing 'git cai' again.
37
+ """
38
+
39
+
40
+ def print_help_and_exit() -> None:
41
+ """
42
+ Print help text and exit.
43
+ """
44
+ typer.echo(HELP_TEXT)
45
+ raise typer.Exit()
@@ -47,6 +47,9 @@ def validate_options(
47
47
  enable_debug: bool,
48
48
  help_flag: bool,
49
49
  version_flag: bool,
50
+ provider_override: str | None = None,
51
+ model_override: str | None = None,
52
+ time_flag: bool = False,
50
53
  ) -> None:
51
54
  """
52
55
  Validates the combination of command-line options provided by the user.
@@ -64,3 +67,17 @@ def validate_options(
64
67
  err=True,
65
68
  )
66
69
  raise typer.Exit(code=1)
70
+
71
+ if (provider_override or model_override) and mode in (Mode.LIST, Mode.UPDATE):
72
+ typer.echo(
73
+ "Error: --provider/--model cannot be used with --list or --update.",
74
+ err=True,
75
+ )
76
+ raise typer.Exit(code=1)
77
+
78
+ if time_flag and mode in (Mode.LIST, Mode.UPDATE):
79
+ typer.echo(
80
+ "Error: --time cannot be used with --list or --update.",
81
+ err=True,
82
+ )
83
+ raise typer.Exit(code=1)
@@ -0,0 +1,186 @@
1
+ """
2
+ Shell completion for git-cai.
3
+
4
+ Generates and installs completion scripts that work for both
5
+ `git-cai` (direct) and `git cai` (as a git subcommand).
6
+ """
7
+
8
+ import logging
9
+ import os
10
+ from pathlib import Path
11
+
12
+ import typer
13
+
14
+ log = logging.getLogger(__name__)
15
+
16
+ # Zsh completion script.
17
+ # Placed in fpath as _git-cai, zsh's git completion auto-discovers it
18
+ # for `git cai <TAB>`. Also registers via compdef for `git-cai <TAB>`.
19
+ _ZSH_SCRIPT = """\
20
+ #compdef git-cai
21
+
22
+ _git-cai() {
23
+ local -a options
24
+ options=(
25
+ '(-h --help)'{-h,--help}'[Show help]'
26
+ '(-v --version)'{-v,--version}'[Show version]'
27
+ '(-a --all)'{-a,--all}'[Stage all tracked files]'
28
+ '(-c --crazy)'{-c,--crazy}'[Commit immediately without editor]'
29
+ '(-d --debug)'{-d,--debug}'[Enable debug logging]'
30
+ '(-g --generate-config)'{-g,--generate-config}'[Generate default config]'
31
+ '(-i --install-completion)'{-i,--install-completion}'[Install shell completion]'
32
+ '(-l --list)'{-l,--list}'[List information]'
33
+ '(-m --model)'{-m,--model}'[Override model (requires --provider)]:model:'
34
+ '(-p --generate-prompts)'{-p,--generate-prompts}'[Generate default prompts]'
35
+ '(-s --squash)'{-s,--squash}'[Squash commits on this branch]'
36
+ '(-t --time)'{-t,--time}'[Measure generation time]'
37
+ '(-u --update)'{-u,--update}'[Check for updates]'
38
+ '(-P --provider)'{-P,--provider}'[Override LLM provider]:provider:(anthropic deepseek gemini groq mistral ollama openai xai)'
39
+ )
40
+ _arguments -s -S $options
41
+ }
42
+
43
+ _git-cai "$@"
44
+ """
45
+
46
+ # Bash completion script.
47
+ _BASH_SCRIPT = """\
48
+ _git_cai_completion() {
49
+ local cur opts
50
+ COMPREPLY=()
51
+ cur="${COMP_WORDS[COMP_CWORD]}"
52
+ opts="-h --help -v --version -a --all -c --crazy -d --debug \\
53
+ -g --generate-config -i --install-completion -l --list \\
54
+ -m --model -p --generate-prompts -s --squash -t --time \\
55
+ -u --update -P --provider"
56
+
57
+ if [[ "${COMP_WORDS[COMP_CWORD-1]}" == "--provider" || \\
58
+ "${COMP_WORDS[COMP_CWORD-1]}" == "-P" ]]; then
59
+ local providers="anthropic deepseek gemini groq mistral ollama openai xai"
60
+ COMPREPLY=( $(compgen -W "$providers" -- "$cur") )
61
+ return 0
62
+ fi
63
+
64
+ COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
65
+ return 0
66
+ }
67
+
68
+ complete -o default -F _git_cai_completion git-cai
69
+
70
+ # Also register for 'git cai' via git's bash completion mechanism
71
+ __git_cai() {
72
+ _git_cai_completion
73
+ }
74
+ """
75
+
76
+ # Fish completion script.
77
+ _FISH_SCRIPT = """\
78
+ # Completions for git-cai / git cai
79
+ complete -c git-cai -s h -l help -d 'Show help'
80
+ complete -c git-cai -s v -l version -d 'Show version'
81
+ complete -c git-cai -s a -l all -d 'Stage all tracked files'
82
+ complete -c git-cai -s c -l crazy -d 'Commit immediately without editor'
83
+ complete -c git-cai -s d -l debug -d 'Enable debug logging'
84
+ complete -c git-cai -s g -l generate-config -d 'Generate default config'
85
+ complete -c git-cai -s i -l install-completion -d 'Install shell completion'
86
+ complete -c git-cai -s l -l list -d 'List information'
87
+ complete -c git-cai -s m -l model -d 'Override model' -r
88
+ complete -c git-cai -s p -l generate-prompts -d 'Generate default prompts'
89
+ complete -c git-cai -s s -l squash -d 'Squash commits on this branch'
90
+ complete -c git-cai -s t -l time -d 'Measure generation time'
91
+ complete -c git-cai -s u -l update -d 'Check for updates'
92
+ complete -c git-cai -s P -l provider -d 'Override LLM provider' -r -a 'anthropic deepseek gemini groq mistral ollama openai xai'
93
+ """
94
+
95
+
96
+ def _detect_shell() -> str:
97
+ """Detect the current shell."""
98
+ shell = os.environ.get("SHELL", "")
99
+ return os.path.basename(shell) if shell else "bash"
100
+
101
+
102
+ def install_completion() -> None:
103
+ """Install shell completion for git-cai."""
104
+ shell = _detect_shell()
105
+
106
+ if shell == "zsh":
107
+ _install_zsh()
108
+ elif shell == "bash":
109
+ _install_bash()
110
+ elif shell == "fish":
111
+ _install_fish()
112
+ else:
113
+ typer.echo(
114
+ f"Unsupported shell '{shell}'. Supported: bash, zsh, fish.", err=True
115
+ )
116
+ raise typer.Exit(code=1)
117
+
118
+
119
+ def _install_zsh() -> None:
120
+ """Install zsh completion."""
121
+ # Determine the target directory
122
+ zfunc_dir = Path.home() / ".zfunc"
123
+ zfunc_dir.mkdir(parents=True, exist_ok=True)
124
+
125
+ target = zfunc_dir / "_git-cai"
126
+ target.write_text(_ZSH_SCRIPT, encoding="utf-8")
127
+
128
+ # Check if ~/.zfunc is in fpath via .zshrc
129
+ zshrc = Path.home() / ".zshrc"
130
+ fpath_line = "fpath=(~/.zfunc $fpath)"
131
+
132
+ needs_fpath = True
133
+ if zshrc.exists():
134
+ content = zshrc.read_text(encoding="utf-8")
135
+ if ".zfunc" in content:
136
+ needs_fpath = False
137
+
138
+ if needs_fpath:
139
+ with zshrc.open("a", encoding="utf-8") as f:
140
+ f.write(
141
+ f"\n# git-cai completion\n{fpath_line}\nautoload -Uz compinit && compinit\n"
142
+ )
143
+ typer.echo(f"Added {fpath_line} to {zshrc}")
144
+
145
+ typer.echo(f"zsh completion installed in {target}.")
146
+ typer.echo("Restart your terminal or run: source ~/.zshrc")
147
+
148
+
149
+ def _install_bash() -> None:
150
+ """Install bash completion."""
151
+ # Try system completions dir first, fall back to user dir
152
+ comp_dir = Path.home() / ".local" / "share" / "bash-completion" / "completions"
153
+ comp_dir.mkdir(parents=True, exist_ok=True)
154
+
155
+ target = comp_dir / "git-cai"
156
+ target.write_text(_BASH_SCRIPT, encoding="utf-8")
157
+
158
+ # Check if the completion dir is sourced
159
+ bashrc = Path.home() / ".bashrc"
160
+ source_line = f"[ -f {target} ] && source {target}"
161
+
162
+ needs_source = True
163
+ if bashrc.exists():
164
+ content = bashrc.read_text(encoding="utf-8")
165
+ if "git-cai" in content or str(comp_dir) in content:
166
+ needs_source = False
167
+
168
+ if needs_source:
169
+ with bashrc.open("a", encoding="utf-8") as f:
170
+ f.write(f"\n# git-cai completion\n{source_line}\n")
171
+ typer.echo(f"Added sourcing line to {bashrc}")
172
+
173
+ typer.echo(f"bash completion installed in {target}.")
174
+ typer.echo("Restart your terminal or run: source ~/.bashrc")
175
+
176
+
177
+ def _install_fish() -> None:
178
+ """Install fish completion."""
179
+ comp_dir = Path.home() / ".config" / "fish" / "completions"
180
+ comp_dir.mkdir(parents=True, exist_ok=True)
181
+
182
+ target = comp_dir / "git-cai.fish"
183
+ target.write_text(_FISH_SCRIPT, encoding="utf-8")
184
+
185
+ typer.echo(f"fish completion installed in {target}.")
186
+ typer.echo("Restart your terminal for completions to take effect.")