gac 3.6.0__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 (79) hide show
  1. gac/__init__.py +4 -6
  2. gac/__version__.py +1 -1
  3. gac/ai_utils.py +59 -43
  4. gac/auth_cli.py +181 -36
  5. gac/cli.py +26 -9
  6. gac/commit_executor.py +59 -0
  7. gac/config.py +81 -2
  8. gac/config_cli.py +19 -7
  9. gac/constants/__init__.py +34 -0
  10. gac/constants/commit.py +63 -0
  11. gac/constants/defaults.py +40 -0
  12. gac/constants/file_patterns.py +110 -0
  13. gac/constants/languages.py +119 -0
  14. gac/diff_cli.py +0 -22
  15. gac/errors.py +8 -2
  16. gac/git.py +6 -6
  17. gac/git_state_validator.py +193 -0
  18. gac/grouped_commit_workflow.py +458 -0
  19. gac/init_cli.py +2 -1
  20. gac/interactive_mode.py +179 -0
  21. gac/language_cli.py +0 -1
  22. gac/main.py +231 -926
  23. gac/model_cli.py +67 -11
  24. gac/model_identifier.py +70 -0
  25. gac/oauth/__init__.py +26 -0
  26. gac/oauth/claude_code.py +89 -22
  27. gac/oauth/qwen_oauth.py +327 -0
  28. gac/oauth/token_store.py +81 -0
  29. gac/oauth_retry.py +161 -0
  30. gac/postprocess.py +155 -0
  31. gac/prompt.py +21 -479
  32. gac/prompt_builder.py +88 -0
  33. gac/providers/README.md +437 -0
  34. gac/providers/__init__.py +70 -78
  35. gac/providers/anthropic.py +12 -46
  36. gac/providers/azure_openai.py +48 -88
  37. gac/providers/base.py +329 -0
  38. gac/providers/cerebras.py +10 -33
  39. gac/providers/chutes.py +16 -62
  40. gac/providers/claude_code.py +64 -87
  41. gac/providers/custom_anthropic.py +51 -81
  42. gac/providers/custom_openai.py +29 -83
  43. gac/providers/deepseek.py +10 -33
  44. gac/providers/error_handler.py +139 -0
  45. gac/providers/fireworks.py +10 -33
  46. gac/providers/gemini.py +66 -63
  47. gac/providers/groq.py +10 -58
  48. gac/providers/kimi_coding.py +19 -55
  49. gac/providers/lmstudio.py +64 -43
  50. gac/providers/minimax.py +10 -33
  51. gac/providers/mistral.py +10 -33
  52. gac/providers/moonshot.py +10 -33
  53. gac/providers/ollama.py +56 -33
  54. gac/providers/openai.py +30 -36
  55. gac/providers/openrouter.py +15 -52
  56. gac/providers/protocol.py +71 -0
  57. gac/providers/qwen.py +64 -0
  58. gac/providers/registry.py +58 -0
  59. gac/providers/replicate.py +140 -82
  60. gac/providers/streamlake.py +26 -46
  61. gac/providers/synthetic.py +35 -37
  62. gac/providers/together.py +10 -33
  63. gac/providers/zai.py +29 -57
  64. gac/py.typed +0 -0
  65. gac/security.py +1 -1
  66. gac/templates/__init__.py +1 -0
  67. gac/templates/question_generation.txt +60 -0
  68. gac/templates/system_prompt.txt +224 -0
  69. gac/templates/user_prompt.txt +28 -0
  70. gac/utils.py +36 -6
  71. gac/workflow_context.py +162 -0
  72. gac/workflow_utils.py +3 -8
  73. {gac-3.6.0.dist-info → gac-3.10.10.dist-info}/METADATA +6 -4
  74. gac-3.10.10.dist-info/RECORD +79 -0
  75. gac/constants.py +0 -321
  76. gac-3.6.0.dist-info/RECORD +0 -53
  77. {gac-3.6.0.dist-info → gac-3.10.10.dist-info}/WHEEL +0 -0
  78. {gac-3.6.0.dist-info → gac-3.10.10.dist-info}/entry_points.txt +0 -0
  79. {gac-3.6.0.dist-info → gac-3.10.10.dist-info}/licenses/LICENSE +0 -0
@@ -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
@@ -2,16 +2,46 @@
2
2
 
3
3
  import locale
4
4
  import logging
5
+ import os
5
6
  import subprocess
6
7
  import sys
8
+ from functools import lru_cache
9
+ from typing import Any
7
10
 
8
11
  from rich.console import Console
9
12
  from rich.theme import Theme
10
13
 
11
- from gac.constants import Logging
14
+ from gac.constants import EnvDefaults, Logging
12
15
  from gac.errors import GacError
13
16
 
14
17
 
18
+ @lru_cache(maxsize=1)
19
+ def should_skip_ssl_verification() -> bool:
20
+ """Return True when SSL certificate verification should be skipped.
21
+
22
+ This is useful for corporate environments with proxy servers that
23
+ intercept SSL traffic and cause certificate verification failures.
24
+
25
+ Can be enabled via:
26
+ - GAC_NO_VERIFY_SSL=true environment variable
27
+ - --no-verify-ssl CLI flag (which sets the env var)
28
+
29
+ Returns:
30
+ True if SSL verification should be skipped, False otherwise.
31
+ """
32
+ value = os.getenv("GAC_NO_VERIFY_SSL", str(EnvDefaults.NO_VERIFY_SSL))
33
+ return value.lower() in ("true", "1", "yes", "on")
34
+
35
+
36
+ def get_ssl_verify() -> bool:
37
+ """Get the SSL verification setting for httpx requests.
38
+
39
+ Returns:
40
+ True to verify SSL certificates (default), False to skip verification.
41
+ """
42
+ return not should_skip_ssl_verification()
43
+
44
+
15
45
  def setup_logging(
16
46
  log_level: int | str = Logging.DEFAULT_LEVEL,
17
47
  quiet: bool = False,
@@ -32,13 +62,13 @@ def setup_logging(
32
62
  if quiet:
33
63
  log_level = logging.ERROR
34
64
 
35
- kwargs = {"force": force} if force else {}
65
+ kwargs: dict[str, Any] = {"force": force} if force else {}
36
66
 
37
67
  logging.basicConfig(
38
68
  level=log_level,
39
69
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
40
70
  datefmt="%Y-%m-%d %H:%M:%S",
41
- **kwargs, # type: ignore[arg-type]
71
+ **kwargs,
42
72
  )
43
73
 
44
74
  if suppress_noisy:
@@ -313,19 +343,19 @@ def edit_commit_message_inplace(message: str) -> str | None:
313
343
  kb = KeyBindings()
314
344
 
315
345
  @kb.add("c-s")
316
- def _(event):
346
+ def _(event: Any) -> None:
317
347
  """Submit with Ctrl+S."""
318
348
  submitted["value"] = True
319
349
  event.app.exit()
320
350
 
321
351
  @kb.add("c-c")
322
- def _(event):
352
+ def _(event: Any) -> None:
323
353
  """Cancel editing."""
324
354
  cancelled["value"] = True
325
355
  event.app.exit()
326
356
 
327
357
  @kb.add("escape", "enter")
328
- def _(event):
358
+ def _(event: Any) -> None:
329
359
  """Submit with Esc+Enter."""
330
360
  submitted["value"] = True
331
361
  event.app.exit()
@@ -0,0 +1,162 @@
1
+ """Workflow context objects to reduce parameter explosion.
2
+
3
+ These dataclasses bundle related parameters that are passed through
4
+ the commit workflow, making function signatures cleaner and more maintainable.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+ from typing import TYPE_CHECKING
11
+
12
+ if TYPE_CHECKING:
13
+ from gac.commit_executor import CommitExecutor
14
+ from gac.git_state_validator import GitState
15
+ from gac.interactive_mode import InteractiveMode
16
+ from gac.prompt_builder import PromptBundle
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class CLIOptions:
21
+ """Options passed from CLI to main workflow.
22
+
23
+ Bundles all command-line arguments to reduce parameter explosion in main().
24
+ """
25
+
26
+ # Git workflow options
27
+ stage_all: bool = False
28
+ push: bool = False
29
+ no_verify: bool = False
30
+ hook_timeout: int = 120
31
+
32
+ # Workflow mode
33
+ group: bool = False
34
+ interactive: bool = False
35
+ require_confirmation: bool = True
36
+ dry_run: bool = False
37
+
38
+ # AI/Model config
39
+ model: str | None = None
40
+
41
+ # Prompt/output format config
42
+ hint: str = ""
43
+ one_liner: bool = False
44
+ infer_scope: bool = False
45
+ verbose: bool = False
46
+ language: str | None = None
47
+
48
+ # Output config
49
+ quiet: bool = False
50
+ message_only: bool = False
51
+ show_prompt: bool = False
52
+
53
+ # Security
54
+ skip_secret_scan: bool = False
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class GenerationConfig:
59
+ """Configuration for AI message generation.
60
+
61
+ These settings control how the AI model generates commit messages.
62
+ """
63
+
64
+ model: str
65
+ temperature: float
66
+ max_output_tokens: int
67
+ max_retries: int
68
+
69
+
70
+ @dataclass(frozen=True)
71
+ class WorkflowFlags:
72
+ """Boolean flags controlling workflow behavior.
73
+
74
+ These flags determine how the commit workflow executes.
75
+ """
76
+
77
+ require_confirmation: bool
78
+ quiet: bool
79
+ no_verify: bool
80
+ dry_run: bool
81
+ message_only: bool
82
+ push: bool
83
+ show_prompt: bool
84
+ interactive: bool
85
+ hook_timeout: int = 120
86
+
87
+
88
+ @dataclass
89
+ class WorkflowState:
90
+ """Runtime state for a commit workflow.
91
+
92
+ Contains the prompts, git state, and executor instances needed
93
+ to execute the workflow. This is mutable as conversation messages
94
+ may be updated during interactive flows.
95
+ """
96
+
97
+ prompts: PromptBundle
98
+ git_state: GitState
99
+ hint: str
100
+ commit_executor: CommitExecutor
101
+ interactive_mode: InteractiveMode
102
+
103
+
104
+ @dataclass(frozen=True)
105
+ class WorkflowContext:
106
+ """Complete context for executing a commit workflow.
107
+
108
+ Bundles all configuration, flags, and state needed to execute
109
+ a single or grouped commit workflow.
110
+ """
111
+
112
+ config: GenerationConfig
113
+ flags: WorkflowFlags
114
+ state: WorkflowState
115
+
116
+ @property
117
+ def model(self) -> str:
118
+ return self.config.model
119
+
120
+ @property
121
+ def temperature(self) -> float:
122
+ return self.config.temperature
123
+
124
+ @property
125
+ def max_output_tokens(self) -> int:
126
+ return self.config.max_output_tokens
127
+
128
+ @property
129
+ def max_retries(self) -> int:
130
+ return self.config.max_retries
131
+
132
+ @property
133
+ def quiet(self) -> bool:
134
+ return self.flags.quiet
135
+
136
+ @property
137
+ def dry_run(self) -> bool:
138
+ return self.flags.dry_run
139
+
140
+ @property
141
+ def message_only(self) -> bool:
142
+ return self.flags.message_only
143
+
144
+ @property
145
+ def interactive(self) -> bool:
146
+ return self.flags.interactive
147
+
148
+ @property
149
+ def system_prompt(self) -> str:
150
+ return self.state.prompts.system_prompt
151
+
152
+ @property
153
+ def user_prompt(self) -> str:
154
+ return self.state.prompts.user_prompt
155
+
156
+ @property
157
+ def hint(self) -> str:
158
+ return self.state.hint
159
+
160
+ @property
161
+ def git_state(self) -> GitState:
162
+ return self.state.git_state
gac/workflow_utils.py CHANGED
@@ -3,6 +3,7 @@ import tempfile
3
3
  from pathlib import Path
4
4
 
5
5
  import click
6
+ from prompt_toolkit import prompt
6
7
  from rich.console import Console
7
8
  from rich.panel import Panel
8
9
 
@@ -157,13 +158,7 @@ def collect_interactive_answers(questions: list[str]) -> dict[str, str] | None:
157
158
  console.print(f"[bold blue]Question {i}:[/bold blue] {question}")
158
159
 
159
160
  try:
160
- answer = click.prompt(
161
- "Your answer",
162
- type=str,
163
- default="", # Allow empty input to skip
164
- show_default=False,
165
- prompt_suffix=": ",
166
- ).strip()
161
+ answer = prompt("Your answer: ").strip()
167
162
 
168
163
  # Handle special commands
169
164
  answer_lower = answer.lower()
@@ -183,7 +178,7 @@ def collect_interactive_answers(questions: list[str]) -> dict[str, str] | None:
183
178
  answers[question] = answer
184
179
  console.print("[dim]↳ Got it![/dim]")
185
180
 
186
- except click.Abort:
181
+ except KeyboardInterrupt:
187
182
  # User pressed Ctrl+C
188
183
  console.print("\n[yellow]⚠️ Interactive mode aborted by user[/yellow]")
189
184
  return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gac
3
- Version: 3.6.0
3
+ Version: 3.10.10
4
4
  Summary: LLM-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
@@ -47,7 +47,7 @@ Description-Content-Type: text/markdown
47
47
  # 🚀 Git Auto Commit (gac)
48
48
 
49
49
  [![PyPI version](https://img.shields.io/pypi/v/gac.svg)](https://pypi.org/project/gac/)
50
- [![Python](https://img.shields.io/badge/python-3.10%20|%203.11%20|%203.12%20|%203.13%20|%203.14-blue.svg)](https://www.python.org/downloads/)
50
+ [![Python](https://img.shields.io/badge/python-3.10--3.14-blue.svg)](https://www.python.org/downloads/)
51
51
  [![Build Status](https://github.com/cellwebb/gac/actions/workflows/ci.yml/badge.svg)](https://github.com/cellwebb/gac/actions)
52
52
  [![codecov](https://codecov.io/gh/cellwebb/gac/branch/main/graph/badge.svg)](https://app.codecov.io/gh/cellwebb/gac)
53
53
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
@@ -109,8 +109,8 @@ uv tool upgrade gac
109
109
  - **Anthropic** • **Azure OpenAI** • **Cerebras** • **Chutes.ai** • **Claude Code (OAuth)**
110
110
  - **DeepSeek** • **Fireworks** • **Gemini** • **Groq** • **Kimi for Coding** • **LM Studio**
111
111
  - **MiniMax.io** • **Mistral AI** • **Moonshot AI** • **Ollama** • **OpenAI** • **OpenRouter**
112
- - **Replicate** • **Streamlake** • **Synthetic.new** • **Together AI** • **Z.AI** • **Z.AI Coding**
113
- - **Custom Endpoints (Anthropic/OpenAI)**
112
+ - **Qwen.ai (OAuth)** • **Replicate** • **Streamlake** • **Synthetic.new** • **Together AI**
113
+ - **Z.AI** • **Z.AI Coding** • **Custom Endpoints (Anthropic/OpenAI)**
114
114
 
115
115
  ### 🧠 **Smart LLM Analysis**
116
116
 
@@ -262,6 +262,8 @@ Track real-time installation metrics and package download statistics.
262
262
  ## Getting Help
263
263
 
264
264
  - **Full documentation**: [docs/USAGE.md](docs/en/USAGE.md) - Complete CLI reference
265
+ - **Claude Code OAuth**: [docs/CLAUDE_CODE.md](docs/en/CLAUDE_CODE.md) - Claude Code setup and authentication
266
+ - **Qwen.ai OAuth**: [docs/QWEN.md](docs/en/QWEN.md) - Qwen.ai setup and authentication
265
267
  - **Custom prompts**: [docs/CUSTOM_SYSTEM_PROMPTS.md](docs/en/CUSTOM_SYSTEM_PROMPTS.md) - Customize commit message style
266
268
  - **Troubleshooting**: [docs/TROUBLESHOOTING.md](docs/en/TROUBLESHOOTING.md) - Common issues and solutions
267
269
  - **Contributing**: [docs/CONTRIBUTING.md](docs/en/CONTRIBUTING.md) - Development setup and guidelines
@@ -0,0 +1,79 @@
1
+ gac/__init__.py,sha256=8MQ-da47gfj3k-K3zC8dVdW-F9R7DzxADILJyPPsvbo,311
2
+ gac/__version__.py,sha256=5bYvim4LGM_rUaBfwXdOz2SItoM3knux0OvqtnhBQdo,68
3
+ gac/ai.py,sha256=HnXmRFmUJin5k755iBqSLgKYssjShjKXz9SwICEpMag,3835
4
+ gac/ai_utils.py,sha256=jrfY_whmRdpUEyTSr_uxUuCfy_wpA4EIKhHE8jZ73sY,9872
5
+ gac/auth_cli.py,sha256=D1UcpOdyLqnKNJQTBq2lHCHBaxFZsRbM4Krvg-1-NfA,6822
6
+ gac/cli.py,sha256=aW7-EC3PhngvR11fVasPgu66aGgom16xc9PoRwG8fo4,8040
7
+ gac/commit_executor.py,sha256=0hhRQFuCpgsCRnP9AGq1V1JIVOAhZrqqRiSDZmoHkCk,2286
8
+ gac/config.py,sha256=qaQ7-udCA0Gb-S8aKEGM40ywVWQyMPtTpnBPq3BTkhg,5208
9
+ gac/config_cli.py,sha256=6tUoi-Xcexv5i2Y6p-wobrYlzeH2DNxlHMkyhFnFBYk,2994
10
+ gac/diff_cli.py,sha256=roBnoPcMn58rMGA475lqXlC2iYERC-13K0CKJH2nSV8,5147
11
+ gac/errors.py,sha256=pBq1nvHwv89KLvOGgap15IWmYTki2lghkkqyHpyVTzA,8035
12
+ gac/git.py,sha256=KuajV-4XywQ1uox_eB-CuoQ85xH_iJxsu3LcOVxLN7Y,13185
13
+ gac/git_state_validator.py,sha256=R_-Ee6umDDSqVnY_EXBO8uFvlpUWRGqRqHHgGO59p6g,7070
14
+ gac/grouped_commit_workflow.py,sha256=efjF_F2Vg8GF13asEhOGVgsa8U03ze6mcYqaq_meTNg,19278
15
+ gac/init_cli.py,sha256=99ga1qrFz9E-cpLLhI1c8FmvVa4BgXZMQK1cv13LM5M,2303
16
+ gac/interactive_mode.py,sha256=EwcqY39O-VKaRwmzT3IffQs8qLcq0dMeB4r5vBYVrnM,6397
17
+ gac/language_cli.py,sha256=3p4W3ezYjaJ2J5XvO1OOG0j-U_Ozla2-K2HMC-TURaQ,12906
18
+ gac/main.py,sha256=275I3vFLSZ4rEgte5DT_9UhdElWpe7tj0VQs93_dAu4,12142
19
+ gac/model_cli.py,sha256=dBJKW3uwkkc3OR57tOQbngk-k_Auau6C0RXE6HG4XAE,18346
20
+ gac/model_identifier.py,sha256=WKVxa31FI8ESRVmWvOLEviL6-t3ji7OGkOq6Dg48ZnM,2315
21
+ gac/oauth_retry.py,sha256=IFlz1KhBCwLWNSbluDBgw-07sEbFdwFvn-pO_kH4Eg8,5070
22
+ gac/postprocess.py,sha256=4cHWbu1PSWEW-1ct0X5i5So_NosxrXk_qC9vEBV7Z7c,4909
23
+ gac/preprocess.py,sha256=hk2p2X4-xVDvuy-T1VMzMa9k5fTUbhlWDyw89DCf81Q,15379
24
+ gac/prompt.py,sha256=Vkh2LSEUkl19z8UMSn8o7bl3uRBdIeDmVKyk9t4f-jI,16627
25
+ gac/prompt_builder.py,sha256=9VEIFGgYQUnnbRh9zrVjDmMGDr9v4Ij2V5NuEtI0cSw,3088
26
+ gac/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ gac/security.py,sha256=RYE3cik9c_zrqQYd0xIju8YUqZ1VPa2cVbktChuSyRg,9931
28
+ gac/utils.py,sha256=evJ0lSKLVjqKWoxvLfV4mBTBHTqaWlQzh591jdhTXcc,12689
29
+ gac/workflow_context.py,sha256=Vq1X2pXMkxgTeQSbkhARqBjwxA5THXlZ3OLrv49LXzo,3752
30
+ gac/workflow_utils.py,sha256=rGN7PqTqeUFLn260gm3hKyzF1PDVVuEsV1i2QHu2EO4,8118
31
+ gac/constants/__init__.py,sha256=un6JAvDggBoX95QD7G6xARQqe7nbtOoTuyA-xcobySE,1094
32
+ gac/constants/commit.py,sha256=z-ssDs1erhMgtq1VFDs9nIXb-8C17X-IdhwaqX5Ydok,1478
33
+ gac/constants/defaults.py,sha256=-VHk3XgV1H0lhHYXusw0CIP4rGvDqF6WmygSNTfV5ds,1301
34
+ gac/constants/file_patterns.py,sha256=eA-BHKYeM3mt_sNMmTVvk2nx1hZGTggtSnqiqiAA5Eg,3960
35
+ gac/constants/languages.py,sha256=UIqJ42WfzPQu_-flNf6YHBBI5MwNOlVeSN8cygJDiBA,3466
36
+ gac/oauth/__init__.py,sha256=wwfeIMGgpIAb8-ptLcSDyK_sM72HI1bkULyJm7BwVs8,614
37
+ gac/oauth/claude_code.py,sha256=KJEc-318aOKuyhQKjRYk8oyNqazhvnBU-rvM9CFNYKg,14092
38
+ gac/oauth/qwen_oauth.py,sha256=W-JCZYtCrhoDJUuGATLWrfxTs8fevd9Cj-x0RAriV5w,11151
39
+ gac/oauth/token_store.py,sha256=HW2sWKwkgyCuGCF5OwHaslH82s77hpFUcKCNQpWCD-8,2517
40
+ gac/providers/README.md,sha256=Vcep039sEqngYhxe18wM0rYpl_VccrRRrTqd9o8g3h4,12106
41
+ gac/providers/__init__.py,sha256=saJF1G2aHmOHzT7sWqXvoYy6c7gWbTB_AEYht7NeQkw,3111
42
+ gac/providers/anthropic.py,sha256=DgONlbKVHH8W4AlqPP-T4AmAxWADMMlqPAfi8GfhH7Q,535
43
+ gac/providers/azure_openai.py,sha256=t2D_r-OxzEy7Av2sRFFs5E_Zclsgk1o40UFuybtti08,2247
44
+ gac/providers/base.py,sha256=w42ILqRPuSJm5-NUmoYB4aY30apweNF4x-X6-Kkr3Jw,11138
45
+ gac/providers/cerebras.py,sha256=jz84u-ALqrYzCz13-FGBzPAhKdWJQ-Qw0KpuX1fuX7s,503
46
+ gac/providers/chutes.py,sha256=nLZBLL-E6qa6YePD_fvbXcI4nOA6L87lx7_292HPkDk,850
47
+ gac/providers/claude_code.py,sha256=-RY3v5xIdfS1UMkl7ZrGtHF678KXZ3eI-AeVusz3RC0,2926
48
+ gac/providers/custom_anthropic.py,sha256=jzZ4ep0BS14isDdmRJ7tqlArzUnJ4CIWEptuWG8X3yI,4360
49
+ gac/providers/custom_openai.py,sha256=11NOpTDG_k29bxnuACW7iXOhf-XKrTt1gxp9J1GBoy0,1578
50
+ gac/providers/deepseek.py,sha256=Zn1npn0DxgAQVHpTxhUn8XZPBBQNj9ajmJcX_Q6Xk28,498
51
+ gac/providers/error_handler.py,sha256=PcddgcgABLfK_pmODLkpwWSn4-aiptzTPn1D5DA9HqA,5640
52
+ gac/providers/fireworks.py,sha256=8ESmRldJDL3aOBMM68jTHvfyznjHOQKcOhhkTxGFwQo,516
53
+ gac/providers/gemini.py,sha256=ke8rshxGkcB9yVWN9qHmvTpDtFAGYaigpghxZt8q8Dw,3438
54
+ gac/providers/groq.py,sha256=rwqBHrM4SfZHVwXHpp9GPDYJozjSzjxj1Lc1WETY_NY,481
55
+ gac/providers/kimi_coding.py,sha256=TTB13J3s2Gp3dvr3SXafjdl2plF4uix2-bHB_DqQZSQ,1038
56
+ gac/providers/lmstudio.py,sha256=egGswgSgyJL4fBYz_L_zAgPsS9xj2dS8D5udzx_ihew,3054
57
+ gac/providers/minimax.py,sha256=rviAMgTdjQ5iSAXgmJKEf-kGrH5Wb-HFAydSjRkzq7Y,493
58
+ gac/providers/mistral.py,sha256=wp9j-uRWQT6oijGOBJumljuZQEUcF8aRhlw_TiVy2KY,491
59
+ gac/providers/moonshot.py,sha256=Q1HtSkRZFCJsVvrDETdojZgVBdB_A1gX5OZqIOHFnq0,496
60
+ gac/providers/ollama.py,sha256=O91Rmn-eptzTHKsbaiZAG3CpUYj2nGvsD6w54YcfLMw,2569
61
+ gac/providers/openai.py,sha256=giQSTxyNHvTxtBODENPTIc7ObdNtV5lu1uf7a3gkgSI,1216
62
+ gac/providers/openrouter.py,sha256=ShpF7ew6n2_7BSr9mqLHf1rG_V_ykrIjmaplbY4jZsk,779
63
+ gac/providers/protocol.py,sha256=QY474-0I8qOkMBxg4l_IoDgrT475OjdRv8pT4ckeAwA,1771
64
+ gac/providers/qwen.py,sha256=7Krb5c44A0yC0hI9JswGcEl--llhrjWypE6nDCdgX2Q,2398
65
+ gac/providers/registry.py,sha256=50BDPZcvbuqPwY98OTDCOIJjnhXHBBrWWCATKGT353s,1991
66
+ gac/providers/replicate.py,sha256=ISYe85kWX0RbHxmYWo3InZDOZsL3jZXUzq7YiEa_QKE,6402
67
+ gac/providers/streamlake.py,sha256=c2QWIvTGlxOHU5HkdS0bPdKLJIfGgHo2GAMfEQJA1dc,1117
68
+ gac/providers/synthetic.py,sha256=WBHQ6glxkndjPgvBoyG0oj24e-yun4aU6UqDtjll0E4,1535
69
+ gac/providers/together.py,sha256=ethi_6WhR6DTe3idZQXpXAeJOdEg_EefP5erAHDtS_A,501
70
+ gac/providers/zai.py,sha256=HSvpxE5uM4kE5zrs3pWHuer7LusRgWCDfYiN1R9sHSw,1010
71
+ gac/templates/__init__.py,sha256=lwaKKSWb21MUxEtYzUOJ3dHsfMgxZ_W60uR9aC6yMrs,50
72
+ gac/templates/question_generation.txt,sha256=nX-eOeW_hqofGXNJVLPxWMxNVxxV_21l25fqnAOJH9o,2868
73
+ gac/templates/system_prompt.txt,sha256=0eMkBTZVjxJDjutVpb5Sxif5QOhAtXWSSF3tNizI0S4,11076
74
+ gac/templates/user_prompt.txt,sha256=QF3bkOnAA5bKcqYnPEi1fHeHS41FWWQLLPRk0Q8YRqw,864
75
+ gac-3.10.10.dist-info/METADATA,sha256=4yUk_r17dJsWriEIxdICfpesJlF3CuC3DUZ9pZUe6Pk,11440
76
+ gac-3.10.10.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
77
+ gac-3.10.10.dist-info/entry_points.txt,sha256=tdjN-XMmcWfL92swuRAjT62bFLOAwk9bTMRLGP5Z4aI,36
78
+ gac-3.10.10.dist-info/licenses/LICENSE,sha256=vOab37NouL1PNs5BswnPayrMCqaN2sqLfMQfqPDrpZg,1103
79
+ gac-3.10.10.dist-info/RECORD,,