git-cai-cli 0.14.0__tar.gz → 0.14.1__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 (96) hide show
  1. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.proselintrc +1 -1
  2. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.pylintrc +1 -1
  3. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/PKG-INFO +8 -1
  4. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/README.md +7 -0
  5. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/docs/git-cai.txt +53 -0
  6. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/docs/man/git-cai.1 +89 -2
  7. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/_version.py +3 -3
  8. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/cli/cli.py +25 -0
  9. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/completion.py +66 -11
  10. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/config.py +48 -1
  11. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/gitutils.py +22 -0
  12. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/llm.py +8 -1
  13. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/options.py +2 -0
  14. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/pr.py +22 -3
  15. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/squash.py +36 -5
  16. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/validate.py +1 -0
  17. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/main.py +23 -1
  18. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli.egg-info/PKG-INFO +8 -1
  19. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_completion.py +60 -0
  20. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_config.py +151 -0
  21. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_gitutils.py +48 -0
  22. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_llm.py +16 -0
  23. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_pr.py +35 -0
  24. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_squash.py +27 -0
  25. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.caiignore +0 -0
  26. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.gitattributes +0 -0
  27. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/cd/.SRCINFO +0 -0
  28. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/cd/PKGBUILD +0 -0
  29. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/ci/_version.py +0 -0
  30. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/ci/cai_config.ci.yml +0 -0
  31. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/ci/tokens.ci.yml +0 -0
  32. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/workflows/python-tests.yml +0 -0
  33. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/workflows/release.yml +0 -0
  34. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.github/workflows/release_aur.yml +0 -0
  35. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.gitignore +0 -0
  36. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.bandit.yml +0 -0
  37. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.checkov.yml +0 -0
  38. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.flake8 +0 -0
  39. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.ls-lint.yml +0 -0
  40. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.markdown-link-check.json +0 -0
  41. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.markdownlint.json +0 -0
  42. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/.yamllint.yml +0 -0
  43. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/check_git_branch_name.sh +0 -0
  44. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/lychee.toml +0 -0
  45. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.linters/pyrightconfig.json +0 -0
  46. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.markdownlintignore +0 -0
  47. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.mega-linter.yml +0 -0
  48. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.semgrepignore +0 -0
  49. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/.trivyignore +0 -0
  50. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/CLAUDE.md +0 -0
  51. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/LICENSE +0 -0
  52. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/Makefile +0 -0
  53. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/cai_config.yml +0 -0
  54. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/pyproject.toml +0 -0
  55. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/setup.cfg +0 -0
  56. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/__init__.py +0 -0
  57. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/cli/__init__.py +0 -0
  58. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/cli/helptext.py +0 -0
  59. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/cli/modes.py +0 -0
  60. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/__init__.py +0 -0
  61. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/editors.py +0 -0
  62. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/init.py +0 -0
  63. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/languages.py +0 -0
  64. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/prompts_fallback.py +0 -0
  65. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/spinner.py +0 -0
  66. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli/core/stats.py +0 -0
  67. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli.egg-info/SOURCES.txt +0 -0
  68. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli.egg-info/dependency_links.txt +0 -0
  69. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli.egg-info/entry_points.txt +0 -0
  70. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli.egg-info/requires.txt +0 -0
  71. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/src/git_cai_cli.egg-info/top_level.txt +0 -0
  72. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/conftest.py +0 -0
  73. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/integration/test_cli_integration.py +0 -0
  74. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/integration/test_config_integration.py +0 -0
  75. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/integration/test_gitutils_integration.py +0 -0
  76. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/integration/test_modes_integration.py +0 -0
  77. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/integration/test_options_integration.py +0 -0
  78. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/integration/test_pr_integration.py +0 -0
  79. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/integration/test_squash_integration.py +0 -0
  80. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_amend.py +0 -0
  81. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_branch_context.py +0 -0
  82. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_cli.py +0 -0
  83. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_conventional.py +0 -0
  84. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_helptext.py +0 -0
  85. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_init.py +0 -0
  86. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_main.py +0 -0
  87. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_modes.py +0 -0
  88. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_options.py +0 -0
  89. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_print.py +0 -0
  90. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_prompt_loading.py +0 -0
  91. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_set_config.py +0 -0
  92. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_signoff.py +0 -0
  93. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_spinner.py +0 -0
  94. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_stats.py +0 -0
  95. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/tests/unit/test_validate.py +0 -0
  96. {git_cai_cli-0.14.0 → git_cai_cli-0.14.1}/uv.lock +0 -0
@@ -48,7 +48,7 @@
48
48
  , "misc.whence": true
49
49
  , "mixed_metaphors.misc": true
50
50
  , "mondegreens.misc": true
51
- , "needless_variants.misc": true
51
+ , "needless_variants.misc": false
52
52
  , "nonwords.misc": true
53
53
  , "oxymorons.misc": true
54
54
  , "psychology.misc": true
@@ -69,7 +69,7 @@ check-protected-access-in-special-methods=no
69
69
  max-args=25 # Max arguments per function
70
70
  max-attributes=12 # Max attributes per class
71
71
  max-branches=30 # Max branches per function
72
- max-locals=65 # Max locals per function
72
+ max-locals=70 # Max locals per function
73
73
  max-returns=10 # Max return statements per function
74
74
  max-statements=120 # 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.14.0
3
+ Version: 0.14.1
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
@@ -90,6 +90,8 @@ Currently supported providers:
90
90
  - Token usage logging for API calls
91
91
  - Branch name as LLM context
92
92
  - Extra context for the LLM
93
+ - Per-invocation overrides for temperature, style, language, and emoji
94
+ - Optional large-diff guard (`max_diff_bytes`) that truncates oversized diffs before sending
93
95
  - Generation time measurement
94
96
  - Local-only usage analytics (per-provider commits, tokens, latency) with opt-in SQLite storage
95
97
  - Shell completion for bash, zsh, and fish
@@ -247,6 +249,7 @@ git cai -g
247
249
  - `squash_prompt_file` - path to the file where the prompt for the squash is stored
248
250
  - `full_files_prompt_file` - path to the prompt used when `-F` / `--full-files` attaches full file contents
249
251
  - `full_files` – attach always the full working-tree contents of affected files alongside the diff
252
+ - `max_diff_bytes` – maximum size (in UTF-8 bytes) of the diff/commit-log sent to the LLM; oversized input is truncated with a marker. `0` (default) means no limit
250
253
  - `timeout` – HTTP timeout for LLM calls in seconds
251
254
  - `branch_context` – include current branch name as LLM context
252
255
  - `conventional` – use Conventional Commits format
@@ -271,6 +274,7 @@ In addition to `git cai`, the following options are available:
271
274
  - `-C`, `--conventional` – use Conventional Commits format (`type(scope): description`)
272
275
  - `-c`, `--crazy` – Trust the LLM and commit without checking
273
276
  - `-d`, `--debug` – enable debug logging
277
+ - `-e`, `--temperature` `TEMPERATURE` – override the active provider's sampling temperature for this invocation (provider-scoped, like `-m`)
274
278
  - `-F`, `--full-files` – attach the full contents of affected files alongside the diff (uses `full_files_prompt.md`)
275
279
  - `-f`, `--files` `PATH` – limit the diff (and full-file content, if enabled) to PATH; repeat for multiple files
276
280
  - `-g`, `--generate-config` – generate the default `cai_config.yml` in the current directory
@@ -293,6 +297,9 @@ In addition to `git cai`, the following options are available:
293
297
  - `--base` `BRANCH` – explicit base branch for `--PR` (overrides auto-detection: `origin/HEAD` → `main` → `master`)
294
298
  - `-S`, `--set` – set a config value (`key=value`) in repo config (requires existing repo config)
295
299
  - `-s`, `--squash` `[N|HASH]` – squash commits on the current branch and summarize them. Without argument: squash all since branch checkout. With a number: squash the last N commits. With a commit hash: squash up to and including that commit
300
+ - `--style` `STYLE` – override the commit message style for this invocation (e.g. `funny`, `neutral`, `none`); validated against the supported styles
301
+ - `--language` `CODE` – override the commit message language for this invocation (e.g. `de`, `fr`, `none`); validated against supported codes
302
+ - `--emoji` / `--no-emoji` – override emoji usage for this invocation (use `--no-emoji` to disable when config enables it)
296
303
  - `-T`, `--timeout` `SECONDS` – HTTP timeout for this invocation (overrides config)
297
304
  - `-t`, `--time` – measure and log commit message generation time
298
305
  - `-u`, `--update` – check for updates
@@ -60,6 +60,8 @@ Currently supported providers:
60
60
  - Token usage logging for API calls
61
61
  - Branch name as LLM context
62
62
  - Extra context for the LLM
63
+ - Per-invocation overrides for temperature, style, language, and emoji
64
+ - Optional large-diff guard (`max_diff_bytes`) that truncates oversized diffs before sending
63
65
  - Generation time measurement
64
66
  - Local-only usage analytics (per-provider commits, tokens, latency) with opt-in SQLite storage
65
67
  - Shell completion for bash, zsh, and fish
@@ -217,6 +219,7 @@ git cai -g
217
219
  - `squash_prompt_file` - path to the file where the prompt for the squash is stored
218
220
  - `full_files_prompt_file` - path to the prompt used when `-F` / `--full-files` attaches full file contents
219
221
  - `full_files` – attach always the full working-tree contents of affected files alongside the diff
222
+ - `max_diff_bytes` – maximum size (in UTF-8 bytes) of the diff/commit-log sent to the LLM; oversized input is truncated with a marker. `0` (default) means no limit
220
223
  - `timeout` – HTTP timeout for LLM calls in seconds
221
224
  - `branch_context` – include current branch name as LLM context
222
225
  - `conventional` – use Conventional Commits format
@@ -241,6 +244,7 @@ In addition to `git cai`, the following options are available:
241
244
  - `-C`, `--conventional` – use Conventional Commits format (`type(scope): description`)
242
245
  - `-c`, `--crazy` – Trust the LLM and commit without checking
243
246
  - `-d`, `--debug` – enable debug logging
247
+ - `-e`, `--temperature` `TEMPERATURE` – override the active provider's sampling temperature for this invocation (provider-scoped, like `-m`)
244
248
  - `-F`, `--full-files` – attach the full contents of affected files alongside the diff (uses `full_files_prompt.md`)
245
249
  - `-f`, `--files` `PATH` – limit the diff (and full-file content, if enabled) to PATH; repeat for multiple files
246
250
  - `-g`, `--generate-config` – generate the default `cai_config.yml` in the current directory
@@ -263,6 +267,9 @@ In addition to `git cai`, the following options are available:
263
267
  - `--base` `BRANCH` – explicit base branch for `--PR` (overrides auto-detection: `origin/HEAD` → `main` → `master`)
264
268
  - `-S`, `--set` – set a config value (`key=value`) in repo config (requires existing repo config)
265
269
  - `-s`, `--squash` `[N|HASH]` – squash commits on the current branch and summarize them. Without argument: squash all since branch checkout. With a number: squash the last N commits. With a commit hash: squash up to and including that commit
270
+ - `--style` `STYLE` – override the commit message style for this invocation (e.g. `funny`, `neutral`, `none`); validated against the supported styles
271
+ - `--language` `CODE` – override the commit message language for this invocation (e.g. `de`, `fr`, `none`); validated against supported codes
272
+ - `--emoji` / `--no-emoji` – override emoji usage for this invocation (use `--no-emoji` to disable when config enables it)
266
273
  - `-T`, `--timeout` `SECONDS` – HTTP timeout for this invocation (overrides config)
267
274
  - `-t`, `--time` – measure and log commit message generation time
268
275
  - `-u`, `--update` – check for updates
@@ -12,6 +12,7 @@ SYNOPSIS
12
12
  [verse]
13
13
  `git cai` [-A | --amend] [-a | --all] [-C | --conventional]
14
14
  [-b | --branch] [-c | --crazy] [-d | --debug]
15
+ [-e TEMPERATURE | --temperature TEMPERATURE]
15
16
  [-F | --full-files | --no-full-files] [-f PATH | --files PATH]
16
17
  [-g | --generate-config]
17
18
  [-H KEY=VALUE | --set-home KEY=VALUE] [-h | --help]
@@ -27,6 +28,7 @@ SYNOPSIS
27
28
  [-S KEY=VALUE | --set KEY=VALUE]
28
29
  [-s [N|HASH] | --squash [N|HASH]]
29
30
  [-q true|false | --sql true|false]
31
+ [--style STYLE] [--language CODE] [--emoji | --no-emoji]
30
32
  [-T SECONDS | --timeout SECONDS]
31
33
  [-t | --time] [-u | --update] [-v | --version]
32
34
  [-x CONTEXT | --context CONTEXT]
@@ -181,6 +183,17 @@ Cannot be combined with `--help` or `--version`.
181
183
  git cai -d
182
184
  ----
183
185
 
186
+ -e, --temperature TEMPERATURE::
187
+ Override the sampling temperature of the active provider for this invocation
188
+ only. Higher values produce more varied wording; lower values are more
189
+ deterministic. The override is provider-scoped, mirroring `--model`, and does
190
+ not change the persisted `cai_config.yml`.
191
+ +
192
+ ----
193
+ git cai -e 0.7
194
+ git cai -P anthropic -e 0.2
195
+ ----
196
+
184
197
  -F, --full-files::
185
198
  Send the full working-tree contents of every staged file alongside the diff.
186
199
  By default, git-cai sends only the staged diff to the LLM. With `-F`, the
@@ -488,6 +501,42 @@ git cai -s 3
488
501
  git cai -s a1b2c3d
489
502
  ----
490
503
 
504
+ --style STYLE::
505
+ Override the commit message tone style for this invocation only (e.g.
506
+ `professional`, `neutral`, `friendly`, `funny`, `excited`, `sarcastic`,
507
+ `apologetic`, `academic`, or `none` to let the model choose). Run
508
+ `git cai -l style` to see all styles with examples. An invalid value is
509
+ rejected with an error. To change the style permanently, set `style:` in
510
+ `cai_config.yml`.
511
+ +
512
+ ----
513
+ git cai --style funny
514
+ git cai --style none
515
+ ----
516
+
517
+ --language CODE::
518
+ Override the commit message language for this invocation only, using a
519
+ supported language code (e.g. `de`, `fr`, `es`), or `none` to omit the
520
+ language instruction. Run `git cai -l language` to list supported codes. An
521
+ unsupported code is rejected with an error. To change it permanently, set
522
+ `language:` in `cai_config.yml`.
523
+ +
524
+ ----
525
+ git cai --language de
526
+ git cai --language none
527
+ ----
528
+
529
+ --emoji / --no-emoji::
530
+ Override emoji usage for this invocation only. `--emoji` instructs the model
531
+ to use relevant emojis; `--no-emoji` disables them even when the persisted
532
+ config enables emoji. To change the default permanently, set `emoji:` in
533
+ `cai_config.yml`.
534
+ +
535
+ ----
536
+ git cai --no-emoji
537
+ git cai --emoji
538
+ ----
539
+
491
540
  -T, --timeout SECONDS::
492
541
  Override the HTTP timeout for the LLM call in this invocation. The default
493
542
  is 30 seconds for remote providers and 300 seconds for Ollama (since local
@@ -824,6 +873,10 @@ Available configuration keys:
824
873
  - `timeout` -- HTTP timeout in seconds for remote LLM calls (default `30`)
825
874
  - `full_files` -- send full working-tree contents of staged files alongside
826
875
  the diff (`true`/`false`, default `false`)
876
+ - `max_diff_bytes` -- maximum size (in UTF-8 bytes) of the diff/commit-log
877
+ sent to the LLM. When the input exceeds this, it is truncated and a marker
878
+ line is appended so the model knows it was cut. `0` (the default) means no
879
+ limit. Useful to avoid context-window errors on very large staged changes.
827
880
  - `pr_to_file` -- when running `--PR`, write the generated PR description
828
881
  to a Markdown file in the repository root instead of printing it to
829
882
  stdout (`true`/`false`, default `false`)
@@ -2,12 +2,12 @@
2
2
  .\" Title: git-cai
3
3
  .\" Author: Thorsten Foltz
4
4
  .\" Generator: Asciidoctor 2.0.26
5
- .\" Date: 2026-05-25
5
+ .\" Date: 2026-06-04
6
6
  .\" Manual: \ \&
7
7
  .\" Source: \ \&
8
8
  .\" Language: English
9
9
  .\"
10
- .TH "GIT\-CAI" "1" "2026-05-25" "\ \&" "\ \&"
10
+ .TH "GIT\-CAI" "1" "2026-06-04" "\ \&" "\ \&"
11
11
  .ie \n(.g .ds Aq \(aq
12
12
  .el .ds Aq '
13
13
  .ss \n[.ss] 0
@@ -34,6 +34,7 @@ git-cai \- AI\-powered commit message generator
34
34
  .nf
35
35
  \f(CRgit cai\fP [\-A | \-\-amend] [\-a | \-\-all] [\-C | \-\-conventional]
36
36
  [\-b | \-\-branch] [\-c | \-\-crazy] [\-d | \-\-debug]
37
+ [\-e TEMPERATURE | \-\-temperature TEMPERATURE]
37
38
  [\-F | \-\-full\-files | \-\-no\-full\-files] [\-f PATH | \-\-files PATH]
38
39
  [\-g | \-\-generate\-config]
39
40
  [\-H KEY=VALUE | \-\-set\-home KEY=VALUE] [\-h | \-\-help]
@@ -49,6 +50,7 @@ git-cai \- AI\-powered commit message generator
49
50
  [\-S KEY=VALUE | \-\-set KEY=VALUE]
50
51
  [\-s [N|HASH] | \-\-squash [N|HASH]]
51
52
  [\-q true|false | \-\-sql true|false]
53
+ [\-\-style STYLE] [\-\-language CODE] [\-\-emoji | \-\-no\-emoji]
52
54
  [\-T SECONDS | \-\-timeout SECONDS]
53
55
  [\-t | \-\-time] [\-u | \-\-update] [\-v | \-\-version]
54
56
  [\-x CONTEXT | \-\-context CONTEXT]
@@ -350,6 +352,23 @@ git cai \-d
350
352
  .if n .RE
351
353
  .RE
352
354
  .sp
355
+ \-e, \-\-temperature TEMPERATURE
356
+ .RS 4
357
+ Override the sampling temperature of the active provider for this invocation
358
+ only. Higher values produce more varied wording; lower values are more
359
+ deterministic. The override is provider\-scoped, mirroring \f(CR\-\-model\fP, and does
360
+ not change the persisted \f(CRcai_config.yml\fP.
361
+ .sp
362
+ .if n .RS 4
363
+ .nf
364
+ .fam C
365
+ git cai \-e 0.7
366
+ git cai \-P anthropic \-e 0.2
367
+ .fam
368
+ .fi
369
+ .if n .RE
370
+ .RE
371
+ .sp
353
372
  \-F, \-\-full\-files
354
373
  .RS 4
355
374
  Send the full working\-tree contents of every staged file alongside the diff.
@@ -773,6 +792,60 @@ git cai \-s a1b2c3d
773
792
  .if n .RE
774
793
  .RE
775
794
  .sp
795
+ \-\-style STYLE
796
+ .RS 4
797
+ Override the commit message tone style for this invocation only (e.g.
798
+ \f(CRprofessional\fP, \f(CRneutral\fP, \f(CRfriendly\fP, \f(CRfunny\fP, \f(CRexcited\fP, \f(CRsarcastic\fP,
799
+ \f(CRapologetic\fP, \f(CRacademic\fP, or \f(CRnone\fP to let the model choose). Run
800
+ \f(CRgit cai \-l style\fP to see all styles with examples. An invalid value is
801
+ rejected with an error. To change the style permanently, set \f(CRstyle:\fP in
802
+ \f(CRcai_config.yml\fP.
803
+ .sp
804
+ .if n .RS 4
805
+ .nf
806
+ .fam C
807
+ git cai \-\-style funny
808
+ git cai \-\-style none
809
+ .fam
810
+ .fi
811
+ .if n .RE
812
+ .RE
813
+ .sp
814
+ \-\-language CODE
815
+ .RS 4
816
+ Override the commit message language for this invocation only, using a
817
+ supported language code (e.g. \f(CRde\fP, \f(CRfr\fP, \f(CRes\fP), or \f(CRnone\fP to omit the
818
+ language instruction. Run \f(CRgit cai \-l language\fP to list supported codes. An
819
+ unsupported code is rejected with an error. To change it permanently, set
820
+ \f(CRlanguage:\fP in \f(CRcai_config.yml\fP.
821
+ .sp
822
+ .if n .RS 4
823
+ .nf
824
+ .fam C
825
+ git cai \-\-language de
826
+ git cai \-\-language none
827
+ .fam
828
+ .fi
829
+ .if n .RE
830
+ .RE
831
+ .sp
832
+ \-\-emoji / \-\-no\-emoji
833
+ .RS 4
834
+ Override emoji usage for this invocation only. \f(CR\-\-emoji\fP instructs the model
835
+ to use relevant emojis; \f(CR\-\-no\-emoji\fP disables them even when the persisted
836
+ config enables emoji. To change the default permanently, set \f(CRemoji:\fP in
837
+ \f(CRcai_config.yml\fP.
838
+ .sp
839
+ .if n .RS 4
840
+ .nf
841
+ .fam C
842
+ git cai \-\-no\-emoji
843
+ git cai \-\-emoji
844
+ .fam
845
+ .fi
846
+ .if n .RE
847
+ .RE
848
+ .sp
776
849
  \-T, \-\-timeout SECONDS
777
850
  .RS 4
778
851
  Override the HTTP timeout for the LLM call in this invocation. The default
@@ -1394,6 +1467,20 @@ the diff (\f(CRtrue\fP/\f(CRfalse\fP, default \f(CRfalse\fP)
1394
1467
  . sp -1
1395
1468
  . IP \(bu 2.3
1396
1469
  .\}
1470
+ \f(CRmax_diff_bytes\fP \(em maximum size (in UTF\-8 bytes) of the diff/commit\-log
1471
+ sent to the LLM. When the input exceeds this, it is truncated and a marker
1472
+ line is appended so the model knows it was cut. \f(CR0\fP (the default) means no
1473
+ limit. Useful to avoid context\-window errors on very large staged changes.
1474
+ .RE
1475
+ .sp
1476
+ .RS 4
1477
+ .ie n \{\
1478
+ \h'-04'\(bu\h'+03'\c
1479
+ .\}
1480
+ .el \{\
1481
+ . sp -1
1482
+ . IP \(bu 2.3
1483
+ .\}
1397
1484
  \f(CRpr_to_file\fP \(em when running \f(CR\-\-PR\fP, write the generated PR description
1398
1485
  to a Markdown file in the repository root instead of printing it to
1399
1486
  stdout (\f(CRtrue\fP/\f(CRfalse\fP, default \f(CRfalse\fP)
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.14.0'
22
- __version_tuple__ = version_tuple = (0, 14, 0)
21
+ __version__ = version = '0.14.1'
22
+ __version_tuple__ = version_tuple = (0, 14, 1)
23
23
 
24
- __commit_id__ = commit_id = 'ge467c3583'
24
+ __commit_id__ = commit_id = 'gbd1b6f7b7'
@@ -179,6 +179,27 @@ def callback( # pylint: disable=too-many-arguments,too-many-positional-argument
179
179
  "--print",
180
180
  help="Generate the commit message, print it to stdout, and exit without committing.",
181
181
  ),
182
+ temperature: float = typer.Option(
183
+ None,
184
+ "-e",
185
+ "--temperature",
186
+ help="Override the active provider's sampling temperature for this invocation.",
187
+ ),
188
+ style: str = typer.Option(
189
+ None,
190
+ "--style",
191
+ help="Override the commit message style for this invocation (e.g. funny, neutral, none).",
192
+ ),
193
+ language: str = typer.Option(
194
+ None,
195
+ "--language",
196
+ help="Override the commit message language code for this invocation (e.g. de, fr, none).",
197
+ ),
198
+ emoji: bool | None = typer.Option(
199
+ None,
200
+ "--emoji/--no-emoji",
201
+ help="Override emoji usage for this invocation. Use --no-emoji to disable when config enables it.",
202
+ ),
182
203
  ):
183
204
  """
184
205
  CLI entry point for git-cai-cli.
@@ -311,6 +332,10 @@ def callback( # pylint: disable=too-many-arguments,too-many-positional-argument
311
332
  stats_reset=stats_reset,
312
333
  signoff=signoff,
313
334
  print_only=print_only,
335
+ temperature_override=temperature,
336
+ style_override=style,
337
+ language_override=language,
338
+ emoji_override=emoji,
314
339
  )
315
340
 
316
341
 
@@ -24,22 +24,42 @@ _git-cai() {
24
24
  options=(
25
25
  '(-A --amend)'{-A,--amend}'[Regenerate and amend last commit message]'
26
26
  '(-a --all)'{-a,--all}'[Stage all tracked files]'
27
+ '(-b --branch)'{-b,--branch}'[Include current branch name as context]'
27
28
  '(-C --conventional)'{-C,--conventional}'[Use Conventional Commits format]'
28
29
  '(-c --crazy)'{-c,--crazy}'[Commit immediately without editor]'
29
30
  '(-d --debug)'{-d,--debug}'[Enable debug logging]'
31
+ '(-e --temperature)'{-e,--temperature}'[Override sampling temperature]:temperature:'
32
+ '(-F --full-files)'{-F,--full-files}'[Send full file contents alongside the diff]'
33
+ '(-f --files)'{-f,--files}'[Limit the diff to these paths]:file:_files'
30
34
  '(-g --generate-config)'{-g,--generate-config}'[Generate default config]'
31
35
  '(-H --set-home)'{-H,--set-home}'[Set config value in home config]:key=value:'
32
36
  '(-h --help)'{-h,--help}'[Show help]'
37
+ '(-I --init)'{-I,--init}'[Interactive setup wizard]'
33
38
  '(-i --install-completion)'{-i,--install-completion}'[Install shell completion]'
34
- '(-l --list)'{-l,--list}'[List information]'
39
+ '(-l --list)'{-l,--list}'[List information]:type:(config editor language model path provider style)'
35
40
  '(-m --model)'{-m,--model}'[Override model (requires --provider)]:model:'
41
+ '(-o --signoff)'{-o,--signoff}'[Append a Signed-off-by trailer]'
36
42
  '(-P --provider)'{-P,--provider}'[Override LLM provider]:provider:(anthropic deepseek gemini groq mistral ollama openai xai)'
37
43
  '(-p --generate-prompts)'{-p,--generate-prompts}'[Generate default prompts]'
44
+ '--print[Print the generated message to stdout and exit]'
45
+ '(-q --sql)'{-q,--sql}'[Override stats writing for this run]:value:(true false)'
46
+ '(-r --PR)'{-r,--PR}'[Generate a Pull Request description]'
47
+ '--base[Base branch for --PR]:branch:'
38
48
  '(-S --set)'{-S,--set}'[Set config value in repo config]:key=value:'
39
49
  '(-s --squash)'{-s,--squash}'[Squash commits on this branch]'
50
+ '(-T --timeout)'{-T,--timeout}'[HTTP timeout in seconds]:seconds:'
40
51
  '(-t --time)'{-t,--time}'[Measure generation time]'
41
52
  '(-u --update)'{-u,--update}'[Check for updates]'
42
53
  '(-v --version)'{-v,--version}'[Show version]'
54
+ '(-x --context)'{-x,--context}'[Provide extra context for the LLM]:context:'
55
+ '(-z --stats)'{-z,--stats}'[Show local usage analytics]'
56
+ '--since[Filter --stats to events on or after a date]:date:'
57
+ '--json[Render --stats output as JSON]'
58
+ '--reset-stats[Delete all rows from the local stats DB]'
59
+ '--style[Override commit message style]:style:(academic apologetic excited friendly funny neutral none professional sarcastic)'
60
+ '--language[Override commit message language code]:language:'
61
+ '--emoji[Enable emoji for this invocation]'
62
+ '--no-emoji[Disable emoji for this invocation]'
43
63
  )
44
64
  _arguments -s -S $options
45
65
  }
@@ -50,22 +70,37 @@ _git-cai "$@"
50
70
  # Bash completion script.
51
71
  _BASH_SCRIPT = """\
52
72
  _git_cai_completion() {
53
- local cur opts
73
+ local cur prev opts
54
74
  COMPREPLY=()
55
75
  cur="${COMP_WORDS[COMP_CWORD]}"
56
- opts="-A --amend -a --all -C --conventional -c --crazy -d --debug \\
57
- -g --generate-config -H --set-home -h --help \\
58
- -i --install-completion -l --list -m --model \\
59
- -P --provider -p --generate-prompts -S --set \\
60
- -s --squash -t --time -u --update -v --version"
61
-
62
- if [[ "${COMP_WORDS[COMP_CWORD-1]}" == "--provider" || \\
63
- "${COMP_WORDS[COMP_CWORD-1]}" == "-P" ]]; then
76
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
77
+ opts="-A --amend -a --all -b --branch -C --conventional -c --crazy \\
78
+ -d --debug -e --temperature -F --full-files -f --files \\
79
+ -g --generate-config -H --set-home -h --help -I --init \\
80
+ -i --install-completion -l --list -m --model -o --signoff \\
81
+ -P --provider -p --generate-prompts --print -q --sql \\
82
+ -r --PR --base -S --set -s --squash -T --timeout -t --time \\
83
+ -u --update -v --version -x --context -z --stats --since \\
84
+ --json --reset-stats --style --language --emoji --no-emoji"
85
+
86
+ if [[ "$prev" == "--provider" || "$prev" == "-P" ]]; then
64
87
  local providers="anthropic deepseek gemini groq mistral ollama openai xai"
65
88
  COMPREPLY=( $(compgen -W "$providers" -- "$cur") )
66
89
  return 0
67
90
  fi
68
91
 
92
+ if [[ "$prev" == "--list" || "$prev" == "-l" ]]; then
93
+ local types="config editor language model path provider style"
94
+ COMPREPLY=( $(compgen -W "$types" -- "$cur") )
95
+ return 0
96
+ fi
97
+
98
+ if [[ "$prev" == "--style" ]]; then
99
+ local styles="academic apologetic excited friendly funny neutral none professional sarcastic"
100
+ COMPREPLY=( $(compgen -W "$styles" -- "$cur") )
101
+ return 0
102
+ fi
103
+
69
104
  COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
70
105
  return 0
71
106
  }
@@ -83,22 +118,42 @@ _FISH_SCRIPT = """\
83
118
  # Completions for git-cai / git cai
84
119
  complete -c git-cai -s A -l amend -d 'Regenerate and amend last commit message'
85
120
  complete -c git-cai -s a -l all -d 'Stage all tracked files'
121
+ complete -c git-cai -s b -l branch -d 'Include current branch name as context'
86
122
  complete -c git-cai -s C -l conventional -d 'Use Conventional Commits format'
87
123
  complete -c git-cai -s c -l crazy -d 'Commit immediately without editor'
88
124
  complete -c git-cai -s d -l debug -d 'Enable debug logging'
125
+ complete -c git-cai -s e -l temperature -d 'Override sampling temperature' -r
126
+ complete -c git-cai -s F -l full-files -d 'Send full file contents alongside the diff'
127
+ complete -c git-cai -s f -l files -d 'Limit the diff to these paths' -r
89
128
  complete -c git-cai -s g -l generate-config -d 'Generate default config'
90
129
  complete -c git-cai -s H -l set-home -d 'Set config value in home config' -r
91
130
  complete -c git-cai -s h -l help -d 'Show help'
131
+ complete -c git-cai -s I -l init -d 'Interactive setup wizard'
92
132
  complete -c git-cai -s i -l install-completion -d 'Install shell completion'
93
- complete -c git-cai -s l -l list -d 'List information'
133
+ complete -c git-cai -s l -l list -d 'List information' -x -a 'config editor language model path provider style'
94
134
  complete -c git-cai -s m -l model -d 'Override model' -r
135
+ complete -c git-cai -s o -l signoff -d 'Append a Signed-off-by trailer'
95
136
  complete -c git-cai -s P -l provider -d 'Override LLM provider' -r -a 'anthropic deepseek gemini groq mistral ollama openai xai'
96
137
  complete -c git-cai -s p -l generate-prompts -d 'Generate default prompts'
138
+ complete -c git-cai -l print -d 'Print the generated message and exit'
139
+ complete -c git-cai -s q -l sql -d 'Override stats writing for this run' -r -a 'true false'
140
+ complete -c git-cai -s r -l PR -d 'Generate a Pull Request description'
141
+ complete -c git-cai -l base -d 'Base branch for --PR' -r
97
142
  complete -c git-cai -s S -l set -d 'Set config value in repo config' -r
98
143
  complete -c git-cai -s s -l squash -d 'Squash commits on this branch'
144
+ complete -c git-cai -s T -l timeout -d 'HTTP timeout in seconds' -r
99
145
  complete -c git-cai -s t -l time -d 'Measure generation time'
100
146
  complete -c git-cai -s u -l update -d 'Check for updates'
101
147
  complete -c git-cai -s v -l version -d 'Show version'
148
+ complete -c git-cai -s x -l context -d 'Provide extra context for the LLM' -r
149
+ complete -c git-cai -s z -l stats -d 'Show local usage analytics'
150
+ complete -c git-cai -l since -d 'Filter --stats to events on or after a date' -r
151
+ complete -c git-cai -l json -d 'Render --stats output as JSON'
152
+ complete -c git-cai -l reset-stats -d 'Delete all rows from the local stats DB'
153
+ complete -c git-cai -l style -d 'Override commit message style' -x -a 'academic apologetic excited friendly funny neutral none professional sarcastic'
154
+ complete -c git-cai -l language -d 'Override commit message language code' -r
155
+ complete -c git-cai -l emoji -d 'Enable emoji for this invocation'
156
+ complete -c git-cai -l no-emoji -d 'Disable emoji for this invocation'
102
157
  """
103
158
 
104
159
 
@@ -60,6 +60,7 @@ DEFAULT_CONFIG: dict[str, Any] = {
60
60
  "measure_time": False,
61
61
  "timeout": 30,
62
62
  "full_files": False,
63
+ "max_diff_bytes": 0,
63
64
  "pr_to_file": False,
64
65
  "pr_file_name": "PR_DESCRIPTION.md",
65
66
  "pr_prompt_file": "",
@@ -74,6 +75,7 @@ TOKENLESS_PROVIDERS: set[str] = {
74
75
 
75
76
  TOKEN_TEMPLATE = {
76
77
  "anthropic": "PUT-YOUR-ANTHROPIC-TOKEN-HERE",
78
+ "deepseek": "PUT-YOUR-DEEPSEEK-TOKEN-HERE",
77
79
  "gemini": "PUT-YOUR-GEMINI-TOKEN-HERE",
78
80
  "groq": "PUT-YOUR-GROQ-TOKEN-HERE",
79
81
  "openai": "PUT-YOUR-OPENAI-TOKEN-HERE",
@@ -460,6 +462,7 @@ def ordered_default_config(
460
462
  "measure_time",
461
463
  "timeout",
462
464
  "full_files",
465
+ "max_diff_bytes",
463
466
  "pr_to_file",
464
467
  "pr_file_name",
465
468
  "pr_prompt_file",
@@ -592,6 +595,9 @@ def apply_cli_overrides(
592
595
  timeout_override: int | None = None,
593
596
  full_files_override: bool | None = None,
594
597
  sql_override: bool | None = None,
598
+ style_override: str | None = None,
599
+ language_override: str | None = None,
600
+ emoji_override: bool | None = None,
595
601
  ) -> None:
596
602
  """Apply per-invocation CLI flag overrides to the config dict in-place.
597
603
 
@@ -602,6 +608,12 @@ def apply_cli_overrides(
602
608
 
603
609
  ``sql_override`` mirrors ``--sql true|false`` and overrides the
604
610
  top-level ``stats`` boolean.
611
+
612
+ ``style_override`` / ``language_override`` / ``emoji_override`` mirror
613
+ ``--style`` / ``--language`` / ``--emoji`` and override the top-level
614
+ generation knobs. Style and language are validated here (the normal
615
+ config validation already ran during ``load_config``, before these
616
+ overrides are applied); invalid values raise ``typer.Exit``.
605
617
  """
606
618
  if conventional is not None:
607
619
  config["conventional"] = conventional
@@ -613,15 +625,38 @@ def apply_cli_overrides(
613
625
  config["full_files"] = full_files_override
614
626
  if sql_override is not None:
615
627
  config["stats"] = sql_override
628
+ if style_override is not None:
629
+ try:
630
+ config["style"] = _validate_style(style_override)
631
+ except ValueError as exc:
632
+ typer.echo(f"Error: {exc}", err=True)
633
+ raise typer.Exit(code=1) from exc
634
+ if language_override is not None:
635
+ normalized = language_override.strip().lower()
636
+ if normalized != "none" and normalized not in ALLOWED_LANGUAGES:
637
+ typer.echo(
638
+ f"Error: unknown language '{language_override}'. "
639
+ "Run 'git cai -l language' to see supported codes.",
640
+ err=True,
641
+ )
642
+ raise typer.Exit(code=1)
643
+ config["language"] = normalized
644
+ if emoji_override is not None:
645
+ config["emoji"] = emoji_override
616
646
 
617
647
 
618
648
  def apply_provider_overrides(
619
649
  config: dict,
620
650
  provider_override: str | None,
621
651
  model_override: str | None,
652
+ temperature_override: float | None = None,
622
653
  ) -> None:
623
654
  """
624
- Apply --provider and --model overrides to the config dict in-place.
655
+ Apply --provider, --model and --temperature overrides to the config
656
+ dict in-place.
657
+
658
+ ``temperature_override`` is provider-scoped (like ``--model``): it
659
+ sets ``config[<active provider>]["temperature"]`` for this run only.
625
660
 
626
661
  Raises typer.Exit on validation errors.
627
662
  """
@@ -664,3 +699,15 @@ def apply_provider_overrides(
664
699
  model_override,
665
700
  provider,
666
701
  )
702
+
703
+ if temperature_override is not None:
704
+ provider = config["default"]
705
+ if provider not in config or not isinstance(config[provider], dict):
706
+ config[provider] = {"temperature": temperature_override}
707
+ else:
708
+ config[provider]["temperature"] = temperature_override
709
+ log.info(
710
+ "Temperature overridden to %s for provider '%s'.",
711
+ temperature_override,
712
+ provider,
713
+ )
@@ -192,6 +192,28 @@ def git_diff_excluding(
192
192
  return result.stdout
193
193
 
194
194
 
195
+ def truncate_diff(diff: str, max_bytes: int) -> tuple[str, bool]:
196
+ """Truncate ``diff`` to at most ``max_bytes`` UTF-8 bytes.
197
+
198
+ A ``max_bytes`` of 0 (or negative) means "no limit" and the diff is
199
+ returned unchanged — preserving the default behavior. When truncation
200
+ occurs, a marker line is appended so both the LLM and the user know the
201
+ input was cut. Returns ``(possibly_truncated_diff, was_truncated)``.
202
+ """
203
+ if max_bytes <= 0:
204
+ return diff, False
205
+
206
+ encoded = diff.encode("utf-8")
207
+ if len(encoded) <= max_bytes:
208
+ return diff, False
209
+
210
+ # Cut on a UTF-8 safe boundary: decoding with errors="ignore" drops any
211
+ # partial trailing multibyte sequence left by the byte-level slice.
212
+ truncated = encoded[:max_bytes].decode("utf-8", errors="ignore")
213
+ marker = f"\n\n[... diff truncated: exceeded max_diff_bytes={max_bytes} ...]"
214
+ return truncated + marker, True
215
+
216
+
195
217
  def _matches_caiignore(path: str, patterns: Sequence[str]) -> bool:
196
218
  """Return True if `path` matches any of the `.caiignore` patterns.
197
219
 
@@ -1148,7 +1148,14 @@ class CommitMessageGenerator:
1148
1148
  getattr(usage, "completion_tokens", None),
1149
1149
  )
1150
1150
 
1151
- return completion.choices[0].message.content.strip()
1151
+ # Some models (e.g. reasoning models that hit a stop/refusal) return
1152
+ # ``None`` content; ``.strip()`` on that would raise AttributeError.
1153
+ # Surface a clean ValueError that ``_validate_llm_call`` can classify.
1154
+ content_out = completion.choices[0].message.content
1155
+ if not content_out:
1156
+ raise ValueError(f"{provider_name} returned an empty response.")
1157
+
1158
+ return content_out.strip()
1152
1159
 
1153
1160
  def generate_xai(
1154
1161
  self,