n2b 0.3.0 โ 0.3.1
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 +4 -4
- data/README.md +89 -5
- data/lib/n2b/cli.rb +146 -7
- data/lib/n2b/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 644455363c88bf95c4ab4f21121ed6b8f56a591fb32bd1a8fa9f8f36d981e515
|
4
|
+
data.tar.gz: f899199e26524f38f88e4416217616c048e588c1f54becb228261b07ffcda3d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b3cfcba02a3c41017737317df2d932e1ff053c2d470c529a3158ccba11696ccf09367369f4530de78fc7669cc26795a3dad8abe49a26da0f5a8f836758baf4d
|
7
|
+
data.tar.gz: f664e6b0e9099aecc969e7d46a71b7cf7da0bf1238e9fbf203f445bed9d7073c2a643cce09a3a50fc1ce666805505c7e8d6222817a207fd3b4ec9491c8fcd4e4
|
data/README.md
CHANGED
@@ -6,10 +6,15 @@ N2B (Natural Language to Bash & Ruby) is a Ruby gem that leverages AI to convert
|
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
9
|
-
- Convert natural language to bash commands
|
10
|
-
- Generate Ruby code from natural language instructions
|
11
|
-
- Analyze
|
12
|
-
-
|
9
|
+
- **๐ค Natural Language to Commands**: Convert natural language to bash commands
|
10
|
+
- **๐ Ruby Code Generation**: Generate Ruby code from natural language instructions
|
11
|
+
- **๐ AI-Powered Diff Analysis**: Analyze git/hg diffs with comprehensive code review
|
12
|
+
- **๐ Requirements Compliance**: Check if code changes meet specified requirements
|
13
|
+
- **๐งช Test Coverage Assessment**: Evaluate test coverage for code changes
|
14
|
+
- **๐ฟ Branch Comparison**: Compare changes against any branch (main/master/default)
|
15
|
+
- **๐ ๏ธ VCS Support**: Full support for both Git and Mercurial repositories
|
16
|
+
- **๐ Errbit Integration**: Analyze Errbit errors and generate detailed reports
|
17
|
+
- **๐ซ Scrum Tickets**: Create formatted Scrum tickets from errors
|
13
18
|
|
14
19
|
## Installation
|
15
20
|
|
@@ -135,6 +140,9 @@ n2b [options] your natural language instruction
|
|
135
140
|
|
136
141
|
Options:
|
137
142
|
- `-x` or `--execute`: Execute the generated commands after confirmation
|
143
|
+
- `-d` or `--diff`: Analyze git/hg diff with AI-powered code review
|
144
|
+
- `-b` or `--branch [BRANCH]`: Compare against specific branch (auto-detects main/master/default)
|
145
|
+
- `-r` or `--requirements FILE`: Requirements file for compliance checking
|
138
146
|
- `-c` or `--config`: Reconfigure the tool
|
139
147
|
- `-h` or `--help`: Display help information
|
140
148
|
|
@@ -152,6 +160,82 @@ Examples:
|
|
152
160
|
|
153
161
|
```n2b -c ```
|
154
162
|
|
163
|
+
## ๐ AI-Powered Diff Analysis
|
164
|
+
|
165
|
+
N2B provides comprehensive AI-powered code review for your git and mercurial repositories.
|
166
|
+
|
167
|
+
### Basic Diff Analysis
|
168
|
+
|
169
|
+
```bash
|
170
|
+
# Analyze uncommitted changes
|
171
|
+
n2b --diff
|
172
|
+
|
173
|
+
# Analyze changes against specific branch
|
174
|
+
n2b --diff --branch main
|
175
|
+
n2b --diff --branch feature/auth
|
176
|
+
|
177
|
+
# Auto-detect default branch (main/master/default)
|
178
|
+
n2b --diff --branch
|
179
|
+
|
180
|
+
# Short form
|
181
|
+
n2b -d -b main
|
182
|
+
```
|
183
|
+
|
184
|
+
### Requirements Compliance Checking
|
185
|
+
|
186
|
+
```bash
|
187
|
+
# Check if changes meet requirements
|
188
|
+
n2b --diff --requirements requirements.md
|
189
|
+
n2b -d -r req.md
|
190
|
+
|
191
|
+
# Combine with branch comparison
|
192
|
+
n2b --diff --branch main --requirements requirements.md
|
193
|
+
```
|
194
|
+
|
195
|
+
### What You Get
|
196
|
+
|
197
|
+
The AI analysis provides:
|
198
|
+
|
199
|
+
- **๐ Summary**: Clear overview of what changed
|
200
|
+
- **๐จ Potential Errors**: Bugs, security issues, logic problems with exact file/line references
|
201
|
+
- **๐ก Suggested Improvements**: Code quality, performance, style recommendations
|
202
|
+
- **๐งช Test Coverage Assessment**: Evaluation of test completeness and quality
|
203
|
+
- **๐ Requirements Evaluation**: Compliance check with clear status indicators:
|
204
|
+
- โ
**IMPLEMENTED**: Requirement fully satisfied
|
205
|
+
- โ ๏ธ **PARTIALLY IMPLEMENTED**: Needs more work
|
206
|
+
- โ **NOT IMPLEMENTED**: Not addressed
|
207
|
+
- ๐ **UNCLEAR**: Cannot determine from diff
|
208
|
+
|
209
|
+
### Example Output
|
210
|
+
|
211
|
+
```
|
212
|
+
Code Diff Analysis:
|
213
|
+
-------------------
|
214
|
+
Summary:
|
215
|
+
Added user authentication with JWT tokens and password validation.
|
216
|
+
|
217
|
+
Potential Errors:
|
218
|
+
- lib/auth.rb line 42: Password validation allows weak passwords
|
219
|
+
- controllers/auth_controller.rb lines 15-20: Missing rate limiting for login attempts
|
220
|
+
|
221
|
+
Suggested Improvements:
|
222
|
+
- lib/auth.rb line 30: Consider using bcrypt for password hashing
|
223
|
+
- spec/auth_spec.rb: Add tests for edge cases and security scenarios
|
224
|
+
|
225
|
+
Test Coverage Assessment:
|
226
|
+
Good: Basic authentication flow is tested. Missing: No tests for password validation edge cases, JWT expiration handling, or security attack scenarios.
|
227
|
+
|
228
|
+
Requirements Evaluation:
|
229
|
+
โ
IMPLEMENTED: User login/logout functionality fully working
|
230
|
+
โ ๏ธ PARTIALLY IMPLEMENTED: Password strength requirements present but not comprehensive
|
231
|
+
โ NOT IMPLEMENTED: Two-factor authentication not addressed in this diff
|
232
|
+
-------------------
|
233
|
+
```
|
234
|
+
|
235
|
+
### Supported Version Control Systems
|
236
|
+
|
237
|
+
- **Git**: Full support with auto-detection of main/master branches
|
238
|
+
- **Mercurial (hg)**: Full support with auto-detection of default branch
|
155
239
|
|
156
240
|
n2r in ruby or rails console
|
157
241
|
n2r "your question", files:['file1.rb', 'file2.rb'], exception: AnError
|
@@ -240,4 +324,4 @@ The generated tickets include:
|
|
240
324
|
- Acceptance criteria
|
241
325
|
- Story point estimate
|
242
326
|
- Priority level
|
243
|
-
- Reference to the original Errbit URL
|
327
|
+
- Reference to the original Errbit URL# Test change
|
data/lib/n2b/cli.rb
CHANGED
@@ -46,7 +46,7 @@ module N2B
|
|
46
46
|
requirements_content = File.read(requirements_filepath)
|
47
47
|
end
|
48
48
|
|
49
|
-
diff_output = execute_vcs_diff(vcs_type)
|
49
|
+
diff_output = execute_vcs_diff(vcs_type, @options[:branch])
|
50
50
|
analyze_diff(diff_output, config, user_prompt_addition, requirements_content)
|
51
51
|
end
|
52
52
|
|
@@ -60,17 +60,139 @@ module N2B
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
def execute_vcs_diff(vcs_type)
|
63
|
+
def execute_vcs_diff(vcs_type, branch_option = nil)
|
64
64
|
case vcs_type
|
65
65
|
when :git
|
66
|
-
|
66
|
+
if branch_option
|
67
|
+
target_branch = branch_option == 'auto' ? detect_git_default_branch : branch_option
|
68
|
+
if target_branch
|
69
|
+
# Validate that the target branch exists
|
70
|
+
unless validate_git_branch_exists(target_branch)
|
71
|
+
puts "Error: Branch '#{target_branch}' does not exist."
|
72
|
+
puts "Available branches:"
|
73
|
+
puts `git branch -a`.lines.map(&:strip).reject(&:empty?)
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
|
77
|
+
puts "Comparing current branch against '#{target_branch}'..."
|
78
|
+
`git diff #{target_branch}...HEAD`
|
79
|
+
else
|
80
|
+
puts "Could not detect default branch, falling back to HEAD diff..."
|
81
|
+
`git diff HEAD`
|
82
|
+
end
|
83
|
+
else
|
84
|
+
`git diff HEAD`
|
85
|
+
end
|
67
86
|
when :hg
|
68
|
-
|
87
|
+
if branch_option
|
88
|
+
target_branch = branch_option == 'auto' ? detect_hg_default_branch : branch_option
|
89
|
+
if target_branch
|
90
|
+
# Validate that the target branch exists
|
91
|
+
unless validate_hg_branch_exists(target_branch)
|
92
|
+
puts "Error: Branch '#{target_branch}' does not exist."
|
93
|
+
puts "Available branches:"
|
94
|
+
puts `hg branches`.lines.map(&:strip).reject(&:empty?)
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
|
98
|
+
puts "Comparing current branch against '#{target_branch}'..."
|
99
|
+
`hg diff -r #{target_branch}`
|
100
|
+
else
|
101
|
+
puts "Could not detect default branch, falling back to standard diff..."
|
102
|
+
`hg diff`
|
103
|
+
end
|
104
|
+
else
|
105
|
+
`hg diff`
|
106
|
+
end
|
69
107
|
else
|
70
108
|
"" # Should not happen if get_vcs_type logic is correct and checked before calling
|
71
109
|
end
|
72
110
|
end
|
73
111
|
|
112
|
+
def detect_git_default_branch
|
113
|
+
# Try multiple methods to detect the default branch
|
114
|
+
|
115
|
+
# Method 1: Check origin/HEAD symbolic ref
|
116
|
+
result = `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null`.strip
|
117
|
+
if $?.success? && !result.empty?
|
118
|
+
return result.split('/').last
|
119
|
+
end
|
120
|
+
|
121
|
+
# Method 2: Check remote show origin
|
122
|
+
result = `git remote show origin 2>/dev/null | grep "HEAD branch"`.strip
|
123
|
+
if $?.success? && !result.empty?
|
124
|
+
match = result.match(/HEAD branch:\s*(\w+)/)
|
125
|
+
return match[1] if match
|
126
|
+
end
|
127
|
+
|
128
|
+
# Method 3: Check if common default branches exist
|
129
|
+
['main', 'master'].each do |branch|
|
130
|
+
result = `git rev-parse --verify origin/#{branch} 2>/dev/null`
|
131
|
+
if $?.success?
|
132
|
+
return branch
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Method 4: Fallback - check local branches
|
137
|
+
['main', 'master'].each do |branch|
|
138
|
+
result = `git rev-parse --verify #{branch} 2>/dev/null`
|
139
|
+
if $?.success?
|
140
|
+
return branch
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# If all else fails, return nil
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
|
148
|
+
def detect_hg_default_branch
|
149
|
+
# Method 1: Check current branch (if it's 'default', that's the main branch)
|
150
|
+
result = `hg branch 2>/dev/null`.strip
|
151
|
+
if $?.success? && result == 'default'
|
152
|
+
return 'default'
|
153
|
+
end
|
154
|
+
|
155
|
+
# Method 2: Look for 'default' branch in branch list
|
156
|
+
result = `hg branches 2>/dev/null`
|
157
|
+
if $?.success? && result.include?('default')
|
158
|
+
return 'default'
|
159
|
+
end
|
160
|
+
|
161
|
+
# Method 3: Check if there are any branches at all
|
162
|
+
result = `hg branches 2>/dev/null`.strip
|
163
|
+
if $?.success? && !result.empty?
|
164
|
+
# Get the first branch (usually the main one)
|
165
|
+
first_branch = result.lines.first&.split&.first
|
166
|
+
return first_branch if first_branch
|
167
|
+
end
|
168
|
+
|
169
|
+
# Fallback to 'default' (standard hg main branch name)
|
170
|
+
'default'
|
171
|
+
end
|
172
|
+
|
173
|
+
def validate_git_branch_exists(branch)
|
174
|
+
# Check if branch exists locally
|
175
|
+
result = `git rev-parse --verify #{branch} 2>/dev/null`
|
176
|
+
return true if $?.success?
|
177
|
+
|
178
|
+
# Check if branch exists on remote
|
179
|
+
result = `git rev-parse --verify origin/#{branch} 2>/dev/null`
|
180
|
+
return true if $?.success?
|
181
|
+
|
182
|
+
false
|
183
|
+
end
|
184
|
+
|
185
|
+
def validate_hg_branch_exists(branch)
|
186
|
+
# Check if branch exists in hg branches
|
187
|
+
result = `hg branches 2>/dev/null`
|
188
|
+
if $?.success?
|
189
|
+
return result.lines.any? { |line| line.strip.start_with?(branch) }
|
190
|
+
end
|
191
|
+
|
192
|
+
# If we can't list branches, assume it exists (hg is more permissive)
|
193
|
+
true
|
194
|
+
end
|
195
|
+
|
74
196
|
private
|
75
197
|
|
76
198
|
def process_natural_language_command(input_text, config)
|
@@ -387,8 +509,13 @@ JSON_INSTRUCTION
|
|
387
509
|
# This internal JSON parsing is for the *content* of a successful LLM response.
|
388
510
|
# The LlmApiError for network/auth issues should be caught before this.
|
389
511
|
begin
|
390
|
-
|
391
|
-
|
512
|
+
# Check if response_json_str is already a Hash (parsed JSON)
|
513
|
+
if response_json_str.is_a?(Hash)
|
514
|
+
response_json_str
|
515
|
+
else
|
516
|
+
parsed_response = JSON.parse(response_json_str)
|
517
|
+
parsed_response
|
518
|
+
end
|
392
519
|
rescue JSON::ParserError => e
|
393
520
|
puts "Error parsing LLM response JSON for command generation: #{e.message}"
|
394
521
|
# This is a fallback for when the LLM response *content* is not valid JSON.
|
@@ -490,7 +617,7 @@ JSON_INSTRUCTION
|
|
490
617
|
|
491
618
|
|
492
619
|
def parse_options
|
493
|
-
options = { execute: false, config: nil, diff: false, requirements: nil }
|
620
|
+
options = { execute: false, config: nil, diff: false, requirements: nil, branch: nil }
|
494
621
|
|
495
622
|
parser = OptionParser.new do |opts|
|
496
623
|
opts.banner = "Usage: n2b [options] [natural language command]"
|
@@ -503,6 +630,10 @@ JSON_INSTRUCTION
|
|
503
630
|
options[:diff] = true
|
504
631
|
end
|
505
632
|
|
633
|
+
opts.on('-b', '--branch [BRANCH]', 'Compare against branch (default: auto-detect main/master)') do |branch|
|
634
|
+
options[:branch] = branch || 'auto'
|
635
|
+
end
|
636
|
+
|
506
637
|
opts.on('-r', '--requirements FILE', 'Requirements file for diff analysis') do |file|
|
507
638
|
options[:requirements] = file
|
508
639
|
end
|
@@ -526,6 +657,14 @@ JSON_INSTRUCTION
|
|
526
657
|
exit 1
|
527
658
|
end
|
528
659
|
|
660
|
+
# Validate option combinations
|
661
|
+
if options[:branch] && !options[:diff]
|
662
|
+
puts "Error: --branch option can only be used with --diff"
|
663
|
+
puts ""
|
664
|
+
puts parser.help
|
665
|
+
exit 1
|
666
|
+
end
|
667
|
+
|
529
668
|
options
|
530
669
|
end
|
531
670
|
end
|
data/lib/n2b/version.rb
CHANGED