gac 3.8.1__py3-none-any.whl → 3.10.10__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.
Files changed (76) hide show
  1. gac/__init__.py +4 -6
  2. gac/__version__.py +1 -1
  3. gac/ai_utils.py +18 -49
  4. gac/cli.py +14 -10
  5. gac/commit_executor.py +59 -0
  6. gac/config.py +28 -3
  7. gac/config_cli.py +19 -7
  8. gac/constants/__init__.py +34 -0
  9. gac/constants/commit.py +63 -0
  10. gac/constants/defaults.py +40 -0
  11. gac/constants/file_patterns.py +110 -0
  12. gac/constants/languages.py +119 -0
  13. gac/diff_cli.py +0 -22
  14. gac/errors.py +8 -2
  15. gac/git.py +6 -6
  16. gac/git_state_validator.py +193 -0
  17. gac/grouped_commit_workflow.py +458 -0
  18. gac/init_cli.py +2 -1
  19. gac/interactive_mode.py +179 -0
  20. gac/language_cli.py +0 -1
  21. gac/main.py +222 -959
  22. gac/model_cli.py +2 -1
  23. gac/model_identifier.py +70 -0
  24. gac/oauth/claude_code.py +2 -2
  25. gac/oauth/qwen_oauth.py +4 -0
  26. gac/oauth/token_store.py +2 -2
  27. gac/oauth_retry.py +161 -0
  28. gac/postprocess.py +155 -0
  29. gac/prompt.py +20 -490
  30. gac/prompt_builder.py +88 -0
  31. gac/providers/README.md +437 -0
  32. gac/providers/__init__.py +70 -81
  33. gac/providers/anthropic.py +12 -56
  34. gac/providers/azure_openai.py +48 -92
  35. gac/providers/base.py +329 -0
  36. gac/providers/cerebras.py +10 -43
  37. gac/providers/chutes.py +16 -72
  38. gac/providers/claude_code.py +64 -97
  39. gac/providers/custom_anthropic.py +51 -85
  40. gac/providers/custom_openai.py +29 -87
  41. gac/providers/deepseek.py +10 -43
  42. gac/providers/error_handler.py +139 -0
  43. gac/providers/fireworks.py +10 -43
  44. gac/providers/gemini.py +66 -73
  45. gac/providers/groq.py +10 -62
  46. gac/providers/kimi_coding.py +19 -59
  47. gac/providers/lmstudio.py +62 -52
  48. gac/providers/minimax.py +10 -43
  49. gac/providers/mistral.py +10 -43
  50. gac/providers/moonshot.py +10 -43
  51. gac/providers/ollama.py +54 -41
  52. gac/providers/openai.py +30 -46
  53. gac/providers/openrouter.py +15 -62
  54. gac/providers/protocol.py +71 -0
  55. gac/providers/qwen.py +55 -67
  56. gac/providers/registry.py +58 -0
  57. gac/providers/replicate.py +137 -91
  58. gac/providers/streamlake.py +26 -56
  59. gac/providers/synthetic.py +35 -47
  60. gac/providers/together.py +10 -43
  61. gac/providers/zai.py +21 -59
  62. gac/py.typed +0 -0
  63. gac/security.py +1 -1
  64. gac/templates/__init__.py +1 -0
  65. gac/templates/question_generation.txt +60 -0
  66. gac/templates/system_prompt.txt +224 -0
  67. gac/templates/user_prompt.txt +28 -0
  68. gac/utils.py +6 -5
  69. gac/workflow_context.py +162 -0
  70. {gac-3.8.1.dist-info → gac-3.10.10.dist-info}/METADATA +1 -1
  71. gac-3.10.10.dist-info/RECORD +79 -0
  72. gac/constants.py +0 -328
  73. gac-3.8.1.dist-info/RECORD +0 -56
  74. {gac-3.8.1.dist-info → gac-3.10.10.dist-info}/WHEEL +0 -0
  75. {gac-3.8.1.dist-info → gac-3.10.10.dist-info}/entry_points.txt +0 -0
  76. {gac-3.8.1.dist-info → gac-3.10.10.dist-info}/licenses/LICENSE +0 -0
gac/providers/together.py CHANGED
@@ -1,48 +1,15 @@
1
1
  """Together AI API provider for gac."""
2
2
 
3
- import logging
4
- import os
3
+ from gac.providers.base import OpenAICompatibleProvider, ProviderConfig
5
4
 
6
- import httpx
7
5
 
8
- from gac.constants import ProviderDefaults
9
- from gac.errors import AIError
10
- from gac.utils import get_ssl_verify
6
+ class TogetherProvider(OpenAICompatibleProvider):
7
+ config = ProviderConfig(
8
+ name="Together",
9
+ api_key_env="TOGETHER_API_KEY",
10
+ base_url="https://api.together.xyz/v1",
11
+ )
11
12
 
12
- logger = logging.getLogger(__name__)
13
-
14
-
15
- def call_together_api(model: str, messages: list[dict], temperature: float, max_tokens: int) -> str:
16
- """Call Together AI API directly."""
17
- api_key = os.getenv("TOGETHER_API_KEY")
18
- if not api_key:
19
- raise AIError.authentication_error("TOGETHER_API_KEY not found in environment variables")
20
-
21
- url = "https://api.together.xyz/v1/chat/completions"
22
- headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
23
-
24
- data = {"model": model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens}
25
-
26
- logger.debug(f"Calling Together AI API with model={model}")
27
-
28
- try:
29
- response = httpx.post(
30
- url, headers=headers, json=data, timeout=ProviderDefaults.HTTP_TIMEOUT, verify=get_ssl_verify()
31
- )
32
- response.raise_for_status()
33
- response_data = response.json()
34
- content = response_data["choices"][0]["message"]["content"]
35
- if content is None:
36
- raise AIError.model_error("Together AI API returned null content")
37
- if content == "":
38
- raise AIError.model_error("Together AI API returned empty content")
39
- logger.debug("Together AI API response received successfully")
40
- return content
41
- except httpx.HTTPStatusError as e:
42
- if e.response.status_code == 429:
43
- raise AIError.rate_limit_error(f"Together AI API rate limit exceeded: {e.response.text}") from e
44
- raise AIError.model_error(f"Together AI API error: {e.response.status_code} - {e.response.text}") from e
45
- except httpx.TimeoutException as e:
46
- raise AIError.timeout_error(f"Together AI API request timed out: {str(e)}") from e
47
- except Exception as e:
48
- raise AIError.model_error(f"Error calling Together AI API: {str(e)}") from e
13
+ def _get_api_url(self, model: str | None = None) -> str:
14
+ """Get Together API URL with /chat/completions endpoint."""
15
+ return f"{self.config.base_url}/chat/completions"
gac/providers/zai.py CHANGED
@@ -1,69 +1,31 @@
1
1
  """Z.AI API provider for gac."""
2
2
 
3
- import logging
4
- import os
3
+ from gac.providers.base import OpenAICompatibleProvider, ProviderConfig
5
4
 
6
- import httpx
7
5
 
8
- from gac.constants import ProviderDefaults
9
- from gac.errors import AIError
10
- from gac.utils import get_ssl_verify
6
+ class ZAIProvider(OpenAICompatibleProvider):
7
+ """Z.AI regular API provider with OpenAI-compatible format."""
11
8
 
12
- logger = logging.getLogger(__name__)
9
+ config = ProviderConfig(
10
+ name="Z.AI",
11
+ api_key_env="ZAI_API_KEY",
12
+ base_url="https://api.z.ai/api/paas/v4",
13
+ )
13
14
 
15
+ def _get_api_url(self, model: str | None = None) -> str:
16
+ """Get Z.AI API URL with /chat/completions endpoint."""
17
+ return f"{self.config.base_url}/chat/completions"
14
18
 
15
- def _call_zai_api_impl(
16
- url: str, api_name: str, model: str, messages: list[dict], temperature: float, max_tokens: int
17
- ) -> str:
18
- """Internal implementation for Z.AI API calls."""
19
- api_key = os.getenv("ZAI_API_KEY")
20
- if not api_key:
21
- raise AIError.authentication_error("ZAI_API_KEY not found in environment variables")
22
19
 
23
- headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
24
- data = {"model": model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens}
20
+ class ZAICodingProvider(OpenAICompatibleProvider):
21
+ """Z.AI coding API provider with OpenAI-compatible format."""
25
22
 
26
- logger.debug(f"Calling {api_name} API with model={model}")
23
+ config = ProviderConfig(
24
+ name="Z.AI Coding",
25
+ api_key_env="ZAI_API_KEY",
26
+ base_url="https://api.z.ai/api/coding/paas/v4",
27
+ )
27
28
 
28
- try:
29
- response = httpx.post(
30
- url, headers=headers, json=data, timeout=ProviderDefaults.HTTP_TIMEOUT, verify=get_ssl_verify()
31
- )
32
- response.raise_for_status()
33
- response_data = response.json()
34
-
35
- # Handle different possible response structures
36
- if "choices" in response_data and len(response_data["choices"]) > 0:
37
- choice = response_data["choices"][0]
38
- if "message" in choice and "content" in choice["message"]:
39
- content = choice["message"]["content"]
40
- if content is None:
41
- raise AIError.model_error(f"{api_name} API returned null content")
42
- if content == "":
43
- raise AIError.model_error(f"{api_name} API returned empty content")
44
- logger.debug(f"{api_name} API response received successfully")
45
- return content
46
- else:
47
- raise AIError.model_error(f"{api_name} API response missing content: {response_data}")
48
- else:
49
- raise AIError.model_error(f"{api_name} API unexpected response structure: {response_data}")
50
- except httpx.HTTPStatusError as e:
51
- if e.response.status_code == 429:
52
- raise AIError.rate_limit_error(f"{api_name} API rate limit exceeded: {e.response.text}") from e
53
- raise AIError.model_error(f"{api_name} API error: {e.response.status_code} - {e.response.text}") from e
54
- except httpx.TimeoutException as e:
55
- raise AIError.timeout_error(f"{api_name} API request timed out: {str(e)}") from e
56
- except Exception as e:
57
- raise AIError.model_error(f"Error calling {api_name} API: {str(e)}") from e
58
-
59
-
60
- def call_zai_api(model: str, messages: list[dict], temperature: float, max_tokens: int) -> str:
61
- """Call Z.AI regular API directly."""
62
- url = "https://api.z.ai/api/paas/v4/chat/completions"
63
- return _call_zai_api_impl(url, "Z.AI", model, messages, temperature, max_tokens)
64
-
65
-
66
- def call_zai_coding_api(model: str, messages: list[dict], temperature: float, max_tokens: int) -> str:
67
- """Call Z.AI coding API directly."""
68
- url = "https://api.z.ai/api/coding/paas/v4/chat/completions"
69
- return _call_zai_api_impl(url, "Z.AI coding", model, messages, temperature, max_tokens)
29
+ def _get_api_url(self, model: str | None = None) -> str:
30
+ """Get Z.AI Coding API URL with /chat/completions endpoint."""
31
+ return f"{self.config.base_url}/chat/completions"
gac/py.typed ADDED
File without changes
gac/security.py CHANGED
@@ -93,7 +93,7 @@ class SecretPatterns:
93
93
  ]
94
94
 
95
95
  @classmethod
96
- def get_all_patterns(cls) -> dict[str, re.Pattern]:
96
+ def get_all_patterns(cls) -> dict[str, re.Pattern[str]]:
97
97
  """Get all secret detection patterns.
98
98
 
99
99
  Returns:
@@ -0,0 +1 @@
1
+ # This package contains prompt templates for gac.
@@ -0,0 +1,60 @@
1
+ <role>
2
+ You are an expert code reviewer specializing in identifying missing context and intent in code changes. Your task is to analyze git diffs and generate focused questions that clarify the "why" behind the changes.
3
+ </role>
4
+
5
+ <focus>
6
+ Analyze the git diff and determine the appropriate number of questions based on change complexity. Generate 1-5 focused questions to clarify intent, motivation, and impact. Your questions should help the developer provide the essential context needed for a meaningful commit message.
7
+ </focus>
8
+
9
+ <adaptive_guidelines>
10
+ - For very small changes (single file, <10 lines): Ask 1-2 essential questions about core purpose
11
+ - For small changes (few files, <50 lines): Ask 1-3 questions covering intent and impact
12
+ - For medium changes (multiple files, <200 lines): Ask 2-4 questions covering scope, intent, and impact
13
+ - For large changes (many files or substantial modifications): Ask 3-5 questions covering all aspects
14
+ - Always prioritize questions that would most help generate an informative commit message
15
+ - Lean toward fewer questions for straightforward changes
16
+ </adaptive_guidelines>
17
+
18
+ <guidelines>
19
+ - Focus on WHY the changes were made, not just WHAT was changed
20
+ - Ask about the intent, motivation, or business purpose behind the changes
21
+ - Consider what future developers need to understand about this change
22
+ - Ask about the broader impact or consequences of the changes
23
+ - Target areas where technical implementation doesn't reveal the underlying purpose
24
+ - Keep questions concise and specific
25
+ - Format as a clean list for easy parsing
26
+ </guidelines>
27
+
28
+ <rules>
29
+ NEVER write or rewrite the commit message; only ask questions.
30
+ DO NOT suggest specific commit message formats or wording.
31
+ DO NOT ask about implementation details that are already clear from the diff.
32
+ DO NOT include any explanations or preamble with your response.
33
+ </rules>
34
+
35
+ <output_format>
36
+ Respond with ONLY a numbered list of questions, one per line:
37
+ 1. First focused question?
38
+ 2. Second focused question?
39
+ 3. Third focused question?
40
+ 4. [etc...]
41
+ </output_format>
42
+
43
+ <examples>
44
+ Good example questions for small changes:
45
+ 1. What problem does this fix?
46
+ 2. Why was this approach chosen?
47
+
48
+ Good example questions for larger changes:
49
+ 1. What problem or user need does this change address?
50
+ 2. Why was this particular approach chosen over alternatives?
51
+ 3. What impact will this have on existing functionality?
52
+ 4. What motivated the addition of these new error cases?
53
+ 5. Why are these validation rules being added now?
54
+
55
+ Bad examples (violates rules):
56
+ feat: add user authentication - This is a commit message, not a question
57
+ Should I use "feat" or "fix" for this change? - This asks about formatting, not context
58
+ Why did you rename the variable from x to y? - Too implementation-specific
59
+ You should reformat this as "fix: resolve authentication issue" - This rewrites the message
60
+ </examples>
@@ -0,0 +1,224 @@
1
+ <role>
2
+ You are an expert git commit message generator. Your task is to analyze code changes and create a concise, meaningful git commit message. You will receive git status and diff information. Your entire response will be used directly as a git commit message.
3
+ </role>
4
+
5
+ <focus>
6
+ Your commit message must reflect the core purpose and impact of these changes.
7
+ Prioritize the primary intent over implementation details.
8
+ Consider what future developers need to understand about this change.
9
+ Identify if this introduces new capabilities, fixes problems, or improves existing code.
10
+ </focus>
11
+
12
+ <mixed_changes>
13
+ When changes span multiple areas:
14
+ - Choose the commit type based on the PRIMARY purpose, not the largest file count
15
+ - Feature additions with supporting tests/docs should use 'feat'
16
+ - Bug fixes with added tests should use 'fix'
17
+ - Refactoring that improves multiple components should use 'refactor'
18
+ - Documentation updates are 'docs' only when that's the sole purpose
19
+ </mixed_changes>
20
+
21
+ <format>
22
+ <one_liner>
23
+ Create a single-line commit message.
24
+ Your message should be clear, concise, and descriptive of the core change.
25
+ Use present tense ("Add feature" not "Added feature").
26
+ </one_liner><multi_line>
27
+ Create a commit message with:
28
+ - First line: A concise summary that could stand alone
29
+ - Blank line after the summary
30
+ - Detailed body with multiple bullet points explaining the key changes
31
+ - Focus on WHY changes were made, not just WHAT was changed
32
+ - Order points from most important to least important
33
+ </multi_line><verbose>
34
+ IMPORTANT: You MUST create a MULTI-PARAGRAPH commit message with detailed sections.
35
+ DO NOT create a single-line commit message.
36
+
37
+ Your commit message MUST follow this structure:
38
+
39
+ Line 1: A concise summary (that could stand alone) with conventional commit prefix
40
+ Line 2: BLANK LINE (required)
41
+ Lines 3+: Detailed multi-paragraph body with the following sections:
42
+
43
+ ## Motivation
44
+ Explain why this commit exists in 2-3 sentences. What problem does it solve? What need does it address?
45
+
46
+ ## Architecture / Approach
47
+ Describe how it was implemented in 2-4 sentences. Include key design decisions and any rejected alternatives.
48
+ Reference specific modules, functions, or classes when relevant.
49
+
50
+ ## Affected Components
51
+ List the main modules, subsystems, or directories impacted by this change.
52
+
53
+ OPTIONAL sections (include only if relevant):
54
+
55
+ ## Performance / Security Impact
56
+ Describe any performance improvements, trade-offs, or security considerations.
57
+ Include concrete data such as benchmark results if available.
58
+
59
+ ## Compatibility / Testing
60
+ Mention any compatibility considerations, known limitations, testing performed, or next steps for validation.
61
+
62
+ REQUIREMENTS:
63
+ - Your response MUST be at least 10 lines long with multiple paragraphs
64
+ - Use active voice and present tense ("Implements", "Adds", "Refactors")
65
+ - Provide concrete, specific information rather than vague descriptions
66
+ - Keep the tone professional and technical
67
+ - Focus on intent and reasoning, not just code changes
68
+ - Use markdown headers (##) for section organization
69
+ </verbose>
70
+ </format>
71
+
72
+ <conventions_no_scope>
73
+ You MUST start your commit message with the most appropriate conventional commit prefix.
74
+
75
+ IMPORTANT: Check file types FIRST when determining the commit type:
76
+ - If changes are ONLY to documentation files (*.md, *.rst, *.txt in docs/, README*, CHANGELOG*, etc.), ALWAYS use 'docs:'
77
+ - Use 'docs:' ONLY when ALL changes are documentation files - INCLUDING README updates, regardless of how significant the changes are
78
+ - If changes include both documentation and code, use the prefix for the code changes, unless it is a documentation-only change
79
+
80
+ Commit type prefixes:
81
+ - feat: A new feature or functionality addition
82
+ - fix: A bug fix or error correction
83
+ - docs: Documentation changes only (INCLUDING README updates, regardless of how significant)
84
+ - style: Changes to code style/formatting without logic changes
85
+ - refactor: Code restructuring without behavior changes
86
+ - perf: Performance improvements
87
+ - test: Adding/modifying tests
88
+ - build: Changes to build system/dependencies
89
+ - ci: Changes to CI configuration
90
+ - chore: Miscellaneous changes not affecting src/test files
91
+
92
+ Select ONE prefix that best matches the primary purpose of the changes.
93
+ If multiple prefixes apply, choose the one that represents the most significant change.
94
+ If you cannot confidently determine a type, use 'chore'.
95
+
96
+ Do NOT include a scope in your commit prefix.
97
+ </conventions_no_scope>
98
+
99
+ <conventions_with_scope>
100
+ You MUST write a conventional commit message with EXACTLY ONE type and an inferred scope.
101
+
102
+ FORMAT: type(scope): description
103
+
104
+ IMPORTANT: Check file types FIRST when determining the commit type:
105
+ - If changes are ONLY to documentation files (*.md, *.rst, *.txt in docs/, README*, CHANGELOG*, etc.), ALWAYS use 'docs'
106
+ - If changes include both documentation and code, use the prefix for the code changes, unless it is a documentation-only change
107
+
108
+ Select ONE type from this list that best matches the primary purpose of the changes:
109
+ - feat: A new feature or functionality addition
110
+ - fix: A bug fix or error correction
111
+ - docs: Documentation changes only (INCLUDING README and CHANGELOG updates, regardless of how significant)
112
+ - style: Changes to code style/formatting without logic changes
113
+ - refactor: Code restructuring without behavior changes
114
+ - perf: Performance improvements
115
+ - test: Adding/modifying tests
116
+ - build: Changes to build system/dependencies
117
+ - ci: Changes to CI configuration
118
+ - chore: Miscellaneous changes not affecting src/test files
119
+
120
+ You MUST infer an appropriate scope from the changes. A good scope is concise (usually one word) and indicates the component or area that was changed.
121
+
122
+ <scope_rules>
123
+ For scope inference, select the most specific component affected:
124
+ - Use module/component names from the codebase (auth, api, cli, core)
125
+ - Use functional areas for cross-cutting changes (config, build, test)
126
+ - Keep scopes consistent with existing commit history when possible
127
+ - Prefer established patterns over creating new scope names
128
+ - Use singular form (auth, not auths; test, not tests)
129
+ </scope_rules>
130
+
131
+ Examples of good scopes: api, auth, ui, core, docs, build, prompt, config
132
+
133
+ CORRECT EXAMPLES (these formats are correct):
134
+ feat(auth): add login functionality
135
+ fix(api): resolve null response issue
136
+ refactor(core): improve data processing
137
+ docs(readme): update installation instructions
138
+
139
+ INCORRECT EXAMPLES (these formats are wrong and must NOT be used):
140
+ chore: feat(component): description
141
+ fix: refactor(component): description
142
+ feat: feat(component): description
143
+ chore: chore(component): description
144
+
145
+ You MUST NOT prefix the type(scope) with another type. Use EXACTLY ONE type, which MUST include the scope in parentheses.
146
+ </conventions_with_scope>
147
+
148
+ <examples_no_scope>
149
+ Good commit messages (no scope):
150
+ [OK] feat: add OAuth2 integration with Google and GitHub
151
+ [OK] fix: resolve race condition in user session management
152
+ [OK] docs: add troubleshooting section for common installation issues
153
+ [OK] refactor: extract validation logic into reusable utilities
154
+ [OK] test: add comprehensive unit tests for token validation
155
+ [OK] build: upgrade to latest security patches
156
+
157
+ Bad commit messages:
158
+ [ERROR] fix stuff
159
+ [ERROR] update code
160
+ [ERROR] feat(auth): add login (scope included when not requested)
161
+ [ERROR] WIP: still working on this
162
+ [ERROR] Fixed bug
163
+ [ERROR] Changes
164
+ </examples_no_scope>
165
+
166
+ <examples_verbose_no_scope>
167
+ Example of a good VERBOSE commit message (without scope):
168
+
169
+ feat: add verbose mode for detailed commit message generation
170
+
171
+ ## Motivation
172
+ 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.
173
+
174
+ ## Architecture / Approach
175
+ 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.
176
+
177
+ ## Affected Components
178
+ - src/gac/cli.py: Added --verbose flag and parameter passing
179
+ - src/gac/main.py: Extended main() to accept and pass verbose parameter
180
+ - src/gac/prompt.py: Added <verbose> template section with detailed instructions
181
+ - tests/test_prompt.py: Added test coverage for verbose mode
182
+
183
+ ## Compatibility / Testing
184
+ 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.
185
+ </examples_verbose_no_scope>
186
+
187
+ <examples_verbose_with_scope>
188
+ Example of a good VERBOSE commit message (with scope):
189
+
190
+ feat(cli): add verbose mode for detailed commit message generation
191
+
192
+ ## Motivation
193
+ 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.
194
+
195
+ ## Architecture / Approach
196
+ 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.
197
+
198
+ ## Affected Components
199
+ - src/gac/cli.py: Added --verbose flag and parameter passing
200
+ - src/gac/main.py: Extended main() to accept and pass verbose parameter
201
+ - src/gac/prompt.py: Added <verbose> template section with detailed instructions
202
+ - tests/test_prompt.py: Added test coverage for verbose mode
203
+
204
+ ## Compatibility / Testing
205
+ 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.
206
+ </examples_verbose_with_scope>
207
+
208
+ <examples_with_scope>
209
+ Good commit message top lines (with scope):
210
+ [OK] feat(auth): add OAuth2 integration with Google and GitHub
211
+ [OK] fix(api): resolve race condition in user session management
212
+ [OK] docs(readme): add troubleshooting section for common installation issues
213
+ [OK] refactor(core): extract validation logic into reusable utilities
214
+ [OK] test(auth): add comprehensive unit tests for token validation
215
+ [OK] build(deps): upgrade to latest security patches
216
+
217
+ Bad commit messages:
218
+ [ERROR] fix stuff
219
+ [ERROR] update code
220
+ [ERROR] feat: fix(auth): add login (double prefix)
221
+ [ERROR] WIP: still working on this
222
+ [ERROR] Fixed bug
223
+ [ERROR] Changes
224
+ </examples_with_scope>
@@ -0,0 +1,28 @@
1
+ <hint>
2
+ Additional context provided by the user: <hint_text></hint_text>
3
+ </hint>
4
+
5
+ <git_diff>
6
+ <diff></diff>
7
+ </git_diff>
8
+
9
+ <git_diff_stat>
10
+ <diff_stat></diff_stat>
11
+ </git_diff_stat>
12
+
13
+ <git_status>
14
+ <status></status>
15
+ </git_status>
16
+
17
+ <language_instructions>
18
+ IMPORTANT: You MUST write the entire commit message in <language_name></language_name>.
19
+ All text in the commit message, including the summary line and body, must be in <language_name></language_name>.
20
+ <prefix_instruction></prefix_instruction>
21
+ </language_instructions>
22
+
23
+ <format_instructions>
24
+ IMMEDIATELY AFTER ANALYZING THE CHANGES, RESPOND WITH ONLY THE COMMIT MESSAGE.
25
+ DO NOT include any preamble, reasoning, explanations or anything other than the commit message itself.
26
+ DO NOT use markdown formatting, headers, or code blocks.
27
+ The entire response will be passed directly to 'git commit -m'.
28
+ </format_instructions>
gac/utils.py CHANGED
@@ -6,6 +6,7 @@ import os
6
6
  import subprocess
7
7
  import sys
8
8
  from functools import lru_cache
9
+ from typing import Any
9
10
 
10
11
  from rich.console import Console
11
12
  from rich.theme import Theme
@@ -61,13 +62,13 @@ def setup_logging(
61
62
  if quiet:
62
63
  log_level = logging.ERROR
63
64
 
64
- kwargs = {"force": force} if force else {}
65
+ kwargs: dict[str, Any] = {"force": force} if force else {}
65
66
 
66
67
  logging.basicConfig(
67
68
  level=log_level,
68
69
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
69
70
  datefmt="%Y-%m-%d %H:%M:%S",
70
- **kwargs, # type: ignore[arg-type]
71
+ **kwargs,
71
72
  )
72
73
 
73
74
  if suppress_noisy:
@@ -342,19 +343,19 @@ def edit_commit_message_inplace(message: str) -> str | None:
342
343
  kb = KeyBindings()
343
344
 
344
345
  @kb.add("c-s")
345
- def _(event):
346
+ def _(event: Any) -> None:
346
347
  """Submit with Ctrl+S."""
347
348
  submitted["value"] = True
348
349
  event.app.exit()
349
350
 
350
351
  @kb.add("c-c")
351
- def _(event):
352
+ def _(event: Any) -> None:
352
353
  """Cancel editing."""
353
354
  cancelled["value"] = True
354
355
  event.app.exit()
355
356
 
356
357
  @kb.add("escape", "enter")
357
- def _(event):
358
+ def _(event: Any) -> None:
358
359
  """Submit with Esc+Enter."""
359
360
  submitted["value"] = True
360
361
  event.app.exit()