ai_git 0.0.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 +7 -0
- data/bin/ai_git +5 -0
- data/lib/ai_git/git.rb +23 -0
- data/lib/ai_git/ollama.rb +91 -0
- data/lib/ai_git/version.rb +3 -0
- data/lib/ai_git.rb +37 -0
- metadata +44 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 7880625a0fd36e0dd667168f8bfe2dbaffc887584d6777f6675eef90202a5889
|
|
4
|
+
data.tar.gz: 17221f5e7db837d7aa155b1a19f36f2065f584ee40c45b098d8f5cf6041b9690
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 24d52e06e1b4d88c63d62fa79cfa79f9feb1ea53ea13437710952a833553eba10f4db1b71ed864ff6d3935d2082e769b34fb2f651d1256827774f2be411fdcf2
|
|
7
|
+
data.tar.gz: 5e2c67e5155fb89160ac2beb0c54d5e93d9b8692be33de686589ee3977cd2505b57532c69683684bc9a053dcff4ad1fcbd860afd181b1441aa07b95e36ee764a
|
data/bin/ai_git
ADDED
data/lib/ai_git/git.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module AIGit
|
|
2
|
+
module Git
|
|
3
|
+
module_function
|
|
4
|
+
|
|
5
|
+
def staged_files
|
|
6
|
+
`git diff --cached --name-only`
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def diff
|
|
10
|
+
`git diff --cached`
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def current_branch
|
|
14
|
+
result = `git rev-parse --abbrev-ref HEAD`
|
|
15
|
+
result.chomp
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def run_command(cmd, args)
|
|
19
|
+
system("#{cmd} #{args} > /dev/null 2>&1")
|
|
20
|
+
raise "Command failed: #{cmd} #{args}" if $?.exitstatus != 0
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module AIGit
|
|
6
|
+
module Ollama
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def escape_json(string)
|
|
10
|
+
string.gsub('\\', '\\\\')
|
|
11
|
+
.gsub('"', '\"')
|
|
12
|
+
.gsub("\n", '\\n')
|
|
13
|
+
.gsub("\r", '\\r')
|
|
14
|
+
.gsub("\t", '\\t')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def generate_commit_message(diff)
|
|
18
|
+
raise 'No staged changes to generate commit message for' if diff.to_s.strip.empty?
|
|
19
|
+
|
|
20
|
+
prompt = <<~PROMPT
|
|
21
|
+
You are an expert Git commit message writer. Your only job is to output a commit message — nothing else.
|
|
22
|
+
|
|
23
|
+
Here are the changes:
|
|
24
|
+
#{diff}
|
|
25
|
+
|
|
26
|
+
Rules you MUST follow exactly:
|
|
27
|
+
- Output ONLY the commit message. No explanations, no quotes, no markdown, no "Here is the commit message", no backticks.
|
|
28
|
+
- Use this exact structure:
|
|
29
|
+
1. First line: Conventional commit type + short imperative title (max 72 chars, ideally < 50)
|
|
30
|
+
2. Second line: blank
|
|
31
|
+
3. Body (optional but recommended): Clear, concise explanation of WHAT changed and WHY.
|
|
32
|
+
|
|
33
|
+
Examples of good output:
|
|
34
|
+
feat: add user authentication flow
|
|
35
|
+
|
|
36
|
+
Implemented JWT-based login with refresh tokens. Added protected routes middleware.
|
|
37
|
+
|
|
38
|
+
fix: prevent null pointer on missing metadata
|
|
39
|
+
|
|
40
|
+
Added nil check in ReportGenerator#process before accessing user preferences.
|
|
41
|
+
|
|
42
|
+
Now generate the commit message:
|
|
43
|
+
PROMPT
|
|
44
|
+
|
|
45
|
+
json_body = {
|
|
46
|
+
# model: 'qwen:14b',
|
|
47
|
+
model: 'ministral-3:8b',
|
|
48
|
+
prompt: prompt,
|
|
49
|
+
stream: false,
|
|
50
|
+
# These parameters help a lot with strictness:
|
|
51
|
+
temperature: 0.3,
|
|
52
|
+
top_p: 0.9,
|
|
53
|
+
stop: ["\n\n\n", "```", "Here is", "The commit message"],
|
|
54
|
+
num_predict: 400 # Limit output length
|
|
55
|
+
}.to_json
|
|
56
|
+
|
|
57
|
+
uri = URI('http://localhost:11434/api/generate')
|
|
58
|
+
request = Net::HTTP::Post.new(uri)
|
|
59
|
+
request['Content-Type'] = 'application/json'
|
|
60
|
+
request.body = json_body
|
|
61
|
+
|
|
62
|
+
response = Net::HTTP.start(uri.host, uri.port, read_timeout: 120) do |http|
|
|
63
|
+
http.request(request)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
raise 'Failed to connect to Ollama. Is it running?' unless response.is_a?(Net::HTTPSuccess)
|
|
67
|
+
|
|
68
|
+
data = JSON.parse(response.body)
|
|
69
|
+
message = data['response'].to_s.strip
|
|
70
|
+
|
|
71
|
+
# Aggressive cleaning
|
|
72
|
+
message = message.gsub(/^(Here is|The commit message is|```|json|markdown)/i, '')
|
|
73
|
+
.gsub(/^>\s*/, '')
|
|
74
|
+
.gsub(/\\n/, "\n")
|
|
75
|
+
.strip
|
|
76
|
+
|
|
77
|
+
# Remove common unwanted prefixes/suffixes
|
|
78
|
+
lines = message.lines.map(&:strip)
|
|
79
|
+
lines.reject! { |line| line.match?(/^(Here|Output|Generated|Based on|The changes)/i) }
|
|
80
|
+
|
|
81
|
+
message = lines.join("\n").strip
|
|
82
|
+
|
|
83
|
+
# Ensure it has at least a title
|
|
84
|
+
if message.lines.count < 1 || message.strip.empty?
|
|
85
|
+
message = "chore: update code" # fallback
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
message
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/ai_git.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'benchmark'
|
|
2
|
+
require_relative 'ai_git/version'
|
|
3
|
+
require_relative 'ai_git/git'
|
|
4
|
+
require_relative 'ai_git/ollama'
|
|
5
|
+
|
|
6
|
+
module AIGit
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def run
|
|
10
|
+
staged = AIGit::Git.staged_files
|
|
11
|
+
abort 'Error: No staged files. Use `git add` first.' if staged.to_s.strip.empty?
|
|
12
|
+
|
|
13
|
+
diff = AIGit::Git.diff
|
|
14
|
+
branch = AIGit::Git.current_branch
|
|
15
|
+
|
|
16
|
+
puts "\e[1mStaged Files:\e[0m #{staged}"
|
|
17
|
+
puts "\e[1mBranch:\e[0m #{branch}"
|
|
18
|
+
puts "\e[1mAI Generating Commit Message\e[0m"
|
|
19
|
+
|
|
20
|
+
result = Benchmark.measure do
|
|
21
|
+
message = AIGit::Ollama.generate_commit_message(diff)
|
|
22
|
+
message = message.gsub(/\n{2,}/, "\n")
|
|
23
|
+
|
|
24
|
+
puts "\e[1mCommit Message:\e[0m\n\n#{message}\n"
|
|
25
|
+
|
|
26
|
+
escaped_msg = message.gsub(/[\\"`$]/) { |c| "\\#{c}" }
|
|
27
|
+
AIGit::Git.run_command('git', "commit -m \"#{escaped_msg}\"")
|
|
28
|
+
puts "\e[1mGit Commited\e[0m"
|
|
29
|
+
|
|
30
|
+
AIGit::Git.run_command('git', 'push')
|
|
31
|
+
puts "\e[1mGit Pushed\e[0m"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
puts "\e[1mBenchmark\e[0m"
|
|
35
|
+
puts result
|
|
36
|
+
end
|
|
37
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ai_git
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Kaíque Kandy Koga
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Generates intelligent commit messages using Ollama LLMs
|
|
13
|
+
executables:
|
|
14
|
+
- ai_git
|
|
15
|
+
extensions: []
|
|
16
|
+
extra_rdoc_files: []
|
|
17
|
+
files:
|
|
18
|
+
- bin/ai_git
|
|
19
|
+
- lib/ai_git.rb
|
|
20
|
+
- lib/ai_git/git.rb
|
|
21
|
+
- lib/ai_git/ollama.rb
|
|
22
|
+
- lib/ai_git/version.rb
|
|
23
|
+
homepage: https://github.com/koga/ai_git
|
|
24
|
+
licenses:
|
|
25
|
+
- BSD-3-Clause
|
|
26
|
+
metadata: {}
|
|
27
|
+
rdoc_options: []
|
|
28
|
+
require_paths:
|
|
29
|
+
- lib
|
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '4.0'
|
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
requirements: []
|
|
41
|
+
rubygems_version: 4.0.9
|
|
42
|
+
specification_version: 4
|
|
43
|
+
summary: AI-powered git commit and push tool using Ollama
|
|
44
|
+
test_files: []
|