Skip to content

Conversation

@GauravJangra9988
Copy link
Contributor

@GauravJangra9988 GauravJangra9988 commented Oct 5, 2025

Description

Used cobra cli to add, delete or update models or api keys instead of setting through environment variables.
Models and API keys data stores in local file system.
Along with Models a default model parameter is also stored to that.
Default model can be changed easily.
Clean command line interface to manage the commit-msg.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • [ x] 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
  • [ x] Code refactoring
  • [x ] Performance improvement
  • Other (please describe):

Related Issue

#37
Fixes #(issue number)
#37

Changes Made

  • Set model with CLI instead of env
  • Models and API keys can persist in a local storage
  • Add, Update, Delete models and api keys

Testing

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

Checklist

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

Screenshots (if applicable)

Screenshot 2025-10-05 172814 Screenshot 2025-10-05 172823 Screenshot 2025-10-05 172731 Screenshot 2025-10-05 172748 Screenshot 2025-10-05 172759

Additional Notes

Added cobra cli to set Models and API keys
Stores Models and API keys data locally on system
Multiple models can added and switch between them
User can add, delete or update the models or API keys

For Hacktoberfest Participants

  • [x ] This PR is submitted as part of Hacktoberfest 2025

Thank you for your contribution! 🎉

Summary by CodeRabbit

  • New Features

    • Interactive CLI for AI-assisted commit message generation with preview and clipboard copy.
    • CLI workflow to add/update/delete LLM providers, store API keys locally, and set a default model.
    • Root command structure and entrypoint to run generation and LLM management.
  • Chores

    • Added new CLI/prompt dependencies.
  • Documentation

    • Fixed trailing newline in LICENSE file.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 5, 2025

Walkthrough

Adds a Cobra-based CLI for LLM provider management and commit-message generation, a JSON-backed local store for LLM configs, refactors main() to delegate to the CLI entrypoint, updates go.mod with prompt/CLI dependencies, and fixes a trailing newline in LICENSE.

Changes

Cohort / File(s) Summary
CLI root & commands
cmd/cli/root.go, cmd/cli/createMsg.go, cmd/cli/llmSetup.go
Adds Cobra rootCmd, llm subcommands (setup, update) and a commit-generation command; implements CreateCommitMsg(), SetupLLM(), and UpdateLLM() and wires them into the CLI.
Config store (LLM providers)
cmd/cli/store/store.go
Adds JSON-backed config types (Config, LLMProvider) and store APIs: Save, DefaultLLMKey, ListSavedModels, ChangeDefault, DeleteModel, UpdateAPIKey, plus path/file helpers and IO handling.
Main refactor
cmd/commit-msg/main.go
Replaces previous inline logic with a single call to cmd.Execute(); moves runtime flow into the cmd package.
Dependencies
go.mod
Adds CLI/prompt dependencies (spf13/cobra, manifoldco/promptui) and related indirect deps.
License newline fix
LICENSE
Fixes trailing newline at end of file; content unchanged otherwise.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Main as main()
  participant CLI as cmd.Execute()
  participant Cobra as Cobra rootCmd
  participant LLMCmd as llm subcommands
  participant Gen as CreateCommitMsg
  participant Store as store (config.json)
  participant Git as Git repo
  participant Provider as LLM API

  User->>Main: run binary
  Main->>CLI: Execute()
  CLI->>Cobra: rootCmd.Execute()

  alt Manage LLM providers
    User->>Cobra: llm setup / llm update
    Cobra->>LLMCmd: RunE -> SetupLLM / UpdateLLM
    LLMCmd->>Store: Save / ChangeDefault / UpdateAPIKey / DeleteModel
    Store-->>LLMCmd: result
    LLMCmd-->>User: confirmation / error
  else Generate commit msg
    User->>Cobra: commit (.)
    Cobra->>Gen: CreateCommitMsg()
    Gen->>Store: DefaultLLMKey()
    Store-->>Gen: provider + api key
    Gen->>Git: validate repo & get changes
    Git-->>Gen: diffs
    Gen->>Provider: request generation
    Provider-->>Gen: generated message
    Gen-->>User: display + clipboard attempt
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • DFanso

Poem

I thump a note beneath the moon,
New commands hop out of the dune.
Models stored in cosy JSON beds,
Commit-lines bloom from tiny heads.
Hooray — the CLI munches bugs and chews carrots too! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive The title “Cli interface” is overly generic and does not clearly convey the addition of a Cobra-based command line interface for managing LLM models, API keys, and automated commit message generation. It references a CLI but omits the main features and scope of the changes, making it hard for reviewers to quickly grasp the purpose. Because it lacks specificity, the title does not effectively summarize the primary change. Please choose a more descriptive title that highlights the core functionality, for example “Add Cobra-based CLI for LLM provider management and commit message generation.”
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ 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: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64baf24 and c360146.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • LICENSE (0 hunks)
  • cmd/cli/createMsg.go (1 hunks)
  • cmd/cli/llmSetup.go (1 hunks)
  • cmd/cli/root.go (1 hunks)
  • cmd/cli/store/store.go (1 hunks)
  • cmd/commit-msg/main.go (1 hunks)
  • go.mod (3 hunks)
💤 Files with no reviewable changes (1)
  • LICENSE
🧰 Additional context used
🧬 Code graph analysis (4)
cmd/cli/createMsg.go (5)
cmd/cli/store/store.go (2)
  • DefaultLLMKey (147-189)
  • Config (18-21)
internal/git/operations.go (2)
  • IsRepository (16-23)
  • GetChanges (26-130)
pkg/types/types.go (1)
  • RepoConfig (10-13)
internal/stats/statistics.go (1)
  • GetFileStatistics (14-74)
internal/display/display.go (3)
  • ShowFileStatistics (20-96)
  • ShowCommitMessage (99-115)
  • ShowChangesPreview (118-133)
cmd/cli/llmSetup.go (1)
cmd/cli/store/store.go (6)
  • LLMProvider (13-16)
  • Save (23-82)
  • ListSavedModels (192-226)
  • ChangeDefault (229-263)
  • UpdateAPIKey (322-362)
  • DeleteModel (266-319)
cmd/commit-msg/main.go (1)
cmd/cli/root.go (1)
  • Execute (24-29)
cmd/cli/root.go (2)
cmd/cli/llmSetup.go (2)
  • SetupLLM (11-48)
  • UpdateLLM (50-113)
cmd/cli/createMsg.go (1)
  • CreateCommitMsg (21-140)

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

♻️ Duplicate comments (1)
cmd/cli/store/store.go (1)

291-294: Return an error when refusing to delete the default model.

Line 294: When the target model is the default and other providers exist, the function prints a warning but returns nil, causing the caller to treat the operation as successful. This was flagged in a previous review and remains unfixed.

Apply this diff to return an error instead:

 	if Model == cfg.Default {
 		if len(cfg.LLMProviders) > 1 {
-			fmt.Println("Please set other model as default, Cant delete default model")
-			return nil
+			return fmt.Errorf("cannot delete %s while it is the default; set another default first", Model)
🧹 Nitpick comments (5)
cmd/cli/store/store.go (5)

24-27: Remove unnecessary struct initialization.

The cfg variable is initialized here but immediately overwritten when unmarshaling existing data from the config file (lines 53-58). This is inefficient and potentially confusing.

Apply this diff to declare cfg without initialization:

-	cfg := Config{
-		LLMConfig.LLM,
-		[]LLMProvider{LLMConfig},
-	}
+	var cfg Config

86-94: Simplify the redundant condition.

Line 89: The condition err != nil || os.IsNotExist(err) is redundant because os.IsNotExist(err) is only meaningful when err != nil. The function can be simplified to just return whether the stat call succeeded.

Apply this diff to simplify the logic:

 func checkConfig(configPath string) bool {
-
-	_,err := os.Stat(configPath)
-	if err != nil ||os.IsNotExist(err)  {
-		return false
-	}
-
-	return true
+	_, err := os.Stat(configPath)
+	return err == nil
 }

97-106: Rename function to match its behavior.

The function is named createConfigFile but only creates the parent directory, not the file itself. This is misleading and could confuse future maintainers.

Apply this diff to rename the function to better reflect its purpose:

-func createConfigFile(configPath string) error {
+func ensureConfigDir(configPath string) error {
 
 	err := os.MkdirAll(filepath.Dir(configPath), 0700)
 	if err != nil {

Then update all call sites (lines 37, etc.) to use the new name:

-		err := createConfigFile(configPath)
+		err := ensureConfigDir(configPath)

181-186: Simplify by returning directly.

Lines 183-184: The intermediate assignment to useModel is unnecessary. You can return the address of the slice element directly.

Apply this diff to simplify:

 	for i, p := range cfg.LLMProviders {
 		if p.LLM == defaultLLM {
-			useModel= cfg.LLMProviders[i]
-			return &useModel, nil
+			return &cfg.LLMProviders[i], nil
 		}
 	}

216-217: Consider moving user-facing message to the caller.

Line 216: This function mixes data access logic with user-facing output. The caller (CLI command) should handle presenting messages to the user based on the returned error, keeping this function focused on data operations.

Apply this diff to remove the user-facing message:

 	} else {
-		fmt.Println("Config file is empty, Please add atlead one LLM Key")
 		return nil, errors.New("config file is empty")
 	}

The caller can then check for this specific error and display an appropriate message.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c360146 and 19a6246.

📒 Files selected for processing (2)
  • cmd/cli/llmSetup.go (1 hunks)
  • cmd/cli/store/store.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/cli/llmSetup.go

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

♻️ Duplicate comments (4)
cmd/cli/store/store.go (4)

47-49: Fix the awkward line break.

The else if statement is split across two lines unnecessarily, reducing readability.

Apply this diff to fix the formatting:

-	} else if
- err != nil {
+	} else if err != nil {
 		return err
 	}

225-259: Validate that the model exists before setting it as default.

Line 251 sets cfg.Default = Model without verifying that Model exists in cfg.LLMProviders. This can result in an invalid default, causing DefaultLLMKey() to fail with "not found default model in config".

Apply this diff to add validation:

 	if len(data) > 0 {
 	err = json.Unmarshal(data, &cfg)
 	if err != nil {
 		return err
 	}
 	}
 
+	// Validate that the model exists
+	found := false
+	for _, p := range cfg.LLMProviders {
+		if p.LLM == Model {
+			found = true
+			break
+		}
+	}
+	if !found {
+		return fmt.Errorf("model %s not found in configuration", Model)
+	}
+
 	cfg.Default = Model

290-296: Return an error when refusing to delete the default model.

Line 293 returns nil when the target is still the default and other providers exist. This causes the caller (which prints "model deleted") to report success even though nothing happened.

Apply this diff:

 	if Model == cfg.Default {
 		if len(cfg.LLMProviders) > 1 {
-			fmt.Println("Please set other model as default, Cant delete default model")
-			return nil
+			return fmt.Errorf("cannot delete %s while it is the default; set another default first", Model)
 		} else {
 			return os.WriteFile(configPath, []byte("{}"), 0600)
 		}

345-356: Return an error if the model is not found.

Lines 345-349 loop through cfg.LLMProviders but never track whether a matching model was found. If the specified Model doesn't exist, the function silently succeeds, writing the unchanged config back to disk and returning nil, misleading the caller.

Apply this diff to track whether the update occurred:

+	found := false
 	for i, p := range cfg.LLMProviders {
 		if p.LLM == Model {
 			cfg.LLMProviders[i].APIKey = APIKey
+			found = true
+			break
 		}
 	}
+	if !found {
+		return fmt.Errorf("model %s not found in configuration", Model)
+	}
 
 	data, err = json.MarshalIndent(cfg, "", " ")
🧹 Nitpick comments (5)
cmd/cli/llmSetup.go (3)

20-23: Wrap the underlying error for better debugging.

Line 22 returns a generic error message without including the underlying error from prompt.Run(), making it harder to diagnose issues.

Apply this diff to wrap the error:

 	_, model, err := prompt.Run()
 	if err != nil {
-		return fmt.Errorf("prompt failed")
+		return fmt.Errorf("prompt failed: %w", err)
 	}

47-47: Add newline to success message.

Line 47 prints a success message without a trailing newline, which may cause formatting issues when subsequent output is displayed.

Apply this diff:

-	fmt.Println("LLM model added")
+	fmt.Println("LLM model added\n")

Or use Printf with \n:

-	fmt.Println("LLM model added")
+	fmt.Printf("LLM model added\n")

90-118: Move prompt declaration inside the switch case.

Lines 90-92 declare apiKeyprompt but it's only used in case 1 (line 103). Declaring it at the top of the function reduces readability and could lead to confusion.

Additionally, lines 101, 111, and 117 are missing trailing newlines in their printf statements.

Apply this diff:

-	apiKeyprompt := promptui.Prompt {
-		Label: "Enter API Key",
-	}
-
-
 	switch opNo {
 		case 0:
 			err := store.ChangeDefault(model)
 			if err != nil {
 				return err
 			}
-			fmt.Printf("%s set as default", model)
+			fmt.Printf("%s set as default\n", model)
 		case 1:
+			apiKeyprompt := promptui.Prompt{
+				Label: "Enter API Key",
+				Mask:  '*',
+			}
 			apiKey, err := apiKeyprompt.Run()
 			if err !=  nil {
 				return err
 			}
 			err = store.UpdateAPIKey(model, apiKey)
 			if err != nil {
 				return err
 			}
-			fmt.Printf("%s API Key Updated", model)
+			fmt.Printf("%s API Key Updated\n", model)
 		case 2:
 			err := store.DeleteModel(model)
 			if err != nil {
 				return err
 			}
-			fmt.Printf("%s model deleted", model)			
+			fmt.Printf("%s model deleted\n", model)
 	}

Note: The diff also adds masking to the API key prompt (as recommended in the earlier comment).

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

24-27: Use named fields for struct initialization.

Lines 24-27 use positional fields to initialize the Config struct. If the struct definition changes, this code will break silently or produce incorrect results.

Apply this diff:

 	cfg := Config{
-		LLMConfig.LLM,
-		[]LLMProvider{LLMConfig},
+		Default:      LLMConfig.LLM,
+		LLMProviders: []LLMProvider{LLMConfig},
 	}

86-94: Simplify the condition.

Line 89 has a redundant condition: if err != nil, checking os.IsNotExist(err) is unnecessary since any error should return false.

Apply this diff:

 func checkConfig(configPath string) bool {
 
 	_,err := os.Stat(configPath)
-	if err != nil ||os.IsNotExist(err)  {
+	if err != nil {
 		return false
 	}
 
 	return true
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19a6246 and 14ef8b7.

📒 Files selected for processing (2)
  • cmd/cli/llmSetup.go (1 hunks)
  • cmd/cli/store/store.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/cli/llmSetup.go (2)
cmd/cli/store/store.go (6)
  • LLMProvider (12-15)
  • Save (22-83)
  • ListSavedModels (191-222)
  • ChangeDefault (225-259)
  • UpdateAPIKey (318-358)
  • DeleteModel (262-315)
cmd/commit-msg/main.go (1)
  • main (22-170)
⏰ 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: GitGuardian Security Checks

@DFanso
Copy link
Owner

DFanso commented Oct 5, 2025

Hey @GauravJangra9988 can u fix merge conflicts

@DFanso DFanso self-requested a review October 5, 2025 14:37
@DFanso DFanso added enhancement New feature or request hacktoberfest Eligible for Hacktoberfest go Pull requests that update go code labels Oct 5, 2025
@DFanso DFanso linked an issue Oct 5, 2025 that may be closed by this pull request
@DFanso DFanso self-requested a review October 5, 2025 15:40
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.

check the coderabbit suggestions i saw some good points there

@GauravJangra9988
Copy link
Contributor Author

Made the required fixes

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: 6

🧹 Nitpick comments (7)
cmd/cli/store/store.go (5)

12-15: Consider renaming the LLM field to Model.

The field LLM stores the model name (e.g., "OpenAI", "Claude"), but the struct is called LLMProvider and the JSON tag is "model". Renaming the field to Model would improve clarity and align with the JSON representation.

Apply this diff:

 type LLMProvider struct {
-	LLM string `json:"model"`
+	Model string `json:"model"`
 	APIKey string `json:"api_key"`
 }

Note: This change would require updating all references to LLMProvider.LLM throughout the codebase (in llmSetup.go and within this file).


24-27: Use named fields in struct initialization.

The Config struct is initialized with positional arguments, which is fragile if fields are reordered or added in the future.

Apply this diff:

 	cfg := Config{
-		LLMConfig.LLM,
-		[]LLMProvider{LLMConfig},
+		Default:      LLMConfig.LLM,
+		LLMProviders: []LLMProvider{LLMConfig},
 	}

169-169: Replace magic number with a descriptive constant or comment.

The check len(data) > 2 assumes minimal JSON is {} (2 bytes). This could be clearer with either a named constant or a comment explaining the rationale.

Apply this diff:

+	// Check if config has content beyond empty JSON object "{}"
 	if len(data) > 2 {

226-260: Consider validation or making the function internal.

While the current callers ensure the model exists before calling ChangeDefault, as a public function it lacks validation. You have two options:

  1. Add validation (defense-in-depth for future callers)
  2. Make it internal by renaming to changeDefault if it's only meant for package use

Based on learnings from past review: The author noted that the UI validates the model exists, so validation here may be redundant. However, public APIs benefit from defensive checks.

For option 1, validation:

 	if len(data) > 0 {
 	err = json.Unmarshal(data, &cfg)
 	if err != nil {
 		return err
 	}
 	}
 
+	// Validate model exists
+	found := false
+	for _, p := range cfg.LLMProviders {
+		if p.LLM == Model {
+			found = true
+			break
+		}
+	}
+	if !found {
+		return fmt.Errorf("model %s not found in configuration", Model)
+	}
+
 	cfg.Default = Model

318-358: Consider validating that the model exists.

Similar to ChangeDefault, this public function silently succeeds even if the specified model doesn't exist. While the current UI ensures valid input, adding validation would make the API more robust.

Based on learnings from past review: The author noted that the UI only allows selection of existing models. However, as this is an exported function, defensive validation would prevent silent failures if called from other contexts.

Apply this diff:

+	found := false
 	for i, p := range cfg.LLMProviders {
 		if p.LLM == Model {
 			cfg.LLMProviders[i].APIKey = APIKey
+			found = true
+			break
 		}
 	}
+	if !found {
+		return fmt.Errorf("model %s not found in configuration", Model)
+	}
 
 	data, err = json.MarshalIndent(cfg, "", " ")
cmd/cli/llmSetup.go (2)

14-14: Consider defining provider types or constants.

The hardcoded list of providers could be better organized. Per the comment from DFanso, consider:

  1. Defining provider constants or an enum
  2. Adding documentation about what API keys are expected for each
  3. Making the list extensible

Based on learnings from past review: DFanso requested adding types to the LLMs, and the author agreed.

Apply this approach:

+// Supported LLM providers
+const (
+	ProviderOpenAI = "OpenAI"
+	ProviderClaude = "Claude"
+	ProviderGemini = "Gemini"
+	ProviderGrok   = "Grok"
+)
+
+var supportedProviders = []string{
+	ProviderOpenAI,
+	ProviderClaude,
+	ProviderGemini,
+	ProviderGrok,
+}
+
 func SetupLLM() error {
 
-	providers := []string{"OpenAI", "Claude", "Gemini", "Grok"}
 	prompt := promptui.Select{
 		Label: "Select LLM",
-		Items: providers,
+		Items: supportedProviders,
 	}

20-23: Preserve the underlying error for better debugging.

Line 22: The error message "prompt failed" is generic and loses the context of what actually went wrong (e.g., user cancelled, I/O error, etc.).

Apply this diff:

 	_, model, err := prompt.Run()
 	if err != nil {
-		return fmt.Errorf("prompt failed")
+		return fmt.Errorf("prompt failed: %w", err)
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3439290 and 49792b5.

📒 Files selected for processing (2)
  • cmd/cli/llmSetup.go (1 hunks)
  • cmd/cli/store/store.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/cli/llmSetup.go (1)
cmd/cli/store/store.go (6)
  • LLMProvider (12-15)
  • Save (22-82)
  • ListSavedModels (192-223)
  • ChangeDefault (226-260)
  • UpdateAPIKey (318-358)
  • DeleteModel (263-315)
⏰ 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: Build Go Binary (windows-latest)
🔇 Additional comments (3)
cmd/cli/store/store.go (3)

107-145: LGTM!

The platform-specific config path resolution is correctly implemented, following OS conventions (Windows LOCALAPPDATA, macOS Application Support, Linux XDG_CONFIG_HOME).


192-223: LGTM!

The function correctly loads and returns the saved models configuration with appropriate error handling.


263-315: LGTM!

The delete logic correctly handles the constraint that the default model cannot be deleted without first changing the default, and properly clears the config when deleting the only model.

@DFanso DFanso self-requested a review October 5, 2025 16:39
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.

approved 🎊

@DFanso DFanso added the hacktoberfest-accepted Approved Hacktoberfest contribution label Oct 5, 2025
@DFanso DFanso merged commit 43b0e8c into DFanso:main Oct 5, 2025
8 checks passed
@DFanso
Copy link
Owner

DFanso commented Oct 5, 2025

hey @GauravJangra9988 can u update the documentation about new cli feature

@GauravJangra9988
Copy link
Contributor Author

ok

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] CLI interface to save credentials (API keys) and manage

2 participants