daytona 0.170.0 → 0.171.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.
- checksums.yaml +4 -4
- data/lib/daytona/code_interpreter.rb +39 -58
- data/lib/daytona/computer_use.rb +1 -1
- data/lib/daytona/daytona.rb +10 -2
- data/lib/daytona/file_system.rb +35 -3
- data/lib/daytona/file_transfer.rb +184 -0
- data/lib/daytona/sdk/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7b07a148abb7ece5ebaef51d75a606301119c2e4b8bda891406e71acbe60dc9a
|
|
4
|
+
data.tar.gz: 66186d6b161ab68bf34df1c4860cc2e7b59c3d8983171efa2c3dbaddc36ef1a6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 392310a933e9c7555db1787abe9247462fa1fffc421a4cdbe8714c620704346ac8416f595a18bc8534999aaed02a4e64569516a53aee41f08d8bef748c66c445
|
|
7
|
+
data.tar.gz: 64201581db64d5df476bed8e55cb22fbeb7d1dc8b8cd9f5b6d0232fc1bdd898303dd76cd9cd7a94c0db3b4b7da8feb6765f74779a2e14ecdc21c2aec6bed0b76
|
|
@@ -103,15 +103,11 @@ module Daytona
|
|
|
103
103
|
'Accept' => 'application/json'
|
|
104
104
|
)
|
|
105
105
|
|
|
106
|
-
# Use queue for synchronization
|
|
107
106
|
completion_queue = Queue.new
|
|
108
|
-
interpreter = self
|
|
109
|
-
last_message_time = Time.now
|
|
110
|
-
message_mutex = Mutex.new
|
|
107
|
+
interpreter = self
|
|
111
108
|
|
|
112
109
|
puts "[DEBUG] Connecting to WebSocket: #{ws_url}" if ENV['DEBUG']
|
|
113
110
|
|
|
114
|
-
# Connect to WebSocket and execute
|
|
115
111
|
ws = WebSocket::Client::Simple.connect(ws_url, headers:)
|
|
116
112
|
|
|
117
113
|
ws.on :open do
|
|
@@ -120,8 +116,6 @@ module Daytona
|
|
|
120
116
|
end
|
|
121
117
|
|
|
122
118
|
ws.on :message do |msg|
|
|
123
|
-
message_mutex.synchronize { last_message_time = Time.now }
|
|
124
|
-
|
|
125
119
|
puts "[DEBUG] Received message (length=#{msg.data.length}): #{msg.data.inspect[0..200]}" if ENV['DEBUG']
|
|
126
120
|
|
|
127
121
|
interpreter.send(:handle_message, msg.data, result, on_stdout, on_stderr, on_error, completion_queue)
|
|
@@ -146,72 +140,59 @@ module Daytona
|
|
|
146
140
|
end
|
|
147
141
|
end
|
|
148
142
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
# Otherwise use short idle timeout for normal completion
|
|
152
|
-
idle_timeout = timeout ? (timeout + 2.0) : 1.0
|
|
153
|
-
max_wait = (timeout || 300) + 3 # Add buffer to configured timeout
|
|
143
|
+
no_timeout = timeout.is_a?(Numeric) && timeout <= 0
|
|
144
|
+
max_wait = no_timeout ? nil : (timeout || 600) + 3
|
|
154
145
|
start_time = Time.now
|
|
155
146
|
completion_reason = nil
|
|
156
147
|
|
|
157
|
-
# Wait for completion or close event
|
|
158
148
|
loop do
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
completion_reason = :completed
|
|
166
|
-
break
|
|
167
|
-
# If it's an error from close event (like timeout), raise it
|
|
168
|
-
elsif completion[:type] == :error_from_close
|
|
169
|
-
error_msg = completion[:error]
|
|
170
|
-
# Raise TimeoutError for timeout cases, regular Error for others
|
|
171
|
-
if error_msg.include?('timed out') || error_msg.include?('Execution timed out')
|
|
172
|
-
raise Sdk::TimeoutError, error_msg
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
raise Sdk::Error, error_msg
|
|
176
|
-
|
|
177
|
-
# Close event during execution (before control message) = likely timeout or error
|
|
178
|
-
elsif completion[:type] == :close
|
|
179
|
-
elapsed = Time.now - start_time
|
|
180
|
-
# If we got close near the timeout, it's likely a timeout
|
|
181
|
-
if timeout && elapsed >= timeout && elapsed < (timeout + 2)
|
|
182
|
-
raise Sdk::TimeoutError,
|
|
183
|
-
'Execution timed out: operation exceeded the configured `timeout`. Provide a larger value if needed.'
|
|
184
|
-
end
|
|
185
|
-
# Otherwise normal close
|
|
186
|
-
completion_reason = :close
|
|
187
|
-
break
|
|
188
|
-
# WebSocket errors
|
|
189
|
-
elsif completion[:type] == :error && !completion[:error].message.include?('stream closed')
|
|
190
|
-
raise Sdk::Error, "WebSocket error: #{completion[:error].message}"
|
|
149
|
+
if max_wait
|
|
150
|
+
remaining = max_wait - (Time.now - start_time)
|
|
151
|
+
if remaining <= 0
|
|
152
|
+
ws.close
|
|
153
|
+
raise Sdk::TimeoutError,
|
|
154
|
+
'Execution timed out: operation exceeded the configured `timeout`. Provide a larger value if needed.'
|
|
191
155
|
end
|
|
192
|
-
rescue ThreadError
|
|
193
|
-
# Queue is empty, check idle timeout
|
|
194
156
|
end
|
|
195
157
|
|
|
196
|
-
|
|
197
|
-
time_since_last_message = message_mutex.synchronize { Time.now - last_message_time }
|
|
198
|
-
if time_since_last_message > idle_timeout
|
|
199
|
-
puts "[DEBUG] Idle timeout reached (#{idle_timeout}s), assuming completion" if ENV['DEBUG']
|
|
200
|
-
completion_reason = :idle_complete
|
|
201
|
-
break
|
|
202
|
-
end
|
|
158
|
+
completion = completion_queue.pop(timeout: max_wait ? remaining : nil)
|
|
203
159
|
|
|
204
|
-
|
|
205
|
-
if Time.now - start_time > max_wait
|
|
160
|
+
if completion.nil?
|
|
206
161
|
ws.close
|
|
207
162
|
raise Sdk::TimeoutError,
|
|
208
163
|
'Execution timed out: operation exceeded the configured `timeout`. Provide a larger value if needed.'
|
|
209
164
|
end
|
|
210
165
|
|
|
211
|
-
|
|
166
|
+
puts "[DEBUG] Got completion signal: #{completion[:type]}" if ENV['DEBUG']
|
|
167
|
+
|
|
168
|
+
if completion[:type] == :completed
|
|
169
|
+
completion_reason = :completed
|
|
170
|
+
break
|
|
171
|
+
elsif completion[:type] == :error_from_close
|
|
172
|
+
error_msg = completion[:error]
|
|
173
|
+
if error_msg.include?('timed out') || error_msg.include?('Execution timed out')
|
|
174
|
+
raise Sdk::TimeoutError, error_msg
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
raise Sdk::Error, error_msg
|
|
178
|
+
elsif completion[:type] == :close
|
|
179
|
+
elapsed = Time.now - start_time
|
|
180
|
+
if timeout && timeout > 0 && elapsed >= timeout && elapsed < (timeout + 2)
|
|
181
|
+
raise Sdk::TimeoutError,
|
|
182
|
+
'Execution timed out: operation exceeded the configured `timeout`. Provide a larger value if needed.'
|
|
183
|
+
end
|
|
184
|
+
completion_reason = :close
|
|
185
|
+
break
|
|
186
|
+
elsif completion[:type] == :error
|
|
187
|
+
unless completion[:error].message.include?('stream closed')
|
|
188
|
+
raise Sdk::Error, "WebSocket error: #{completion[:error].message}"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
completion_reason = :close
|
|
192
|
+
break
|
|
193
|
+
end
|
|
212
194
|
end
|
|
213
195
|
|
|
214
|
-
# Close WebSocket if not already closed
|
|
215
196
|
ws.close if completion_reason != :close
|
|
216
197
|
sleep 0.05
|
|
217
198
|
|
data/lib/daytona/computer_use.rb
CHANGED
|
@@ -91,7 +91,7 @@ module Daytona
|
|
|
91
91
|
#
|
|
92
92
|
# @example
|
|
93
93
|
# result = sandbox.computer_use.mouse.drag(start_x: 50, start_y: 50, end_x: 150, end_y: 150)
|
|
94
|
-
# puts "
|
|
94
|
+
# puts "Drag ended at #{result.x}, #{result.y}"
|
|
95
95
|
def drag(start_x:, start_y:, end_x:, end_y:, button: 'left')
|
|
96
96
|
request = DaytonaToolboxApiClient::MouseDragRequest.new(start_x:, start_y:, end_x:, end_y:, button:)
|
|
97
97
|
toolbox_api.drag(request)
|
data/lib/daytona/daytona.rb
CHANGED
|
@@ -224,8 +224,16 @@ module Daytona
|
|
|
224
224
|
def ensure_access_token_defined
|
|
225
225
|
return if config.api_key
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
unless config.jwt_token
|
|
228
|
+
raise Sdk::Error,
|
|
229
|
+
'Authentication credentials not found. Set DAYTONA_API_KEY, or both DAYTONA_JWT_TOKEN and ' \
|
|
230
|
+
'DAYTONA_ORGANIZATION_ID. These can also be provided via Daytona::Config.'
|
|
231
|
+
end
|
|
232
|
+
return if config.organization_id
|
|
233
|
+
|
|
234
|
+
raise Sdk::Error,
|
|
235
|
+
'DAYTONA_ORGANIZATION_ID is required when authenticating with DAYTONA_JWT_TOKEN. ' \
|
|
236
|
+
'It can also be provided via Daytona::Config.'
|
|
229
237
|
end
|
|
230
238
|
|
|
231
239
|
# @return [DaytonaApiClient::ApiClient]
|
data/lib/daytona/file_system.rb
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
require 'tempfile'
|
|
7
7
|
require 'fileutils'
|
|
8
|
+
require_relative 'file_transfer'
|
|
8
9
|
|
|
9
10
|
module Daytona
|
|
10
|
-
class FileSystem
|
|
11
|
+
class FileSystem # rubocop:disable Metrics/ClassLength
|
|
11
12
|
include Instrumentation
|
|
12
13
|
|
|
13
14
|
# @return [String] The Sandbox ID
|
|
@@ -153,6 +154,37 @@ module Daytona
|
|
|
153
154
|
raise Sdk::Error, "Failed to download file: #{e.message}"
|
|
154
155
|
end
|
|
155
156
|
|
|
157
|
+
# Downloads a single file from the Sandbox as a stream without buffering the entire
|
|
158
|
+
# file into memory. Yields file content in chunks to the given block, or returns an
|
|
159
|
+
# Enumerator if no block is given.
|
|
160
|
+
#
|
|
161
|
+
# @param remote_path [String] Path to the file in the Sandbox. Relative paths are resolved
|
|
162
|
+
# based on the sandbox working directory.
|
|
163
|
+
# @param timeout [Integer] Timeout for the download operation in seconds. 0 means no timeout.
|
|
164
|
+
# Default is 30 minutes.
|
|
165
|
+
# @yield [chunk] Yields each chunk of file content as it arrives
|
|
166
|
+
# @yieldparam chunk [String] A binary string chunk of file content
|
|
167
|
+
# @return [Enumerator, nil] An Enumerator yielding chunks if no block given, nil otherwise
|
|
168
|
+
# @raise [Daytona::Sdk::Error] If the file does not exist or the operation fails
|
|
169
|
+
#
|
|
170
|
+
# @example Stream to a local file without loading into memory
|
|
171
|
+
# File.open("local_copy.bin", "wb") do |f|
|
|
172
|
+
# sandbox.fs.download_file_stream("workspace/large-file.bin") { |chunk| f.write(chunk) }
|
|
173
|
+
# end
|
|
174
|
+
#
|
|
175
|
+
# @example Collect chunks with an Enumerator
|
|
176
|
+
# content = sandbox.fs.download_file_stream("workspace/data.json").reduce(:+)
|
|
177
|
+
# puts content
|
|
178
|
+
def download_file_stream(remote_path, timeout: 30 * 60, &)
|
|
179
|
+
return enum_for(__method__, remote_path, timeout:) unless block_given?
|
|
180
|
+
|
|
181
|
+
FileTransfer.stream_download(api_client: toolbox_api.api_client, remote_path: remote_path,
|
|
182
|
+
timeout: timeout, &)
|
|
183
|
+
nil
|
|
184
|
+
rescue StandardError => e
|
|
185
|
+
raise Sdk::Error, "Failed to download file: #{e.message}"
|
|
186
|
+
end
|
|
187
|
+
|
|
156
188
|
# Uploads a file to the specified path in the Sandbox. If a file already exists at
|
|
157
189
|
# the destination path, it will be overwritten.
|
|
158
190
|
#
|
|
@@ -364,8 +396,8 @@ module Daytona
|
|
|
364
396
|
end
|
|
365
397
|
|
|
366
398
|
instrument :create_folder, :delete_file, :get_file_info, :list_files, :download_file,
|
|
367
|
-
:upload_file, :upload_files, :find_files,
|
|
368
|
-
:replace_in_files, :set_file_permissions,
|
|
399
|
+
:download_file_stream, :upload_file, :upload_files, :find_files,
|
|
400
|
+
:search_files, :move_files, :replace_in_files, :set_file_permissions,
|
|
369
401
|
component: 'FileSystem'
|
|
370
402
|
|
|
371
403
|
private
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'typhoeus'
|
|
8
|
+
|
|
9
|
+
module Daytona
|
|
10
|
+
class MultipartDownloadStreamParser
|
|
11
|
+
attr_reader :error_message
|
|
12
|
+
attr_writer :boundary_token
|
|
13
|
+
|
|
14
|
+
def initialize(&on_file_chunk)
|
|
15
|
+
@on_file_chunk = on_file_chunk
|
|
16
|
+
@boundary_token = nil
|
|
17
|
+
@buffer = String.new.b
|
|
18
|
+
@state = :preamble
|
|
19
|
+
@part_name = nil
|
|
20
|
+
@error_buffer = String.new.b
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def <<(chunk)
|
|
24
|
+
@buffer << chunk.b
|
|
25
|
+
process!
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def finish!
|
|
29
|
+
process!
|
|
30
|
+
|
|
31
|
+
return if @state == :done || @buffer.empty?
|
|
32
|
+
|
|
33
|
+
emit(@buffer)
|
|
34
|
+
finalize_part!
|
|
35
|
+
@buffer = String.new.b
|
|
36
|
+
@state = :done
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def process!
|
|
42
|
+
loop do
|
|
43
|
+
advanced = case @state
|
|
44
|
+
when :preamble then consume_preamble?
|
|
45
|
+
when :headers then consume_headers?
|
|
46
|
+
when :body then consume_body?
|
|
47
|
+
else false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
break unless advanced
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def consume_preamble?
|
|
55
|
+
start_marker = "#{boundary}\r\n".b
|
|
56
|
+
index = @buffer.index(start_marker)
|
|
57
|
+
return retain_tail?(start_marker.bytesize - 1) unless index
|
|
58
|
+
|
|
59
|
+
@buffer = remaining_bytes(index + start_marker.bytesize)
|
|
60
|
+
@state = :headers
|
|
61
|
+
true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def consume_headers?
|
|
65
|
+
separator = "\r\n\r\n".b
|
|
66
|
+
index = @buffer.index(separator)
|
|
67
|
+
return false unless index
|
|
68
|
+
|
|
69
|
+
headers = @buffer.byteslice(0, index)
|
|
70
|
+
@buffer = remaining_bytes(index + separator.bytesize)
|
|
71
|
+
@part_name = headers[/Content-Disposition:\s*[^\r\n]*\bname="([^"]+)"/i, 1]
|
|
72
|
+
raise Sdk::Error, 'Invalid multipart response' if @part_name.nil?
|
|
73
|
+
|
|
74
|
+
@state = :body
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def consume_body? # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
79
|
+
marker = "\r\n#{boundary}".b
|
|
80
|
+
index = @buffer.index(marker)
|
|
81
|
+
|
|
82
|
+
if index
|
|
83
|
+
emit(@buffer.byteslice(0, index))
|
|
84
|
+
@buffer = remaining_bytes(index + marker.bytesize)
|
|
85
|
+
finalize_part!
|
|
86
|
+
@state = :done
|
|
87
|
+
return true
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
flushable = @buffer.bytesize - marker.bytesize + 1
|
|
91
|
+
return false if flushable <= 0
|
|
92
|
+
|
|
93
|
+
emit(@buffer.byteslice(0, flushable))
|
|
94
|
+
@buffer = remaining_bytes(flushable)
|
|
95
|
+
false
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def emit(data)
|
|
99
|
+
return if data.nil? || data.empty?
|
|
100
|
+
|
|
101
|
+
case @part_name
|
|
102
|
+
when 'file'
|
|
103
|
+
@on_file_chunk.call(data)
|
|
104
|
+
when 'error'
|
|
105
|
+
@error_buffer << data
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def finalize_part!
|
|
110
|
+
return unless @part_name == 'error'
|
|
111
|
+
|
|
112
|
+
@error_message = extract_error_message(@error_buffer)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def extract_error_message(payload)
|
|
116
|
+
parsed = JSON.parse(payload)
|
|
117
|
+
parsed['message'] || parsed['error'] || payload
|
|
118
|
+
rescue JSON::ParserError
|
|
119
|
+
payload
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def retain_tail?(size)
|
|
123
|
+
@buffer = @buffer.byteslice(-size, size) || String.new.b if size.positive? && @buffer.bytesize > size
|
|
124
|
+
false
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def remaining_bytes(offset)
|
|
128
|
+
@buffer.byteslice(offset, @buffer.bytesize - offset) || String.new.b
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def boundary
|
|
132
|
+
"--#{@boundary_token}".b
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
module FileTransfer
|
|
137
|
+
def self.extract_multipart_boundary(content_type)
|
|
138
|
+
match = content_type&.match(/boundary=(?:"([^"]+)"|([^;]+))/i)
|
|
139
|
+
return unless match
|
|
140
|
+
|
|
141
|
+
match.captures.compact.first
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def self.stream_download(api_client:, remote_path:, timeout:, &) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
145
|
+
config = api_client.config
|
|
146
|
+
parser = MultipartDownloadStreamParser.new(&)
|
|
147
|
+
response = nil
|
|
148
|
+
|
|
149
|
+
request = Typhoeus::Request.new(
|
|
150
|
+
"#{config.base_url}/files/bulk-download",
|
|
151
|
+
method: :post,
|
|
152
|
+
headers: api_client.default_headers.dup.merge(
|
|
153
|
+
'Accept' => 'multipart/form-data',
|
|
154
|
+
'Content-Type' => 'application/json'
|
|
155
|
+
),
|
|
156
|
+
body: JSON.generate(paths: [remote_path]),
|
|
157
|
+
timeout: timeout,
|
|
158
|
+
ssl_verifypeer: config.verify_ssl,
|
|
159
|
+
ssl_verifyhost: config.verify_ssl_host ? 2 : 0
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
request.on_headers do |stream_response|
|
|
163
|
+
boundary = extract_multipart_boundary(stream_response.headers['Content-Type'])
|
|
164
|
+
raise Sdk::Error, 'Missing multipart boundary in download response' unless boundary
|
|
165
|
+
|
|
166
|
+
parser.boundary_token = boundary
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
request.on_body do |chunk|
|
|
170
|
+
parser << chunk
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
request.on_complete do |completed_response|
|
|
174
|
+
response = completed_response
|
|
175
|
+
parser.finish!
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
request.run
|
|
179
|
+
|
|
180
|
+
raise Sdk::Error, parser.error_message if parser.error_message
|
|
181
|
+
raise Sdk::Error, "HTTP #{response.code}" if response && !response.success?
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
data/lib/daytona/sdk/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: daytona
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.171.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daytona Platforms Inc.
|
|
@@ -85,28 +85,28 @@ dependencies:
|
|
|
85
85
|
requirements:
|
|
86
86
|
- - '='
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: 0.
|
|
88
|
+
version: 0.171.0
|
|
89
89
|
type: :runtime
|
|
90
90
|
prerelease: false
|
|
91
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
93
|
- - '='
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: 0.
|
|
95
|
+
version: 0.171.0
|
|
96
96
|
- !ruby/object:Gem::Dependency
|
|
97
97
|
name: daytona_toolbox_api_client
|
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
100
|
- - '='
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: 0.
|
|
102
|
+
version: 0.171.0
|
|
103
103
|
type: :runtime
|
|
104
104
|
prerelease: false
|
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
|
107
107
|
- - '='
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: 0.
|
|
109
|
+
version: 0.171.0
|
|
110
110
|
- !ruby/object:Gem::Dependency
|
|
111
111
|
name: dotenv
|
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -196,6 +196,7 @@ files:
|
|
|
196
196
|
- lib/daytona/config.rb
|
|
197
197
|
- lib/daytona/daytona.rb
|
|
198
198
|
- lib/daytona/file_system.rb
|
|
199
|
+
- lib/daytona/file_transfer.rb
|
|
199
200
|
- lib/daytona/git.rb
|
|
200
201
|
- lib/daytona/lsp_server.rb
|
|
201
202
|
- lib/daytona/object_storage.rb
|