mirror of
https://github.com/prdlk/gh-commit.git
synced 2026-09-16 23:16:25 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3086dac5d6 | ||
|
|
f1302fd1ec | ||
|
|
ae36a7052d | ||
|
|
9647c854c9 |
@@ -1,2 +0,0 @@
|
||||
/.omc
|
||||
/__pycache__
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Prad
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,6 +1,11 @@
|
||||
# gh-commit
|
||||
|
||||
AI-powered scoped git commits. Groups changes by project area, generates commit messages with `crush run`, and pushes — all in one command.
|
||||
AI-powered scoped git commits as a GitHub CLI extension, driven by the
|
||||
[Crush](https://github.com/charmbracelet/crush) CLI. Scopes map Conventional
|
||||
Commit scope names to path prefixes. They are generated from the repository
|
||||
file tree, stored in a local DuckDB database, and auto-regenerate whenever
|
||||
`.gitignore` changes. Changed files are grouped by scope and committed one
|
||||
scope at a time with generated `type(scope): message` subjects.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -11,64 +16,33 @@ gh extension install prdlk/gh-commit
|
||||
### Requirements
|
||||
|
||||
- [uv](https://docs.astral.sh/uv) — Python package runner (handles dependencies automatically)
|
||||
- [Crush](https://github.com/charmbracelet/crush) — non-interactive AI runner
|
||||
- `GROQ_API_KEY` — authenticates the default Groq model
|
||||
- [Crush](https://github.com/charmbracelet/crush) — configured with an authenticated model provider
|
||||
|
||||
By default, gh-commit uses Groq's `openai/gpt-oss-120b`. Override the model with `GH_COMMIT_CRUSH_MODEL`.
|
||||
By default, gh-commit uses `openrouter/qwen/qwen3.6-27b`. Configure OpenRouter in Crush or override the model with `GH_COMMIT_CRUSH_MODEL`.
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
# Initialize scopes for your repo (uses Crush to analyze structure)
|
||||
gh commit init
|
||||
|
||||
# Commit changes grouped by scope
|
||||
gh commit
|
||||
|
||||
# Auto-confirm + auto-push
|
||||
gh commit --auto --push
|
||||
|
||||
# Manually refresh scopes after structural changes
|
||||
gh commit refresh
|
||||
|
||||
# Sync scopes as GitHub labels
|
||||
gh commit sync
|
||||
cd your-repo
|
||||
gh commit init # generate scopes for this repo
|
||||
gh commit # commit changes grouped by scope
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
1. **`gh commit init`** — `crush run` analyzes your repo structure and generates scope definitions (e.g., `core → src/`, `docs → docs/, README.md`, `ci → .github/workflows/`)
|
||||
2. **`gh commit`** — Groups dirty files by scope, sends each staged diff to `crush run`, and commits each group separately
|
||||
3. **Auto-refresh** — Whenever your `.gitignore` changes, scopes are automatically regenerated before committing (a content hash of `.gitignore` is tracked per repo)
|
||||
4. Remaining unscoped files are handled in a final pass
|
||||
5. Unpushed commits are offered for push
|
||||
|
||||
Scopes are stored in a local DuckDB database (`~/.local/share/gh-commit/gh-commit.db`) — no config files in your repo.
|
||||
|
||||
### Why Crush?
|
||||
|
||||
The former Mods roles now live directly in `smartcommit.py`, so gh-commit no longer depends on Mods configuration. Each generation invokes Crush's supported non-interactive mode with a self-contained prompt.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `gh commit` | Commit changes grouped by scope |
|
||||
| `gh commit init` | Generate scopes for current repo |
|
||||
| `gh commit refresh` | Update scopes from current structure |
|
||||
| `gh commit sync` | Sync scopes → GitHub labels |
|
||||
| `gh commit list` | List all configured repositories |
|
||||
| `gh commit remove` | Remove current repo from database |
|
||||
| `gh commit db-path` | Print database file path |
|
||||
| `gh commit version` | Print version |
|
||||
| `gh commit help` | Show help |
|
||||
| Command | Behavior |
|
||||
|---|---|
|
||||
| `gh commit` | Full scoped-commit flow: group changed files by scope, generate a message per group, confirm, commit, offer to push |
|
||||
| `gh commit init` | Generate scopes from the file tree via Crush; migrates legacy configs; confirms overwrite |
|
||||
| `gh commit refresh` | Show current scopes, regenerate with existing scopes as context, confirm apply |
|
||||
| `gh commit sync` | Create/update GitHub labels from scopes (color = first 6 hex chars of MD5 of the scope name) |
|
||||
| `gh commit list` | Table of configured repositories: name, path, scope count |
|
||||
| `gh commit remove` | Delete the current repo from the database after confirmation |
|
||||
| `gh commit db-path` | Print the database file path |
|
||||
| `gh commit version` | Print `gh-commit <version>` |
|
||||
| `gh commit help` | Help, including the DB path and environment variable docs |
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--auto` | Skip all confirmation prompts |
|
||||
| `--push` | Auto-push after committing |
|
||||
Flags: `--auto` (skip confirmations), `--push` (auto-push).
|
||||
|
||||
## Environment
|
||||
|
||||
@@ -78,14 +52,39 @@ The former Mods roles now live directly in `smartcommit.py`, so gh-commit no lon
|
||||
| `GH_COMMIT_PUSH=1` | Auto-push after commits |
|
||||
| `GH_COMMIT_NO_AUTO_REFRESH=1` | Don't auto-regenerate scopes when `.gitignore` changes |
|
||||
| `GH_COMMIT_CRUSH_CMD` | Override the Crush command (default `crush`) |
|
||||
| `GH_COMMIT_CRUSH_MODEL` | Override the Crush model (default `groq/openai/gpt-oss-120b`) |
|
||||
| `GH_COMMIT_CRUSH_MODEL` | Override the Crush model (default `openrouter/qwen/qwen3.6-27b`) |
|
||||
| `GH_COMMIT_CRUSH_TIMEOUT` | Per-prompt timeout in seconds (default `120`) |
|
||||
| `GH_COMMIT_DEBUG=1` | Show scope-response parse diagnostics |
|
||||
|
||||
## Migration
|
||||
## Storage
|
||||
|
||||
Existing `.github/Repo.toml` or `.github/scopes.json` files are automatically detected and migrated to DuckDB on first run.
|
||||
Scopes live in `${XDG_DATA_HOME:-~/.local/share}/gh-commit/gh-commit.db`
|
||||
(DuckDB). Legacy `.github/Repo.toml` and `.github/scopes.json` files are
|
||||
migrated automatically on first run (the source file is archived as
|
||||
`*.migrated.<timestamp>`).
|
||||
|
||||
## License
|
||||
## Manual acceptance
|
||||
|
||||
MIT
|
||||
```sh
|
||||
mkdir /tmp/accept && cd /tmp/accept && git init
|
||||
mkdir -p src docs
|
||||
echo 'package app' > src/app.go
|
||||
echo '# Docs' > docs/README.md
|
||||
gh commit init # scopes generated and saved
|
||||
echo '// change' >> src/app.go
|
||||
echo 'More docs' >> docs/README.md
|
||||
gh commit # one commit per scope
|
||||
git log --format='%s' # verify type(scope): message subjects
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
The extension is a bash launcher (`gh-commit`) that runs `smartcommit.py`
|
||||
with `uv run --script`; uv resolves the inline dependencies (duckdb, rich,
|
||||
questionary) automatically.
|
||||
|
||||
```sh
|
||||
python -m py_compile smartcommit.py # syntax check
|
||||
bash -n gh-commit # launcher check
|
||||
./gh-commit version # smoke test
|
||||
```
|
||||
|
||||
Binary file not shown.
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"$schema": "https://charm.land/crush.json",
|
||||
"providers": {
|
||||
"groq": {
|
||||
"type": "openai-compat",
|
||||
"base_url": "https://api.groq.com/openai/v1",
|
||||
"api_key": "$GROQ_API_KEY",
|
||||
"models": [
|
||||
{
|
||||
"id": "openai/gpt-oss-120b",
|
||||
"name": "GPT-OSS 120B on Groq",
|
||||
"context_window": 131072,
|
||||
"default_max_tokens": 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
# gh-commit launcher — runs the bundled Python implementation via uv.
|
||||
set -euo pipefail
|
||||
|
||||
# gh-commit: AI-powered scoped git commits (Crush for scopes and messages)
|
||||
# Install: gh extension install prdlk/gh-commit
|
||||
# Requires: uv (https://docs.astral.sh/uv) and the Crush CLI
|
||||
# (https://github.com/charmbracelet/crush)
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
EXTENSION_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SCRIPT="${EXTENSION_DIR}/smartcommit.py"
|
||||
|
||||
if ! command -v uv &>/dev/null; then
|
||||
echo "error: 'uv' is required but not installed"
|
||||
echo "install: curl -LsSf https://astral.sh/uv/install.sh | sh"
|
||||
if ! command -v uv >/dev/null 2>&1; then
|
||||
echo "gh-commit: 'uv' is required (https://docs.astral.sh/uv)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${GH_COMMIT_CRUSH_CMD:-}" ]] && ! command -v crush &>/dev/null; then
|
||||
echo "warning: 'crush' not found — gh-commit uses 'crush run' for scopes and commit messages."
|
||||
echo "install Crush (https://github.com/charmbracelet/crush), or set GH_COMMIT_CRUSH_CMD."
|
||||
fi
|
||||
|
||||
exec uv run --script "${SCRIPT}" "$@"
|
||||
exec uv run --script "$DIR/smartcommit.py" "$@"
|
||||
|
||||
Binary file not shown.
+4
-9
@@ -44,9 +44,7 @@ DB_PATH = DB_DIR / "gh-commit.db"
|
||||
# Crush handles both AI steps in non-interactive mode. The instructions formerly
|
||||
# stored as mods roles are embedded below so this tool is self-contained.
|
||||
CRUSH_CMD = os.environ.get("GH_COMMIT_CRUSH_CMD", "crush").split()
|
||||
DEFAULT_CRUSH_MODEL = "groq/openai/gpt-oss-120b"
|
||||
CRUSH_MODEL = os.environ.get("GH_COMMIT_CRUSH_MODEL", DEFAULT_CRUSH_MODEL)
|
||||
CRUSH_CONFIG_DIR = Path(__file__).with_name("crush-provider")
|
||||
CRUSH_MODEL = os.environ.get("GH_COMMIT_CRUSH_MODEL", "openrouter/qwen/qwen3.6-27b")
|
||||
CRUSH_TIMEOUT = int(os.environ.get("GH_COMMIT_CRUSH_TIMEOUT", "120"))
|
||||
|
||||
AUTO_CONFIRM = os.environ.get("GH_COMMIT_AUTO", "0") == "1"
|
||||
@@ -54,7 +52,7 @@ AUTO_PUSH = os.environ.get("GH_COMMIT_PUSH", "0") == "1"
|
||||
NO_AUTO_REFRESH = os.environ.get("GH_COMMIT_NO_AUTO_REFRESH", "0") == "1"
|
||||
DEBUG = os.environ.get("GH_COMMIT_DEBUG", "0") == "1"
|
||||
|
||||
VERSION = "2.0.0"
|
||||
VERSION = "5.0.0"
|
||||
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
@@ -117,12 +115,9 @@ def crush_prompt(text: str, cwd: Path) -> str:
|
||||
cmd = [*CRUSH_CMD, "run", "--quiet"]
|
||||
if CRUSH_MODEL:
|
||||
cmd += ["--model", CRUSH_MODEL]
|
||||
env = os.environ.copy()
|
||||
if CRUSH_MODEL == DEFAULT_CRUSH_MODEL:
|
||||
env.setdefault("CRUSH_GLOBAL_CONFIG", str(CRUSH_CONFIG_DIR))
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd, input=text, capture_output=True, text=True, env=env,
|
||||
cmd, input=text, capture_output=True, text=True,
|
||||
cwd=str(cwd), timeout=CRUSH_TIMEOUT,
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
@@ -677,7 +672,7 @@ def cmd_help():
|
||||
console.print(" GH_COMMIT_PUSH=1 Auto-push after commits")
|
||||
console.print(" GH_COMMIT_NO_AUTO_REFRESH=1 Don't auto-regenerate scopes on .gitignore change")
|
||||
console.print(" GH_COMMIT_CRUSH_CMD=... Override the Crush command")
|
||||
console.print(f" GH_COMMIT_CRUSH_MODEL=... Override the Crush model (default: {DEFAULT_CRUSH_MODEL})")
|
||||
console.print(" GH_COMMIT_CRUSH_MODEL=... Override the Crush model (default: openrouter/qwen/qwen3.6-27b)")
|
||||
console.print(" GH_COMMIT_CRUSH_TIMEOUT=... Per-prompt timeout in seconds (default: 120)")
|
||||
console.print(" GH_COMMIT_DEBUG=1 Show parse diagnostics\n")
|
||||
console.print("[cyan]Scopes auto-refresh whenever .gitignore changes.[/]")
|
||||
|
||||
Reference in New Issue
Block a user