gac 1.8.0__py3-none-any.whl → 1.9.1__py3-none-any.whl

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.

Potentially problematic release.


This version of gac might be problematic. Click here for more details.

gac/__version__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Version information for gac package."""
2
2
 
3
- __version__ = "1.8.0"
3
+ __version__ = "1.9.1"
gac/ai.py CHANGED
@@ -73,7 +73,7 @@ def generate_commit_message(
73
73
  "chutes": call_chutes_api,
74
74
  "gemini": call_gemini_api,
75
75
  "groq": call_groq_api,
76
- "lmstudio": call_lmstudio_api,
76
+ "lm-studio": call_lmstudio_api,
77
77
  "ollama": call_ollama_api,
78
78
  "openai": call_openai_api,
79
79
  "openrouter": call_openrouter_api,
gac/ai_utils.py CHANGED
@@ -96,6 +96,7 @@ def generate_with_retries(
96
96
  supported_providers = [
97
97
  "anthropic",
98
98
  "cerebras",
99
+ "chutes",
99
100
  "gemini",
100
101
  "groq",
101
102
  "lm-studio",
gac/cli.py CHANGED
@@ -45,7 +45,12 @@ logger = logging.getLogger(__name__)
45
45
  @click.option("--model", "-m", help="Override the default model (format: 'provider:model_name')")
46
46
  # Output options
47
47
  @click.option("--quiet", "-q", is_flag=True, help="Suppress non-error output")
48
- @click.option("--verbose", "-v", is_flag=True, help="Increase output verbosity to INFO")
48
+ @click.option(
49
+ "--verbose",
50
+ "-v",
51
+ is_flag=True,
52
+ help="Generate detailed commit messages with motivation, architecture, and impact sections",
53
+ )
49
54
  @click.option(
50
55
  "--log-level",
51
56
  default=config["log_level"],
@@ -82,8 +87,6 @@ def cli(
82
87
  print(f"Git Auto Commit (gac) version: {__version__}")
83
88
  sys.exit(0)
84
89
  effective_log_level = log_level
85
- if verbose and log_level not in ("DEBUG", "INFO"):
86
- effective_log_level = "INFO"
87
90
  if quiet:
88
91
  effective_log_level = "ERROR"
89
92
  setup_logging(effective_log_level)
@@ -92,6 +95,9 @@ def cli(
92
95
  # Determine if we should infer scope based on -s flag or always_include_scope setting
93
96
  infer_scope = bool(scope or config.get("always_include_scope", False))
94
97
 
98
+ # Determine if verbose mode should be enabled based on -v flag or verbose config setting
99
+ use_verbose = bool(verbose or config.get("verbose", False))
100
+
95
101
  try:
96
102
  main(
97
103
  stage_all=add_all,
@@ -104,6 +110,7 @@ def cli(
104
110
  push=push,
105
111
  quiet=quiet,
106
112
  dry_run=dry_run,
113
+ verbose=use_verbose,
107
114
  no_verify=no_verify,
108
115
  skip_secret_scan=skip_secret_scan or bool(config.get("skip_secret_scan", False)),
109
116
  )
gac/config.py CHANGED
@@ -37,6 +37,7 @@ def load_config() -> dict[str, str | int | float | bool]:
37
37
  in ("true", "1", "yes", "on"),
38
38
  "skip_secret_scan": os.getenv("GAC_SKIP_SECRET_SCAN", str(EnvDefaults.SKIP_SECRET_SCAN)).lower()
39
39
  in ("true", "1", "yes", "on"),
40
+ "verbose": os.getenv("GAC_VERBOSE", str(EnvDefaults.VERBOSE)).lower() in ("true", "1", "yes", "on"),
40
41
  }
41
42
 
42
43
  return config
gac/constants.py CHANGED
@@ -25,6 +25,7 @@ class EnvDefaults:
25
25
  WARNING_LIMIT_TOKENS: int = 16384
26
26
  ALWAYS_INCLUDE_SCOPE: bool = False
27
27
  SKIP_SECRET_SCAN: bool = False
28
+ VERBOSE: bool = False
28
29
 
29
30
 
30
31
  class Logging:
gac/main.py CHANGED
@@ -43,6 +43,7 @@ def main(
43
43
  push: bool = False,
44
44
  quiet: bool = False,
45
45
  dry_run: bool = False,
46
+ verbose: bool = False,
46
47
  no_verify: bool = False,
47
48
  skip_secret_scan: bool = False,
48
49
  ) -> None:
@@ -178,6 +179,7 @@ def main(
178
179
  one_liner=one_liner,
179
180
  hint=hint,
180
181
  infer_scope=infer_scope,
182
+ verbose=verbose,
181
183
  )
182
184
 
183
185
  if show_prompt:
@@ -275,6 +277,7 @@ def main(
275
277
  one_liner=one_liner,
276
278
  hint=combined_hint,
277
279
  infer_scope=infer_scope,
280
+ verbose=verbose,
278
281
  )
279
282
  else:
280
283
  # No hint given, just reroll with same prompts
gac/prompt.py CHANGED
@@ -43,7 +43,43 @@ When changes span multiple areas:
43
43
  - Detailed body with multiple bullet points explaining the key changes
44
44
  - Focus on WHY changes were made, not just WHAT was changed
45
45
  - Order points from most important to least important
46
- </multi_line>
46
+ </multi_line><verbose>
47
+ IMPORTANT: You MUST create a MULTI-PARAGRAPH commit message with detailed sections.
48
+ DO NOT create a single-line commit message.
49
+
50
+ Your commit message MUST follow this structure:
51
+
52
+ Line 1: A concise summary (up to ~72 characters) with conventional commit prefix
53
+ Line 2: BLANK LINE (required)
54
+ Lines 3+: Detailed multi-paragraph body with the following sections:
55
+
56
+ ## Motivation
57
+ Explain why this commit exists in 2-3 sentences. What problem does it solve? What need does it address?
58
+
59
+ ## Architecture / Approach
60
+ Describe how it was implemented in 2-4 sentences. Include key design decisions and any rejected alternatives.
61
+ Reference specific modules, functions, or classes when relevant.
62
+
63
+ ## Affected Components
64
+ List the main modules, subsystems, or directories impacted by this change.
65
+
66
+ OPTIONAL sections (include only if relevant):
67
+
68
+ ## Performance / Security Impact
69
+ Describe any performance improvements, trade-offs, or security considerations.
70
+ Include concrete data such as benchmark results if available.
71
+
72
+ ## Compatibility / Testing
73
+ Mention any compatibility considerations, known limitations, testing performed, or next steps for validation.
74
+
75
+ REQUIREMENTS:
76
+ - Your response MUST be at least 10 lines long with multiple paragraphs
77
+ - Use active voice and present tense ("Implements", "Adds", "Refactors")
78
+ - Provide concrete, specific information rather than vague descriptions
79
+ - Keep the tone professional and technical
80
+ - Focus on intent and reasoning, not just code changes
81
+ - Use markdown headers (##) for section organization
82
+ </verbose>
47
83
  </format>
48
84
 
49
85
  <conventions_no_scope>
@@ -158,8 +194,50 @@ Bad commit messages:
158
194
  [ERROR] Changes
159
195
  </examples_no_scope>
160
196
 
197
+ <examples_verbose_no_scope>
198
+ Example of a good VERBOSE commit message (without scope):
199
+
200
+ feat: add verbose mode for detailed commit message generation
201
+
202
+ ## Motivation
203
+ Users need the ability to generate comprehensive commit messages that follow best practices for code review and documentation. The existing one-liner and multi-line modes don't provide sufficient structure for complex changes that require detailed explanations of motivation, architecture decisions, and impact.
204
+
205
+ ## Architecture / Approach
206
+ Adds a new --verbose/-v flag to the CLI that modifies the prompt generation in build_prompt(). When enabled, the prompt instructs the AI to generate commit messages with structured sections including Motivation, Architecture/Approach, Affected Components, and optional Performance/Testing sections. The implementation uses the existing format selection logic with verbose taking priority over one_liner and multi_line modes.
207
+
208
+ ## Affected Components
209
+ - src/gac/cli.py: Added --verbose flag and parameter passing
210
+ - src/gac/main.py: Extended main() to accept and pass verbose parameter
211
+ - src/gac/prompt.py: Added <verbose> template section with detailed instructions
212
+ - tests/test_prompt.py: Added test coverage for verbose mode
213
+
214
+ ## Compatibility / Testing
215
+ Added new test test_build_prompt_verbose_mode to verify the verbose template generation. All existing tests pass. The verbose mode is opt-in via the -v flag, maintaining backward compatibility.
216
+ </examples_verbose_no_scope>
217
+
218
+ <examples_verbose_with_scope>
219
+ Example of a good VERBOSE commit message (with scope):
220
+
221
+ feat(cli): add verbose mode for detailed commit message generation
222
+
223
+ ## Motivation
224
+ Users need the ability to generate comprehensive commit messages that follow best practices for code review and documentation. The existing one-liner and multi-line modes don't provide sufficient structure for complex changes that require detailed explanations of motivation, architecture decisions, and impact.
225
+
226
+ ## Architecture / Approach
227
+ Adds a new --verbose/-v flag to the CLI that modifies the prompt generation in build_prompt(). When enabled, the prompt instructs the AI to generate commit messages with structured sections including Motivation, Architecture/Approach, Affected Components, and optional Performance/Testing sections. The implementation uses the existing format selection logic with verbose taking priority over one_liner and multi_line modes.
228
+
229
+ ## Affected Components
230
+ - src/gac/cli.py: Added --verbose flag and parameter passing
231
+ - src/gac/main.py: Extended main() to accept and pass verbose parameter
232
+ - src/gac/prompt.py: Added <verbose> template section with detailed instructions
233
+ - tests/test_prompt.py: Added test coverage for verbose mode
234
+
235
+ ## Compatibility / Testing
236
+ Added new test test_build_prompt_verbose_mode to verify the verbose template generation. All existing tests pass. The verbose mode is opt-in via the -v flag, maintaining backward compatibility.
237
+ </examples_verbose_with_scope>
238
+
161
239
  <examples_with_scope>
162
- Good commit messages (with scope):
240
+ Good commit message top lines (with scope):
163
241
  [OK] feat(auth): add OAuth2 integration with Google and GitHub
164
242
  [OK] fix(api): resolve race condition in user session management
165
243
  [OK] docs(readme): add troubleshooting section for common installation issues
@@ -201,6 +279,7 @@ def build_prompt(
201
279
  one_liner: bool = False,
202
280
  infer_scope: bool = False,
203
281
  hint: str = "",
282
+ verbose: bool = False,
204
283
  ) -> tuple[str, str]:
205
284
  """Build system and user prompts for the AI model using the provided template and git information.
206
285
 
@@ -211,6 +290,7 @@ def build_prompt(
211
290
  one_liner: Whether to request a one-line commit message
212
291
  infer_scope: Whether to infer scope for the commit message
213
292
  hint: Optional hint to guide the AI
293
+ verbose: Whether to generate detailed commit messages with motivation, architecture, and impact sections
214
294
 
215
295
  Returns:
216
296
  Tuple of (system_prompt, user_prompt) ready to be sent to an AI model
@@ -251,21 +331,60 @@ def build_prompt(
251
331
  template = re.sub(r"<hint>.*?</hint>", "", template, flags=re.DOTALL)
252
332
  logger.debug("No hint provided")
253
333
 
254
- # Process format options (one-liner vs multi-line)
255
- if one_liner:
334
+ # Process format options (verbose, one-liner, or multi-line)
335
+ # Priority: verbose > one_liner > multi_line
336
+ if verbose:
337
+ # Verbose mode: remove one_liner and multi_line, keep verbose
338
+ template = re.sub(r"<one_liner>.*?</one_liner>", "", template, flags=re.DOTALL)
339
+ template = re.sub(r"<multi_line>.*?</multi_line>", "", template, flags=re.DOTALL)
340
+ elif one_liner:
341
+ # One-liner mode: remove multi_line and verbose
256
342
  template = re.sub(r"<multi_line>.*?</multi_line>", "", template, flags=re.DOTALL)
343
+ template = re.sub(r"<verbose>.*?</verbose>", "", template, flags=re.DOTALL)
257
344
  else:
345
+ # Multi-line mode (default): remove one_liner and verbose
258
346
  template = re.sub(r"<one_liner>.*?</one_liner>", "", template, flags=re.DOTALL)
347
+ template = re.sub(r"<verbose>.*?</verbose>", "", template, flags=re.DOTALL)
259
348
 
260
- # Clean up examples sections based on infer_scope settings
261
- if infer_scope:
262
- # With scope (inferred) - keep scope examples, remove no_scope examples
349
+ # Clean up examples sections based on verbose and infer_scope settings
350
+ if verbose and infer_scope:
351
+ # Verbose mode with scope - keep verbose_with_scope examples
352
+ template = re.sub(r"<examples_no_scope>.*?</examples_no_scope>\n?", "", template, flags=re.DOTALL)
353
+ template = re.sub(r"<examples_with_scope>.*?</examples_with_scope>\n?", "", template, flags=re.DOTALL)
354
+ template = re.sub(
355
+ r"<examples_verbose_no_scope>.*?</examples_verbose_no_scope>\n?", "", template, flags=re.DOTALL
356
+ )
357
+ template = template.replace("<examples_verbose_with_scope>", "<examples>")
358
+ template = template.replace("</examples_verbose_with_scope>", "</examples>")
359
+ elif verbose:
360
+ # Verbose mode without scope - keep verbose_no_scope examples
361
+ template = re.sub(r"<examples_no_scope>.*?</examples_no_scope>\n?", "", template, flags=re.DOTALL)
362
+ template = re.sub(r"<examples_with_scope>.*?</examples_with_scope>\n?", "", template, flags=re.DOTALL)
363
+ template = re.sub(
364
+ r"<examples_verbose_with_scope>.*?</examples_verbose_with_scope>\n?", "", template, flags=re.DOTALL
365
+ )
366
+ template = template.replace("<examples_verbose_no_scope>", "<examples>")
367
+ template = template.replace("</examples_verbose_no_scope>", "</examples>")
368
+ elif infer_scope:
369
+ # With scope (inferred) - keep scope examples, remove all others
263
370
  template = re.sub(r"<examples_no_scope>.*?</examples_no_scope>\n?", "", template, flags=re.DOTALL)
371
+ template = re.sub(
372
+ r"<examples_verbose_no_scope>.*?</examples_verbose_no_scope>\n?", "", template, flags=re.DOTALL
373
+ )
374
+ template = re.sub(
375
+ r"<examples_verbose_with_scope>.*?</examples_verbose_with_scope>\n?", "", template, flags=re.DOTALL
376
+ )
264
377
  template = template.replace("<examples_with_scope>", "<examples>")
265
378
  template = template.replace("</examples_with_scope>", "</examples>")
266
379
  else:
267
- # No scope - keep no_scope examples, remove scope examples
380
+ # No scope - keep no_scope examples, remove all others
268
381
  template = re.sub(r"<examples_with_scope>.*?</examples_with_scope>\n?", "", template, flags=re.DOTALL)
382
+ template = re.sub(
383
+ r"<examples_verbose_no_scope>.*?</examples_verbose_no_scope>\n?", "", template, flags=re.DOTALL
384
+ )
385
+ template = re.sub(
386
+ r"<examples_verbose_with_scope>.*?</examples_verbose_with_scope>\n?", "", template, flags=re.DOTALL
387
+ )
269
388
  template = template.replace("<examples_no_scope>", "<examples>")
270
389
  template = template.replace("</examples_no_scope>", "</examples>")
271
390
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gac
3
- Version: 1.8.0
3
+ Version: 1.9.1
4
4
  Summary: AI-powered Git commit message generator with multi-provider support
5
5
  Project-URL: Homepage, https://github.com/cellwebb/gac
6
6
  Project-URL: Documentation, https://github.com/cellwebb/gac#readme
@@ -60,7 +60,7 @@ Description-Content-Type: text/markdown
60
60
  - **Deep Contextual Analysis:** Understands your code by analyzing staged changes, repository structure, and recent commit history to provide highly relevant suggestions.
61
61
  - **Multi-Provider & Model Support:** Flexibly works with leading AI providers (Anthropic, Cerebras, Chutes.ai, Gemini, Groq, OpenAI, OpenRouter, Streamlake/Vanchin, Synthetic.new, & Z.AI) and local providers (LM Studio & Ollama), easily configured through an interactive setup or environment variables.
62
62
  - **Seamless Git Workflow:** Integrates smoothly into your existing Git routine as a simple drop-in replacement for `git commit`.
63
- - **Extensive Customization:** Tailor commit messages to your needs with a rich set of flags, including one-liners (`-o`), AI hints (`-h`), scope inference (`-s`), and specific model selection (`-m`).
63
+ - **Extensive Customization:** Tailor commit messages to your needs with a rich set of flags, including one-liners (`-o`), detailed verbose messages (`-v`), AI hints (`-h`), scope inference (`-s`), and specific model selection (`-m`).
64
64
  - **Streamlined Workflow Commands:** Boost your productivity with convenient options to stage all changes (`-a`), auto-confirm commits (`-y`), and push to your remote repository (`-p`) in a single step.
65
65
  - **Interactive Reroll with Feedback:** Not satisfied with the generated commit message? Use `r` for a simple regeneration, or `r <feedback>` to provide specific improvement suggestions (e.g., `r make it shorter`, `r focus on the bug fix`).
66
66
  - **Token Usage Tracking:** Display token consumption statistics (prompt, completion, and total tokens).
@@ -1,18 +1,18 @@
1
1
  gac/__init__.py,sha256=z9yGInqtycFIT3g1ca24r-A3699hKVaRqGUI79wsmMc,415
2
- gac/__version__.py,sha256=ZrEUwsZomybTNkOGMfS08i073_U6EUzf2X5DfW6ia3g,66
3
- gac/ai.py,sha256=T8o7ZenWDB94ILMvt5hp8mp_J6BbMJ3h5Y_0y2kRrX8,3512
4
- gac/ai_utils.py,sha256=kz_ROoJjFZGPXxiyy225MuvMv9DikiqJBXOqKVlLVlc,7253
5
- gac/cli.py,sha256=nvJW_FmS0xA8Vs7x-JdIu4mW9Ze7IelYP8bnZYVFB4E,4885
6
- gac/config.py,sha256=N62phuLUyVj54eLDiDL6VN8-2_Zt6yB5zsnimFavU3I,1630
2
+ gac/__version__.py,sha256=G1n_WKkZXSioJbRY3wekL5t5AcCwR3K2fA6ITDQQ1NI,66
3
+ gac/ai.py,sha256=-0rIZQCHC7yOEmkLtCLDzeInnrm960hVpiEELi8NM_U,3513
4
+ gac/ai_utils.py,sha256=dGfac6ZWQARZDnH6ygnqQ2W4eTIDh_wOx6iGg5lA_Gw,7271
5
+ gac/cli.py,sha256=15Io35xSvoZ7_q9ADgely1un0tAprNuLRPdghGaIQTg,5058
6
+ gac/config.py,sha256=nVEnjCPmobspQl9NEcFLBYcIeUi2J9cui8CEzqIHnFY,1739
7
7
  gac/config_cli.py,sha256=v9nFHZO1RvK9fzHyuUS6SG-BCLHMsdOMDwWamBhVVh4,1608
8
- gac/constants.py,sha256=hGzmLGhVDB2KPIqwtl6tHMNuSwHj-2P1RK0cGm4pyNA,4962
8
+ gac/constants.py,sha256=R3oUwPLk_uWnBkg-J7Or-vomRr-iVKeLf1xljJeKclo,4988
9
9
  gac/diff_cli.py,sha256=wnVQ9OFGnM0d2Pj9WVjWbo0jxqIuRHVAwmb8wU9Pa3E,5676
10
10
  gac/errors.py,sha256=ysDIVRCd0YQVTOW3Q6YzdolxCdtkoQCAFf3_jrqbjUY,7916
11
11
  gac/git.py,sha256=_Co25XA1Nku03h50C_HiEf4ugEz6rK5j_IYi-rr5gco,8005
12
12
  gac/init_cli.py,sha256=LEw26g-tb6GZdN3DaUuLx3OFvZPKPOIFKnqgDRe6Y8s,4677
13
- gac/main.py,sha256=ot1DEbJHsZ0SzdZUuRXIm9pz1xbm4hxARzUjwytGdfc,15670
13
+ gac/main.py,sha256=odWu_1Z0KVr--3duc4iFOE9ix0SGqykgzRDz-JY482c,15771
14
14
  gac/preprocess.py,sha256=krrLPHsccYMdn_YAtUrppBJIoRgevxGWusDwhE40LEo,15366
15
- gac/prompt.py,sha256=K6r9q2cAlyPu1fud6-jJsZ4zeweEo3yt6_WeYv8a_SQ,17087
15
+ gac/prompt.py,sha256=d_kBXmhf3bDVLyDj8J7AS7GBAxF2jlc8lXoHX3Dzi5k,24255
16
16
  gac/security.py,sha256=M1MZm6BLOeKl6rH_-UdXsSKol39FnA5fIP3YP394yZE,9898
17
17
  gac/utils.py,sha256=W3ladtmsH01MNLdckQYTzYrYbTGEdzCKI36he9C-y_E,3945
18
18
  gac/providers/__init__.py,sha256=ejIM5vvmfTp7vfJSNeQQPIEJusOkKTUZpUE7OeWBc9Y,876
@@ -28,8 +28,8 @@ gac/providers/openrouter.py,sha256=H3ce8JcRUYq1I30lOjGESdX7jfoPkW3mKAYnc2aYfBw,2
28
28
  gac/providers/streamlake.py,sha256=KAA2ZnpuEI5imzvdWVWUhEBHSP0BMnprKXte6CbwBWY,2047
29
29
  gac/providers/synthetic.py,sha256=sRMIJTS9LpcXd9A7qp_ZjZxdqtTKRn9fl1W4YwJZP4c,1855
30
30
  gac/providers/zai.py,sha256=kywhhrCfPBu0rElZyb-iENxQxxpVGykvePuL4xrXlaU,2739
31
- gac-1.8.0.dist-info/METADATA,sha256=4z_AS3NKai5FD1xvY8hYH_lWVGioLT7tpv93y_dhIAY,9245
32
- gac-1.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
- gac-1.8.0.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
34
- gac-1.8.0.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
35
- gac-1.8.0.dist-info/RECORD,,
31
+ gac-1.9.1.dist-info/METADATA,sha256=xUSS5EcAO1_k4RJ-ukG_XN7g_twtCy2F0jgjgn0RBLE,9279
32
+ gac-1.9.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
+ gac-1.9.1.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
34
+ gac-1.9.1.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
35
+ gac-1.9.1.dist-info/RECORD,,
File without changes