e2b 0.3.4 → 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.
@@ -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
 
@@ -155,9 +156,9 @@ module E2B
155
156
  def send_stdin(pid, data, headers: nil)
156
157
  encoded = Base64.strict_encode64(data.is_a?(String) ? data : data.to_s)
157
158
  envd_rpc("process.Process", "SendInput", body: {
158
- process: { pid: pid },
159
- input: { pty: encoded }
160
- }, headers: headers)
159
+ process: { pid: pid },
160
+ input: { pty: encoded }
161
+ }, headers: headers)
161
162
  end
162
163
 
163
164
  # Kill a PTY process with SIGKILL.
@@ -169,9 +170,9 @@ module E2B
169
170
  # sandbox.pty.kill(12345)
170
171
  def kill(pid, headers: nil)
171
172
  envd_rpc("process.Process", "SendSignal", body: {
172
- process: { pid: pid },
173
- signal: 9 # SIGKILL
174
- }, headers: headers)
173
+ process: { pid: pid },
174
+ signal: 9 # SIGKILL
175
+ }, headers: headers)
175
176
  true
176
177
  rescue E2B::E2BError
177
178
  false
@@ -191,11 +192,11 @@ module E2B
191
192
  # sandbox.pty.resize(pid, PtySize.new(cols: 120, rows: 40))
192
193
  def resize(pid, size)
193
194
  envd_rpc("process.Process", "Update", body: {
194
- process: { pid: pid },
195
- pty: {
196
- size: size.to_h
197
- }
198
- })
195
+ process: { pid: pid },
196
+ pty: {
197
+ size: size.to_h
198
+ }
199
+ })
199
200
  end
200
201
 
201
202
  # Close the stdin of a PTY process.
@@ -208,8 +209,8 @@ module E2B
208
209
  # @raise [E2B::E2BError] if the process is not found
209
210
  def close_stdin(pid)
210
211
  envd_rpc("process.Process", "CloseStdin", body: {
211
- process: { pid: pid }
212
- })
212
+ process: { pid: pid }
213
+ })
213
214
  end
214
215
 
215
216
  # List running processes in the sandbox.
@@ -235,13 +236,10 @@ module E2B
235
236
  result["LANG"] = "C.UTF-8"
236
237
  result["LC_ALL"] = "C.UTF-8"
237
238
 
238
- if envs.is_a?(Hash)
239
- envs.each { |k, v| result[k.to_s] = v.to_s }
240
- end
239
+ envs.each { |k, v| result[k.to_s] = v.to_s } if envs.is_a?(Hash)
241
240
 
242
241
  result
243
242
  end
244
-
245
243
  end
246
244
  end
247
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.4"
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.4
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
  - - "~>"
@@ -151,6 +179,7 @@ metadata:
151
179
  source_code_uri: https://github.com/ya-luotao/e2b-ruby
152
180
  documentation_uri: https://e2b.dev/docs
153
181
  changelog_uri: https://github.com/ya-luotao/e2b-ruby/blob/main/CHANGELOG.md
182
+ rubygems_mfa_required: 'true'
154
183
  rdoc_options: []
155
184
  require_paths:
156
185
  - lib