llama_bot_rails 0.1.11 → 0.1.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab8f2052c6695abc545b10879f23262d1c444011c28aa60e035fe94e12e62e35
4
- data.tar.gz: 21532f0afe7f6bf345da06b89e0e472d6e219eba9a3da0a5387a09a2f3ddbc39
3
+ metadata.gz: 73211770ce4e13b9fb835721ed12f0d422889a84d0c45473174b7bf97ff76e93
4
+ data.tar.gz: b70b8fdcc9375f45d317427cd62546c3d2190fab82d9769f50afeaabc3af4870
5
5
  SHA512:
6
- metadata.gz: a4400caf025fb253e8734003046a8256d6dcd6862ef6ddc9b45a3ac7a0a016749ef77eccf5ed9b17d5310ed1029a98af4873737765471d17aa665e0f60c7865c
7
- data.tar.gz: 5ee28cfaa7c097dcce2fd95490c3721643abc0600cdbb3bd591bb255a2d21c27558810f43194206a10ae4ea0de7ee1ec71e9c5c0c62defb731238751fc8f1dd5
6
+ metadata.gz: c7b9a928144a765964510b4e1d2ce51a0736b3105a083503f98cb7681e229a6e7fd2c7d9246c13ee9233f04adbd2448d03bc4dfd626b550bbb8c38bf848cbbdb
7
+ data.tar.gz: e94b2ee65ac23a81ba952bfd14fd2679c442a80058f42743cd06c0c132dd6164dcebdca885c1979eeeeac89732ae4fa2726d51266669df2834a4a85ae1a8d857
data/README.md CHANGED
@@ -160,6 +160,23 @@ Rails.application.configure do
160
160
  end
161
161
  ```
162
162
 
163
+ ## **Principle of Least Priviledge**: Whitelisting Controller Actions
164
+
165
+ Rather than giving the agent full access to your Rails app via the Rails console, You can whitelist controller actions instead.
166
+
167
+ ```
168
+ class PagesController < ApplicationController
169
+ include LlamaBotRails::ControllerExtensions
170
+ include LlamaBotRails::AgentAuth
171
+
172
+ # ─── Allow the agent to hit these actions ────────────────────────────────
173
+ llama_bot_allow :update #uses llama_bot_rails "authenticate_user_or_agent!" on top of your existing devise authentication.
174
+
175
+ skip_before_action :authenticate_user_or_agent!, only: [:show] #NOTE: You must change any skip_before_action callbacks that skip devise Authentication, to use :authenticate_user_or_agent!
176
+ ```
177
+
178
+ When you include LlamaBotRails::AgentAuth, the gem aliases any authenticate_<scope>! filters to a unified guard. You can keep your old callbacks/skips for now, but you’ll see a deprecation warning—switch to authenticate_user_or_agent! at your convenience.
179
+
163
180
  ## 🧪 **What You Can Build**
164
181
 
165
182
  ### Developer Assistant
@@ -47,11 +47,6 @@ module LlamaBotRails
47
47
  # Use a begin/rescue block to catch thread creation errors
48
48
  begin
49
49
 
50
- @api_token = Rails.application.message_verifier(:llamabot_ws).generate(
51
- { session_id: SecureRandom.uuid },
52
- expires_in: 30.minutes
53
- )
54
-
55
50
  @worker = Thread.new do
56
51
  Thread.current[:connection_id] = @connection_id
57
52
  Thread.current.abort_on_exception = true # This will help surface errors
@@ -126,7 +121,15 @@ module LlamaBotRails
126
121
  # through external websocket to FastAPI/Python backend.
127
122
  def receive(data)
128
123
  begin
129
- #used to validate the message before it's sent to the backend.
124
+ #used to validate the message before it's sent to the llamabot-backend.
125
+
126
+ # Get the currently logged in user from the environment.
127
+ current_user = LlamaBotRails.current_user_resolver.call(connection.env)
128
+
129
+ @api_token = Rails.application.message_verifier(:llamabot_ws).generate(
130
+ { session_id: SecureRandom.uuid, user_id: current_user&.id},
131
+ expires_in: 30.minutes
132
+ )
130
133
 
131
134
  #This could be an example of how we might implement hooks & filters in the future.
132
135
  validate_message(data) #Placeholder for now, we are using this to mock errors being thrown. In the future, we can add actual validation logic.
@@ -148,6 +151,7 @@ module LlamaBotRails
148
151
  Rails.logger.info "[LlamaBot] Got message from Javascript LlamaBot Frontend: #{data.inspect}"
149
152
  rescue => e
150
153
  Rails.logger.error "[LlamaBot] Error in receive method: #{e.message}"
154
+ Rails.logger.error "[LlamaBot] Backtrace: #{e.backtrace.join("\n")}"
151
155
  send_message_to_frontend("error", e.message)
152
156
  end
153
157
  end
@@ -2,11 +2,25 @@ require 'llama_bot_rails/llama_bot'
2
2
  module LlamaBotRails
3
3
  class AgentController < ActionController::Base
4
4
  include ActionController::Live
5
+ include LlamaBotRails::AgentAuth
6
+ include LlamaBotRails::ControllerExtensions
7
+
8
+ llama_bot_allow :command
9
+
5
10
  skip_before_action :verify_authenticity_token, only: [:command, :send_message]
6
- before_action :authenticate_agent!, only: [:command]
11
+ # skip_before_action :authenticate_user_or_agent!, only: [:command]
12
+
13
+ before_action :check_agent_authentication
7
14
 
8
15
  # POST /agent/command
9
16
  def command
17
+
18
+ unless LlamaBotRails.config.enable_console_tool
19
+ Rails.logger.warn("[[LlamaBot Debug]] Console tool is disabled")
20
+ render json: { error: "Console tool is disabled" }, status: :forbidden
21
+ return
22
+ end
23
+
10
24
  input = params[:command]
11
25
 
12
26
  # Capture both stdout and return value
@@ -16,18 +30,15 @@ module LlamaBotRails
16
30
  $stdout = output
17
31
  result = safety_eval(input)
18
32
  $stdout = STDOUT
19
-
20
- # If result is a string and output has content, prefer output
21
- final_result = if output.string.present?
22
- output.string.strip
23
- else
24
- result
25
- end
26
-
27
- render json: { result: final_result }
33
+
34
+ # Return both output and result
35
+ render json: {
36
+ output: output.string.strip,
37
+ result: result
38
+ }
28
39
  rescue => e
29
40
  $stdout = STDOUT # Reset stdout on error
30
- render json: { error: e.class.name, message: e.message }, status: :unprocessable_entity
41
+ render json: { error: "#{e.class.name}: #{e.message}" }
31
42
  end
32
43
 
33
44
  def index
@@ -78,10 +89,13 @@ module LlamaBotRails
78
89
  response.headers['Cache-Control'] = 'no-cache'
79
90
  response.headers['Connection'] = 'keep-alive'
80
91
 
92
+ # Get the currently logged in user from the environment.
93
+ current_user = LlamaBotRails.current_user_resolver.call(request.env)
94
+
81
95
  @api_token = Rails.application.message_verifier(:llamabot_ws).generate(
82
- { session_id: SecureRandom.uuid },
96
+ { session_id: SecureRandom.uuid, user_id: current_user&.id},
83
97
  expires_in: 30.minutes
84
- )
98
+ )
85
99
 
86
100
  # 1. Instantiate the builder
87
101
  builder = state_builder_class.new(
@@ -131,25 +145,15 @@ module LlamaBotRails
131
145
  private
132
146
 
133
147
  def safety_eval(input)
134
- begin
135
- # Change to Rails root directory for file operations
136
- Dir.chdir(Rails.root) do
137
- # Create a safer evaluation context
138
- Rails.logger.info "[[LlamaBot]] Evaluating input: #{input}"
139
- binding.eval(input)
140
- end
141
- rescue => exception
142
- Rails.logger.error "Error in safety_eval: #{exception.message}"
143
- return exception.message
148
+ # Change to Rails root directory for file operations
149
+ Dir.chdir(Rails.root) do
150
+ # Create a safer evaluation context
151
+ Rails.logger.info "[[LlamaBot]] Evaluating input: #{input}"
152
+ binding.eval(input)
144
153
  end
145
- end
146
-
147
- def authenticate_agent!
148
- auth_header = request.headers["Authorization"]
149
- token = auth_header&.split("Bearer ")&.last # Extract token after "Bearer "
150
- @session_payload = Rails.application.message_verifier(:llamabot_ws).verify(token)
151
- rescue ActiveSupport::MessageVerifier::InvalidSignature
152
- head :unauthorized
154
+ rescue => exception
155
+ Rails.logger.error "Error in safety_eval: #{exception.message}"
156
+ raise exception
153
157
  end
154
158
 
155
159
  def state_builder_class
@@ -575,7 +575,7 @@ This deprecated and will be removed over time.
575
575
  <img src="https://service-jobs-images.s3.us-east-2.amazonaws.com/7rl98t1weu387r43il97h6ipk1l7" alt="LlamaBot Logo" class="logo">
576
576
  <div id="connectionStatusIconForLlamaBot" class="connection-status status-yellow"></div>
577
577
  </div>
578
- <h1>LlamaBot Chat</h1>
578
+ <h1>Lenny the Llama</h1>
579
579
  </div>
580
580
  <button class="compose-button" onclick="startNewConversation()">
581
581
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
data/bin/bundle ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'bundler' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ version = ">= 0.a"
12
+
13
+ str = ARGV.first
14
+ if str
15
+ str = str.b[/\A_(.*)_\z/, 1]
16
+ if str and Gem::Version.correct?(str)
17
+ version = str
18
+ ENV['BUNDLER_VERSION'] = str
19
+
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('bundler', 'bundle', version)
26
+ else
27
+ gem "bundler", version
28
+ load Gem.bin_path("bundler", "bundle", version)
29
+ end
data/bin/bundle.lock ADDED
File without changes
data/bin/bundler ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'bundler' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ version = ">= 0.a"
12
+
13
+ str = ARGV.first
14
+ if str
15
+ str = str.b[/\A_(.*)_\z/, 1]
16
+ if str and Gem::Version.correct?(str)
17
+ version = str
18
+ ENV['BUNDLER_VERSION'] = str
19
+
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('bundler', 'bundler', version)
26
+ else
27
+ gem "bundler", version
28
+ load Gem.bin_path("bundler", "bundler", version)
29
+ end
data/bin/bundler.lock ADDED
File without changes
data/bin/byebug ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'byebug' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('byebug', 'byebug', version)
26
+ else
27
+ gem "byebug", version
28
+ load Gem.bin_path("byebug", "byebug", version)
29
+ end
data/bin/coderay ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'coderay' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('coderay', 'coderay', version)
26
+ else
27
+ gem "coderay", version
28
+ load Gem.bin_path("coderay", "coderay", version)
29
+ end
data/bin/erb ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'erb' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('erb', 'erb', version)
26
+ else
27
+ gem "erb", version
28
+ load Gem.bin_path("erb", "erb", version)
29
+ end
data/bin/faker ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'faker' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('faker', 'faker', version)
26
+ else
27
+ gem "faker", version
28
+ load Gem.bin_path("faker", "faker", version)
29
+ end
data/bin/htmldiff ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'diff-lcs' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('diff-lcs', 'htmldiff', version)
26
+ else
27
+ gem "diff-lcs", version
28
+ load Gem.bin_path("diff-lcs", "htmldiff", version)
29
+ end
data/bin/irb ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'irb' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('irb', 'irb', version)
26
+ else
27
+ gem "irb", version
28
+ load Gem.bin_path("irb", "irb", version)
29
+ end
data/bin/ldiff ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'diff-lcs' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('diff-lcs', 'ldiff', version)
26
+ else
27
+ gem "diff-lcs", version
28
+ load Gem.bin_path("diff-lcs", "ldiff", version)
29
+ end
data/bin/nokogiri ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'nokogiri' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('nokogiri', 'nokogiri', version)
26
+ else
27
+ gem "nokogiri", version
28
+ load Gem.bin_path("nokogiri", "nokogiri", version)
29
+ end
data/bin/pry ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'pry' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('pry', 'pry', version)
26
+ else
27
+ gem "pry", version
28
+ load Gem.bin_path("pry", "pry", version)
29
+ end
data/bin/puma ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'puma' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('puma', 'puma', version)
26
+ else
27
+ gem "puma", version
28
+ load Gem.bin_path("puma", "puma", version)
29
+ end
data/bin/pumactl ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'puma' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('puma', 'pumactl', version)
26
+ else
27
+ gem "puma", version
28
+ load Gem.bin_path("puma", "pumactl", version)
29
+ end
data/bin/racc ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'racc' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('racc', 'racc', version)
26
+ else
27
+ gem "racc", version
28
+ load Gem.bin_path("racc", "racc", version)
29
+ end
data/bin/rackup ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'rackup' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('rackup', 'rackup', version)
26
+ else
27
+ gem "rackup", version
28
+ load Gem.bin_path("rackup", "rackup", version)
29
+ end
data/bin/rake ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by RubyGems.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'rubygems'
10
+
11
+ Gem.use_gemdeps
12
+
13
+ version = ">= 0.a"
14
+
15
+ str = ARGV.first
16
+ if str
17
+ str = str.b[/\A_(.*)_\z/, 1]
18
+ if str and Gem::Version.correct?(str)
19
+ version = str
20
+ ARGV.shift
21
+ end
22
+ end
23
+
24
+ if Gem.respond_to?(:activate_bin_path)
25
+ load Gem.activate_bin_path('rake', 'rake', version)
26
+ else
27
+ gem "rake", version
28
+ load Gem.bin_path("rake", "rake", version)
29
+ end