aigcm 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1f0e2c18c6c1c820563cc9f640a319709b1cbb752fdee4464617759cd2e6f963
4
+ data.tar.gz: 3a74e5f33183449a690f5ae8892bd55d438cff57193eb90af1b358458f215c77
5
+ SHA512:
6
+ metadata.gz: e203e403e07b9865c879d6bee4cedb9545fc460a8cbaa990d9257e00e49a7bf735ac5ee4bd403f2e7dd1ad4ee399734e194d49e55c723d7f184684cee8c5a548
7
+ data.tar.gz: 22ff6406f1aba1ab8defeac098bc1dab5b0aece00c04801c3aa4b888399a23db974ed89b0387e373a5f05e77a0a99b7834c1da8ffb95c240f926429330d6b1ba
data/.envrc ADDED
@@ -0,0 +1,4 @@
1
+
2
+ export RR=`pwd`
3
+
4
+ PATH_add $RR/bin
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Change Log
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [0.1.0] - 2025-02-08
6
+
7
+ - changed gem name to aigc
8
+
9
+ ## [0.1.0] - 2025-02-07
10
+
11
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Dewayne VanHoozer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # aigcm
2
+
3
+ The **AI git commit message** generator.
4
+ ƒ
5
+ ## Overview
6
+
7
+ **aigcm** is a Ruby gem designed to generate high-quality commit messages for git diffs. It leverages AI to analyze changes in your codebase and create concise, meaningful commit messages following best practices.
8
+
9
+ ## Features
10
+
11
+ - **Automatic Commit Message Generation**: Automatically generate commit messages based on code diffs.
12
+ - **Security-Aware Provider Selection**: Detects execution in a private repository and ensures non-local providers are not used for security reasons. This means that if you are working within a private repository, the gem will default to local providers unless explicitly forced otherwise.
13
+ - **Configurable Style Guide**: Allows using a specific style guide for commit messages, either from a default location or specified by the user.
14
+ - **AI Model Integration**: Integration with various AI models for enhanced message generation.
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'aigcm'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ ```shell
27
+ bundle install
28
+ ```
29
+
30
+ Or install it yourself as:
31
+
32
+ ```shell
33
+ gem install aigcm
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ To generate a commit message:
39
+
40
+ ```shell
41
+ aigcm [options] [ref]
42
+ ```
43
+
44
+ ### Options
45
+
46
+ - `-a, --amend`: Amend the last commit.
47
+ - `-c, --context=CONTEXT`: Extra context beyond the diff.
48
+ - `-d, --dry`: Dry run the command without making any changes.
49
+ - `-m, --model=MODEL`: Specify the AI model to use.
50
+ - `--provider=PROVIDER`: Specify the provider (ollama, openai, anthropic, etc). Note: This only needs to be used when the specified model is available from multiple providers; otherwise, the owner of the model is used by default.
51
+ - `--force-external`: Force using external AI provider even for private repos.
52
+ - `-s, --style=STYLE`: Path to the style guide file. If not provided, the system looks for `COMMITS.md` in the repo root or uses the default style guide.
53
+ - `--default`: Print the default style guide and exit the application.
54
+ - `--version`: Show version.
55
+
56
+ ### Examples
57
+
58
+ If your commit involves refactoring a function to improve its performance, you might provide context like:
59
+ ```shell
60
+ aigcm -m MODEL -c "Refactored to improve performance by using algorithm X"
61
+ ```
62
+
63
+ This context helps the AI craft a more informative commit message.
64
+
65
+ When your commit is related to a specific JIRA ticket:
66
+ ```shell
67
+ aigcm -m MODEL -c "Resolved issues as per JIRA ticket JIRA-1234"
68
+ ```
69
+
70
+ Including the JIRA ticket helps relate the commit to external tracking systems.
71
+
72
+ Including multiple context strings:
73
+ ```shell
74
+ aigcm -m MODEL -c "Refactored for performance" -c "JIRA-1234"
75
+ ```
76
+
77
+ Multiple context strings can be added by repeating the `-c` option.
78
+
79
+ Using environment variables in context:
80
+ ```shell
81
+ aigcm -c "Put the work ticket as the first entry on the subject line" -c "Ticket: $TICKET"
82
+ ```
83
+
84
+ This allows you to dynamically include environment variables in your commit message.
85
+
86
+ ### Style Guide Example
87
+
88
+ The style guide is used as part of the generative AI prompt that instructs the large language model (LLM) how to craft its summary of the `git diff` results. The see the default style guide use the `--default` option.
89
+
90
+ You can create your own style guide named `COMMITS.md` in the root directory of your repository. You can also use the `--style` option to point `aigcm` to your style guide if you choose to keep it in a different place. This is handy when you want to have consistent commit messages across several different projects.
91
+
92
+ This would be a simple style guide:
93
+
94
+ ```
95
+ - Use conventional commits format (type: description)
96
+ - Keep first line under 72 characters
97
+ - Use present tense ("add" not "added")
98
+ - Be descriptive but concise
99
+ - Have fun. Be creative. Add ASCII art if you feel like it.
100
+ ```
101
+
102
+ ## Last Thoughts
103
+
104
+ This gem saves its commit message in the file `.aigcm_msg` at the root directory of the repository. Its there even if you do a `--dry` run. This could be handy if you want to incorporate `aigcm` into some larger workflow.
105
+
106
+ Remember that the style guide can be extended using one or more `--context` strings. For example you could create a shell alias like this:
107
+
108
+ ```
109
+ alias gc='aigcm -c "JIRA $JIRA_TICKET"'
110
+ ```
111
+
112
+ ## Development
113
+
114
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
115
+
116
+ To install this gem onto your local machine, run `bundle exec rake install`.
117
+
118
+ ## Contributing
119
+
120
+ 1. Fork it (<https://github.com/your_username/aigcm/fork>)
121
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
122
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
123
+ 4. Push to the branch (`git push origin my-new-feature`)
124
+ 5. Create a new Pull Request
125
+
126
+ ## License
127
+
128
+ The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ task default: :test
data/bin/aigcm ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/aigcm'
4
+
5
+ Aigcm.run
@@ -0,0 +1,113 @@
1
+
2
+ require "net/http"
3
+ require "json"
4
+ require "open3"
5
+ require "ai_client"
6
+
7
+ module Aigcm
8
+ class CommitMessageGenerator
9
+ class Error < StandardError; end
10
+
11
+ MAX_DIFF_SIZE = 4000 # Characters
12
+
13
+ def initialize(model:, provider:, max_tokens:, force_external:)
14
+ @force_external = force_external
15
+ validate_model_provider_combination(model)
16
+ check_provider_availability
17
+
18
+ @client = AiClient.new(model, provider: provider)
19
+ rescue StandardError => e
20
+ raise Error, "Failed to initialize AI client: #{e.message}"
21
+ end
22
+
23
+ def generate(diff, style_guide, context = [])
24
+ return "No changes to commit" if diff.strip.empty?
25
+
26
+ check_repository_privacy unless @force_external
27
+
28
+ # Truncate diff if too large
29
+ if diff.length > MAX_DIFF_SIZE
30
+ diff = diff[0...MAX_DIFF_SIZE] + "\n...[diff truncated]"
31
+ end
32
+
33
+ processed_context = process_context(context)
34
+ prompt = build_prompt(diff, style_guide, processed_context)
35
+
36
+ begin
37
+ response = @client.chat(prompt)
38
+ response.to_s.strip
39
+ rescue StandardError => e
40
+ "Error generating commit message: #{e.message}"
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def validate_model_provider_combination(model)
47
+ client = AiClient.new(model)
48
+ @provider = client.provider
49
+ rescue ArgumentError => e
50
+ raise Error, "Invalid model/provider combination: #{e.message}"
51
+ end
52
+
53
+ def check_provider_availability
54
+ case @provider
55
+ when :ollama
56
+ check_ollama_running
57
+ when :localai
58
+ check_localai_running
59
+ end
60
+ rescue StandardError => e
61
+ raise Error, "Provider not available: #{e.message}"
62
+ end
63
+
64
+ def check_ollama_running
65
+ Net::HTTP.get(URI("http://localhost:11434/api/version"))
66
+ rescue StandardError
67
+ raise Error, "Ollama is not running. Please start ollama first."
68
+ end
69
+
70
+ def check_localai_running
71
+ Net::HTTP.get(URI("http://localhost:8080/v1/models"))
72
+ rescue StandardError
73
+ raise Error, "LocalAI is not running. Please start localai first."
74
+ end
75
+
76
+ def process_context(context_array)
77
+ context_array.map do |ctx|
78
+ if ctx.start_with?("@")
79
+ filename = ctx[1..]
80
+ File.read(filename) rescue "Could not read #{filename}"
81
+ else
82
+ ctx
83
+ end
84
+ end
85
+ end
86
+
87
+ def check_repository_privacy
88
+ return if @provider == :ollama # Local provider is always safe
89
+
90
+ stdout, _, status = Open3.capture3("gh repo view --json isPrivate -q '.isPrivate'")
91
+
92
+ if status.success? && stdout.strip == "true"
93
+ raise Error, "This is a private repository. Use a local model (ollama) or run with --force-external flag"
94
+ end
95
+ rescue Errno::ENOENT
96
+ puts "Warning: Unable to check repository privacy status (gh command not found)"
97
+ end
98
+
99
+ def build_prompt(diff, style_guide, context)
100
+ <<~PROMPT
101
+ Generate a commit message for the git diff that follows these instructions.
102
+ Do not wrap your response in a code block.
103
+ Follow these style guidelines when constructing your response:
104
+ #{style_guide}
105
+
106
+ #{context.join("\n") unless context.empty?}
107
+
108
+ Git diff:
109
+ #{diff}
110
+ PROMPT
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,44 @@
1
+ require "open3"
2
+
3
+ module Aigcm
4
+ class GitDiff
5
+ class Error < StandardError; end
6
+
7
+ def initialize(dir:, commit_hash: nil, amend: false)
8
+ @dir = dir
9
+ @commit_hash = commit_hash
10
+ @amend = amend
11
+ validate_git_repo
12
+ end
13
+
14
+ def generate_diff
15
+ Dir.chdir(@dir) do
16
+ cmd = if @amend
17
+ "git diff --cached HEAD^ 2>/dev/null || git diff --cached"
18
+ elsif @commit_hash
19
+ "git diff #{@commit_hash}^..#{@commit_hash}"
20
+ else
21
+ "git diff --cached"
22
+ end
23
+
24
+ stdout, _, status = Open3.capture3(cmd)
25
+
26
+ raise Error, "Git command failed" unless status.success?
27
+ raise Error, "No changes detected" if stdout.strip.empty?
28
+
29
+ stdout
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def validate_git_repo
36
+ Dir.chdir(@dir) do
37
+ _, _, status = Open3.capture3("git rev-parse --git-dir")
38
+ raise Error, "Not a git repository" unless status.success?
39
+ end
40
+ rescue Errno::ENOENT
41
+ raise Error, "Directory not found: #{@dir}"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ require 'erb'
2
+
3
+ module Aigcm
4
+ class StyleGuide
5
+ LINE_MAX = 72
6
+ DEFAULT_GUIDE = ERB.new(
7
+ File.read(__FILE__)
8
+ .split("__END__")
9
+ .last
10
+ .strip
11
+ ).result
12
+
13
+ def self.load(dir, custom_path = nil)
14
+ # If a custom path is provided, use it
15
+ if custom_path
16
+ return load_from_file(custom_path)
17
+ end
18
+
19
+ # Check for COMMITS.md in the repository root
20
+ config_file = File.join(dir, "COMMITS.md")
21
+ return load_from_file(config_file) if File.exist?(config_file)
22
+
23
+ # Fallback to the default style guide
24
+ DEFAULT_GUIDE
25
+ rescue StandardError => e
26
+ puts "Warning: Error reading style guide: #{e.message}"
27
+ DEFAULT_GUIDE
28
+ end
29
+
30
+ private_class_method def self.load_from_file(path)
31
+ File.read(path)
32
+ end
33
+ end
34
+ end
35
+
36
+ __END__
37
+
38
+ 1. Craft a Clear Subject Line:
39
+ • Summarize Concisely: Begin with a brief summary (<%= Aigcm::StyleGuide::LINE_MAX %> characters max).
40
+ • Capitalize the Subject: Start the subject line with a capital letter.
41
+ • Omit Periods in Subject Line: Avoid ending with a period to save space.
42
+ • Use Imperative Mood: Phrase commands as direct actions (e.g., "Add feature" instead of "Added feature").
43
+
44
+ 2. Provide a Detailed Body:
45
+ • Seperate the body from the subject line with a blank line.
46
+ • Explain the Reason: Clearly articulate the rationale for the change rather than just summarizing the modification.
47
+ • Wrap Body Text at <%= Aigcm::StyleGuide::LINE_MAX %> Characters: Ensure that the body text wraps at <%= Aigcm::StyleGuide::LINE_MAX %> characters per line.
48
+
49
+ 3. Reference Issues/Tickets:
50
+ • Include relevant issue numbers, ticket IDs and/or references when they are provided. Dp not invent your own reference. Use what has been provided.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aigcm
4
+ VERSION = "0.2.0"
5
+ end
data/lib/aigcm.rb ADDED
@@ -0,0 +1,146 @@
1
+ # lib/aigcm.rb
2
+
3
+ require 'debug_me'
4
+ include DebugMe
5
+
6
+ require 'optparse'
7
+ require 'ai_client'
8
+ require 'time'
9
+
10
+ require_relative 'aigcm/version'
11
+ require_relative 'aigcm/git_diff'
12
+ require_relative 'aigcm/commit_message_generator'
13
+ require_relative 'aigcm/style_guide'
14
+
15
+ module Aigcm
16
+ COMMIT_MESSAGE_FILE = '.aigcm_msg'
17
+ RECENT_THRESHOLD = 60 # seconds (1 minute)
18
+
19
+ class Error < StandardError; end
20
+
21
+ def self.run(test_mode: false)
22
+ dir = Dir.pwd
23
+ options = parse_options
24
+
25
+ if options[:amend]
26
+ system('git commit --amend')
27
+ return
28
+ end
29
+
30
+ commit_message = check_recent_commit(dir)
31
+
32
+ # Generate a new commit message if not reusing an existing one
33
+ commit_message ||= generate_commit_message(dir, options)
34
+
35
+ perform_commit(dir, commit_message, options)
36
+
37
+ rescue OptionParser::InvalidOption => e
38
+ STDERR.puts "Error: '#{e.message}'"
39
+ exit 1
40
+ rescue GitDiff::Error => e
41
+ puts "Git error: #{e.message}"
42
+ exit 1
43
+ rescue StandardError => e
44
+ puts "Error: #{e.message}"
45
+ exit 1
46
+ end
47
+
48
+ private_class_method def self.parse_options
49
+ options = {
50
+ amend: false,
51
+ context: [],
52
+ dry: false,
53
+ model: 'gpt-4o-mini',
54
+ provider: nil,
55
+ force_external: false,
56
+ style: nil
57
+ }
58
+
59
+ OptionParser.new do |opts|
60
+ opts.banner = "Usage: aigcm [options] [ref]"
61
+
62
+ opts.on("-a", "--amend", "Amend the last commit") { options[:amend] = true }
63
+
64
+ opts.on("-cCONTEXT", "--context=CONTEXT", "Extra context beyond the diff") do |context|
65
+ options[:context] << context
66
+ end
67
+
68
+ opts.on("-d", "--dry", "Dry run the command") { options[:dry] = true }
69
+
70
+ opts.on("-mMODEL", "--model=MODEL", "The model to use") { |model| options[:model] = model }
71
+
72
+ opts.on("--provider=PROVIDER", "Specify the provider (ollama, openai, anthropic, etc)") do |provider|
73
+ provider = provider.to_sym
74
+ unless [:ollama, :openai, :anthropic, :google, :mistral].include?(provider)
75
+ puts "Invalid provider specified. Valid providers are: ollama, openai, anthropic, google, mistral"
76
+ exit 1
77
+ end
78
+ options[:provider] = provider
79
+ end
80
+
81
+ opts.on("--force-external", "Force using external AI provider even for private repos") {
82
+ options[:force_external] = true
83
+ }
84
+
85
+ opts.on("-sSTYLE", "--style=STYLE", "Path to the style guide file") { |style| options[:style] = style }
86
+
87
+ opts.on("--default", "Print the default style guide and exit") do
88
+ puts "\nDefault Style Guide:"
89
+ puts "-------------------"
90
+ puts StyleGuide::DEFAULT_GUIDE
91
+ exit
92
+ end
93
+
94
+ opts.on("--version", "Show version") { puts Aigcm::VERSION; exit }
95
+
96
+ end.parse!
97
+
98
+ options
99
+ end
100
+
101
+ private_class_method def self.check_recent_commit(dir)
102
+ commit_file_path = File.join(dir, COMMIT_MESSAGE_FILE)
103
+
104
+ if File.exist?(commit_file_path)
105
+ file_mod_time = File.mtime(commit_file_path)
106
+ current_time = Time.now
107
+ if (current_time - file_mod_time).to_i < RECENT_THRESHOLD
108
+ return File.read(commit_file_path)
109
+ end
110
+ end
111
+
112
+ nil
113
+ end
114
+
115
+ private_class_method def self.generate_commit_message(dir, options)
116
+ diff_generator = GitDiff.new(dir: dir, commit_hash: ARGV.shift, amend: options[:amend])
117
+ diff = diff_generator.generate_diff
118
+
119
+ style_guide = StyleGuide.load(dir, options[:style])
120
+ generator = CommitMessageGenerator.new(
121
+ model: options[:model],
122
+ provider: options[:provider],
123
+ max_tokens: 1000,
124
+ force_external: options[:force_external]
125
+ )
126
+
127
+ commit_message = generator.generate(diff, style_guide, options[:context])
128
+ File.write(File.join(dir, COMMIT_MESSAGE_FILE), commit_message)
129
+ commit_message
130
+ end
131
+
132
+ private_class_method def self.perform_commit(dir, commit_message, options)
133
+ commit_file_path = File.join(dir, COMMIT_MESSAGE_FILE)
134
+
135
+ if options[:dry]
136
+ puts "\nDry run - would generate commit message:"
137
+ puts "-"*StyleGuide::LINE_MAX
138
+ puts commit_message
139
+ puts "-"*StyleGuide::LINE_MAX
140
+ puts
141
+ else
142
+ File.write(commit_file_path, commit_message)
143
+ system("git commit --edit -F #{commit_file_path}")
144
+ end
145
+ end
146
+ end
data/sig/aicommit.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Aicommit
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aigcm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Dewayne VanHoozer
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-02-09 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ai_client
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.4.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.4.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: minitest
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.16'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.16'
40
+ - !ruby/object:Gem::Dependency
41
+ name: mocha
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rake
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '13.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '13.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rubocop
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.21'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.21'
82
+ description: |
83
+ `aigcm` generates meaningful git commit messages using artificial
84
+ intelligence. It supports multiple AI providers including OpenAI,
85
+ Anthropic, Google, and local models via Ollama. The gem
86
+ automatically detects private repositories and defaults to using
87
+ local models for security. It integrates seamlessly with git
88
+ workflows and supports various commit scenarios including amending
89
+ commits and handling staged changes. The gem follows conventional
90
+ commit message formats and allows customization of commit message
91
+ styles through configuration.
92
+ email:
93
+ - dvanhoozer@gmail.com
94
+ executables:
95
+ - aigcm
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - ".envrc"
100
+ - CHANGELOG.md
101
+ - LICENSE.txt
102
+ - README.md
103
+ - Rakefile
104
+ - bin/aigcm
105
+ - lib/aigcm.rb
106
+ - lib/aigcm/commit_message_generator.rb
107
+ - lib/aigcm/git_diff.rb
108
+ - lib/aigcm/style_guide.rb
109
+ - lib/aigcm/version.rb
110
+ - sig/aicommit.rbs
111
+ homepage: https://github.com/MadBomber/aigcm
112
+ licenses:
113
+ - MIT
114
+ metadata:
115
+ allowed_push_host: https://rubygems.org
116
+ homepage_uri: https://github.com/MadBomber/aigcm
117
+ source_code_uri: https://github.com/MadBomber/aigcm
118
+ changelog_uri: https://github.com/MadBomber/aigcm/blob/main/CHANGELOG.md
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: 3.1.0
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubygems_version: 3.6.3
134
+ specification_version: 4
135
+ summary: AI-powered git commit message generator
136
+ test_files: []