Skip to content

Conversation

@Muneer320
Copy link
Contributor

@Muneer320 Muneer320 commented Oct 7, 2025

Description

Introduces an interactive commit review loop so contributors can accept, regenerate, or edit AI-generated commit messages. Regeneration attempts now send incremental context to the LLM, encouraging varied outputs and honoring tone presets or custom instructions.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Other (please describe):

Related Issue

Fixes #58

Changes Made

  • Added attempt-tracking to the CLI regenerate flow with preset/custom tone selection
  • Updated LLM prompt builder to include regeneration context and optional style guidance
  • Adjusted all providers to accept generation options and expanded automated tests for prompt behavior

Testing

  • Tested with Gemini API
  • Tested with Grok API
  • Tested with Groq API
  • Tested on Windows
  • Tested on Linux
  • Tested on macOS
  • Added/updated tests (if applicable)

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have tested this in a real Git repository
  • I have read the CONTRIBUTING.md guidelines

Screenshots (if applicable)

N/A

Additional Notes

Regeneration prompts now encourage distinct alternatives, helping users pick the best-fitting commit summary without manual tweaking.


For Hacktoberfest Participants

  • This PR is submitted as part of Hacktoberfest 2025

Thank you for your contribution! 🎉

Summary by CodeRabbit

  • New Features

    • Interactive commit message workflow with preview, accept/copy, regenerate (style presets or custom), edit in your editor, and exit.
    • Persistent LLM provider management: save/list/change default/update keys/delete providers.
    • Style guidance and regeneration context for message generation; Ollama model/url configurable via environment.
  • Documentation

    • README expanded with interactive workflow, examples, visuals, and LLM setup guidance.
  • Tests

    • Added tests for prompt construction covering style instructions and regeneration attempts.
  • Chores

    • Added .gitignore rule to ignore test_* files.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Walkthrough

Introduces an interactive commit-message review loop in the CLI, adds GenerationOptions and BuildCommitPrompt, updates all LLM providers to accept options, persists LLM provider configs, adds prompt/build tests, updates README and .gitignore, and adds a shlex dependency.

Changes

Cohort / File(s) Summary of changes
Interactive CLI workflow
cmd/cli/createMsg.go
Adds an interactive review loop (Accept/Copy, Regenerate with presets/custom, Edit in editor, Exit), style presets, editor detection/integration, provider error display, and a unified generateMessage dispatcher using GenerationOptions.
LLM provider updates
internal/chatgpt/chatgpt.go, internal/claude/claude.go, internal/gemini/gemini.go, internal/grok/grok.go, internal/groq/groq.go, internal/ollama/ollama.go
Changes GenerateCommitMessage(...) signatures to accept opts *types.GenerationOptions; replaces per-provider prompt construction with types.BuildCommitPrompt(changes, opts); adds provider-specific request/response types (Claude, Ollama) and minor provider docs; Grok adds a shared HTTP client.
Types: options & prompt builder
pkg/types/options.go, pkg/types/prompt.go
Adds GenerationOptions (StyleInstruction, Attempt) and BuildCommitPrompt(changes, opts) to append regeneration context and additional style instructions when provided.
Persistence for LLM configs
cmd/cli/store/store.go
Adds on-disk config types and functions: LLMProvider, Config, Save, DefaultLLMKey, ListSavedModels, ChangeDefault, DeleteModel, and UpdateAPIKey.
Tests
internal/groq/groq_test.go, pkg/types/types_test.go
Updates tests to pass the new opts parameter; adds tests verifying style instruction inclusion and regeneration context in built prompts.
Documentation & examples
README.md
Adds/expands “Interactive Commit Workflow” and usage flow, images/assets, updated environment/model notes and interactive options; reorganized headings for LLM management.
Dependency
go.mod
Adds github.com/google/shlex dependency.
Ignore rules
.gitignore
Adds "Test Files" section with pattern test_*.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant CLI as CLI (createMsg)
  participant Types as types.BuildCommitPrompt
  participant Provider as LLM Provider

  User->>CLI: Request generate commit message
  CLI->>Types: BuildCommitPrompt(changes, opts{Attempt=1})
  Types-->>CLI: Prompt
  CLI->>Provider: GenerateCommitMessage(config, changes, key/url/model, opts)
  Provider-->>CLI: Message or error

  loop Interactive review
    CLI->>User: Show message + actions [Accept | Regenerate | Edit | Exit]
    alt Accept
      CLI->>User: Copy to clipboard and finish
    else Regenerate
      CLI->>CLI: opts.Attempt++, set opts.StyleInstruction
      CLI->>Types: BuildCommitPrompt(changes, opts)
      Types-->>CLI: Prompt
      CLI->>Provider: GenerateCommitMessage(..., opts)
      Provider-->>CLI: New message or error
    else Edit
      CLI->>CLI: Open editor with message, return edited content
    else Exit
      CLI-->>User: Abort without copying
    end
  end
Loading
sequenceDiagram
  autonumber
  participant CLI
  participant Providers as ChatGPT/Claude/Gemini/Grok/Groq/Ollama
  participant Types as BuildCommitPrompt

  CLI->>Types: BuildCommitPrompt(changes, opts)
  Types-->>CLI: Prompt
  CLI->>Providers: GenerateCommitMessage(..., opts)
  Providers-->>CLI: Commit message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement, documentation, go, hacktoberfest, hacktoberfest-accepted

Suggested reviewers

  • DFanso

Poem

A nibble of bytes, a hop through the flow,
I tweak your tone — then off we go!
Accept or regen, edit if you please,
Clipboard ready, commit with ease.
Thump-thump, new prompt — one more try 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Beyond the interactive commit message editing functionality described in issue #58, this PR adds an unrelated .gitignore rule for test files (test_*), which is not required by the linked feature objectives. Please remove or isolate the .gitignore addition for ignoring test_* files into a separate pull request, keeping this changeset focused on the interactive commit flow feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly states the main feature that is being added—an interactive review flow for commit messages—matching the core changes in the PR. It is concise, clear, and focused without extraneous details.
Linked Issues Check ✅ Passed The pull request fully implements all features requested in issue #58 by adding an interactive loop with options to accept, regenerate with style presets or custom instructions, and edit the AI-generated commit message before finalizing, alongside prompt builder updates and provider adaptations.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90459f3 and 97470d5.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (14)
  • .gitignore (1 hunks)
  • README.md (6 hunks)
  • cmd/cli/createMsg.go (4 hunks)
  • go.mod (1 hunks)
  • internal/chatgpt/chatgpt.go (1 hunks)
  • internal/claude/claude.go (1 hunks)
  • internal/gemini/gemini.go (1 hunks)
  • internal/grok/grok.go (1 hunks)
  • internal/groq/groq.go (1 hunks)
  • internal/groq/groq_test.go (4 hunks)
  • internal/ollama/ollama.go (1 hunks)
  • pkg/types/options.go (1 hunks)
  • pkg/types/prompt.go (2 hunks)
  • pkg/types/types_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
pkg/types/prompt.go (1)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
internal/ollama/ollama.go (2)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (28-49)
internal/gemini/gemini.go (3)
internal/chatgpt/chatgpt.go (1)
  • GenerateCommitMessage (13-32)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (28-49)
internal/groq/groq.go (6)
internal/chatgpt/chatgpt.go (1)
  • GenerateCommitMessage (13-32)
internal/claude/claude.go (1)
  • GenerateCommitMessage (33-85)
internal/gemini/gemini.go (1)
  • GenerateCommitMessage (13-44)
internal/ollama/ollama.go (1)
  • GenerateCommitMessage (23-74)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (28-49)
internal/chatgpt/chatgpt.go (2)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (28-49)
internal/claude/claude.go (7)
internal/chatgpt/chatgpt.go (1)
  • GenerateCommitMessage (13-32)
internal/gemini/gemini.go (1)
  • GenerateCommitMessage (13-44)
internal/grok/grok.go (1)
  • GenerateCommitMessage (15-87)
internal/groq/groq.go (1)
  • GenerateCommitMessage (46-111)
internal/ollama/ollama.go (1)
  • GenerateCommitMessage (23-74)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (28-49)
internal/grok/grok.go (2)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (28-49)
internal/groq/groq_test.go (2)
internal/groq/groq.go (1)
  • GenerateCommitMessage (46-111)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
cmd/cli/createMsg.go (8)
pkg/types/types.go (9)
  • RepoConfig (59-62)
  • LLMProvider (3-3)
  • Config (53-56)
  • ProviderGemini (8-8)
  • ProviderOpenAI (6-6)
  • ProviderClaude (7-7)
  • ProviderGroq (10-10)
  • ProviderOllama (11-11)
  • ProviderGrok (9-9)
internal/display/display.go (2)
  • ShowCommitMessage (99-115)
  • ShowChangesPreview (118-133)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
internal/chatgpt/chatgpt.go (1)
  • GenerateCommitMessage (13-32)
internal/claude/claude.go (1)
  • GenerateCommitMessage (33-85)
internal/gemini/gemini.go (1)
  • GenerateCommitMessage (13-44)
internal/groq/groq.go (1)
  • GenerateCommitMessage (46-111)
internal/ollama/ollama.go (1)
  • GenerateCommitMessage (23-74)
pkg/types/types_test.go (2)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (28-49)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
🪛 markdownlint-cli2 (0.18.1)
README.md

183-183: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


189-189: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

🔇 Additional comments (13)
pkg/types/prompt.go (1)

26-49: LGTM! Well-structured prompt builder with proper null safety.

The BuildCommitPrompt function is well-implemented:

  • Uses efficient strings.Builder for concatenation
  • Properly handles nil opts parameter
  • Trims whitespace from StyleInstruction before checking if it's empty
  • Provides clear regeneration context when Attempt > 1

The implementation correctly constructs prompts that will help the LLM generate varied, context-aware commit messages.

pkg/types/options.go (1)

3-10: LGTM! Clean and well-documented options struct.

The GenerationOptions struct is well-designed:

  • Clear, concise field names
  • Comprehensive documentation explaining the purpose of each field
  • The 1-indexed Attempt convention is explicitly documented
README.md (2)

34-34: LGTM! Clear feature description.

The new interactive review flow feature is well-documented and aligns with the PR objectives.


141-150: LGTM! Helpful workflow documentation.

The interactive commit workflow section provides clear, user-friendly guidance on the new features:

  • Accept & copy
  • Regenerate with presets
  • Edit in editor
  • Exit

This documentation will help users understand and adopt the new interactive flow.

internal/claude/claude.go (1)

33-35: LGTM! Consistent integration of GenerationOptions.

The changes properly integrate the new GenerationOptions parameter:

  • Function signature updated to accept opts *types.GenerationOptions
  • Prompt construction delegated to types.BuildCommitPrompt(changes, opts)
  • Implementation is consistent with other providers (Groq, ChatGPT, Gemini)
internal/chatgpt/chatgpt.go (1)

13-17: LGTM! Consistent integration of GenerationOptions.

The changes properly integrate the new GenerationOptions parameter:

  • Function signature updated to accept opts *types.GenerationOptions
  • Prompt construction delegated to types.BuildCommitPrompt(changes, opts)
  • Implementation is consistent with other providers
internal/groq/groq.go (1)

46-51: LGTM! Consistent integration of GenerationOptions.

The changes properly integrate the new GenerationOptions parameter:

  • Function signature updated to accept opts *types.GenerationOptions
  • Prompt construction delegated to types.BuildCommitPrompt(changes, opts)
  • Implementation is consistent with other providers

The validation for empty changes string (line 47-49) remains in place, which is good defensive programming.

go.mod (1)

9-9: No action needed: github.com/google/shlex usage confirmed. The package is imported and shlex.Split is called in cmd/cli/createMsg.go.

internal/ollama/ollama.go (1)

23-31: Prompt builder integration looks solid.

Switching to BuildCommitPrompt cleanly threads regeneration context and style guidance without altering the rest of the flow.

internal/gemini/gemini.go (1)

13-31: Gemini now respects generation options.

Passing opts through BuildCommitPrompt keeps the provider aligned with the shared prompt strategy. Looks good.

internal/grok/grok.go (1)

15-87: Grok request updates align with the new prompt builder.

The change cleanly injects regeneration context/style instructions while leaving transport logic intact.

pkg/types/types_test.go (1)

52-105: Great coverage on the new prompt builder paths.

These tests pin the default, style, and regeneration behaviors, making future regressions unlikely.

internal/groq/groq_test.go (1)

7-145: Test updates thoroughly exercise the new options plumbing.

The additional assertions confirm request payloads include style instructions and regeneration context—exactly what we need.

Comment on lines +14 to +16
# Test Files
test_*

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Reconsider the test file ignore pattern.

The pattern test_* is overly broad and doesn't follow Go conventions:

  • Standard Go test files are named *_test.go, not test_*
  • This pattern could accidentally ignore legitimate files like test_data/, test_config.json, or test_helpers.go
  • Go test binaries created with go test -c are already covered by the *.test pattern on line 12

If the intent is to ignore temporary test files or test artifacts, consider either:

  1. Removing this pattern entirely (Go conventions already covered)
  2. Using a more specific pattern like test_output/ or test_artifacts/
  3. Documenting what specific files this is meant to ignore

Apply this diff to remove the overly broad pattern:

-# Test Files
-test_*
-

Or if specific test artifacts need to be ignored, use a more targeted pattern:

 # Test Files
-test_*
+test_output/
+test_artifacts/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Test Files
test_*
# Test Files
test_output/
test_artifacts/
🤖 Prompt for AI Agents
In .gitignore around lines 14 to 16, the broad pattern `test_*` will erroneously
ignore valid files and folders (e.g. test_data/, test_config.json,
test_helpers.go) and doesn't match Go test naming; remove the `test_*` line and,
if specific test artifacts should be ignored, replace it with targeted patterns
such as `test_output/`, `test_artifacts/`, or any explicit filenames/directories
you intend to exclude (do not add a blanket `test_*` pattern).

@DFanso
Copy link
Owner

DFanso commented Oct 7, 2025

Hey @Muneer320 did u check the code coderabbit review

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
cmd/cli/store/store.go (2)

220-255: Prevent setting default to a non-existent provider

ChangeDefault doesn’t verify that the target exists in LLMProviders. Add a check and error out if missing.

 func ChangeDefault(Model types.LLMProvider) error {
@@
-	cfg.Default = Model
+	// Ensure the model exists before setting default
+	found := false
+	for _, p := range cfg.LLMProviders {
+		if p.LLM == Model {
+			found = true
+			break
+		}
+	}
+	if !found {
+		return fmt.Errorf("cannot set default to %s: no saved entry", Model.String())
+	}
+	cfg.Default = Model
@@
 	return os.WriteFile(configPath, data, 0600)
 }

338-349: UpdateAPIKey should error when provider not found

Currently it writes the file even if nothing was updated. Return an error when the model doesn’t exist.

-	for i, p := range cfg.LLMProviders {
+	updated := false
+	for i, p := range cfg.LLMProviders {
 		if p.LLM == Model {
 			cfg.LLMProviders[i].APIKey = APIKey
+			updated = true
 		}
 	}
+	if !updated {
+		return fmt.Errorf("no saved entry for %s to update", Model.String())
+	}
♻️ Duplicate comments (1)
cmd/cli/createMsg.go (1)

147-176: Custom style is dropped on subsequent regenerations; preserve and reselect it

The selector doesn’t include the active custom label; defaulting to it silently falls back to the first preset, losing instructions. Keep the active custom label in options and reuse stored GenerationOptions when reselected.

Apply these diffs:

  1. Track current style options and pass them to the selector
-	currentStyleLabel := stylePresets[0].Label
+	currentStyleLabel := stylePresets[0].Label
+	var currentStyleOpts *types.GenerationOptions
@@
-			opts, styleLabel, err := promptStyleSelection(currentStyleLabel)
+			opts, styleLabel, err := promptStyleSelection(currentStyleLabel, currentStyleOpts)
@@
-			if styleLabel != "" {
+			if styleLabel != "" {
 				currentStyleLabel = styleLabel
 			}
+			// Persist selected style options for future regenerations
+			if opts != nil {
+				currentStyleOpts = opts
+			}
  1. Include the active custom label in the selector and return stored opts when chosen
-func promptStyleSelection(currentLabel string) (*types.GenerationOptions, string, error) {
-	options := make([]string, 0, len(stylePresets)+2)
-	for _, preset := range stylePresets {
-		options = append(options, preset.Label)
-	}
-	options = append(options, customStyleOption, styleBackOption)
+func promptStyleSelection(currentLabel string, currentOpts *types.GenerationOptions) (*types.GenerationOptions, string, error) {
+	options := make([]string, 0, len(stylePresets)+3)
+	foundCurrent := false
+	for _, preset := range stylePresets {
+		options = append(options, preset.Label)
+		if preset.Label == currentLabel {
+			foundCurrent = true
+		}
+	}
+	if currentOpts != nil && currentLabel != "" && !foundCurrent {
+		options = append(options, currentLabel)
+	}
+	options = append(options, customStyleOption, styleBackOption)
@@
 	choice, err := selector.Show()
@@
 	switch choice {
@@
 	case customStyleOption:
@@
 		return &types.GenerationOptions{StyleInstruction: text}, formatCustomStyleLabel(text), nil
 	default:
 		for _, preset := range stylePresets {
 			if choice == preset.Label {
 				if strings.TrimSpace(preset.Instruction) == "" {
 					return nil, preset.Label, nil
 				}
 				return &types.GenerationOptions{StyleInstruction: preset.Instruction}, preset.Label, nil
 			}
 		}
+		// If the user reselected the current custom label, reuse previous options
+		if currentOpts != nil && choice == currentLabel {
+			clone := *currentOpts
+			return &clone, currentLabel, nil
+		}
 	}
 
-	return nil, currentLabel, nil
+	// Default: keep current selection and options
+	if currentOpts != nil && currentLabel != "" {
+		clone := *currentOpts
+		return &clone, currentLabel, nil
+	}
+	return nil, currentLabel, nil

Also applies to: 263-307

🧹 Nitpick comments (7)
pkg/types/types.go (3)

22-23: Misplaced inline comment inside switch

Doc belongs near the type, not inside IsValid(). Please remove here and attach to LLMProvider type.

Apply this diff to remove the inline comment:

 	case ProviderOpenAI, ProviderClaude, ProviderGemini, ProviderGrok, ProviderGroq, ProviderOllama:
 		return true
-	// LLMProvider identifies the large language model backend used to author
-	// commit messages.

Add this doc where the type is declared (outside this hunk):

// LLMProvider identifies the large language model backend used to author commit messages.
type LLMProvider string

35-37: Stray/misleading comment in provider list

This comment describes String(), but it sits next to ProviderGroq in GetSupportedProviders. Remove it.

 		ProviderGrok,
-		// String returns the string form of the provider identifier.
 		ProviderGroq,

41-42: Doc comments attached to wrong declarations

Several doc comments are placed above unrelated items. Please relocate for correct go doc generation.

Apply this diff to remove the misplaced comments:

-// IsValid reports whether the provider is part of the supported set.
 
@@
-// GetSupportedProviders returns all available provider enums.
 
@@
-// GetSupportedProviderStrings returns the human-friendly names for providers.
 
@@
-	// ParseLLMProvider converts a string into an LLMProvider enum when supported.

Then add properly placed docs (outside this hunk):

// GetSupportedProviders returns all available provider enums.
func GetSupportedProviders() []LLMProvider { ... }

// IsValid reports whether the provider is part of the supported set.
func (p LLMProvider) IsValid() bool { ... }

// GetSupportedProviderStrings returns the human‑friendly names for providers.
func GetSupportedProviderStrings() []string { ... }

// ParseLLMProvider converts a string into an LLMProvider enum when supported.
func ParseLLMProvider(s string) (LLMProvider, bool) { ... }

Also applies to: 52-53, 65-66, 75-76

cmd/cli/store/store.go (1)

21-25: Naming collisions increase confusion

Local Config and LLMProvider types shadow pkg/types.Config and types.LLMProvider. Consider renaming to StoreConfig and ProviderEntry for clarity.

cmd/cli/createMsg.go (1)

239-251: Overloading APIKey as Ollama URL is leaky and confusing

Treating the stored APIKey as the Ollama URL complicates UX and storage semantics. Prefer a provider-specific config (e.g., URL, Model) or read Ollama URL/model from env/config only.

internal/grok/grok.go (1)

50-64: Consider reusing HTTP client instances.

The HTTP client is created on every GenerateCommitMessage call, which incurs TLS handshake overhead. For better performance, consider creating the client once (e.g., as a package-level or struct-level variable) and reusing it across calls.

Example refactor:

var (
	grokClientOnce sync.Once
	grokClient     *http.Client
)

func getGrokClient() *http.Client {
	grokClientOnce.Do(func() {
		transport := &http.Transport{
			TLSHandshakeTimeout: 10 * time.Second,
			MaxIdleConns:        10,
			IdleConnTimeout:     30 * time.Second,
			DisableCompression:  true,
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: false,
			},
		}
		grokClient = &http.Client{
			Timeout:   30 * time.Second,
			Transport: transport,
		}
	})
	return grokClient
}

Then use client := getGrokClient() instead of creating a new client.

internal/claude/claude.go (1)

20-24: Consolidate duplicate Message type.

The Message type defined here is identical to types.Message in pkg/types/types.go (lines 81-84). To reduce duplication and ensure consistency, use the shared type from the types package.

Apply this diff to use the shared type:

-// Message represents a single role/content pair exchanged with Claude.
-type Message struct {
-	Role    string `json:"role"`
-	Content string `json:"content"`
-}
-
 // ClaudeResponse captures the subset of fields used from Anthropic responses.
 type ClaudeResponse struct {
 	ID      string `json:"id"`
@@ -42,7 +37,7 @@ func GenerateCommitMessage(config *types.Config, changes string, apiKey string,
 	reqBody := ClaudeRequest{
 		Model:     "claude-3-5-sonnet-20241022",
 		MaxTokens: 200,
-		Messages: []Message{
+		Messages: []types.Message{
 			{
 				Role:    "user",
 				Content: prompt,
@@ -13,7 +13,7 @@
 // ClaudeRequest describes the payload sent to Anthropic's Claude messages API.
 type ClaudeRequest struct {
 	Model     string    `json:"model"`
-	Messages  []Message `json:"messages"`
+	Messages  []types.Message `json:"messages"`
 	MaxTokens int       `json:"max_tokens"`
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 97470d5 and ec3d2bc.

📒 Files selected for processing (10)
  • cmd/cli/createMsg.go (4 hunks)
  • cmd/cli/llmSetup.go (2 hunks)
  • cmd/cli/store/store.go (7 hunks)
  • internal/chatgpt/chatgpt.go (1 hunks)
  • internal/claude/claude.go (2 hunks)
  • internal/gemini/gemini.go (1 hunks)
  • internal/grok/grok.go (1 hunks)
  • internal/ollama/ollama.go (1 hunks)
  • pkg/types/prompt.go (2 hunks)
  • pkg/types/types.go (5 hunks)
✅ Files skipped from review due to trivial changes (1)
  • cmd/cli/llmSetup.go
🧰 Additional context used
🧬 Code graph analysis (8)
internal/chatgpt/chatgpt.go (2)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (30-51)
cmd/cli/store/store.go (1)
pkg/types/types.go (1)
  • LLMProvider (3-3)
internal/grok/grok.go (2)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (30-51)
internal/ollama/ollama.go (2)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (30-51)
pkg/types/prompt.go (1)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
internal/gemini/gemini.go (3)
internal/chatgpt/chatgpt.go (1)
  • GenerateCommitMessage (15-34)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (30-51)
internal/claude/claude.go (3)
pkg/types/types.go (2)
  • Message (82-85)
  • Config (60-63)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (30-51)
cmd/cli/createMsg.go (9)
pkg/types/types.go (2)
  • RepoConfig (68-71)
  • Config (60-63)
internal/display/display.go (2)
  • ShowCommitMessage (99-115)
  • ShowChangesPreview (118-133)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
internal/chatgpt/chatgpt.go (1)
  • GenerateCommitMessage (15-34)
internal/claude/claude.go (1)
  • GenerateCommitMessage (37-89)
internal/gemini/gemini.go (1)
  • GenerateCommitMessage (15-46)
internal/grok/grok.go (1)
  • GenerateCommitMessage (17-89)
internal/ollama/ollama.go (1)
  • GenerateCommitMessage (27-78)
internal/groq/groq.go (1)
  • GenerateCommitMessage (46-111)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Package Binaries
🔇 Additional comments (7)
cmd/cli/createMsg.go (1)

395-410: Helpful provider-specific errors — LGTM

Clear, actionable guidance per provider. Good UX.

pkg/types/prompt.go (1)

28-51: Prompt builder logic looks solid

Correctly appends regeneration context when Attempt > 1 and optional style guidance, then changes. Centralizing this across providers is good.

If not already covered, ensure tests assert:

  • Attempt == 1 omits regeneration section.
  • Attempt > 1 includes both lines of regeneration context.
  • StyleInstruction with surrounding whitespace is trimmed.
internal/gemini/gemini.go (1)

13-18: Switched to centralized prompt builder — good

Signature and prompt sourcing updated consistently; response checks remain intact.

Also applies to: 31-46

internal/grok/grok.go (1)

15-19: LGTM! Function signature and prompt construction updated correctly.

The addition of the opts parameter and the use of types.BuildCommitPrompt(changes, opts) align with the interactive regeneration feature. The prompt builder handles nil opts safely.

internal/chatgpt/chatgpt.go (1)

13-19: LGTM! Function signature and prompt construction updated correctly.

The addition of the opts parameter and the use of types.BuildCommitPrompt(changes, opts) are consistent with the broader refactoring across all LLM providers. The prompt builder handles nil opts safely.

internal/claude/claude.go (1)

36-39: LGTM! Function signature and prompt construction updated correctly.

The addition of the opts parameter and the use of types.BuildCommitPrompt(changes, opts) align with the interactive regeneration feature across all providers.

internal/ollama/ollama.go (1)

25-34: LGTM! Function signature and prompt construction updated correctly.

The addition of the opts parameter and the use of types.BuildCommitPrompt(changes, opts) are consistent with the broader refactoring. The prompt builder handles nil opts safely.

Comment on lines 16 to 19
type LLMProvider struct {
LLM types.LLMProvider `json:"model"`
APIKey string `json:"api_key"`
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Plain-text storage of API keys to disk

Storing API keys unencrypted in config.json is a security risk (even with 0600). Prefer OS keychains or secret stores; at minimum, allow env-var override and document the risk.

Options:

  • Windows: DPAPI/Credential Manager; macOS: Keychain; Linux: libsecret/gnome-keyring.
  • Or let users opt out of persistence and read from env only; if persisting, encrypt at rest with OS facilities.

Also applies to: 82-83

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
README.md (1)

178-194: Use proper markdown headings for better document structure.

Lines 178, 183, and 189 use bold text for section labels. These should be proper headings (e.g., ### Set LLM as default) for better document hierarchy, accessibility, and consistency with markdown best practices.

Apply this diff to fix the markdown structure:

-**Set LLM as default**
-
+### Set LLM as default
+
 ```bash
 Select: Set Default

-Change API Key

+### Change API Key
+

Select: Change API Key

-Delete LLM

+### Delete LLM
+

Select: Delete

Based on static analysis hints.

</blockquote></details>
<details>
<summary>cmd/cli/createMsg.go (1)</summary><blockquote>

`412-427`: **LGTM!**

Provider-specific error messages are helpful and guide users to the correct remediation steps.

**Note:** There's no specific case for `types.ProviderOllama`, so Ollama errors will use the generic message. This is acceptable since Ollama is local and doesn't use API keys, but you could add a specific message mentioning Ollama URL and model configuration if desired.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: CodeRabbit UI

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between ec3d2bc9b29d3a2180de9cc8d79cb85622f637f7 and 5f65d558d17b4d8c763d6c32df30351434b1384d.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `README.md` (6 hunks)
* `cmd/cli/createMsg.go` (4 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code graph analysis (1)</summary>

<details>
<summary>cmd/cli/createMsg.go (9)</summary><blockquote>

<details>
<summary>pkg/types/types.go (9)</summary>

* `RepoConfig` (68-71)
* `LLMProvider` (3-3)
* `Config` (60-63)
* `ProviderGemini` (8-8)
* `ProviderOpenAI` (6-6)
* `ProviderClaude` (7-7)
* `ProviderGroq` (10-10)
* `ProviderOllama` (11-11)
* `ProviderGrok` (9-9)

</details>
<details>
<summary>pkg/types/options.go (1)</summary>

* `GenerationOptions` (4-10)

</details>
<details>
<summary>internal/display/display.go (2)</summary>

* `ShowCommitMessage` (99-115)
* `ShowChangesPreview` (118-133)

</details>
<details>
<summary>internal/chatgpt/chatgpt.go (1)</summary>

* `GenerateCommitMessage` (15-34)

</details>
<details>
<summary>internal/gemini/gemini.go (1)</summary>

* `GenerateCommitMessage` (15-46)

</details>
<details>
<summary>internal/grok/grok.go (1)</summary>

* `GenerateCommitMessage` (17-89)

</details>
<details>
<summary>internal/ollama/ollama.go (1)</summary>

* `GenerateCommitMessage` (27-78)

</details>
<details>
<summary>internal/groq/groq.go (1)</summary>

* `GenerateCommitMessage` (46-111)

</details>
<details>
<summary>internal/claude/claude.go (1)</summary>

* `GenerateCommitMessage` (37-89)

</details>

</blockquote></details>

</details><details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>

<details>
<summary>README.md</summary>

183-183: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

---

189-189: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary>

* GitHub Check: Build Go Binary (windows-latest)

</details>

<details>
<summary>🔇 Additional comments (10)</summary><blockquote>

<details>
<summary>README.md (2)</summary><blockquote>

`34-34`: **LGTM!**

The feature description accurately reflects the new interactive review flow introduced in this PR.

---

`141-151`: **LGTM!**

The interactive workflow documentation is clear, comprehensive, and provides helpful context for users about the new review loop.

</blockquote></details>
<details>
<summary>cmd/cli/createMsg.go (8)</summary><blockquote>

`4-25`: **LGTM!**

All new imports are necessary for the interactive review flow functionality: `errors` for custom errors, `exec` for editor spawning, `runtime` for OS detection, `strings` for text processing, and `shlex` for shell command parsing.

---

`106-203`: **LGTM!**

The interactive loop is well-structured and implements all the actions specified in the PR objectives: Accept, Regenerate, Edit, and Exit. Error handling and flow control are appropriate.

---

`205-228`: **LGTM!**

The style preset system is well-designed with clear labels and appropriate instructions. The use of `errSelectionCancelled` as a sentinel error is a good pattern for flow control.

---

`265-324`: **Custom style persistence is now correctly implemented.**

The logic now properly persists custom style instructions across regenerations:
- Lines 274-276 ensure the custom label appears in the selector options
- Lines 280-282 set it as the default when present
- Lines 313-316 return the stored options when the custom label is reselected
- Lines 319-323 provide a fallback

This addresses the concern raised in the previous review about custom instructions being silently dropped.

---

`326-363`: **LGTM!**

The editor integration is well-implemented with proper temp file management, error handling at each step, and cleanup via `defer os.Remove` (line 336).

---

`365-392`: **LGTM!**

The editor resolution logic follows standard conventions by checking `GIT_EDITOR`, `VISUAL`, and `EDITOR` in order. The use of `shlex.Split` (line 377) properly handles editor commands that may include arguments, and platform-specific fallbacks (notepad on Windows, nano elsewhere) are appropriate.



Based on learnings about shlex usage.

---

`394-401`: **LGTM!**

The label formatting correctly uses runes for proper Unicode handling and provides a reasonable 40-character display limit with ellipsis for truncated text.

---

`403-410`: **LGTM!**

The function correctly clones the `styleOpts` to avoid mutation (line 407) and properly sets the attempt number. This ensures the original options are not modified.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
cmd/cli/store/store.go (2)

27-83: Add file locking to prevent concurrent modification issues.

Multiple processes or goroutines could simultaneously read/write the config file, leading to race conditions and data corruption. Consider using syscall.Flock (Unix) or equivalent locking mechanisms to ensure atomic operations.

Additionally, the logic at lines 48-53 catches os.ErrNotExist and sets data = []byte("{}"), but createConfigFile (lines 40-46) already ensures the file exists. This fallback is redundant. Also, lines 55-60 unmarshal into cfg that was initialized at lines 30-33, overwriting the initial setup—consider moving the initialization after the read.


146-185: Inconsistent empty-config check and error message formatting.

Line 167 uses len(data) > 2, which is brittle (assumes {} with spaces or content), whereas ListSavedModels (line 207) uses len(data) > 0. These checks should be consistent. Also, line 159's error message "config file Not exists" has inconsistent capitalization compared to other functions (lines 199, 232, 281, 334 use lowercase "not exists").

Consider extracting the repeated config-loading pattern (lines 148-174, 189-214, 225-245, 274-294, 327-347) into a helper function like loadConfig() (*Config, error) to reduce duplication and ensure consistency.

🧹 Nitpick comments (3)
internal/grok/grok.go (1)

23-35: Set a TLS minimum version on the Grok client transport.

The custom HTTP client doesn’t set MinVersion on tls.Config, so it can silently negotiate TLS 1.0/1.1 if the server offers it. Please pin the minimum to TLS 1.2 (or 1.3 if the API supports it) to avoid downgrades.

Suggested patch:

-			TLSClientConfig: &tls.Config{
-				InsecureSkipVerify: false,
-			},
+			TLSClientConfig: &tls.Config{
+				InsecureSkipVerify: false,
+				MinVersion:         tls.VersionTLS12,
+			},
cmd/cli/store/store.go (2)

85-93: Simplify redundant error check.

Line 88 checks err != nil || os.IsNotExist(err). If err is os.ErrNotExist, the first condition already evaluates to true, making the second check redundant.

Apply this diff:

-	if err != nil || os.IsNotExist(err) {
+	if err != nil {
 		return false
 	}

95-104: Function name is misleading.

createConfigFile only creates the parent directory structure but not the file itself. Consider renaming to ensureConfigDir or adding file creation logic to match the name.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f65d55 and 9bcb696.

📒 Files selected for processing (6)
  • README.md (6 hunks)
  • cmd/cli/createMsg.go (4 hunks)
  • cmd/cli/store/store.go (9 hunks)
  • internal/claude/claude.go (2 hunks)
  • internal/grok/grok.go (3 hunks)
  • pkg/types/types.go (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
cmd/cli/store/store.go (1)
pkg/types/types.go (1)
  • LLMProvider (5-5)
pkg/types/types.go (1)
cmd/cli/store/store.go (1)
  • LLMProvider (16-19)
internal/claude/claude.go (3)
pkg/types/types.go (1)
  • Message (80-83)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (30-51)
internal/grok/grok.go (2)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
pkg/types/prompt.go (1)
  • BuildCommitPrompt (30-51)
cmd/cli/createMsg.go (9)
pkg/types/types.go (9)
  • RepoConfig (66-69)
  • LLMProvider (5-5)
  • Config (60-63)
  • ProviderGemini (10-10)
  • ProviderOpenAI (8-8)
  • ProviderClaude (9-9)
  • ProviderGroq (12-12)
  • ProviderOllama (13-13)
  • ProviderGrok (11-11)
pkg/types/options.go (1)
  • GenerationOptions (4-10)
internal/display/display.go (2)
  • ShowCommitMessage (99-115)
  • ShowChangesPreview (118-133)
internal/claude/claude.go (1)
  • GenerateCommitMessage (31-83)
internal/grok/grok.go (1)
  • GenerateCommitMessage (42-99)
internal/chatgpt/chatgpt.go (1)
  • GenerateCommitMessage (15-34)
internal/gemini/gemini.go (1)
  • GenerateCommitMessage (15-46)
internal/ollama/ollama.go (1)
  • GenerateCommitMessage (27-78)
internal/groq/groq.go (1)
  • GenerateCommitMessage (46-111)
🪛 ast-grep (0.39.5)
internal/grok/grok.go

[warning] 27-29: MinVersionis missing from this TLS configuration. By default, TLS 1.2 is currently used as the minimum when acting as a client, and TLS 1.0 when acting as a server. General purpose web applications should default to TLS 1.3 with all other protocols disabled. Only where it is known that a web server must support legacy clients with unsupported an insecure browsers (such as Internet Explorer 10), it may be necessary to enable TLS 1.0 to provide support. AddMinVersion: tls.VersionTLS13' to the TLS configuration to bump the minimum version to TLS 1.3.
Context: tls.Config{
InsecureSkipVerify: false,
}
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
https://owasp.org/Top10/A02_2021-Cryptographic_Failures

(missing-ssl-minversion-go)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Package Binaries
🔇 Additional comments (3)
cmd/cli/store/store.go (3)

106-144: LGTM!

Cross-platform path resolution correctly handles Windows, macOS, and Linux with appropriate fallbacks for missing environment variables.


247-256: LGTM!

Validation ensures the target provider exists before updating the default, preventing orphaned references.


268-320: LGTM!

The delete logic correctly prevents removing the default provider when alternatives exist and appropriately resets the config when deleting the last provider.

Comment on lines +349 to +359
updated := false
for i, p := range cfg.LLMProviders {
if p.LLM == Model {
cfg.LLMProviders[i].APIKey = APIKey
updated = true
}
}

if !updated {
return fmt.Errorf("no saved entry for %s to update", Model.String())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add break after updating API key.

Line 353 sets updated = true but the loop continues unnecessarily. Add a break statement for efficiency.

Apply this diff:

 	for i, p := range cfg.LLMProviders {
 		if p.LLM == Model {
 			cfg.LLMProviders[i].APIKey = APIKey
 			updated = true
+			break
 		}
 	}

The validation at lines 357-359 correctly ensures the provider exists before updating.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
updated := false
for i, p := range cfg.LLMProviders {
if p.LLM == Model {
cfg.LLMProviders[i].APIKey = APIKey
updated = true
}
}
if !updated {
return fmt.Errorf("no saved entry for %s to update", Model.String())
}
updated := false
for i, p := range cfg.LLMProviders {
if p.LLM == Model {
cfg.LLMProviders[i].APIKey = APIKey
updated = true
break
}
}
if !updated {
return fmt.Errorf("no saved entry for %s to update", Model.String())
}
🤖 Prompt for AI Agents
In cmd/cli/store/store.go around lines 349 to 359, the loop that updates a
provider's APIKey sets updated = true but keeps iterating; add a break
immediately after setting cfg.LLMProviders[i].APIKey = APIKey (right after
updated = true) so the loop exits once the matching provider is updated,
improving efficiency.

Copy link
Owner

@DFanso DFanso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👾

@DFanso DFanso self-requested a review October 7, 2025 16:33
@DFanso DFanso merged commit bc0e7c3 into DFanso:main Oct 7, 2025
8 checks passed
@DFanso DFanso added enhancement New feature or request hacktoberfest Eligible for Hacktoberfest hacktoberfest-accepted Approved Hacktoberfest contribution go Pull requests that update go code labels Oct 7, 2025
@Muneer320
Copy link
Contributor Author

Wow, this rabbit really have nitpicks. 😭
Anyway, had fun with this.

Also on an unrelated note, there's a mismatch corners of the commit message panel, internal\display\display.go, it's a simple fix in the lines: 109-113, let me know if I should raise an issue.

image

@DFanso
Copy link
Owner

DFanso commented Oct 7, 2025

Sometime it also shows fixed parts 🤣. Btw can u raise a issue I will assign u if u like to work on that issue 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request go Pull requests that update go code hacktoberfest Eligible for Hacktoberfest hacktoberfest-accepted Approved Hacktoberfest contribution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Interactive Commit Message Editing

2 participants