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 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
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/ai_git"
4
+
5
+ AIGit.run
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
@@ -0,0 +1,3 @@
1
+ module AIGit
2
+ VERSION = "0.0.0"
3
+ 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: []