code_sage 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.
@@ -0,0 +1,226 @@
1
+ require 'llm_chain'
2
+
3
+ module CodeSage
4
+ class Reviewer
5
+ attr_reader :options
6
+
7
+ def initialize(options = {})
8
+ @options = {
9
+ branch: 'main',
10
+ files: nil,
11
+ format: 'console',
12
+ config_path: nil,
13
+ verbose: false,
14
+ enable_rag: false # Отключаем RAG по умолчанию
15
+ }.merge(options)
16
+
17
+ @git_analyzer = GitAnalyzer.new(@options)
18
+ @formatter = ReportFormatter.new(@options[:format])
19
+ @llm_chain = setup_llm_chain
20
+ end
21
+
22
+ def review
23
+ puts "🔍 Analyzing code changes..." if @options[:verbose]
24
+
25
+ changes = @git_analyzer.get_changes
26
+
27
+ if changes.empty?
28
+ return { success: true, message: "No changes to review" }
29
+ end
30
+
31
+ puts "📝 Found #{changes.length} changed files" if @options[:verbose]
32
+
33
+ reviews = []
34
+
35
+ changes.each do |change|
36
+ puts "Reviewing #{change[:file]}..." if @options[:verbose]
37
+
38
+ review = review_file(change)
39
+ reviews << review if review
40
+ end
41
+
42
+ report = generate_report(reviews)
43
+ output_report(report)
44
+
45
+ { success: true, reviews: reviews, report: report }
46
+ rescue => e
47
+ { success: false, error: e.message }
48
+ end
49
+
50
+ private
51
+
52
+ def setup_llm_chain
53
+ # Load configuration
54
+ config = @options[:config_path] ? Config.new(@options[:config_path]) : Config.new
55
+
56
+ llm_config = config.data['llm']
57
+ provider = llm_config['provider'] || 'openai'
58
+ model = llm_config['model'] || 'gpt-4'
59
+
60
+ # Configure LLM chain for code review using proper API
61
+ case provider.downcase
62
+ when 'openai'
63
+ LLMChain::Chain.new(
64
+ model: model,
65
+ retriever: false,
66
+ client_options: {
67
+ api_key: llm_config['api_key'] || ENV['OPENAI_API_KEY'],
68
+ temperature: llm_config['temperature'] || 0.1,
69
+ max_tokens: llm_config['max_tokens'] || 2000
70
+ }
71
+ )
72
+ when 'ollama'
73
+ # For local Ollama models
74
+ LLMChain::Chain.new(
75
+ model: model,
76
+ retriever: false,
77
+ client_options: {
78
+ temperature: llm_config['temperature'] || 0.1,
79
+ base_url: ENV['OLLAMA_BASE_URL'] || 'http://localhost:11434'
80
+ }
81
+ )
82
+ when 'qwen'
83
+ # For Qwen models via Ollama
84
+ LLMChain::Chain.new(
85
+ model: model.include?('qwen') ? model : 'qwen2:7b',
86
+ retriever: false,
87
+ client_options: {
88
+ temperature: llm_config['temperature'] || 0.1,
89
+ base_url: ENV['OLLAMA_BASE_URL'] || 'http://localhost:11434'
90
+ }
91
+ )
92
+ else
93
+ # Default to OpenAI
94
+ LLMChain::Chain.new(
95
+ model: 'gpt-4',
96
+ retriever: false,
97
+ client_options: {
98
+ api_key: ENV['OPENAI_API_KEY'],
99
+ temperature: 0.1
100
+ }
101
+ )
102
+ end
103
+ end
104
+
105
+ def build_system_message
106
+ <<~PROMPT
107
+ You are CodeSage, an expert code reviewer specializing in Ruby development.
108
+
109
+ Your role is to:
110
+ 1. Identify potential bugs, security issues, and performance problems
111
+ 2. Suggest improvements for code readability and maintainability
112
+ 3. Check for adherence to Ruby best practices and conventions
113
+ 4. Provide constructive feedback with specific examples
114
+ 5. Highlight both positive aspects and areas for improvement
115
+
116
+ Focus on:
117
+ - Code quality and structure
118
+ - Potential runtime errors
119
+ - Security vulnerabilities
120
+ - Performance optimizations
121
+ - Ruby idioms and best practices
122
+ - Testing considerations
123
+
124
+ Provide your feedback in a structured format with clear categories and actionable suggestions.
125
+ PROMPT
126
+ end
127
+
128
+ def review_file(change)
129
+ prompt = build_file_review_prompt(change)
130
+
131
+ # Use llm_chain's ask method with system message context
132
+ full_prompt = "#{build_system_message}\n\n#{prompt}"
133
+ response = @llm_chain.ask(full_prompt)
134
+
135
+ {
136
+ file: change[:file],
137
+ change_type: change[:type],
138
+ lines_added: change[:lines_added],
139
+ lines_removed: change[:lines_removed],
140
+ review: response,
141
+ timestamp: Time.now
142
+ }
143
+ rescue => e
144
+ puts "Error reviewing #{change[:file]}: #{e.message}".colorize(:red)
145
+ nil
146
+ end
147
+
148
+ def build_file_review_prompt(change)
149
+ <<~PROMPT
150
+ Please review the following Ruby code changes:
151
+
152
+ File: #{change[:file]}
153
+ Change Type: #{change[:type]}
154
+ Lines Added: #{change[:lines_added]}
155
+ Lines Removed: #{change[:lines_removed]}
156
+
157
+ Code Diff:
158
+ ```
159
+ #{change[:diff]}
160
+ ```
161
+
162
+ Full File Context (if available):
163
+ ```ruby
164
+ #{change[:content] || 'Not available'}
165
+ ```
166
+
167
+ Please provide a comprehensive review focusing on:
168
+ 1. Code quality and best practices
169
+ 2. Potential bugs or issues
170
+ 3. Security considerations
171
+ 4. Performance implications
172
+ 5. Suggestions for improvement
173
+
174
+ Format your response as structured feedback with clear sections.
175
+ PROMPT
176
+ end
177
+
178
+ def generate_report(reviews)
179
+ {
180
+ summary: generate_summary(reviews),
181
+ reviews: reviews,
182
+ metrics: calculate_metrics(reviews),
183
+ recommendations: generate_recommendations(reviews),
184
+ generated_at: Time.now
185
+ }
186
+ end
187
+
188
+ def generate_summary(reviews)
189
+ total_files = reviews.length
190
+
191
+ {
192
+ total_files_reviewed: total_files,
193
+ files_with_issues: reviews.count { |r| r[:review].include?('issue') || r[:review].include?('problem') },
194
+ total_lines_changed: reviews.sum { |r| r[:lines_added] + r[:lines_removed] }
195
+ }
196
+ end
197
+
198
+ def calculate_metrics(reviews)
199
+ {
200
+ avg_lines_per_file: if reviews.empty?
201
+ 0
202
+ else
203
+ reviews.sum do |r|
204
+ r[:lines_added] + r[:lines_removed]
205
+ end / reviews.length
206
+ end,
207
+ files_by_type: reviews.group_by { |r| r[:change_type] }.transform_values(&:count)
208
+ }
209
+ end
210
+
211
+ def generate_recommendations(reviews)
212
+ # Extract common patterns and generate overall recommendations
213
+ # This could be enhanced with more sophisticated analysis
214
+ [
215
+ "Review suggested improvements for each file",
216
+ "Consider adding or updating tests for modified code",
217
+ "Ensure all security recommendations are addressed"
218
+ ]
219
+ end
220
+
221
+ def output_report(report)
222
+ formatted_report = @formatter.format(report)
223
+ puts formatted_report
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,3 @@
1
+ module CodeSage
2
+ VERSION = "0.1.0"
3
+ end
data/lib/code_sage.rb ADDED
@@ -0,0 +1,15 @@
1
+ require_relative "code_sage/version"
2
+ require_relative "code_sage/config"
3
+ require_relative "code_sage/cli"
4
+ require_relative "code_sage/reviewer"
5
+ require_relative "code_sage/git_analyzer"
6
+ require_relative "code_sage/report_formatter"
7
+
8
+ module CodeSage
9
+ class Error < StandardError; end
10
+
11
+ # Main entry point for the gem
12
+ def self.review(options = {})
13
+ Reviewer.new(options).review
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: code_sage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - FuryCow
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-07-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: llm_chain
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: colorize
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.8'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rugged
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '13.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Wisdom for your code - an intelligent code review assistant using LLM
126
+ email:
127
+ - info@furycow.com
128
+ executables:
129
+ - code_sage
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".github/workflows/gem.yml"
134
+ - ".gitignore"
135
+ - ".rspec"
136
+ - CHANGELOG.md
137
+ - Gemfile
138
+ - Gemfile.lock
139
+ - LICENSE
140
+ - README.md
141
+ - Rakefile
142
+ - bin/console
143
+ - bin/setup
144
+ - code_sage.gemspec
145
+ - exe/code_sage
146
+ - lib/code_sage.rb
147
+ - lib/code_sage/cli.rb
148
+ - lib/code_sage/config.rb
149
+ - lib/code_sage/git_analyzer.rb
150
+ - lib/code_sage/report_formatter.rb
151
+ - lib/code_sage/reviewer.rb
152
+ - lib/code_sage/version.rb
153
+ homepage: https://github.com/FuryCow/code_sage
154
+ licenses:
155
+ - MIT
156
+ metadata:
157
+ homepage_uri: https://github.com/FuryCow/code_sage
158
+ source_code_uri: https://github.com/FuryCow/code_sage
159
+ changelog_uri: https://github.com/FuryCow/code_sage/blob/master/CHANGELOG.md
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: 2.7.0
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubygems_version: 3.4.10
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: AI-powered code review tool for Ruby
179
+ test_files: []