git-aicommit-message 0.1.0__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.
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.1
2
+ Name: git-aicommit-message
3
+ Version: 0.1.0
4
+ Summary: AI-powered git commit message generator using Ollama
5
+ Author: TRAORE Timothée Rachid
6
+ License: MIT
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: requests>=2.28.0
10
+
11
+ # git-ai-commit
12
+
13
+ > Generate smart commit messages using AI — powered by Ollama (local, private).
14
+
15
+ ## Prerequisites
16
+
17
+ - Python 3.8+
18
+ - Ollama installed and running
19
+
20
+ ## Install everything in one command
21
+ ```bash
22
+ curl -fsSL https://raw.githubusercontent.com/rachid-traore/git-ai-commit/main/install.sh | sh
23
+ ```
24
+
25
+ This script will automatically install Ollama, pull the `mistral` model, and install `git-ai-commit`.
26
+
27
+ ## Manual installation
28
+
29
+ **1. Install Ollama**
30
+
31
+ | OS | Command |
32
+ |---|---|
33
+ | Mac | `brew install ollama` |
34
+ | Linux | `curl -fsSL https://ollama.com/install.sh \| sh` |
35
+ | Windows | [ollama.com/download](https://ollama.com/download) |
36
+
37
+ **2. Start Ollama and pull the model**
38
+ ```bash
39
+ ollama serve &
40
+ ollama pull mistral
41
+ ```
42
+
43
+ **3. Install git-ai-commit**
44
+ ```bash
45
+ pip install git-ai-commit
46
+ ```
47
+
48
+ ## Usage
49
+ ```bash
50
+ # Stage your changes
51
+ git add .
52
+
53
+ # Generate and commit
54
+ git ai-commit
55
+
56
+ # Open message in $EDITOR before committing
57
+ git ai-commit --edit
58
+ ```
59
+
60
+ ## Example output
61
+ ```
62
+ 🤖 Analyse du diff en cours...
63
+ → feat: add user authentication via JWT
64
+
65
+ [Y] Valider [e] Éditer [n] Annuler :
66
+ ```
67
+
68
+ ## How it works
69
+
70
+ 1. Reads your staged diff (`git diff --cached`)
71
+ 2. Detects commit type instantly via heuristics (`feat`, `fix`, `chore`...)
72
+ 3. Sends diff to local Ollama (`mistral` model)
73
+ 4. Proposes a [Conventional Commits](https://www.conventionalcommits.org) message
74
+ 5. You validate, edit, or cancel
75
+
76
+ ## Privacy
77
+
78
+ Your code never leaves your machine. Ollama runs 100% locally.
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,72 @@
1
+ # git-ai-commit
2
+
3
+ > Generate smart commit messages using AI — powered by Ollama (local, private).
4
+
5
+ ## Prerequisites
6
+
7
+ - Python 3.8+
8
+ - Ollama installed and running
9
+
10
+ ## Install everything in one command
11
+ ```bash
12
+ curl -fsSL https://raw.githubusercontent.com/rachid-traore/git-ai-commit/main/install.sh | sh
13
+ ```
14
+
15
+ This script will automatically install Ollama, pull the `mistral` model, and install `git-ai-commit`.
16
+
17
+ ## Manual installation
18
+
19
+ **1. Install Ollama**
20
+
21
+ | OS | Command |
22
+ |---|---|
23
+ | Mac | `brew install ollama` |
24
+ | Linux | `curl -fsSL https://ollama.com/install.sh \| sh` |
25
+ | Windows | [ollama.com/download](https://ollama.com/download) |
26
+
27
+ **2. Start Ollama and pull the model**
28
+ ```bash
29
+ ollama serve &
30
+ ollama pull mistral
31
+ ```
32
+
33
+ **3. Install git-ai-commit**
34
+ ```bash
35
+ pip install git-ai-commit
36
+ ```
37
+
38
+ ## Usage
39
+ ```bash
40
+ # Stage your changes
41
+ git add .
42
+
43
+ # Generate and commit
44
+ git ai-commit
45
+
46
+ # Open message in $EDITOR before committing
47
+ git ai-commit --edit
48
+ ```
49
+
50
+ ## Example output
51
+ ```
52
+ 🤖 Analyse du diff en cours...
53
+ → feat: add user authentication via JWT
54
+
55
+ [Y] Valider [e] Éditer [n] Annuler :
56
+ ```
57
+
58
+ ## How it works
59
+
60
+ 1. Reads your staged diff (`git diff --cached`)
61
+ 2. Detects commit type instantly via heuristics (`feat`, `fix`, `chore`...)
62
+ 3. Sends diff to local Ollama (`mistral` model)
63
+ 4. Proposes a [Conventional Commits](https://www.conventionalcommits.org) message
64
+ 5. You validate, edit, or cancel
65
+
66
+ ## Privacy
67
+
68
+ Your code never leaves your machine. Ollama runs 100% locally.
69
+
70
+ ## License
71
+
72
+ MIT
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.1
2
+ Name: git-aicommit-message
3
+ Version: 0.1.0
4
+ Summary: AI-powered git commit message generator using Ollama
5
+ Author: TRAORE Timothée Rachid
6
+ License: MIT
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: requests>=2.28.0
10
+
11
+ # git-ai-commit
12
+
13
+ > Generate smart commit messages using AI — powered by Ollama (local, private).
14
+
15
+ ## Prerequisites
16
+
17
+ - Python 3.8+
18
+ - Ollama installed and running
19
+
20
+ ## Install everything in one command
21
+ ```bash
22
+ curl -fsSL https://raw.githubusercontent.com/rachid-traore/git-ai-commit/main/install.sh | sh
23
+ ```
24
+
25
+ This script will automatically install Ollama, pull the `mistral` model, and install `git-ai-commit`.
26
+
27
+ ## Manual installation
28
+
29
+ **1. Install Ollama**
30
+
31
+ | OS | Command |
32
+ |---|---|
33
+ | Mac | `brew install ollama` |
34
+ | Linux | `curl -fsSL https://ollama.com/install.sh \| sh` |
35
+ | Windows | [ollama.com/download](https://ollama.com/download) |
36
+
37
+ **2. Start Ollama and pull the model**
38
+ ```bash
39
+ ollama serve &
40
+ ollama pull mistral
41
+ ```
42
+
43
+ **3. Install git-ai-commit**
44
+ ```bash
45
+ pip install git-ai-commit
46
+ ```
47
+
48
+ ## Usage
49
+ ```bash
50
+ # Stage your changes
51
+ git add .
52
+
53
+ # Generate and commit
54
+ git ai-commit
55
+
56
+ # Open message in $EDITOR before committing
57
+ git ai-commit --edit
58
+ ```
59
+
60
+ ## Example output
61
+ ```
62
+ 🤖 Analyse du diff en cours...
63
+ → feat: add user authentication via JWT
64
+
65
+ [Y] Valider [e] Éditer [n] Annuler :
66
+ ```
67
+
68
+ ## How it works
69
+
70
+ 1. Reads your staged diff (`git diff --cached`)
71
+ 2. Detects commit type instantly via heuristics (`feat`, `fix`, `chore`...)
72
+ 3. Sends diff to local Ollama (`mistral` model)
73
+ 4. Proposes a [Conventional Commits](https://www.conventionalcommits.org) message
74
+ 5. You validate, edit, or cancel
75
+
76
+ ## Privacy
77
+
78
+ Your code never leaves your machine. Ollama runs 100% locally.
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,14 @@
1
+ README.md
2
+ pyproject.toml
3
+ git_aicommit_message.egg-info/PKG-INFO
4
+ git_aicommit_message.egg-info/SOURCES.txt
5
+ git_aicommit_message.egg-info/dependency_links.txt
6
+ git_aicommit_message.egg-info/entry_points.txt
7
+ git_aicommit_message.egg-info/requires.txt
8
+ git_aicommit_message.egg-info/top_level.txt
9
+ src/__init__.py
10
+ src/editor.py
11
+ src/git.py
12
+ src/heuristic.py
13
+ src/main.py
14
+ src/ollama.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ git-aicommit-message = src.main:main
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "git-aicommit-message"
7
+ version = "0.1.0"
8
+ description = "AI-powered git commit message generator using Ollama"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "TRAORE Timothée Rachid"}
14
+ ]
15
+ dependencies = [
16
+ "requests>=2.28.0",
17
+ ]
18
+
19
+ [project.scripts]
20
+ git-aicommit-message = "src.main:main"
21
+
22
+ [tool.setuptools.packages.find]
23
+ where = ["."]
24
+ include = ["src*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,40 @@
1
+ import os
2
+ import subprocess
3
+ import tempfile
4
+ import sys
5
+
6
+ def open_in_editor(message: str) -> str:
7
+ """
8
+ Ouvre le message dans $EDITOR pour que l'utilisateur puisse le modifier.
9
+ Retourne le message modifié.
10
+ """
11
+ editor = os.environ.get("EDITOR", _default_editor())
12
+ # Écrit le message dans un fichier temporaire
13
+ with tempfile.NamedTemporaryFile(
14
+ mode="w", suffix=".txt", delete=False, prefix="git_ai_commit_"
15
+ ) as f:
16
+ f.write(message)
17
+ f.write("\n\n# Modifie le message ci-dessus puis sauvegarde et ferme l'éditeur.")
18
+ f.write("\n# Les lignes commençant par # sont ignorées.")
19
+ tmp_path = f.name
20
+ try:
21
+ subprocess.call([editor, tmp_path])
22
+ with open(tmp_path, "r") as f:
23
+ lines = f.readlines()
24
+ # Ignore les commentaires et lignes vides
25
+ edited = "".join(
26
+ line for line in lines
27
+ if not line.startswith("#")
28
+ ).strip()
29
+ if not edited:
30
+ print("❌ Message vide, commit annulé.")
31
+ sys.exit(0)
32
+ return edited
33
+ finally:
34
+ os.unlink(tmp_path)
35
+
36
+ def _default_editor():
37
+ """Retourne un éditeur par défaut selon l'OS."""
38
+ if os.name == "nt": # Windows
39
+ return "notepad"
40
+ return "nano" # Mac / Linux
@@ -0,0 +1,44 @@
1
+ import subprocess
2
+ import sys
3
+
4
+ def check_git_repo():
5
+ """Vérifie qu'on est bien dans un repo git."""
6
+ result = subprocess.run(
7
+ ["git", "rev-parse", "--is-inside-work-tree"],
8
+ capture_output=True, text=True
9
+ )
10
+ if result.returncode != 0:
11
+ print("❌ Tu n'es pas dans un repo git.")
12
+ sys.exit(1)
13
+
14
+ def get_staged_diff():
15
+ """Récupère le diff des fichiers stagés."""
16
+ result = subprocess.run(
17
+ ["git", "diff", "--cached"],
18
+ capture_output=True, text=True
19
+ )
20
+ diff = result.stdout.strip()
21
+ if not diff:
22
+ print("❌ Aucun fichier stagé. Fais d'abord un `git add`.")
23
+ sys.exit(1)
24
+ return diff
25
+
26
+ def get_staged_files():
27
+ """Retourne la liste des fichiers stagés."""
28
+ result = subprocess.run(
29
+ ["git", "diff", "--cached", "--name-only"],
30
+ capture_output=True, text=True
31
+ )
32
+ return result.stdout.strip().splitlines()
33
+
34
+ def do_commit(message):
35
+ """Exécute le commit avec le message donné."""
36
+ result = subprocess.run(
37
+ ["git", "commit", "-m", message],
38
+ capture_output=True, text=True
39
+ )
40
+ if result.returncode == 0:
41
+ print(f"✅ Commit effectué :\n {message}")
42
+ else:
43
+ print(f"❌ Erreur lors du commit :\n{result.stderr}")
44
+ sys.exit(1)
@@ -0,0 +1,27 @@
1
+ import os
2
+ from typing import List
3
+
4
+ # Règles : si un fichier matche → on suggère ce type
5
+ RULES = [
6
+ (["test_", "_test.", ".spec.", ".test."], "test"),
7
+ (["package.json", "requirements.txt", "pyproject.toml",
8
+ "Makefile", "Dockerfile", ".github/", ".gitignore",
9
+ "setup.cfg", "setup.py"], "chore"),
10
+ (["README", ".md", "docs/", "CHANGELOG"], "docs"),
11
+ (["fix", "bug", "hotfix", "patch"], "fix"),
12
+ (["refactor", "clean", "rename", "move"], "refactor"),
13
+ ]
14
+
15
+ def detect_type(staged_files: List[str]) -> str:
16
+ """
17
+ Analyse les noms de fichiers stagés et devine le type Conventional Commit.
18
+ Retourne 'feat' par défaut si rien ne matche.
19
+ """
20
+ for file in staged_files:
21
+ filename = os.path.basename(file).lower()
22
+ filepath = file.lower()
23
+ for patterns, commit_type in RULES:
24
+ for pattern in patterns:
25
+ if pattern.lower() in filename or pattern.lower() in filepath:
26
+ return commit_type
27
+ return "feat" # fallback par défaut
@@ -0,0 +1,64 @@
1
+ import sys
2
+ import argparse
3
+ from src.git import check_git_repo, get_staged_diff, get_staged_files, do_commit
4
+ from src.heuristic import detect_type
5
+ from src.ollama import generate_message
6
+ from src.editor import open_in_editor
7
+
8
+ def main():
9
+ parser = argparse.ArgumentParser(
10
+ description="🤖 Génère un message de commit via Ollama"
11
+ )
12
+ parser.add_argument(
13
+ "--edit", "-e",
14
+ action="store_true",
15
+ help="Ouvre le message dans $EDITOR avant de committer"
16
+ )
17
+ args = parser.parse_args()
18
+
19
+ # 1. Vérifications de base
20
+ check_git_repo()
21
+
22
+ # 2. Récupère les infos git
23
+ diff = get_staged_diff()
24
+ staged_files = get_staged_files()
25
+
26
+ # 3. Heuristique immédiate (pendant qu'Ollama réfléchit)
27
+ fallback_type = detect_type(staged_files)
28
+
29
+ # 4. Génère le message via Ollama
30
+ print("🤖 Analyse du diff en cours...")
31
+ message = generate_message(diff, fallback_type)
32
+
33
+ # 5. Si Ollama a échoué → on construit un message minimal avec l'heuristique
34
+ if not message:
35
+ staged_names = ", ".join(staged_files[:3])
36
+ message = f"{fallback_type}: update {staged_names}"
37
+ print(f" Message de fallback : {message}")
38
+
39
+ # 6. Mode --edit : ouvre dans $EDITOR
40
+ if args.edit:
41
+ message = open_in_editor(message)
42
+
43
+ # 7. Affiche la proposition
44
+ print(f"\n→ {message}\n")
45
+
46
+ # 8. Demande confirmation
47
+ try:
48
+ choice = input("[Y] Valider [e] Éditer [n] Annuler : ").strip().lower()
49
+ except KeyboardInterrupt:
50
+ print("\n❌ Annulé.")
51
+ sys.exit(0)
52
+
53
+ if choice in ("", "y"):
54
+ do_commit(message)
55
+ elif choice == "e":
56
+ message = open_in_editor(message)
57
+ print(f"\n→ {message}\n")
58
+ confirm = input("Valider ce message ? [Y/n] : ").strip().lower()
59
+ if confirm in ("", "y"):
60
+ do_commit(message)
61
+ else:
62
+ print("❌ Commit annulé.")
63
+ else:
64
+ print("❌ Commit annulé.")
@@ -0,0 +1,81 @@
1
+ import requests
2
+ import sys
3
+
4
+ OLLAMA_URL = "http://localhost:11434/api/generate"
5
+ MODEL = "mistral"
6
+ MAX_DIFF_CHARS = 4000 # ~1000 tokens, suffisant pour un diff normal
7
+
8
+ PROMPT_TEMPLATE = """You are a git commit message assistant.
9
+ Analyze the following git diff and write a commit message.
10
+
11
+ Rules:
12
+ - Use Conventional Commits format: type: short description
13
+ - Types allowed: feat, fix, chore, docs, refactor, test, style
14
+ - Title only, NO body, NO bullet points
15
+ - Maximum 72 characters total
16
+ - Always write in English
17
+ - Be specific and concise
18
+
19
+ Git diff:
20
+ {diff}
21
+
22
+ Respond with ONLY the commit message, nothing else."""
23
+
24
+ def check_ollama():
25
+ """Vérifie qu'Ollama est accessible."""
26
+ try:
27
+ response = requests.get("http://localhost:11434", timeout=3)
28
+ return True
29
+ except requests.exceptions.ConnectionError:
30
+ print("❌ Ollama n'est pas détecté sur cette machine.")
31
+ print("")
32
+ print(" Installe-le :")
33
+ print(" → Mac : brew install ollama")
34
+ print(" → Linux : curl -fsSL https://ollama.com/install.sh | sh")
35
+ print(" → Win : https://ollama.com/download")
36
+ print("")
37
+ print(" Puis lance :")
38
+ print(" → ollama serve (démarre le serveur)")
39
+ print(" → ollama pull mistral (télécharge le modèle)")
40
+ sys.exit(1)
41
+
42
+ def truncate_diff(diff: str) -> str:
43
+ """Tronque le diff si trop long, en gardant le début."""
44
+ if len(diff) <= MAX_DIFF_CHARS:
45
+ return diff
46
+ truncated = diff[:MAX_DIFF_CHARS]
47
+ return truncated + "\n\n[... diff tronqué pour respecter la fenêtre de contexte ...]"
48
+
49
+ def generate_message(diff: str, fallback_type: str) -> str:
50
+ """Envoie le diff à Ollama et retourne le message généré."""
51
+ check_ollama()
52
+ diff = truncate_diff(diff)
53
+ prompt = PROMPT_TEMPLATE.format(diff=diff)
54
+ try:
55
+ response = requests.post(
56
+ OLLAMA_URL,
57
+ json={"model": MODEL, "prompt": prompt, "stream": False},
58
+ timeout=30
59
+ )
60
+ response.raise_for_status()
61
+ message = response.json().get("response", "").strip()
62
+ # Nettoyage : enlève les guillemets si l'IA en met
63
+ message = message.strip('"').strip("'")
64
+ # Vérifie que le message a un type Conventional Commit
65
+ # Sinon on préfixe avec le fallback heuristique
66
+ known_types = ["feat", "fix", "chore", "docs", "refactor", "test", "style"]
67
+ has_type = any(message.startswith(f"{t}:") or
68
+ message.startswith(f"{t}(") for t in known_types)
69
+ if not has_type:
70
+ message = f"{fallback_type}: {message}"
71
+ # Tronque si > 72 caractères
72
+ if len(message) > 72:
73
+ message = message[:72]
74
+ return message
75
+ except requests.exceptions.Timeout:
76
+ print("⚠️ Ollama a mis trop de temps à répondre.")
77
+ print(f" Utilisation de l'heuristique : type détecté = '{fallback_type}'")
78
+ return None
79
+ except Exception as e:
80
+ print(f"❌ Erreur Ollama : {e}")
81
+ return None