git-cai-cli 0.14.2__tar.gz → 0.15.2__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 (105) hide show
  1. git_cai_cli-0.15.2/.caiignore +1 -0
  2. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.gitignore +2 -0
  3. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.pylintrc +4 -4
  4. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.mega-linter.yml +1 -0
  5. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/PKG-INFO +56 -6
  6. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/README.md +55 -5
  7. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/docs/git-cai.txt +61 -0
  8. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/docs/man/git-cai.1 +101 -2
  9. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/__init__.py +2 -0
  10. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/_version.py +3 -3
  11. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/cli/cli.py +25 -0
  12. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/cli/helptext.py +3 -0
  13. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/cli/modes.py +7 -3
  14. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/config.py +39 -0
  15. git_cai_cli-0.15.2/src/git_cai_cli/core/doctor.py +195 -0
  16. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/gitutils.py +73 -0
  17. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/llm.py +190 -29
  18. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/options.py +2 -0
  19. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/pr.py +15 -4
  20. git_cai_cli-0.15.2/src/git_cai_cli/core/secrets.py +172 -0
  21. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/squash.py +28 -5
  22. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/validate.py +9 -1
  23. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/main.py +97 -17
  24. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli.egg-info/PKG-INFO +56 -6
  25. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli.egg-info/SOURCES.txt +7 -1
  26. git_cai_cli-0.15.2/src/git_cai_cli.egg-info/scm_file_list.json +96 -0
  27. git_cai_cli-0.15.2/src/git_cai_cli.egg-info/scm_version.json +8 -0
  28. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/integration/test_cli_integration.py +2 -1
  29. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/integration/test_pr_integration.py +4 -4
  30. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_amend.py +61 -1
  31. git_cai_cli-0.15.2/tests/unit/test_classification.py +81 -0
  32. git_cai_cli-0.15.2/tests/unit/test_doctor.py +117 -0
  33. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_gitutils.py +27 -0
  34. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_main.py +75 -1
  35. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_pr.py +8 -6
  36. git_cai_cli-0.15.2/tests/unit/test_secrets.py +187 -0
  37. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_set_config.py +78 -1
  38. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_squash.py +13 -2
  39. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/uv.lock +64 -76
  40. git_cai_cli-0.14.2/.caiignore +0 -5
  41. git_cai_cli-0.14.2/docs/superpowers/specs/2026-06-14-custom-styles-design.md +0 -203
  42. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.gitattributes +0 -0
  43. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/cd/.SRCINFO +0 -0
  44. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/cd/PKGBUILD +0 -0
  45. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/ci/_version.py +0 -0
  46. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/ci/cai_config.ci.yml +0 -0
  47. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/ci/tokens.ci.yml +0 -0
  48. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/workflows/python-tests.yml +0 -0
  49. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/workflows/release.yml +0 -0
  50. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.github/workflows/release_aur.yml +0 -0
  51. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.bandit.yml +0 -0
  52. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.checkov.yml +0 -0
  53. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.flake8 +0 -0
  54. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.ls-lint.yml +0 -0
  55. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.markdown-link-check.json +0 -0
  56. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.markdownlint.json +0 -0
  57. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.proselintrc +0 -0
  58. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/.yamllint.yml +0 -0
  59. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/check_git_branch_name.sh +0 -0
  60. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/lychee.toml +0 -0
  61. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.linters/pyrightconfig.json +0 -0
  62. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.markdownlintignore +0 -0
  63. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.semgrepignore +0 -0
  64. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/.trivyignore +0 -0
  65. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/CLAUDE.md +0 -0
  66. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/LICENSE +0 -0
  67. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/Makefile +0 -0
  68. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/cai_config.yml +0 -0
  69. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/pyproject.toml +0 -0
  70. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/setup.cfg +0 -0
  71. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/cli/__init__.py +0 -0
  72. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/__init__.py +0 -0
  73. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/completion.py +0 -0
  74. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/editors.py +0 -0
  75. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/init.py +0 -0
  76. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/languages.py +0 -0
  77. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/prompts_fallback.py +0 -0
  78. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/spinner.py +0 -0
  79. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli/core/stats.py +0 -0
  80. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli.egg-info/dependency_links.txt +0 -0
  81. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli.egg-info/entry_points.txt +0 -0
  82. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli.egg-info/requires.txt +0 -0
  83. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/src/git_cai_cli.egg-info/top_level.txt +0 -0
  84. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/conftest.py +0 -0
  85. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/integration/test_config_integration.py +0 -0
  86. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/integration/test_gitutils_integration.py +0 -0
  87. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/integration/test_modes_integration.py +0 -0
  88. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/integration/test_options_integration.py +0 -0
  89. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/integration/test_squash_integration.py +0 -0
  90. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_branch_context.py +0 -0
  91. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_cli.py +0 -0
  92. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_completion.py +0 -0
  93. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_config.py +0 -0
  94. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_conventional.py +0 -0
  95. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_helptext.py +0 -0
  96. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_init.py +0 -0
  97. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_llm.py +0 -0
  98. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_modes.py +0 -0
  99. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_options.py +0 -0
  100. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_print.py +0 -0
  101. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_prompt_loading.py +0 -0
  102. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_signoff.py +0 -0
  103. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_spinner.py +0 -0
  104. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_stats.py +0 -0
  105. {git_cai_cli-0.14.2 → git_cai_cli-0.15.2}/tests/unit/test_validate.py +0 -0
@@ -0,0 +1 @@
1
+ tests/unit/test_secrets.py
@@ -7,6 +7,8 @@ src/git_cai_cli.egg-info/
7
7
  megalinter-reports/
8
8
  __pycache__/
9
9
  .ruff_cache/
10
+ .pytest_cache/
11
+ .mypy_cache/
10
12
  .venv/
11
13
 
12
14
  # files
@@ -7,7 +7,7 @@ persistent=yes # Save data between runs (improves inference cac
7
7
  unsafe-load-any-extension=no # Prevent loading arbitrary C extensions for safety
8
8
 
9
9
  ignore=venv,build,dist,__pycache__,tests # Ignore common generated/virtual dirs
10
- ignore-paths=.*[\\/](\.venv|\.mypy_cache|\.pytest_cache|build|dist|docs)([\\/].*)?$
10
+ ignore-paths=.*[\\/](\.venv|\.mypy_cache|\.pytest_cache|build|dist|docs)([\\/].*)?$,.*[\\/]_version\.py$
11
11
 
12
12
  ignore-patterns=^\.#,^__init__\.py$ # Ignore editor lockfiles (e.g., Emacs)
13
13
 
@@ -66,12 +66,12 @@ check-protected-access-in-special-methods=no
66
66
  # Don’t warn about protected attr access in dunder methods
67
67
 
68
68
  [DESIGN]
69
- max-args=25 # Max arguments per function
69
+ max-args=30 # 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=70 # Max locals per function
72
+ max-locals=80 # Max locals per function
73
73
  max-returns=10 # Max return statements per function
74
- max-statements=120 # Max total statements per function
74
+ max-statements=130 # Max total statements per function
75
75
  max-public-methods=20 # Max public methods per class
76
76
  min-public-methods=1 # Min public methods per class
77
77
  max-nested-blocks=15 # Max nesting depth
@@ -67,6 +67,7 @@ REPOSITORY_SEMGREP_RULESETS:
67
67
  "p/r2c-security-audit",
68
68
  "p/secure-defaults",
69
69
  ]
70
+ SECURITY_SUGGESTIONS: false
70
71
  SHOW_ELAPSED_TIME: true
71
72
  SHOW_SKIPPED_LINTERS: true
72
73
  SPELL_PROSELINT_RULES_PATH: .linters
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-cai-cli
3
- Version: 0.14.2
3
+ Version: 0.15.2
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
@@ -79,7 +79,7 @@ Currently supported providers:
79
79
  - Global configuration with per-repository overrides
80
80
  - Interactive `--init` wizard for first-time setup (provider, token, language, style)
81
81
  - Repository-specific language, style, and model selection
82
- - Amend the last commit message with a regenerated one
82
+ - Amend mode refines the existing commit message instead of regenerating it from scratch, preserving trailers and intent
83
83
  - Conventional Commits format support
84
84
  - `Signed-off-by:` (DCO) trailer support via `--signoff`
85
85
  - `--print` mode that emits the generated message to stdout for scripting
@@ -95,6 +95,9 @@ Currently supported providers:
95
95
  - Generation time measurement
96
96
  - Local-only usage analytics (per-provider commits, tokens, latency) with opt-in SQLite storage
97
97
  - Shell completion for bash, zsh, and fish
98
+ - Local secret scan that blocks the diff before it reaches the provider when likely credentials are detected
99
+ - Configuration doctor (`--check`) that validates your setup offline, with an optional live provider probe (`--ping`)
100
+ - Mixed code and documentation diffs are classified by the functional change rather than mislabelled as docs
98
101
 
99
102
  ---
100
103
 
@@ -261,6 +264,8 @@ git cai -g
261
264
  - `stats` – opt in to local-only usage analytics (per-run row in a SQLite DB at `~/.local/share/git-cai/stats.db`); default `false`.
262
265
  No diff content, commit messages, or file paths are stored — only metadata (provider, model, kind, repo name, token counts, latency, settings)
263
266
  - `signoff` – append a `Signed-off-by:` trailer (built from git `user.name` / `user.email`) to every commit message; default `false`
267
+ - `secret_scan` – scan the outgoing diff for likely secrets and ask before sending; default `true`. Bypass once with `-B` / `--allow-secrets`,
268
+ or disable entirely by setting it to `false`. Skipped for tokenless providers (Ollama), where nothing leaves the machine
264
269
 
265
270
  ---
266
271
 
@@ -268,8 +273,9 @@ No diff content, commit messages, or file paths are stored — only metadata (pr
268
273
 
269
274
  In addition to `git cai`, the following options are available:
270
275
 
271
- - `-A`, `--amend` – regenerate and amend the last commit message
276
+ - `-A`, `--amend` – refine the last commit message against its diff and amend it (preserves trailers and original intent)
272
277
  - `-a`, `--all` – stage all tracked modified and deleted files
278
+ - `-B`, `--allow-secrets` – bypass the local secret scan and send the diff even if a likely secret is detected
273
279
  - `-b`, `--branch` – include current branch name as context for the LLM
274
280
  - `-C`, `--conventional` – use Conventional Commits format (`type(scope): description`)
275
281
  - `-c`, `--crazy` – Trust the LLM and commit without checking
@@ -282,8 +288,10 @@ In addition to `git cai`, the following options are available:
282
288
  - `-h`, `--help` – show help and available commands
283
289
  - `-I`, `--init` – interactive setup wizard (writes home config and tokens.yml)
284
290
  - `-i`, `--install-completion` – install shell completion for bash, zsh, or fish
291
+ - `-k`, `--check` – run configuration diagnostics offline (config source, provider, token, prompts, editor, style)
285
292
  - `-l`, `--list` – list available information. Valid types: `config`, `editor`, `language`, `model`, `path`, `provider`, `style`
286
293
  - `-m`, `--model` – override the model for this invocation (requires `-P`)
294
+ - `-n`, `--ping` – with `--check`, also send a tiny request to the active provider to confirm reachability
287
295
  - `-o`, `--signoff` / `--no-signoff` – append a `Signed-off-by:` trailer (uses git `user.name` / `user.email`); applies to commit, amend, and squash modes
288
296
  - `-P`, `--provider` – override the LLM provider for this invocation
289
297
  - `-p`, `--generate-prompts` – generate default `commit_prompt.md` and `squash_prompt.md` in the current directory (for customization)
@@ -310,14 +318,17 @@ In addition to `git cai`, the following options are available:
310
318
 
311
319
  ### Amend
312
320
 
313
- To regenerate the last commit message and amend it:
321
+ To refine the last commit message and amend it:
314
322
 
315
323
  ```sh
316
324
  git cai -A
317
325
  ```
318
326
 
319
- This reads the diff from the most recent commit, sends it to the LLM, and opens the editor for review.
320
- Use with `-c` to amend immediately without the editor: `git cai -A -c`.
327
+ This reads the diff from the most recent commit and sends both the diff and the
328
+ existing message to the LLM, which improves the wording while keeping the
329
+ original intent and any trailers (issue IDs, `Co-authored-by`). The result opens
330
+ in the editor for review. Use with `-c` to amend immediately without the editor:
331
+ `git cai -A -c`.
321
332
 
322
333
  ### Conventional Commits
323
334
 
@@ -466,6 +477,45 @@ git cai -H language=de
466
477
  git cai -H emoji=false
467
478
  ```
468
479
 
480
+ ### Configuration check (doctor)
481
+
482
+ `-k` / `--check` runs a set of offline diagnostics so you can confirm cai is
483
+ set up correctly without contacting any provider. It reports the authoritative
484
+ config source, validates the config keys, checks the active provider block, the
485
+ token and `tokens.yml` permissions, prompt resolution, the editor on your PATH,
486
+ and the configured style.
487
+
488
+ ```sh
489
+ git cai -k # offline diagnostics only
490
+ git cai --check # long form
491
+ git cai -k -n # also probe the provider for reachability
492
+ git cai --check --ping # long form
493
+ ```
494
+
495
+ Add `-n` / `--ping` to send one tiny synthetic diff to the active provider and
496
+ confirm it is reachable (this consumes a minimal request). The command exits
497
+ non-zero if any check fails, so it works in scripts and CI.
498
+
499
+ ### Secret scanning
500
+
501
+ Before any diff leaves your machine, cai scans it for likely credentials
502
+ (private keys, AWS, OpenAI, GitHub, Slack, and Google keys). When something is
503
+ found, the location is shown as `path:line` with a masked value and you are
504
+ asked to confirm before anything is sent.
505
+
506
+ ```sh
507
+ git cai # scan runs automatically, prompts on a hit
508
+ git cai -B # bypass the scan for this run
509
+ git cai --allow-secrets # long form
510
+ git cai -S secret_scan=false # disable the scan persistently
511
+ ```
512
+
513
+ Obvious placeholders (`example`, `dummy`, repeated filler, and similar) are
514
+ ignored to keep the noise down, and the scan is skipped entirely for tokenless
515
+ providers such as Ollama, where nothing leaves the machine. In non-interactive
516
+ runs (`-c` / `--crazy`, or no TTY) a detection aborts the send instead of
517
+ prompting; re-run with `-B` to override.
518
+
469
519
  ---
470
520
 
471
521
  ## License
@@ -49,7 +49,7 @@ Currently supported providers:
49
49
  - Global configuration with per-repository overrides
50
50
  - Interactive `--init` wizard for first-time setup (provider, token, language, style)
51
51
  - Repository-specific language, style, and model selection
52
- - Amend the last commit message with a regenerated one
52
+ - Amend mode refines the existing commit message instead of regenerating it from scratch, preserving trailers and intent
53
53
  - Conventional Commits format support
54
54
  - `Signed-off-by:` (DCO) trailer support via `--signoff`
55
55
  - `--print` mode that emits the generated message to stdout for scripting
@@ -65,6 +65,9 @@ Currently supported providers:
65
65
  - Generation time measurement
66
66
  - Local-only usage analytics (per-provider commits, tokens, latency) with opt-in SQLite storage
67
67
  - Shell completion for bash, zsh, and fish
68
+ - Local secret scan that blocks the diff before it reaches the provider when likely credentials are detected
69
+ - Configuration doctor (`--check`) that validates your setup offline, with an optional live provider probe (`--ping`)
70
+ - Mixed code and documentation diffs are classified by the functional change rather than mislabelled as docs
68
71
 
69
72
  ---
70
73
 
@@ -231,6 +234,8 @@ git cai -g
231
234
  - `stats` – opt in to local-only usage analytics (per-run row in a SQLite DB at `~/.local/share/git-cai/stats.db`); default `false`.
232
235
  No diff content, commit messages, or file paths are stored — only metadata (provider, model, kind, repo name, token counts, latency, settings)
233
236
  - `signoff` – append a `Signed-off-by:` trailer (built from git `user.name` / `user.email`) to every commit message; default `false`
237
+ - `secret_scan` – scan the outgoing diff for likely secrets and ask before sending; default `true`. Bypass once with `-B` / `--allow-secrets`,
238
+ or disable entirely by setting it to `false`. Skipped for tokenless providers (Ollama), where nothing leaves the machine
234
239
 
235
240
  ---
236
241
 
@@ -238,8 +243,9 @@ No diff content, commit messages, or file paths are stored — only metadata (pr
238
243
 
239
244
  In addition to `git cai`, the following options are available:
240
245
 
241
- - `-A`, `--amend` – regenerate and amend the last commit message
246
+ - `-A`, `--amend` – refine the last commit message against its diff and amend it (preserves trailers and original intent)
242
247
  - `-a`, `--all` – stage all tracked modified and deleted files
248
+ - `-B`, `--allow-secrets` – bypass the local secret scan and send the diff even if a likely secret is detected
243
249
  - `-b`, `--branch` – include current branch name as context for the LLM
244
250
  - `-C`, `--conventional` – use Conventional Commits format (`type(scope): description`)
245
251
  - `-c`, `--crazy` – Trust the LLM and commit without checking
@@ -252,8 +258,10 @@ In addition to `git cai`, the following options are available:
252
258
  - `-h`, `--help` – show help and available commands
253
259
  - `-I`, `--init` – interactive setup wizard (writes home config and tokens.yml)
254
260
  - `-i`, `--install-completion` – install shell completion for bash, zsh, or fish
261
+ - `-k`, `--check` – run configuration diagnostics offline (config source, provider, token, prompts, editor, style)
255
262
  - `-l`, `--list` – list available information. Valid types: `config`, `editor`, `language`, `model`, `path`, `provider`, `style`
256
263
  - `-m`, `--model` – override the model for this invocation (requires `-P`)
264
+ - `-n`, `--ping` – with `--check`, also send a tiny request to the active provider to confirm reachability
257
265
  - `-o`, `--signoff` / `--no-signoff` – append a `Signed-off-by:` trailer (uses git `user.name` / `user.email`); applies to commit, amend, and squash modes
258
266
  - `-P`, `--provider` – override the LLM provider for this invocation
259
267
  - `-p`, `--generate-prompts` – generate default `commit_prompt.md` and `squash_prompt.md` in the current directory (for customization)
@@ -280,14 +288,17 @@ In addition to `git cai`, the following options are available:
280
288
 
281
289
  ### Amend
282
290
 
283
- To regenerate the last commit message and amend it:
291
+ To refine the last commit message and amend it:
284
292
 
285
293
  ```sh
286
294
  git cai -A
287
295
  ```
288
296
 
289
- This reads the diff from the most recent commit, sends it to the LLM, and opens the editor for review.
290
- Use with `-c` to amend immediately without the editor: `git cai -A -c`.
297
+ This reads the diff from the most recent commit and sends both the diff and the
298
+ existing message to the LLM, which improves the wording while keeping the
299
+ original intent and any trailers (issue IDs, `Co-authored-by`). The result opens
300
+ in the editor for review. Use with `-c` to amend immediately without the editor:
301
+ `git cai -A -c`.
291
302
 
292
303
  ### Conventional Commits
293
304
 
@@ -436,6 +447,45 @@ git cai -H language=de
436
447
  git cai -H emoji=false
437
448
  ```
438
449
 
450
+ ### Configuration check (doctor)
451
+
452
+ `-k` / `--check` runs a set of offline diagnostics so you can confirm cai is
453
+ set up correctly without contacting any provider. It reports the authoritative
454
+ config source, validates the config keys, checks the active provider block, the
455
+ token and `tokens.yml` permissions, prompt resolution, the editor on your PATH,
456
+ and the configured style.
457
+
458
+ ```sh
459
+ git cai -k # offline diagnostics only
460
+ git cai --check # long form
461
+ git cai -k -n # also probe the provider for reachability
462
+ git cai --check --ping # long form
463
+ ```
464
+
465
+ Add `-n` / `--ping` to send one tiny synthetic diff to the active provider and
466
+ confirm it is reachable (this consumes a minimal request). The command exits
467
+ non-zero if any check fails, so it works in scripts and CI.
468
+
469
+ ### Secret scanning
470
+
471
+ Before any diff leaves your machine, cai scans it for likely credentials
472
+ (private keys, AWS, OpenAI, GitHub, Slack, and Google keys). When something is
473
+ found, the location is shown as `path:line` with a masked value and you are
474
+ asked to confirm before anything is sent.
475
+
476
+ ```sh
477
+ git cai # scan runs automatically, prompts on a hit
478
+ git cai -B # bypass the scan for this run
479
+ git cai --allow-secrets # long form
480
+ git cai -S secret_scan=false # disable the scan persistently
481
+ ```
482
+
483
+ Obvious placeholders (`example`, `dummy`, repeated filler, and similar) are
484
+ ignored to keep the noise down, and the scan is skipped entirely for tokenless
485
+ providers such as Ollama, where nothing leaves the machine. In non-interactive
486
+ runs (`-c` / `--crazy`, or no TTY) a detection aborts the send instead of
487
+ prompting; re-run with `-B` to override.
488
+
439
489
  ---
440
490
 
441
491
  ## License
@@ -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
+ [-B | --allow-secrets] [-k | --check] [-n | --ping]
15
16
  [-e TEMPERATURE | --temperature TEMPERATURE]
16
17
  [-F | --full-files | --no-full-files] [-f PATH | --files PATH]
17
18
  [-g | --generate-config]
@@ -93,6 +94,10 @@ so you can review or adjust the message before amending. This is useful when
93
94
  the original commit message was poorly worded or when you want the LLM to
94
95
  produce a better summary.
95
96
  +
97
+ git-cai also sends the existing commit message to the LLM, so it refines and
98
+ improves the current wording instead of starting over, preserving issue
99
+ references and trailers such as `Co-authored-by`.
100
+ +
96
101
  Combine with `-c` to skip the editor and amend immediately.
97
102
  +
98
103
  Cannot be combined with `--squash` or `--list`.
@@ -113,6 +118,18 @@ Cannot be combined with `--list`, `--update`, or `--squash`.
113
118
  git cai -a
114
119
  ----
115
120
 
121
+ -B, --allow-secrets::
122
+ Bypass the local secret scan for this invocation and send the diff to the LLM
123
+ even if a likely secret (API key, token, private key) is detected. By default
124
+ git-cai scans the exact content it is about to send and blocks on a match; use
125
+ this flag in non-interactive contexts where you have confirmed the match is a
126
+ false positive. See also the `secret_scan` config key.
127
+ +
128
+ ----
129
+ git cai -B
130
+ git cai -A --allow-secrets
131
+ ----
132
+
116
133
  -b, --branch / --no-branch::
117
134
  Include the current Git branch name as context when generating the commit
118
135
  message. The LLM uses the branch name to better understand the intent and
@@ -306,6 +323,31 @@ file for the completions to take effect.
306
323
  git cai -i
307
324
  ----
308
325
 
326
+ -k, --check::
327
+ Run configuration diagnostics and exit. The check is offline by default: it
328
+ reports which config is authoritative (repository, home, or built-in), validates
329
+ the config keys, confirms the default provider has a model/temperature and a
330
+ usable token, that the commit/squash/full-files/PR prompts resolve, and that the
331
+ configured editor is on `PATH`. Exits non-zero if any check fails. Add `--ping`
332
+ to also probe the active provider with a tiny live request.
333
+ +
334
+ Cannot be combined with other mode flags (`--amend`, `--squash`, `--PR`,
335
+ `--list`, `--stats`, `--init`, `--update`).
336
+ +
337
+ ----
338
+ git cai --check
339
+ git cai --check --ping
340
+ ----
341
+
342
+ -n, --ping::
343
+ Only meaningful together with `--check`. After the offline checks, send one
344
+ small request to the active provider and report whether it is reachable and how
345
+ long it took. Useful to confirm an API key and network path end to end.
346
+ +
347
+ ----
348
+ git cai --check --ping
349
+ ----
350
+
309
351
  -l, --list [config|editor|language|model|path|provider|style]::
310
352
  List information about a specific category. Provide one of the supported
311
353
  list types as the next argument. Without an argument, a help text is shown
@@ -865,6 +907,25 @@ Available configuration keys:
865
907
  - `emoji` -- enable or disable emojis in commit messages (`true`/`false`)
866
908
  - `branch_context` -- include current branch name as LLM context (`true`/`false`)
867
909
  - `conventional` -- use Conventional Commits format (`true`/`false`)
910
+ - `secret_scan` -- scan the diff (and any full-file contents) for likely
911
+ secrets before sending to the LLM (`true`/`false`, default `true`). On a
912
+ match the send is blocked and you are asked to confirm (or pass
913
+ `--allow-secrets`); each finding reports the file and line. Only distinctive
914
+ credential formats are flagged (private keys, AWS/GitHub/Slack/Google/OpenAI
915
+ keys); obvious placeholders (values containing `example`, `sample`, `dummy`,
916
+ and repeated-character filler) are ignored. Local providers (Ollama) skip the
917
+ scan, since nothing leaves the machine. When you confirm a flagged send in an
918
+ interactive commit (a false alarm), git-cai offers, per flagged file, to
919
+ remember the decision: add the file to `.caiignore` (drop it from git-cai
920
+ entirely), add it to `secret_scan_exclude` (keep sending it but skip its
921
+ scan), or skip (remember nothing).
922
+ - `secret_scan_exclude` -- list of repo-relative paths whose contents are
923
+ exempt from the secret scan while still being sent to the LLM (default empty).
924
+ Use this for files that keep tripping a false positive (such as test fixtures)
925
+ but that you still want git-cai to see. Paths are matched with gitignore
926
+ semantics, like `.caiignore`, so directory patterns work too. The
927
+ false-alarm prompt writes here when you choose "keep, skip scan", targeting
928
+ the repository `cai_config.yml` if one exists, otherwise the home config.
868
929
  - `load_tokens_from` -- path to the tokens file
869
930
  - `prompt_file` -- path to the commit prompt Markdown file
870
931
  - `squash_prompt_file` -- path to the squash prompt Markdown file
@@ -2,12 +2,12 @@
2
2
  .\" Title: git-cai
3
3
  .\" Author: Thorsten Foltz
4
4
  .\" Generator: Asciidoctor 2.0.26
5
- .\" Date: 2026-06-14
5
+ .\" Date: 2026-06-24
6
6
  .\" Manual: \ \&
7
7
  .\" Source: \ \&
8
8
  .\" Language: English
9
9
  .\"
10
- .TH "GIT\-CAI" "1" "2026-06-14" "\ \&" "\ \&"
10
+ .TH "GIT\-CAI" "1" "2026-06-24" "\ \&" "\ \&"
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
+ [\-B | \-\-allow\-secrets] [\-k | \-\-check] [\-n | \-\-ping]
37
38
  [\-e TEMPERATURE | \-\-temperature TEMPERATURE]
38
39
  [\-F | \-\-full\-files | \-\-no\-full\-files] [\-f PATH | \-\-files PATH]
39
40
  [\-g | \-\-generate\-config]
@@ -219,6 +220,10 @@ so you can review or adjust the message before amending. This is useful when
219
220
  the original commit message was poorly worded or when you want the LLM to
220
221
  produce a better summary.
221
222
  .sp
223
+ git\-cai also sends the existing commit message to the LLM, so it refines and
224
+ improves the current wording instead of starting over, preserving issue
225
+ references and trailers such as \f(CRCo\-authored\-by\fP.
226
+ .sp
222
227
  Combine with \f(CR\-c\fP to skip the editor and amend immediately.
223
228
  .sp
224
229
  Cannot be combined with \f(CR\-\-squash\fP or \f(CR\-\-list\fP.
@@ -250,6 +255,24 @@ git cai \-a
250
255
  .if n .RE
251
256
  .RE
252
257
  .sp
258
+ \-B, \-\-allow\-secrets
259
+ .RS 4
260
+ Bypass the local secret scan for this invocation and send the diff to the LLM
261
+ even if a likely secret (API key, token, private key) is detected. By default
262
+ git\-cai scans the exact content it is about to send and blocks on a match; use
263
+ this flag in non\-interactive contexts where you have confirmed the match is a
264
+ false positive. See also the \f(CRsecret_scan\fP config key.
265
+ .sp
266
+ .if n .RS 4
267
+ .nf
268
+ .fam C
269
+ git cai \-B
270
+ git cai \-A \-\-allow\-secrets
271
+ .fam
272
+ .fi
273
+ .if n .RE
274
+ .RE
275
+ .sp
253
276
  \-b, \-\-branch / \-\-no\-branch
254
277
  .RS 4
255
278
  Include the current Git branch name as context when generating the commit
@@ -527,6 +550,43 @@ git cai \-i
527
550
  .if n .RE
528
551
  .RE
529
552
  .sp
553
+ \-k, \-\-check
554
+ .RS 4
555
+ Run configuration diagnostics and exit. The check is offline by default: it
556
+ reports which config is authoritative (repository, home, or built\-in), validates
557
+ the config keys, confirms the default provider has a model/temperature and a
558
+ usable token, that the commit/squash/full\-files/PR prompts resolve, and that the
559
+ configured editor is on \f(CRPATH\fP. Exits non\-zero if any check fails. Add \f(CR\-\-ping\fP
560
+ to also probe the active provider with a tiny live request.
561
+ .sp
562
+ Cannot be combined with other mode flags (\f(CR\-\-amend\fP, \f(CR\-\-squash\fP, \f(CR\-\-PR\fP,
563
+ \f(CR\-\-list\fP, \f(CR\-\-stats\fP, \f(CR\-\-init\fP, \f(CR\-\-update\fP).
564
+ .sp
565
+ .if n .RS 4
566
+ .nf
567
+ .fam C
568
+ git cai \-\-check
569
+ git cai \-\-check \-\-ping
570
+ .fam
571
+ .fi
572
+ .if n .RE
573
+ .RE
574
+ .sp
575
+ \-n, \-\-ping
576
+ .RS 4
577
+ Only meaningful together with \f(CR\-\-check\fP. After the offline checks, send one
578
+ small request to the active provider and report whether it is reachable and how
579
+ long it took. Useful to confirm an API key and network path end to end.
580
+ .sp
581
+ .if n .RS 4
582
+ .nf
583
+ .fam C
584
+ git cai \-\-check \-\-ping
585
+ .fam
586
+ .fi
587
+ .if n .RE
588
+ .RE
589
+ .sp
530
590
  \-l, \-\-list [config|editor|language|model|path|provider|style]
531
591
  .RS 4
532
592
  List information about a specific category. Provide one of the supported
@@ -1389,6 +1449,45 @@ Available configuration keys:
1389
1449
  . sp -1
1390
1450
  . IP \(bu 2.3
1391
1451
  .\}
1452
+ \f(CRsecret_scan\fP \(em scan the diff (and any full\-file contents) for likely
1453
+ secrets before sending to the LLM (\f(CRtrue\fP/\f(CRfalse\fP, default \f(CRtrue\fP). On a
1454
+ match the send is blocked and you are asked to confirm (or pass
1455
+ \f(CR\-\-allow\-secrets\fP); each finding reports the file and line. Only distinctive
1456
+ credential formats are flagged (private keys, AWS/GitHub/Slack/Google/OpenAI
1457
+ keys); obvious placeholders (values containing \f(CRexample\fP, \f(CRsample\fP, \f(CRdummy\fP,
1458
+ and repeated\-character filler) are ignored. Local providers (Ollama) skip the
1459
+ scan, since nothing leaves the machine. When you confirm a flagged send in an
1460
+ interactive commit (a false alarm), git\-cai offers, per flagged file, to
1461
+ remember the decision: add the file to \f(CR.caiignore\fP (drop it from git\-cai
1462
+ entirely), add it to \f(CRsecret_scan_exclude\fP (keep sending it but skip its
1463
+ scan), or skip (remember nothing).
1464
+ .RE
1465
+ .sp
1466
+ .RS 4
1467
+ .ie n \{\
1468
+ \h'-04'\(bu\h'+03'\c
1469
+ .\}
1470
+ .el \{\
1471
+ . sp -1
1472
+ . IP \(bu 2.3
1473
+ .\}
1474
+ \f(CRsecret_scan_exclude\fP \(em list of repo\-relative paths whose contents are
1475
+ exempt from the secret scan while still being sent to the LLM (default empty).
1476
+ Use this for files that keep tripping a false positive (such as test fixtures)
1477
+ but that you still want git\-cai to see. Paths are matched with gitignore
1478
+ semantics, like \f(CR.caiignore\fP, so directory patterns work too. The
1479
+ false\-alarm prompt writes here when you choose "keep, skip scan", targeting
1480
+ the repository \f(CRcai_config.yml\fP if one exists, otherwise the home config.
1481
+ .RE
1482
+ .sp
1483
+ .RS 4
1484
+ .ie n \{\
1485
+ \h'-04'\(bu\h'+03'\c
1486
+ .\}
1487
+ .el \{\
1488
+ . sp -1
1489
+ . IP \(bu 2.3
1490
+ .\}
1392
1491
  \f(CRload_tokens_from\fP \(em path to the tokens file
1393
1492
  .RE
1394
1493
  .sp
@@ -1,3 +1,5 @@
1
+ """git-cai-cli: AI-powered git commit message generator."""
2
+
1
3
  from ._version import __version__
2
4
 
3
5
  __all__ = ["__version__"]
@@ -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.2'
22
- __version_tuple__ = version_tuple = (0, 14, 2)
21
+ __version__ = version = '0.15.2'
22
+ __version_tuple__ = version_tuple = (0, 15, 2)
23
23
 
24
- __commit_id__ = commit_id = 'gf575cff14'
24
+ __commit_id__ = commit_id = 'g12ea7cd4d'
@@ -203,6 +203,24 @@ def callback( # pylint: disable=too-many-arguments,too-many-positional-argument
203
203
  "--emoji/--no-emoji",
204
204
  help="Override emoji usage for this invocation. Use --no-emoji to disable when config enables it.",
205
205
  ),
206
+ check: bool = typer.Option(
207
+ False,
208
+ "-k",
209
+ "--check",
210
+ help="Run configuration diagnostics (offline). Add --ping for a live provider probe.",
211
+ ),
212
+ ping: bool = typer.Option(
213
+ False,
214
+ "-n",
215
+ "--ping",
216
+ help="With --check, also send a tiny request to the active provider to confirm reachability.",
217
+ ),
218
+ allow_secrets: bool = typer.Option(
219
+ False,
220
+ "-B",
221
+ "--allow-secrets",
222
+ help="Bypass the local secret scan and send the diff even if a likely secret is detected.",
223
+ ),
206
224
  ):
207
225
  """
208
226
  CLI entry point for git-cai-cli.
@@ -224,6 +242,7 @@ def callback( # pylint: disable=too-many-arguments,too-many-positional-argument
224
242
 
225
243
  mode = resolve_mode(
226
244
  amend=amend,
245
+ check=check,
227
246
  init=init,
228
247
  list_flag=list_flag,
229
248
  pr=pr,
@@ -232,6 +251,10 @@ def callback( # pylint: disable=too-many-arguments,too-many-positional-argument
232
251
  update=update,
233
252
  )
234
253
 
254
+ if ping and not check:
255
+ typer.echo("Error: --ping is only valid together with --check.", err=True)
256
+ raise typer.Exit(code=1)
257
+
235
258
  sql_override: bool | None = None
236
259
  if sql is not None:
237
260
  normalized = sql.strip().lower()
@@ -339,6 +362,8 @@ def callback( # pylint: disable=too-many-arguments,too-many-positional-argument
339
362
  style_override=style,
340
363
  language_override=language,
341
364
  emoji_override=emoji,
365
+ live_check=ping,
366
+ allow_secrets=allow_secrets,
342
367
  )
343
368
 
344
369
 
@@ -17,6 +17,7 @@ Usage:
17
17
  Flags:
18
18
  -A, --amend Regenerate and amend the last commit message
19
19
  -a, --all Stage all modified and deleted files that are already tracked by Git
20
+ -B, --allow-secrets Bypass the local secret scan and send even if a secret is detected
20
21
  -b, --branch Include current branch name as context for the LLM
21
22
  -C, --conventional Use Conventional Commits format (type(scope): description)
22
23
  -c, --crazy Commit immediately without opening editor (trust LLM output)
@@ -30,10 +31,12 @@ Flags:
30
31
  -h, --help Show this help message or opens manual
31
32
  -I, --init Interactive setup wizard (writes home config and tokens.yml)
32
33
  -i, --install-completion Install shell completion for git-cai
34
+ -k, --check Run configuration diagnostics (offline; add --ping for a live probe)
33
35
  -L, --language CODE Override the commit message language (e.g. de, fr, none)
34
36
  -l, --list [TYPE] List information. TYPE: config, editor, language,
35
37
  model, path, provider, style
36
38
  -m, --model NAME Override model for this invocation (requires --provider)
39
+ -n, --ping With --check, probe the active provider for reachability
37
40
  -o, --signoff Append a `Signed-off-by:` trailer (git user.name / user.email)
38
41
  -P, --provider NAME Override LLM provider for this invocation
39
42
  -p, --generate-prompts Generate default commit/squash/full_files/pr prompt files
@@ -13,6 +13,7 @@ class Mode(Enum):
13
13
  """
14
14
 
15
15
  AMEND = auto()
16
+ CHECK = auto()
16
17
  COMMIT = auto()
17
18
  INIT = auto()
18
19
  LIST = auto()
@@ -25,6 +26,7 @@ class Mode(Enum):
25
26
  def resolve_mode(
26
27
  *,
27
28
  amend: bool,
29
+ check: bool = False,
28
30
  init: bool = False,
29
31
  list_flag: bool,
30
32
  pr: bool,
@@ -35,17 +37,19 @@ def resolve_mode(
35
37
  """
36
38
  Resolves the operational mode based on the provided flags.
37
39
  """
38
- flags = [amend, init, list_flag, pr, squash, stats, update]
40
+ flags = [amend, check, init, list_flag, pr, squash, stats, update]
39
41
  if sum(flags) > 1:
40
42
  typer.echo(
41
- "Error: --amend, --init, --list, --PR, --squash, --stats, and --update "
42
- "cannot be used together.",
43
+ "Error: --amend, --check, --init, --list, --PR, --squash, --stats, and "
44
+ "--update cannot be used together.",
43
45
  err=True,
44
46
  )
45
47
  raise typer.Exit(code=1)
46
48
 
47
49
  if amend:
48
50
  return Mode.AMEND
51
+ if check:
52
+ return Mode.CHECK
49
53
  if init:
50
54
  return Mode.INIT
51
55
  if list_flag: