git-copilot-commit 0.2.2__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.justfile +2 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/PKG-INFO +2 -2
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/pyproject.toml +1 -1
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/cli.py +37 -107
- git_copilot_commit-0.3.1/src/git_copilot_commit/prompts/commit-message-generator-prompt.md +58 -0
- git_copilot_commit-0.3.1/uv.lock +1174 -0
- git_copilot_commit-0.2.2/src/git_copilot_commit/prompts/commit-message-generator-prompt.md +0 -62
- git_copilot_commit-0.2.2/uv.lock +0 -334
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.github/workflows/ci.yml +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.gitignore +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/.python-version +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/LICENSE +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/README.md +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/__init__.py +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/git.py +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/py.typed +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/settings.py +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/src/git_copilot_commit/version.py +0 -0
- {git_copilot_commit-0.2.2 → git_copilot_commit-0.3.1}/vhs/demo.vhs +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-copilot-commit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Automatically generate and commit changes using copilot
|
|
5
5
|
Author-email: Dheepak Krishnamurthy <1813121+kdheepak@users.noreply.github.com>
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Requires-Python: >=3.12
|
|
8
|
+
Requires-Dist: litellm>=1.75.4
|
|
8
9
|
Requires-Dist: platformdirs>=4.0.0
|
|
9
|
-
Requires-Dist: pycopilot>=0.1.7
|
|
10
10
|
Requires-Dist: rich>=14.0.0
|
|
11
11
|
Requires-Dist: typer>=0.16.0
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
@@ -3,17 +3,14 @@ git-copilot-commit - AI-powered Git commit assistant
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import rich.terminal_theme
|
|
6
|
-
import sys
|
|
7
6
|
import typer
|
|
8
7
|
from rich.console import Console
|
|
9
8
|
from rich.prompt import Confirm
|
|
10
9
|
from rich.panel import Panel
|
|
11
|
-
from rich.table import Table
|
|
12
10
|
import rich
|
|
13
11
|
from pathlib import Path
|
|
14
12
|
|
|
15
|
-
from
|
|
16
|
-
from pycopilot.auth import Authentication
|
|
13
|
+
from litellm import completion
|
|
17
14
|
from .git import GitRepository, GitError, NotAGitRepositoryError
|
|
18
15
|
from .settings import Settings
|
|
19
16
|
from .version import __version__
|
|
@@ -87,6 +84,29 @@ def load_system_prompt() -> str:
|
|
|
87
84
|
raise typer.Exit(1)
|
|
88
85
|
|
|
89
86
|
|
|
87
|
+
def ask(prompt, model) -> str:
|
|
88
|
+
response = completion(
|
|
89
|
+
model=model,
|
|
90
|
+
messages=[
|
|
91
|
+
{"role": "system", "content": load_system_prompt()},
|
|
92
|
+
{"role": "user", "content": prompt},
|
|
93
|
+
],
|
|
94
|
+
extra_headers={
|
|
95
|
+
"editor-version": "vscode/1.85.1",
|
|
96
|
+
"Copilot-Integration-Id": "vscode-chat",
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
text = response.choices[0].message.content
|
|
100
|
+
text = text.strip()
|
|
101
|
+
# Remove triple backticks if they wrap the entire text
|
|
102
|
+
if text.startswith("```") and text.endswith("```"):
|
|
103
|
+
text = text[3:-3].strip()
|
|
104
|
+
# Otherwise remove single backticks if they wrap the entire text
|
|
105
|
+
elif text.startswith("`") and text.endswith("`"):
|
|
106
|
+
text = text[1:-1].strip()
|
|
107
|
+
return text
|
|
108
|
+
|
|
109
|
+
|
|
90
110
|
def generate_commit_message(
|
|
91
111
|
repo: GitRepository, model: str | None = None, context: str = ""
|
|
92
112
|
) -> str:
|
|
@@ -99,9 +119,6 @@ def generate_commit_message(
|
|
|
99
119
|
console.print("[red]No staged changes to commit.[/red]")
|
|
100
120
|
raise typer.Exit()
|
|
101
121
|
|
|
102
|
-
system_prompt = load_system_prompt()
|
|
103
|
-
client = Copilot(system_prompt=system_prompt)
|
|
104
|
-
|
|
105
122
|
prompt_parts = [
|
|
106
123
|
"`git status`:\n",
|
|
107
124
|
f"```\n{status.get_porcelain_output()}\n```",
|
|
@@ -116,11 +133,19 @@ def generate_commit_message(
|
|
|
116
133
|
|
|
117
134
|
prompt = "\n".join(prompt_parts)
|
|
118
135
|
|
|
136
|
+
if model is None:
|
|
137
|
+
model = "github_copilot/gpt-4"
|
|
138
|
+
|
|
139
|
+
if not model.startswith("github_copilot/"):
|
|
140
|
+
model = f"github_copilot/{model}"
|
|
141
|
+
|
|
119
142
|
try:
|
|
120
|
-
|
|
121
|
-
response = client.ask(prompt, model=model) if model else client.ask(prompt)
|
|
122
|
-
return response.content
|
|
143
|
+
return ask(prompt, model=model)
|
|
123
144
|
except Exception as _:
|
|
145
|
+
console.print(
|
|
146
|
+
"Prompt failed, falling back to simpler commit message generation."
|
|
147
|
+
)
|
|
148
|
+
|
|
124
149
|
fallback_prompt_parts = [
|
|
125
150
|
"`git status`:\n",
|
|
126
151
|
f"```\n{status.get_porcelain_output()}\n```",
|
|
@@ -137,13 +162,7 @@ def generate_commit_message(
|
|
|
137
162
|
|
|
138
163
|
fallback_prompt = "\n".join(fallback_prompt_parts)
|
|
139
164
|
|
|
140
|
-
|
|
141
|
-
response = (
|
|
142
|
-
client.ask(fallback_prompt, model=model)
|
|
143
|
-
if model
|
|
144
|
-
else client.ask(fallback_prompt)
|
|
145
|
-
)
|
|
146
|
-
return response.content
|
|
165
|
+
return ask(fallback_prompt, model=model)
|
|
147
166
|
|
|
148
167
|
|
|
149
168
|
@app.command()
|
|
@@ -221,9 +240,7 @@ def commit(
|
|
|
221
240
|
):
|
|
222
241
|
commit_message = generate_commit_message(repo, model, context=context)
|
|
223
242
|
|
|
224
|
-
console.print(
|
|
225
|
-
"[yellow]Generated commit message based on [bold]`git diff --staged`[/] ...[/yellow]"
|
|
226
|
-
)
|
|
243
|
+
console.print("[yellow]Generated commit message.[/yellow]")
|
|
227
244
|
|
|
228
245
|
# Display commit message
|
|
229
246
|
console.print(
|
|
@@ -275,47 +292,6 @@ def commit(
|
|
|
275
292
|
console.print(f"[green]✓ Successfully committed: {commit_sha[:8]}[/green]")
|
|
276
293
|
|
|
277
294
|
|
|
278
|
-
@app.command()
|
|
279
|
-
def authenticate():
|
|
280
|
-
"""Autheticate with GitHub Copilot."""
|
|
281
|
-
Authentication().auth()
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
@app.command()
|
|
285
|
-
def models():
|
|
286
|
-
"""List models available for chat in a table."""
|
|
287
|
-
models = Copilot().models
|
|
288
|
-
|
|
289
|
-
console = Console()
|
|
290
|
-
table = Table(title="Available Models")
|
|
291
|
-
|
|
292
|
-
table.add_column("ID", style="cyan", no_wrap=True)
|
|
293
|
-
table.add_column("Name", style="magenta")
|
|
294
|
-
table.add_column("Vendor", style="green")
|
|
295
|
-
table.add_column("Version", style="yellow")
|
|
296
|
-
table.add_column("Family", style="white")
|
|
297
|
-
table.add_column("Max Tokens", style="white")
|
|
298
|
-
table.add_column("Streaming", style="white")
|
|
299
|
-
|
|
300
|
-
for model in models:
|
|
301
|
-
capabilities = model.get("capabilities", {})
|
|
302
|
-
family = capabilities.get("family", "N/A")
|
|
303
|
-
max_tokens = capabilities.get("limits", {}).get("max_output_tokens", "N/A")
|
|
304
|
-
streaming = capabilities.get("supports", {}).get("streaming", False)
|
|
305
|
-
|
|
306
|
-
table.add_row(
|
|
307
|
-
model.get("id", "N/A"),
|
|
308
|
-
model.get("name", "N/A"),
|
|
309
|
-
model.get("vendor", "N/A"),
|
|
310
|
-
model.get("version", "N/A"),
|
|
311
|
-
family,
|
|
312
|
-
str(max_tokens),
|
|
313
|
-
str(streaming),
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
console.print(table)
|
|
317
|
-
|
|
318
|
-
|
|
319
295
|
@app.command()
|
|
320
296
|
def config(
|
|
321
297
|
set_default_model: str | None = typer.Option(
|
|
@@ -347,51 +323,5 @@ def config(
|
|
|
347
323
|
console.print(f"Config file: [dim]{settings.config_file}[/dim]")
|
|
348
324
|
|
|
349
325
|
|
|
350
|
-
@app.command()
|
|
351
|
-
def echo(
|
|
352
|
-
model: str | None = typer.Option(
|
|
353
|
-
None, "--model", "-m", help="Model to use for generating commit message"
|
|
354
|
-
),
|
|
355
|
-
):
|
|
356
|
-
"""
|
|
357
|
-
Generate commit message from stdin input (useful for pipes).
|
|
358
|
-
"""
|
|
359
|
-
# Read from stdin
|
|
360
|
-
input_text = sys.stdin.read()
|
|
361
|
-
|
|
362
|
-
if not input_text.strip():
|
|
363
|
-
console.print("[red]Error: No input provided via stdin[/red]")
|
|
364
|
-
raise typer.Exit(1)
|
|
365
|
-
|
|
366
|
-
# Load settings and use default model if none provided
|
|
367
|
-
settings = Settings()
|
|
368
|
-
if model is None:
|
|
369
|
-
model = settings.default_model
|
|
370
|
-
|
|
371
|
-
# Load system prompt and create client
|
|
372
|
-
system_prompt = load_system_prompt()
|
|
373
|
-
client = Copilot(system_prompt=system_prompt)
|
|
374
|
-
|
|
375
|
-
# Generate commit message from the input
|
|
376
|
-
prompt = f"""
|
|
377
|
-
`git diff --staged`:
|
|
378
|
-
|
|
379
|
-
```
|
|
380
|
-
{input_text.strip()}
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
Generate a conventional commit message based on the input above:"""
|
|
384
|
-
|
|
385
|
-
try:
|
|
386
|
-
response = client.ask(prompt, model=model) if model else client.ask(prompt)
|
|
387
|
-
# Print the commit message directly to stdout (no rich formatting for pipes)
|
|
388
|
-
import builtins
|
|
389
|
-
|
|
390
|
-
builtins.print(response.content)
|
|
391
|
-
except CopilotAPIError as e:
|
|
392
|
-
console.print(f"[red]Error generating commit message: {e}[/red]")
|
|
393
|
-
raise typer.Exit(1)
|
|
394
|
-
|
|
395
|
-
|
|
396
326
|
if __name__ == "__main__":
|
|
397
327
|
app()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Commit Message Generator System Prompt
|
|
2
|
+
|
|
3
|
+
You are a Git commit message assistant trained to write a single clear, structured, and informative commit message following the Conventional Commits specification.
|
|
4
|
+
|
|
5
|
+
Your task is to generate a commit message in the [Conventional Commits](https://www.conventionalcommits.org/) format based on both inputs.
|
|
6
|
+
|
|
7
|
+
## Output Format
|
|
8
|
+
|
|
9
|
+
<type>(<optional scope>): <description>
|
|
10
|
+
|
|
11
|
+
- Do not include a body or footer.
|
|
12
|
+
- Do not wrap the message in backticks or code blocks.
|
|
13
|
+
- Keep the title line ≤72 characters.
|
|
14
|
+
|
|
15
|
+
## `<type>`
|
|
16
|
+
|
|
17
|
+
- `feat`: New feature
|
|
18
|
+
- `fix`: Bug fix
|
|
19
|
+
- `docs`: Documentation changes
|
|
20
|
+
- `style`: Code formatting (no logic changes)
|
|
21
|
+
- `refactor`: Code restructuring (no behavior changes)
|
|
22
|
+
- `perf`: Performance improvements
|
|
23
|
+
- `test`: Adding or updating tests
|
|
24
|
+
- `chore`: Maintenance tasks (e.g., CI/CD, dependencies)
|
|
25
|
+
- `revert`: Revert of a previous commit
|
|
26
|
+
|
|
27
|
+
## `(<optional scope>)`
|
|
28
|
+
|
|
29
|
+
- Lowercase, single word or hyphenated phrase
|
|
30
|
+
- Represents the affected area, module, or file
|
|
31
|
+
- Use broad area if multiple related files are affected
|
|
32
|
+
|
|
33
|
+
## `<description>`
|
|
34
|
+
|
|
35
|
+
- Use imperative mood ("remove" not "removed")
|
|
36
|
+
- Focus on **what** changed, not why or how
|
|
37
|
+
- Be concise and specific
|
|
38
|
+
- Use abbreviations (e.g., "config" not "configuration")
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Do Not
|
|
43
|
+
|
|
44
|
+
- Do not speculate or infer what the diff is doing
|
|
45
|
+
- Do not use vague phrases ("made changes", "updated code")
|
|
46
|
+
- Do not use past tense ("added", "removed")
|
|
47
|
+
- Do not use terms like "unused", "duplicate", or "deprecated" unless explicitly stated by the user or clearly shown in the diff.
|
|
48
|
+
- Do not explain implementation or reasoning ("to fix bug", "because of issue")
|
|
49
|
+
- Do not guess purpose based on intuition or incomplete file context
|
|
50
|
+
- Do not wrap the response in single backticks or triple backticks or code blocks
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
The user will provide a Git diff, a list of modified files, or a short description of changes.
|
|
55
|
+
|
|
56
|
+
Generate a single, short, clear and structured Conventional Commit message following the above rules. If multiple changes are detected, prioritize the most important changes in a single commit message. Do not add any body or footer. You can only give one reply for each conversation.
|
|
57
|
+
|
|
58
|
+
Return the commit message as the output without any additional text, explanations, or formatting markers.
|