smart-commit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fc1d59ff49319c54e1f73ced0cbf81c80546300a72c2fbdcc167fb0fbbbf8424
4
+ data.tar.gz: 72c46e4dbc7a18fa36c786416b39fa7ef54e664d551f0569f137c2ece8ddce2a
5
+ SHA512:
6
+ metadata.gz: 9e3f8c6187d3162752779729cb2e2c57736e5fa7df6ee949569b36c15f3452df1e06cf819e2459de97b82f5a4071572c29d961ce6fcc39b85e598e257ce09b5a
7
+ data.tar.gz: 112fdd778c200dbf88a0f91cf4ac643e891aa5d98cf925e30f953f9ceb39d1d4a510b1d3922e8962957ec5d25fe3dfdb5c21067bf98055f915cf3e8f93c3963e
data/.commit-prompts ADDED
@@ -0,0 +1,12 @@
1
+ # Custom commit message prompts
2
+ # Add your project-specific context and preferences here
3
+ # Lines starting with # are ignored
4
+
5
+ # Example prompts:
6
+ # - Always include the JIRA ticket number in the scope
7
+ # - Use 'feat' for new features, 'fix' for bug fixes
8
+ # - Keep descriptions under 50 characters
9
+ # - Prefer active voice and present tense
10
+ # - Include breaking change indicators when applicable
11
+
12
+ # Your custom prompts go here:
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.1
3
+
4
+ Style/StringLiterals:
5
+ EnforcedStyle: double_quotes
6
+
7
+ Style/StringLiteralsInInterpolation:
8
+ EnforcedStyle: double_quotes
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-08-25
4
+
5
+ - Initial release
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Behrang Mirzamani
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,137 @@
1
+ # AI Commit 🤖
2
+
3
+ Generate intelligent, conventional commit messages using Claude AI. No more struggling with commit message writer's block!
4
+
5
+ ## Features
6
+
7
+ - ✨ **AI-Powered**: Uses Claude AI to analyze your git diff and generate meaningful commit messages
8
+ - 📝 **Conventional Commits**: Follows conventional commit format (feat, fix, docs, etc.)
9
+ - 🔒 **Secure**: API keys stored securely with proper file permissions
10
+ - 🚀 **Fast**: Quick generation with Claude 3 Haiku
11
+ - 🎯 **Smart**: Contextual analysis of your actual code changes
12
+ - 💎 **Ruby Gem**: Simple installation and usage
13
+
14
+ ## Installation
15
+
16
+ Install the gem:
17
+
18
+ ```bash
19
+ gem install smart-commit
20
+ ```
21
+
22
+ Or add to your Gemfile:
23
+
24
+ ```ruby
25
+ gem 'smart-commit'
26
+ ```
27
+
28
+ ## Setup
29
+
30
+ First, configure your Anthropic API key:
31
+
32
+ ```bash
33
+ smart-commit setup
34
+ ```
35
+
36
+ You'll be prompted to enter your API key. Get one at [Anthropic Console](https://console.anthropic.com/).
37
+
38
+ ## Usage
39
+
40
+ ### Basic Usage
41
+
42
+ 1. Stage your changes:
43
+ ```bash
44
+ git add .
45
+ ```
46
+
47
+ 2. Generate a commit message:
48
+ ```bash
49
+ smart-commit generate
50
+ ```
51
+
52
+ 3. The tool will analyze your diff and suggest a commit message:
53
+ ```
54
+ ✨ Generated commit message:
55
+ feat: add user authentication with JWT tokens
56
+
57
+ To commit with this message, run:
58
+ git commit -m "feat: add user authentication with JWT tokens"
59
+ ```
60
+
61
+ ### Commands
62
+
63
+ - `smart-commit setup` - Configure your API key
64
+ - `smart-commit generate` - Generate commit message from staged changes
65
+ - `smart-commit config` - Show current configuration
66
+ - `smart-commit help` - Show help information
67
+
68
+ ## Examples
69
+
70
+ The AI generates contextual commit messages based on your actual changes:
71
+
72
+ ```bash
73
+ # Adding a new feature
74
+ git add lib/user_auth.rb
75
+ smart-commit generate
76
+ # → "feat: add JWT-based user authentication system"
77
+
78
+ # Fixing a bug
79
+ git add lib/payment_processor.rb
80
+ smart-commit generate
81
+ # → "fix: handle null payment amounts in processor"
82
+
83
+ # Documentation updates
84
+ git add README.md
85
+ smart-commit generate
86
+ # → "docs: update installation instructions"
87
+
88
+ # Refactoring code
89
+ git add lib/user_model.rb
90
+ smart-commit generate
91
+ # → "refactor: extract user validation into separate method"
92
+ ```
93
+
94
+ ## Configuration
95
+
96
+ ### API Key Storage
97
+ - Config stored in: `~/.smart-commit/config.yml`
98
+ - File permissions: `600` (secure)
99
+ - Environment variable: `ANTHROPIC_API_KEY` (fallback)
100
+
101
+ ### Customizing the Prompt
102
+ The commit message generation prompt can be customized by editing:
103
+ `lib/ai/commit/claude_client.rb` in the `build_prompt` method.
104
+
105
+ ## Requirements
106
+
107
+ - Ruby 3.1.0+
108
+ - Git repository
109
+ - Anthropic API key
110
+ - Staged changes in git
111
+
112
+ ## Development
113
+
114
+ After checking out the repo:
115
+
116
+ ```bash
117
+ bin/setup # Install dependencies
118
+ rake test # Run tests
119
+ bin/console # Interactive prompt
120
+ bundle exec exe/smart-commit # Run locally
121
+ ```
122
+
123
+ ## Contributing
124
+
125
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bmirzamani/smart-commit.
126
+
127
+ ## License
128
+
129
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
130
+
131
+ ## Changelog
132
+
133
+ See [CHANGELOG.md](CHANGELOG.md) for version history.
134
+
135
+ ---
136
+
137
+ Made with ❤️ by [Behrang Mirzamani](https://github.com/bmirzamani)
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[test rubocop]
data/exe/smart-commit ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/ai/commit'
5
+
6
+ Ai::Commit::CLI.start(ARGV)
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module Ai
8
+ module Commit
9
+ class ClaudeClient
10
+ API_URL = 'https://api.anthropic.com/v1/messages'
11
+
12
+ def initialize(api_key)
13
+ @api_key = api_key
14
+ end
15
+
16
+ def generate_commit_message(diff)
17
+ prompt = build_prompt(diff)
18
+
19
+ response = make_request(prompt)
20
+ extract_message(response)
21
+ end
22
+
23
+ private
24
+
25
+ def build_prompt(diff)
26
+ custom_prompts = Config.custom_prompts
27
+ custom_prompt_text = custom_prompts.empty? ? '' : "\n\nAdditional context and preferences:\n#{custom_prompts.join("\n")}"
28
+
29
+ <<~PROMPT
30
+ You are a helpful assistant that generates conventional commit messages.
31
+
32
+ Based on the following git diff, generate a conventional commit message that:
33
+ 1. Use conventional commit format: type(scope): description
34
+ 2. Keep subject line under 50 characters
35
+ 3. Use imperative mood ("add" not "added")
36
+ 4. Separate subject from body with blank line
37
+ 5. Wrap body at 72 characters
38
+ 6. Use 'feat' for new features, 'fix' for bug fixes, 'docs' for documentation, 'style' for formatting, 'refactor' for code refactoring, 'test' for tests, 'chore' for build/tooling
39
+ 7. Be clear and specific about what changed, not just "update"
40
+ 8. Explain the impact/benefit when relevant
41
+ 9. Include scope based on file structure (e.g., auth, bank, api, components)
42
+ 10. Reference any related components or services affected
43
+ 11. For breaking changes, start with 'BREAKING CHANGE:'
44
+ 12. Use bullet points in body for multiple changes
45
+ 13. Reference ticket numbers when applicable
46
+ 14. Match existing project commit style
47
+
48
+ #{custom_prompt_text}
49
+
50
+ Git diff:
51
+ #{diff}
52
+
53
+ Respond with the complete commit message including subject and body, preserving line breaks.
54
+ PROMPT
55
+ end
56
+
57
+ def make_request(prompt)
58
+ uri = URI(API_URL)
59
+ http = Net::HTTP.new(uri.host, uri.port)
60
+ http.use_ssl = true
61
+
62
+ request = Net::HTTP::Post.new(uri)
63
+ request['Content-Type'] = 'application/json'
64
+ request['x-api-key'] = @api_key
65
+ request['anthropic-version'] = '2023-06-01'
66
+
67
+ request.body = {
68
+ model: 'claude-3-haiku-20240307',
69
+ max_tokens: 300,
70
+ messages: [
71
+ {
72
+ role: 'user',
73
+ content: prompt
74
+ }
75
+ ]
76
+ }.to_json
77
+
78
+ response = http.request(request)
79
+
80
+ unless response.code == '200'
81
+ raise Error, "API request failed: #{response.code} - #{response.body}"
82
+ end
83
+
84
+ JSON.parse(response.body)
85
+ end
86
+
87
+ def extract_message(response)
88
+ content = response.dig('content', 0, 'text')
89
+ return content.strip if content
90
+
91
+ raise Error, "Unexpected response format: #{response}"
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'io/console'
5
+ require_relative 'config'
6
+
7
+ module Ai
8
+ module Commit
9
+ class CLI < Thor
10
+ def self.exit_on_failure?
11
+ true
12
+ end
13
+ desc "setup", "Configure AI Commit with your Anthropic API key"
14
+ def setup
15
+ puts "Welcome to AI Commit setup!"
16
+ print "Enter your Anthropic API key: "
17
+ api_key = STDIN.noecho(&:gets).chomp
18
+ puts
19
+
20
+ if api_key.empty?
21
+ puts "No API key provided. Setup cancelled."
22
+ exit 1
23
+ end
24
+
25
+ Config.set_api_key(api_key)
26
+ puts "✓ API key saved successfully!"
27
+ puts "You can now use 'smart-commit generate' to create commit messages."
28
+ end
29
+
30
+ desc "generate", "Generate a commit message based on staged changes"
31
+ def generate
32
+ unless Config.api_key_configured?
33
+ puts "❌ No API key configured. Please run 'smart-commit setup' first."
34
+ exit 1
35
+ end
36
+
37
+ unless Git.in_git_repo?
38
+ puts "❌ Not in a git repository"
39
+ exit 1
40
+ end
41
+
42
+ unless Git.has_staged_changes?
43
+ puts "❌ No staged changes found. Stage your changes with 'git add' first."
44
+ exit 1
45
+ end
46
+
47
+ puts "🤖 Generating commit message..."
48
+
49
+ begin
50
+ diff = Git.staged_diff
51
+ client = ClaudeClient.new(Config.api_key)
52
+ message = client.generate_commit_message(diff)
53
+
54
+ puts "\n✨ Generated commit message:"
55
+ puts "#{message}"
56
+ puts "\nTo commit with this message, run:"
57
+ puts "git commit -m \"#{message}\""
58
+
59
+ rescue Error => e
60
+ puts "❌ Error: #{e.message}"
61
+ exit 1
62
+ rescue => e
63
+ puts "❌ Unexpected error: #{e.message}"
64
+ exit 1
65
+ end
66
+ end
67
+
68
+ desc "commit", "Generate a commit message and commit with confirmation"
69
+ def commit
70
+ unless Config.api_key_configured?
71
+ puts "❌ No API key configured. Please run 'smart-commit setup' first."
72
+ exit 1
73
+ end
74
+
75
+ unless Git.in_git_repo?
76
+ puts "❌ Not in a git repository"
77
+ exit 1
78
+ end
79
+
80
+ unless Git.has_staged_changes?
81
+ puts "❌ No staged changes found. Stage your changes with 'git add' first."
82
+ exit 1
83
+ end
84
+
85
+ puts "🤖 Generating commit message..."
86
+
87
+ begin
88
+ diff = Git.staged_diff
89
+ client = ClaudeClient.new(Config.api_key)
90
+ message = client.generate_commit_message(diff)
91
+
92
+ puts "\n✨ Generated commit message:"
93
+ puts "=" * 50
94
+ puts message
95
+ puts "=" * 50
96
+
97
+ print "\nCommit with this message? (y/N): "
98
+ response = STDIN.gets.chomp.downcase
99
+
100
+ if response == 'y' || response == 'yes'
101
+ puts "\n🚀 Committing..."
102
+ result = `git commit -m "#{message}"`
103
+
104
+ if $?.exitstatus == 0
105
+ puts "✅ Successfully committed!"
106
+ puts result
107
+ else
108
+ puts "❌ Failed to commit:"
109
+ puts result
110
+ exit 1
111
+ end
112
+ else
113
+ puts "❌ Commit cancelled."
114
+ exit 0
115
+ end
116
+
117
+ rescue Error => e
118
+ puts "❌ Error: #{e.message}"
119
+ exit 1
120
+ rescue => e
121
+ puts "❌ Unexpected error: #{e.message}"
122
+ exit 1
123
+ end
124
+ end
125
+
126
+ desc "config", "Show current configuration"
127
+ def config
128
+ if Config.api_key_configured?
129
+ masked_key = Config.api_key[0..10] + "..." if Config.api_key
130
+ puts "✓ API key configured: #{masked_key}"
131
+ else
132
+ puts "❌ No API key configured"
133
+ end
134
+
135
+ if Config.has_custom_prompts?
136
+ puts "✓ Custom prompts found: #{Config.custom_prompts.length} prompt(s)"
137
+ Config.custom_prompts.each_with_index do |prompt, i|
138
+ puts " #{i + 1}. #{prompt}"
139
+ end
140
+ else
141
+ puts "ℹ️ No custom prompts found"
142
+ puts " Create a .commit-prompts file in your project root to add custom context"
143
+ end
144
+ end
145
+
146
+ desc "init-prompts", "Create a sample .commit-prompts file"
147
+ def init_prompts
148
+ prompts_file = Config::PROMPTS_FILE
149
+
150
+ if File.exist?(prompts_file)
151
+ puts "❌ .commit-prompts file already exists"
152
+ exit 1
153
+ end
154
+
155
+ sample_content = <<~PROMPTS
156
+ # Custom commit message prompts
157
+ # Add your project-specific context and preferences here
158
+ # Lines starting with # are ignored
159
+
160
+ # Example prompts:
161
+ # - Always include the JIRA ticket number in the scope
162
+ # - Use 'feat' for new features, 'fix' for bug fixes
163
+ # - Keep descriptions under 50 characters
164
+ # - Prefer active voice and present tense
165
+ # - Include breaking change indicators when applicable
166
+
167
+ # Your custom prompts go here:
168
+
169
+ PROMPTS
170
+
171
+ File.write(prompts_file, sample_content)
172
+ puts "✅ Created #{prompts_file} with sample content"
173
+ puts "📝 Edit the file to add your custom prompts"
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+
6
+ module Ai
7
+ module Commit
8
+ class Config
9
+ CONFIG_FILE = File.expand_path('~/.smart-commit/config.yml').freeze
10
+ PROMPTS_FILE = '.commit-prompts'.freeze
11
+
12
+ def self.api_key
13
+ config = load_config
14
+ config['api_key'] || ENV['ANTHROPIC_API_KEY']
15
+ end
16
+
17
+ def self.set_api_key(key)
18
+ config = load_config
19
+ config['api_key'] = key
20
+ save_config(config)
21
+ end
22
+
23
+ def self.api_key_configured?
24
+ !api_key.nil? && !api_key.empty?
25
+ end
26
+
27
+ def self.custom_prompts
28
+ prompts_file = find_prompts_file
29
+ return [] unless prompts_file && File.exist?(prompts_file)
30
+
31
+ File.readlines(prompts_file)
32
+ .map(&:strip)
33
+ .reject(&:empty?)
34
+ .reject { |line| line.start_with?('#') }
35
+ end
36
+
37
+ def self.find_prompts_file
38
+ # Look for .commit-prompts in current directory or parent directories
39
+ current_dir = Dir.pwd
40
+ while current_dir != File.dirname(current_dir)
41
+ prompts_file = File.join(current_dir, PROMPTS_FILE)
42
+ return prompts_file if File.exist?(prompts_file)
43
+ current_dir = File.dirname(current_dir)
44
+ end
45
+ nil
46
+ end
47
+
48
+ def self.has_custom_prompts?
49
+ !custom_prompts.empty?
50
+ end
51
+
52
+ private
53
+
54
+ def self.load_config
55
+ return {} unless File.exist?(CONFIG_FILE)
56
+
57
+ YAML.load_file(CONFIG_FILE) || {}
58
+ rescue Psych::SyntaxError
59
+ {}
60
+ end
61
+
62
+ def self.save_config(config)
63
+ FileUtils.mkdir_p(File.dirname(CONFIG_FILE))
64
+ File.write(CONFIG_FILE, YAML.dump(config))
65
+ File.chmod(0o600, CONFIG_FILE) # Secure permissions
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ai
4
+ module Commit
5
+ class Git
6
+ def self.staged_diff
7
+ result = `git diff --cached`
8
+
9
+ if $?.exitstatus != 0
10
+ raise Error, "Failed to get git diff. Are you in a git repository?"
11
+ end
12
+
13
+ if result.empty?
14
+ raise Error, "No staged changes found. Stage your changes with 'git add' first."
15
+ end
16
+
17
+ result
18
+ end
19
+
20
+ def self.in_git_repo?
21
+ system('git rev-parse --git-dir', out: File::NULL, err: File::NULL)
22
+ end
23
+
24
+ def self.has_staged_changes?
25
+ !`git diff --cached --name-only`.strip.empty?
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ai
4
+ module Commit
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
data/lib/ai/commit.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "commit/version"
4
+ require_relative "commit/config"
5
+ require_relative "commit/cli"
6
+ require_relative "commit/claude_client"
7
+ require_relative "commit/git"
8
+
9
+ module Ai
10
+ module Commit
11
+ class Error < StandardError; end
12
+ end
13
+ end
data/sig/ai/commit.rbs ADDED
@@ -0,0 +1,6 @@
1
+ module Ai
2
+ module Commit
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smart-commit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Behrang Mirzamani
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-08-27 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: thor
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: net-http
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.3'
40
+ - !ruby/object:Gem::Dependency
41
+ name: json
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ description: AI-powered commit message generator that analyzes your git diff and creates
55
+ meaningful, conventional commit messages using Claude AI. No more commit message
56
+ writer's block!
57
+ email:
58
+ - behraaang@gmail.com
59
+ executables:
60
+ - smart-commit
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".commit-prompts"
65
+ - ".rubocop.yml"
66
+ - CHANGELOG.md
67
+ - CODE_OF_CONDUCT.md
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - exe/smart-commit
72
+ - lib/ai/commit.rb
73
+ - lib/ai/commit/claude_client.rb
74
+ - lib/ai/commit/cli.rb
75
+ - lib/ai/commit/config.rb
76
+ - lib/ai/commit/git.rb
77
+ - lib/ai/commit/version.rb
78
+ - sig/ai/commit.rbs
79
+ homepage: https://github.com/behraaang/smart-commit
80
+ licenses:
81
+ - MIT
82
+ metadata:
83
+ allowed_push_host: https://rubygems.org
84
+ homepage_uri: https://github.com/behraaang/smart-commit
85
+ source_code_uri: https://github.com/behraaang/smart-commit
86
+ changelog_uri: https://github.com/behraaang/smart-commit/blob/main/CHANGELOG.md
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 3.1.0
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.6.5
102
+ specification_version: 4
103
+ summary: Generate intelligent conventional commit messages using Claude AI
104
+ test_files: []