e2b 0.3.3 → 0.3.5

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.
@@ -99,9 +99,9 @@ module E2B
99
99
  # entries.each { |e| puts "#{e.name} (#{e.type})" }
100
100
  def list(path, depth: 1, user: nil, request_timeout: 60)
101
101
  response = envd_rpc("filesystem.Filesystem", "ListDir",
102
- body: { path: path, depth: depth },
103
- timeout: request_timeout,
104
- headers: user_auth_headers(user))
102
+ body: { path: path, depth: depth },
103
+ timeout: request_timeout,
104
+ headers: user_auth_headers(user))
105
105
 
106
106
  entries = extract_entries(response)
107
107
  entries.map { |e| Models::EntryInfo.from_hash(e) }
@@ -132,9 +132,9 @@ module E2B
132
132
  # @return [Models::EntryInfo] File/directory info
133
133
  def get_info(path, user: nil, request_timeout: 30)
134
134
  response = envd_rpc("filesystem.Filesystem", "Stat",
135
- body: { path: path },
136
- timeout: request_timeout,
137
- headers: user_auth_headers(user))
135
+ body: { path: path },
136
+ timeout: request_timeout,
137
+ headers: user_auth_headers(user))
138
138
 
139
139
  entry_data = extract_entry(response)
140
140
  Models::EntryInfo.from_hash(entry_data)
@@ -147,9 +147,9 @@ module E2B
147
147
  # @param request_timeout [Integer] Request timeout in seconds
148
148
  def remove(path, user: nil, request_timeout: 30)
149
149
  envd_rpc("filesystem.Filesystem", "Remove",
150
- body: { path: path },
151
- timeout: request_timeout,
152
- headers: user_auth_headers(user))
150
+ body: { path: path },
151
+ timeout: request_timeout,
152
+ headers: user_auth_headers(user))
153
153
  end
154
154
 
155
155
  # Rename/move a file or directory
@@ -161,9 +161,9 @@ module E2B
161
161
  # @return [Models::EntryInfo] Info about the moved entry
162
162
  def rename(old_path, new_path, user: nil, request_timeout: 30)
163
163
  response = envd_rpc("filesystem.Filesystem", "Move",
164
- body: { source: old_path, destination: new_path },
165
- timeout: request_timeout,
166
- headers: user_auth_headers(user))
164
+ body: { source: old_path, destination: new_path },
165
+ timeout: request_timeout,
166
+ headers: user_auth_headers(user))
167
167
 
168
168
  entry_data = extract_entry(response)
169
169
  Models::EntryInfo.from_hash(entry_data)
@@ -177,9 +177,9 @@ module E2B
177
177
  # @return [Boolean] true if created successfully
178
178
  def make_dir(path, user: nil, request_timeout: 30)
179
179
  envd_rpc("filesystem.Filesystem", "MakeDir",
180
- body: { path: path },
181
- timeout: request_timeout,
182
- headers: user_auth_headers(user))
180
+ body: { path: path },
181
+ timeout: request_timeout,
182
+ headers: user_auth_headers(user))
183
183
  true
184
184
  end
185
185
 
@@ -202,13 +202,13 @@ module E2B
202
202
  def watch_dir(path, recursive: false, user: nil, request_timeout: 30)
203
203
  if recursive && !supports_recursive_watch?
204
204
  raise E2B::TemplateError,
205
- "You need to update the template to use recursive watching. You can do this by running `e2b template build` in the directory with the template."
205
+ "You need to update the template to use recursive watching. You can do this by running `e2b template build` in the directory with the template."
206
206
  end
207
207
 
208
208
  response = envd_rpc("filesystem.Filesystem", "CreateWatcher",
209
- body: { path: path, recursive: recursive },
210
- timeout: request_timeout,
211
- headers: user_auth_headers(user))
209
+ body: { path: path, recursive: recursive },
210
+ timeout: request_timeout,
211
+ headers: user_auth_headers(user))
212
212
 
213
213
  watcher_id = response[:events]&.first&.dig("watcherId") ||
214
214
  response["watcherId"] ||
@@ -257,9 +257,8 @@ module E2B
257
257
 
258
258
  response = execute_http_request(uri, request, timeout: timeout)
259
259
  unless successful_response?(response)
260
- if response.code.to_i == 404
261
- raise E2B::NotFoundError.new("File not found", status_code: 404)
262
- end
260
+ raise E2B::NotFoundError.new("File not found", status_code: 404) if response.code.to_i == 404
261
+
263
262
  raise E2B::E2BError, "File read failed: HTTP #{response.code}"
264
263
  end
265
264
 
@@ -281,9 +280,7 @@ module E2B
281
280
  apply_request_headers(request)
282
281
 
283
282
  response = execute_http_request(uri, request, timeout: timeout)
284
- unless successful_response?(response)
285
- raise E2B::E2BError, "File upload failed: HTTP #{response.code}"
286
- end
283
+ raise E2B::E2BError, "File upload failed: HTTP #{response.code}" unless successful_response?(response)
287
284
 
288
285
  parse_upload_response(response.body)
289
286
  end
@@ -344,13 +341,11 @@ module E2B
344
341
  rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET, EOFError, Net::OpenTimeout, Net::ReadTimeout => e
345
342
  retry_count += 1
346
343
 
347
- if retry_count <= max_retries
348
- sleep_time = 2**retry_count
349
- sleep(sleep_time)
350
- retry
351
- else
352
- raise E2B::E2BError, "#{operation} failed after #{max_retries} retries: #{e.message}"
353
- end
344
+ raise E2B::E2BError, "#{operation} failed after #{max_retries} retries: #{e.message}" unless retry_count <= max_retries
345
+
346
+ sleep_time = 2**retry_count
347
+ sleep(sleep_time)
348
+ retry
354
349
  end
355
350
  end
356
351
 
@@ -365,6 +360,7 @@ module E2B
365
360
 
366
361
  events.each do |event|
367
362
  next unless event.is_a?(Hash)
363
+
368
364
  # Direct entries field
369
365
  if event["entries"]
370
366
  entries.concat(Array(event["entries"]))
@@ -400,6 +396,7 @@ module E2B
400
396
  events.each do |event|
401
397
  next unless event.is_a?(Hash)
402
398
  return event["watcherId"] || event["watcher_id"] if event["watcherId"] || event["watcher_id"]
399
+
403
400
  result = event["result"]
404
401
  return result["watcherId"] || result["watcher_id"] if result.is_a?(Hash) && (result["watcherId"] || result["watcher_id"])
405
402
  end
@@ -84,7 +84,7 @@ module E2B
84
84
  #
85
85
  # @return [Boolean]
86
86
  def has_conflicts?
87
- file_status.any? { |f| f.index_status == "u" || f.index_status == "U" }
87
+ file_status.any? { |f| %w[u U].include?(f.index_status) }
88
88
  end
89
89
 
90
90
  # Number of staged files
@@ -105,7 +105,7 @@ module E2B
105
105
  #
106
106
  # @return [Integer]
107
107
  def conflict_count
108
- file_status.count { |f| f.index_status == "u" || f.index_status == "U" }
108
+ file_status.count { |f| %w[u U].include?(f.index_status) }
109
109
  end
110
110
 
111
111
  # Number of modified files (in the working tree)
@@ -571,7 +571,7 @@ module E2B
571
571
  envs: nil, user: nil, cwd: nil, timeout: nil)
572
572
  # Configure credential helper to use the store
573
573
  set_config("credential.helper", "store", scope: "global",
574
- envs: envs, user: user, cwd: cwd, timeout: timeout)
574
+ envs: envs, user: user, cwd: cwd, timeout: timeout)
575
575
 
576
576
  # Write credentials to the credential store via git credential approve
577
577
  credential_input = [
@@ -583,7 +583,7 @@ module E2B
583
583
  ].join("\n")
584
584
 
585
585
  escaped_input = Shellwords.escape(credential_input)
586
- args = ["credential", "approve"]
586
+ args = %w[credential approve]
587
587
  cmd = build_git_command(args, nil)
588
588
  full_cmd = "echo #{escaped_input} | #{cmd}"
589
589
 
@@ -604,9 +604,9 @@ module E2B
604
604
  # @return [void]
605
605
  def configure_user(name, email, scope: "global", path: nil, envs: nil, user: nil, cwd: nil, timeout: nil)
606
606
  set_config("user.name", name, scope: scope, path: path,
607
- envs: envs, user: user, cwd: cwd, timeout: timeout)
607
+ envs: envs, user: user, cwd: cwd, timeout: timeout)
608
608
  set_config("user.email", email, scope: scope, path: path,
609
- envs: envs, user: user, cwd: cwd, timeout: timeout)
609
+ envs: envs, user: user, cwd: cwd, timeout: timeout)
610
610
  end
611
611
 
612
612
  private
@@ -781,7 +781,7 @@ module E2B
781
781
  def validate_scope!(scope)
782
782
  return if VALID_SCOPES.include?(scope)
783
783
 
784
- raise E2B::E2BError, "Invalid git config scope '#{scope}'. Must be one of: #{VALID_SCOPES.join(', ')}"
784
+ raise E2B::E2BError, "Invalid git config scope '#{scope}'. Must be one of: #{VALID_SCOPES.join(", ")}"
785
785
  end
786
786
 
787
787
  # Convert a scope name to its git CLI flag
@@ -835,7 +835,7 @@ module E2B
835
835
  file_status << GitFileStatus.new(path: filepath.split("\t").first, index_status: idx, work_tree_status: wt)
836
836
  when /\Au (.)(.) .+ .+ .+ .+ .+ (.+)\z/
837
837
  # Unmerged entry
838
- idx = Regexp.last_match(1)
838
+ Regexp.last_match(1)
839
839
  wt = Regexp.last_match(2)
840
840
  filepath = Regexp.last_match(3)
841
841
  file_status << GitFileStatus.new(path: filepath, index_status: "u", work_tree_status: wt)
@@ -22,31 +22,31 @@ module E2B
22
22
 
23
23
  begin
24
24
  envd_rpc("process.Process", rpc_method,
25
- body: body,
26
- timeout: timeout,
27
- headers: headers,
28
- on_event: lambda { |event_data|
29
- stream_event = event_data[:event]
30
- stream.push(stream_event) if stream_event
31
-
32
- stdout_chunk = event_data[:stdout]
33
- stderr_chunk = event_data[:stderr]
34
-
35
- on_stdout&.call(stdout_chunk) if stdout_chunk && !stdout_chunk.empty?
36
- on_stderr&.call(stderr_chunk) if stderr_chunk && !stderr_chunk.empty?
37
-
38
- stream_block&.call(:stdout, stdout_chunk) if stdout_chunk && !stdout_chunk.empty?
39
- stream_block&.call(:stderr, stderr_chunk) if stderr_chunk && !stderr_chunk.empty?
40
-
41
- unless start_signal_sent
42
- extracted_pid = extract_pid_from_event(stream_event)
43
- if extracted_pid
44
- pid = extracted_pid
45
- start_signal_sent = true
46
- start_queue << [:pid, pid]
47
- end
48
- end
49
- })
25
+ body: body,
26
+ timeout: timeout,
27
+ headers: headers,
28
+ on_event: lambda { |event_data|
29
+ stream_event = event_data[:event]
30
+ stream.push(stream_event) if stream_event
31
+
32
+ stdout_chunk = event_data[:stdout]
33
+ stderr_chunk = event_data[:stderr]
34
+
35
+ on_stdout&.call(stdout_chunk) if stdout_chunk && !stdout_chunk.empty?
36
+ on_stderr&.call(stderr_chunk) if stderr_chunk && !stderr_chunk.empty?
37
+
38
+ stream_block&.call(:stdout, stdout_chunk) if stdout_chunk && !stdout_chunk.empty?
39
+ stream_block&.call(:stderr, stderr_chunk) if stderr_chunk && !stderr_chunk.empty?
40
+
41
+ unless start_signal_sent
42
+ extracted_pid = extract_pid_from_event(stream_event)
43
+ if extracted_pid
44
+ pid = extracted_pid
45
+ start_signal_sent = true
46
+ start_queue << [:pid, pid]
47
+ end
48
+ end
49
+ })
50
50
 
51
51
  unless start_signal_sent
52
52
  start_signal_sent = true
@@ -54,6 +54,7 @@ module E2B
54
54
  # handle = pty.connect(pid)
55
55
  class Pty < BaseService
56
56
  include LiveStreamable
57
+
57
58
  # Default shell to use for PTY sessions
58
59
  DEFAULT_SHELL = "/bin/bash"
59
60
 
@@ -98,7 +99,8 @@ module E2B
98
99
  process: process_spec,
99
100
  pty: {
100
101
  size: size.to_h
101
- }
102
+ },
103
+ stdin: false
102
104
  }
103
105
 
104
106
  build_live_handle(
@@ -154,9 +156,9 @@ module E2B
154
156
  def send_stdin(pid, data, headers: nil)
155
157
  encoded = Base64.strict_encode64(data.is_a?(String) ? data : data.to_s)
156
158
  envd_rpc("process.Process", "SendInput", body: {
157
- process: { pid: pid },
158
- input: { pty: encoded }
159
- }, headers: headers)
159
+ process: { pid: pid },
160
+ input: { pty: encoded }
161
+ }, headers: headers)
160
162
  end
161
163
 
162
164
  # Kill a PTY process with SIGKILL.
@@ -168,9 +170,9 @@ module E2B
168
170
  # sandbox.pty.kill(12345)
169
171
  def kill(pid, headers: nil)
170
172
  envd_rpc("process.Process", "SendSignal", body: {
171
- process: { pid: pid },
172
- signal: 9 # SIGKILL
173
- }, headers: headers)
173
+ process: { pid: pid },
174
+ signal: 9 # SIGKILL
175
+ }, headers: headers)
174
176
  true
175
177
  rescue E2B::E2BError
176
178
  false
@@ -190,11 +192,11 @@ module E2B
190
192
  # sandbox.pty.resize(pid, PtySize.new(cols: 120, rows: 40))
191
193
  def resize(pid, size)
192
194
  envd_rpc("process.Process", "Update", body: {
193
- process: { pid: pid },
194
- pty: {
195
- size: size.to_h
196
- }
197
- })
195
+ process: { pid: pid },
196
+ pty: {
197
+ size: size.to_h
198
+ }
199
+ })
198
200
  end
199
201
 
200
202
  # Close the stdin of a PTY process.
@@ -207,8 +209,8 @@ module E2B
207
209
  # @raise [E2B::E2BError] if the process is not found
208
210
  def close_stdin(pid)
209
211
  envd_rpc("process.Process", "CloseStdin", body: {
210
- process: { pid: pid }
211
- })
212
+ process: { pid: pid }
213
+ })
212
214
  end
213
215
 
214
216
  # List running processes in the sandbox.
@@ -234,13 +236,10 @@ module E2B
234
236
  result["LANG"] = "C.UTF-8"
235
237
  result["LC_ALL"] = "C.UTF-8"
236
238
 
237
- if envs.is_a?(Hash)
238
- envs.each { |k, v| result[k.to_s] = v.to_s }
239
- end
239
+ envs.each { |k, v| result[k.to_s] = v.to_s } if envs.is_a?(Hash)
240
240
 
241
241
  result
242
242
  end
243
-
244
243
  end
245
244
  end
246
245
  end
data/lib/e2b/template.rb CHANGED
@@ -45,9 +45,9 @@ module E2B
45
45
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
46
46
  http_client = build_http_client(**credentials, domain: resolve_domain(domain))
47
47
  response = http_client.post("/templates/tags", body: {
48
- target: target_name,
49
- tags: normalize_tags(tags)
50
- })
48
+ target: target_name,
49
+ tags: normalize_tags(tags)
50
+ })
51
51
 
52
52
  Models::TemplateTagInfo.from_hash(response)
53
53
  end
@@ -56,9 +56,9 @@ module E2B
56
56
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
57
57
  http_client = build_http_client(**credentials, domain: resolve_domain(domain))
58
58
  http_client.delete("/templates/tags", body: {
59
- name: name,
60
- tags: normalize_tags(tags)
61
- })
59
+ name: name,
60
+ tags: normalize_tags(tags)
61
+ })
62
62
  nil
63
63
  end
64
64
 
@@ -179,7 +179,7 @@ module E2B
179
179
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
180
180
  http_client = build_http_client(**credentials, domain: resolve_domain(domain))
181
181
 
182
- tags_message = Array(tags).any? ? " with tags #{Array(tags).join(', ')}" : ""
182
+ tags_message = Array(tags).any? ? " with tags #{Array(tags).join(", ")}" : ""
183
183
  on_build_logs&.call(log_entry("Requesting build for template: #{resolved_name}#{tags_message}"))
184
184
 
185
185
  body = {
@@ -338,11 +338,11 @@ module E2B
338
338
 
339
339
  if build_info.is_a?(Hash)
340
340
  resolved_template_id = build_info[:template_id] || build_info["template_id"] ||
341
- build_info[:templateID] || build_info["templateID"]
341
+ build_info[:templateID] || build_info["templateID"]
342
342
  resolved_build_id = build_info[:build_id] || build_info["build_id"] ||
343
- build_info[:buildID] || build_info["buildID"]
343
+ build_info[:buildID] || build_info["buildID"]
344
344
  resolved_build_step_origins ||= build_info[:build_step_origins] || build_info["build_step_origins"] ||
345
- build_info[:buildStepOrigins] || build_info["buildStepOrigins"]
345
+ build_info[:buildStepOrigins] || build_info["buildStepOrigins"]
346
346
 
347
347
  return [resolved_template_id, resolved_build_id, Array(resolved_build_step_origins).compact]
348
348
  end
@@ -404,12 +404,12 @@ module E2B
404
404
  end
405
405
 
406
406
  def resolve_credentials(api_key:, access_token:)
407
- resolved_api_key = api_key || E2B.configuration&.api_key || ENV["E2B_API_KEY"]
408
- resolved_access_token = access_token || E2B.configuration&.access_token || ENV["E2B_ACCESS_TOKEN"]
407
+ resolved_api_key = api_key || E2B.configuration&.api_key || ENV.fetch("E2B_API_KEY", nil)
408
+ resolved_access_token = access_token || E2B.configuration&.access_token || ENV.fetch("E2B_ACCESS_TOKEN", nil)
409
409
 
410
410
  unless (resolved_api_key && !resolved_api_key.empty?) || (resolved_access_token && !resolved_access_token.empty?)
411
411
  raise ConfigurationError,
412
- "E2B credentials are required. Set E2B_API_KEY or E2B_ACCESS_TOKEN, or pass api_key:/access_token:."
412
+ "E2B credentials are required. Set E2B_API_KEY or E2B_ACCESS_TOKEN, or pass api_key:/access_token:."
413
413
  end
414
414
 
415
415
  { api_key: resolved_api_key, access_token: resolved_access_token }
@@ -638,7 +638,7 @@ module E2B
638
638
 
639
639
  def pip_install(packages = nil, g: true)
640
640
  package_list = packages.nil? ? nil : Array(packages).map(&:to_s)
641
- args = ["pip", "install"]
641
+ args = %w[pip install]
642
642
  args << "--user" unless g
643
643
  args.concat(package_list || ["."])
644
644
  run_cmd(args.join(" "), user: g ? "root" : nil)
@@ -646,7 +646,7 @@ module E2B
646
646
 
647
647
  def npm_install(packages = nil, g: false, dev: false)
648
648
  package_list = packages.nil? ? nil : Array(packages).map(&:to_s)
649
- args = ["npm", "install"]
649
+ args = %w[npm install]
650
650
  args << "-g" if g
651
651
  args << "--save-dev" if dev
652
652
  args.concat(package_list) if package_list
@@ -655,7 +655,7 @@ module E2B
655
655
 
656
656
  def bun_install(packages = nil, g: false, dev: false)
657
657
  package_list = packages.nil? ? nil : Array(packages).map(&:to_s)
658
- args = ["bun", "install"]
658
+ args = %w[bun install]
659
659
  args << "-g" if g
660
660
  args << "--dev" if dev
661
661
  args.concat(package_list) if package_list
@@ -668,7 +668,7 @@ module E2B
668
668
  run_cmd(
669
669
  [
670
670
  "apt-get update",
671
- "DEBIAN_FRONTEND=noninteractive DEBCONF_NOWARNINGS=yes apt-get install -y #{install_flags}#{package_list.join(' ')}"
671
+ "DEBIAN_FRONTEND=noninteractive DEBCONF_NOWARNINGS=yes apt-get install -y #{install_flags}#{package_list.join(" ")}"
672
672
  ],
673
673
  user: "root"
674
674
  )
@@ -683,7 +683,7 @@ module E2B
683
683
  end
684
684
 
685
685
  server_list = Array(servers).map(&:to_s)
686
- run_cmd("mcp-gateway pull #{server_list.join(' ')}", user: "root")
686
+ run_cmd("mcp-gateway pull #{server_list.join(" ")}", user: "root")
687
687
  end
688
688
 
689
689
  def git_clone(url, path = nil, branch: nil, depth: nil, user: nil)
@@ -730,7 +730,7 @@ module E2B
730
730
 
731
731
  def make_dir(path, mode: nil, user: nil)
732
732
  args = ["mkdir", "-p"]
733
- args << "-m #{format('%04o', mode)}" if mode
733
+ args << "-m #{format("%04o", mode)}" if mode
734
734
  args.concat(Array(path).map(&:to_s))
735
735
  run_cmd(args.join(" "), user: user)
736
736
  end
@@ -777,9 +777,12 @@ module E2B
777
777
  )
778
778
  end
779
779
 
780
- raise template_error("No base image specified for template", source_location: capture_source_location) unless @base_image
780
+ unless @base_image
781
+ raise template_error("No base image specified for template",
782
+ source_location: capture_source_location)
783
+ end
781
784
 
782
- dockerfile = +"FROM #{@base_image}\n"
785
+ dockerfile = "FROM #{@base_image}\n"
783
786
  @instructions.each do |instruction|
784
787
  case instruction[:type]
785
788
  when "RUN"
@@ -788,9 +791,9 @@ module E2B
788
791
  dockerfile << "COPY #{instruction[:args][0]} #{instruction[:args][1]}\n"
789
792
  when "ENV"
790
793
  values = instruction[:args].each_slice(2).map { |key, value| "#{key}=#{value}" }
791
- dockerfile << "ENV #{values.join(' ')}\n"
794
+ dockerfile << "ENV #{values.join(" ")}\n"
792
795
  else
793
- dockerfile << "#{instruction[:type]} #{instruction[:args].join(' ')}\n"
796
+ dockerfile << "#{instruction[:type]} #{instruction[:args].join(" ")}\n"
794
797
  end
795
798
  end
796
799
  dockerfile << "ENTRYPOINT #{@start_cmd}\n" if @start_cmd
@@ -913,7 +916,7 @@ module E2B
913
916
 
914
917
  def collect_files(src)
915
918
  matches = Dir.glob(src, base: @file_context_path, flags: File::FNM_DOTMATCH)
916
- .reject { |entry| entry == "." || entry == ".." }
919
+ .reject { |entry| [".", ".."].include?(entry) }
917
920
 
918
921
  files = []
919
922
  matches.each do |match|
@@ -991,14 +994,14 @@ module E2B
991
994
  end
992
995
 
993
996
  def normalize_ignore_pattern(pattern)
994
- normalized = pattern.to_s.tr(File::SEPARATOR, "/").sub(/\A\.\//, "")
995
- return "/#{normalized.sub(%r{\A/+}, '')}" if normalized.start_with?("/")
997
+ normalized = pattern.to_s.tr(File::SEPARATOR, "/").sub(%r{\A\./}, "")
998
+ return "/#{normalized.sub(%r{\A/+}, "")}" if normalized.start_with?("/")
996
999
 
997
1000
  normalized.sub(%r{\A/+}, "")
998
1001
  end
999
1002
 
1000
1003
  def normalize_ignore_path(path)
1001
- path.to_s.tr(File::SEPARATOR, "/").sub(/\A\.\//, "").sub(%r{\A/+}, "")
1004
+ path.to_s.tr(File::SEPARATOR, "/").sub(%r{\A\./}, "").sub(%r{\A/+}, "")
1002
1005
  end
1003
1006
 
1004
1007
  def build_step_origins
@@ -1013,8 +1016,8 @@ module E2B
1013
1016
  return [] unless File.exist?(dockerignore_path)
1014
1017
 
1015
1018
  File.readlines(dockerignore_path, chomp: true)
1016
- .map(&:strip)
1017
- .reject { |line| line.empty? || line.start_with?("#") }
1019
+ .map(&:strip)
1020
+ .reject { |line| line.empty? || line.start_with?("#") }
1018
1021
  end
1019
1022
 
1020
1023
  def read_gcp_service_account_json(path_or_content)
data/lib/e2b/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module E2B
4
- VERSION = "0.3.3"
4
+ VERSION = "0.3.5"
5
5
  end
metadata CHANGED
@@ -1,14 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: e2b
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tao Luo
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-05-05 00:00:00.000000000 Z
10
+ date: 2026-05-10 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.2'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: faraday
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -44,35 +58,49 @@ dependencies:
44
58
  - !ruby/object:Gem::Version
45
59
  version: '1.0'
46
60
  - !ruby/object:Gem::Dependency
47
- name: base64
61
+ name: rake
48
62
  requirement: !ruby/object:Gem::Requirement
49
63
  requirements:
50
64
  - - "~>"
51
65
  - !ruby/object:Gem::Version
52
- version: '0.2'
53
- type: :runtime
66
+ version: '13.0'
67
+ type: :development
54
68
  prerelease: false
55
69
  version_requirements: !ruby/object:Gem::Requirement
56
70
  requirements:
57
71
  - - "~>"
58
72
  - !ruby/object:Gem::Version
59
- version: '0.2'
73
+ version: '13.0'
60
74
  - !ruby/object:Gem::Dependency
61
- name: rake
75
+ name: rspec
62
76
  requirement: !ruby/object:Gem::Requirement
63
77
  requirements:
64
78
  - - "~>"
65
79
  - !ruby/object:Gem::Version
66
- version: '13.0'
80
+ version: '3.0'
67
81
  type: :development
68
82
  prerelease: false
69
83
  version_requirements: !ruby/object:Gem::Requirement
70
84
  requirements:
71
85
  - - "~>"
72
86
  - !ruby/object:Gem::Version
73
- version: '13.0'
87
+ version: '3.0'
74
88
  - !ruby/object:Gem::Dependency
75
- name: rspec
89
+ name: rubocop
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '1.72'
95
+ type: :development
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.72'
102
+ - !ruby/object:Gem::Dependency
103
+ name: rubocop-rspec
76
104
  requirement: !ruby/object:Gem::Requirement
77
105
  requirements:
78
106
  - - "~>"
@@ -134,6 +162,7 @@ files:
134
162
  - lib/e2b/services/base_service.rb
135
163
  - lib/e2b/services/command_handle.rb
136
164
  - lib/e2b/services/commands.rb
165
+ - lib/e2b/services/envd_base64.rb
137
166
  - lib/e2b/services/filesystem.rb
138
167
  - lib/e2b/services/git.rb
139
168
  - lib/e2b/services/live_streamable.rb
@@ -150,6 +179,7 @@ metadata:
150
179
  source_code_uri: https://github.com/ya-luotao/e2b-ruby
151
180
  documentation_uri: https://e2b.dev/docs
152
181
  changelog_uri: https://github.com/ya-luotao/e2b-ruby/blob/main/CHANGELOG.md
182
+ rubygems_mfa_required: 'true'
153
183
  rdoc_options: []
154
184
  require_paths:
155
185
  - lib