#!/bin/bash set -euo pipefail # Source shared library SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/git-ai-lib.sh" # Check for llm installation if ! command -v llm >/dev/null 2>&1; then echo "Error: llm command not found. Install from https://llm.datasette.io/en/stable/setup.html" >&2 exit 1 fi usage() { cat << EOF Usage: $(basename "$0") [options] Generate and commit changes using AI messages. Commits both staged and unstaged changes to tracked files (like git commit -a). By default, also stages and commits untracked files (skip with --no-verify). Options: -m, --model MODEL Specify the LLM model to use (default: deepseek-coder or o1-mini) Examples: gpt-4, claude-3-opus, mistral-7b, ... -d, --dry-run Show changes without committing -n, --no-verify Skip pre-commit hooks, skip adding untracked files, and pass --no-verify to git commit --author= Set commit author -s, --signoff, --no-signoff Add or remove signoff --cleanup= Set commit cleanup mode -e, --edit, --no-edit Edit or skip editing commit message -l, --list List available models -h, --help Show this help EOF exit 1 } # Default values model=$(select_default_model) script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Capture original arguments before parsing original_args=("$@") dry_run=false no_verify=false extra_commit_args=() # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in -m|--model) model="$2" shift 2 ;; -d|--dry-run) dry_run=true shift ;; -n|--no-verify) no_verify=true extra_commit_args+=("--no-verify") shift ;; -l|--list) echo "Available models:" llm models exit 0 ;; -h|--help) usage ;; --author=*|--cleanup=*|-e|--edit|--no-edit|-s|--signoff|--no-signoff) extra_commit_args+=("$1") shift ;; *) echo "Error: Unknown option: $1" >&2 usage ;; esac done # Check if we're in a git repository if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then echo "Error: Not in a git repository" >&2 exit 1 fi # Run pre-commit hook unless --no-verify was specified if [ "$no_verify" = false ]; then git_dir=$(git rev-parse --git-dir) pre_commit_hook="$git_dir/hooks/pre-commit" if [ -x "$pre_commit_hook" ]; then echo "Running pre-commit hook..." "$pre_commit_hook" fi fi # Check for any changes (staged, unstaged, or untracked) if [ -z "$(git status --porcelain)" ]; then echo "Error: No changes to commit" >&2 exit 1 fi if [ "$dry_run" = true ]; then echo "=== Changes to be committed ===" git status --short fi # Load additional instructions from config files repo_root=$(git rev-parse --show-toplevel) additional_instructions=$(load_additional_instructions "$repo_root") # Combine additional instructions with custom prompt (git-ai-commit doesn't have custom_prompt variable, so just use additional_instructions) combined_prompt="$additional_instructions" # Generate commit message with progress indicator model_display=$(resolve_model_display "$model") echo -e "\n== Commit Message (via ${model_display}) ==" echo -n "Generating commit message... " >&2 # Generate the diff and pipe through the message generator if [ "$no_verify" = false ]; then # Include untracked files commit_msg=$({ git diff HEAD; git ls-files --others --exclude-standard | xargs -I{} echo "A {}"; } | generate_commit_message "$model" "$combined_prompt" "") else # Only tracked files commit_msg=$(git diff HEAD | generate_commit_message "$model" "$combined_prompt" "") fi printf "\r\033[K" >&2 # Clear progress message # Display the message echo "$commit_msg" if [ "$dry_run" = true ]; then # Build suggestion command safely suggestion="$(basename "$0")" filtered_args=() for arg in "${original_args[@]}"; do [[ "$arg" != "-d" && "$arg" != "--dry-run" ]] && filtered_args+=("$arg") done if [ ${#filtered_args[@]} -gt 0 ]; then suggestion+=" ${filtered_args[*]}" fi echo -e "\n== Next Steps ==\nTo use a message like this, run:\n $suggestion" else # Stage and commit changes echo -e "\n== Committing changes... ==" >&2 if [ "$no_verify" = false ]; then git add -A # Add all changes including untracked files else git add -u # Only add changes to tracked files fi git commit -m "$commit_msg" ${extra_commit_args[@]:-} >/dev/null && echo "Changes committed successfully!" fi