diff --git a/README.md b/README.md index 2891ae3..b76f3da 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Generate Git commit messages from staged diffs using your preferred LLM CLI. git-ai-commit does not talk to LLM APIs directly. -Instead, it delegates generation to existing LLM CLIs such as Claude Code, Gemini, or Codex, so no API keys, SDKs, or vendor-specific integrations are required. +Instead, it delegates generation to existing LLM CLIs such as Claude Code, Antigravity, or Codex, so no API keys, SDKs, or vendor-specific integrations are required. ## Install @@ -132,7 +132,8 @@ git-ai-commit treats LLMs as external commands, not as APIs. This design avoids Supported engines: - `claude` -- `gemini` +- `agy` (Antigravity CLI) +- `gemini` (deprecated — see note below) - `codex` Built-in defaults are applied when `engines..args` is not set. @@ -141,7 +142,9 @@ For `claude`, defaults include: - `-p --model haiku` - `--settings "{\"attribution\":{\"commit\":\"\",\"pr\":\"\"}}"` (prevents automatic `Co-authored-by` metadata) -If no engine is configured, auto-detection tries commands in this order: `claude` → `gemini` → `codex`. The first available command is used. +If no engine is configured, auto-detection tries commands in this order: `claude` → `agy` → `gemini` → `codex`. The first available command is used. + +> **Gemini CLI deprecation:** Google is transitioning Gemini CLI to Antigravity CLI (`agy`). After **June 18, 2026**, Gemini CLI stops serving requests for Google AI Pro/Ultra subscribers and free users. Gemini CLI continues to work for users on Gemini Code Assist Standard/Enterprise or paid API keys. If you previously used `engine = "gemini"`, switch to `engine = "agy"`. Any other engine name is treated as a direct command and executed with the prompt on stdin. diff --git a/internal/app/app_test.go b/internal/app/app_test.go index 37e09de..f3a34bc 100644 --- a/internal/app/app_test.go +++ b/internal/app/app_test.go @@ -172,6 +172,20 @@ func TestSelectEngineGeminiDefault(t *testing.T) { } } +func TestSelectEngineAgyDefault(t *testing.T) { + cfg := config.Default() + cfg.DefaultEngine = "agy" + cfg.Engines = map[string]config.EngineConfig{} + + _, command, err := selectEngine(cfg) + if err != nil { + t.Fatalf("selectEngine error: %v", err) + } + if command != "agy -p {{prompt}}" { + t.Fatalf("command = %q", command) + } +} + func TestSelectEngineCustomArgs(t *testing.T) { cfg := config.Default() cfg.DefaultEngine = "claude" diff --git a/internal/config/config.go b/internal/config/config.go index e35596c..541515a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -56,6 +56,7 @@ var DefaultEngineArgs = map[string][]string{ "claude": {"-p", "--model", "haiku", "--settings", "{\"attribution\":{\"commit\":\"\",\"pr\":\"\"}}", "--no-session-persistence"}, "cursor-agent": {"-p"}, "gemini": {"-m", "gemini-2.5-flash", "-p", "{{prompt}}"}, + "agy": {"-p", "{{prompt}}"}, } func Default() Config { @@ -353,7 +354,7 @@ func LoadPromptPreset(name string) (string, error) { } func autodetectEngine() string { - candidates := []string{"claude", "gemini", "codex"} + candidates := []string{"claude", "agy", "gemini", "codex"} for _, name := range candidates { if _, err := exec.LookPath(name); err == nil { return name diff --git a/internal/config/config_test.go b/internal/config/config_test.go index e27a69e..df51b19 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -82,6 +82,30 @@ func TestAutodetectEngineOrder(t *testing.T) { }) } +func TestAutodetectEnginePrefersAgyOverGemini(t *testing.T) { + configHome := t.TempDir() + binDir := filepath.Join(configHome, "bin") + if err := os.MkdirAll(binDir, 0o755); err != nil { + t.Fatalf("mkdir bin: %v", err) + } + makeExecutable(t, binDir, "codex") + makeExecutable(t, binDir, "gemini") + makeExecutable(t, binDir, "agy") + + t.Setenv("PATH", binDir) + t.Setenv("XDG_CONFIG_HOME", t.TempDir()) + + withDir(t, t.TempDir(), func() { + cfg, err := Load() + if err != nil { + t.Fatalf("Load error: %v", err) + } + if cfg.DefaultEngine != "agy" { + t.Fatalf("DefaultEngine = %q", cfg.DefaultEngine) + } + }) +} + func makeExecutable(t *testing.T, dir, name string) { t.Helper() path := filepath.Join(dir, name)