@hanzo/runtime 0.0.0-dev
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.
- package/LICENSE +190 -0
- package/README.md +147 -0
- package/hanzo-runtime-0.0.0-dev.tgz +0 -0
- package/hooks/typedoc-custom.mjs +640 -0
- package/jest.config.js +15 -0
- package/package.json +24 -0
- package/project.json +57 -0
- package/src/ComputerUse.ts +618 -0
- package/src/Daytona.ts +644 -0
- package/src/FileSystem.ts +414 -0
- package/src/Git.ts +303 -0
- package/src/Image.ts +643 -0
- package/src/LspServer.ts +245 -0
- package/src/ObjectStorage.ts +232 -0
- package/src/Process.ts +357 -0
- package/src/Sandbox.ts +478 -0
- package/src/Snapshot.ts +260 -0
- package/src/Volume.ts +110 -0
- package/src/code-toolbox/SandboxPythonCodeToolbox.ts +366 -0
- package/src/code-toolbox/SandboxTsCodeToolbox.ts +17 -0
- package/src/errors/DaytonaError.ts +15 -0
- package/src/index.ts +50 -0
- package/src/types/Charts.ts +193 -0
- package/src/types/ExecuteResponse.ts +33 -0
- package/src/utils/ArtifactParser.ts +58 -0
- package/src/utils/Path.ts +25 -0
- package/src/utils/Stream.ts +89 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +16 -0
- package/tsconfig.spec.json +12 -0
- package/typedoc.json +33 -0
package/src/Process.ts
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Daytona Platforms Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Command, Session, SessionExecuteRequest, SessionExecuteResponse, ToolboxApi } from '@daytonaio/api-client'
|
|
7
|
+
import { SandboxCodeToolbox } from './Sandbox'
|
|
8
|
+
import { ExecuteResponse } from './types/ExecuteResponse'
|
|
9
|
+
import { ArtifactParser } from './utils/ArtifactParser'
|
|
10
|
+
import { processStreamingResponse } from './utils/Stream'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parameters for code execution.
|
|
14
|
+
*/
|
|
15
|
+
export class CodeRunParams {
|
|
16
|
+
/**
|
|
17
|
+
* Command line arguments
|
|
18
|
+
*/
|
|
19
|
+
argv?: string[]
|
|
20
|
+
/**
|
|
21
|
+
* Environment variables
|
|
22
|
+
*/
|
|
23
|
+
env?: Record<string, string>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Handles process and code execution within a Sandbox.
|
|
28
|
+
*
|
|
29
|
+
* @class
|
|
30
|
+
*/
|
|
31
|
+
export class Process {
|
|
32
|
+
constructor(
|
|
33
|
+
private readonly sandboxId: string,
|
|
34
|
+
private readonly codeToolbox: SandboxCodeToolbox,
|
|
35
|
+
private readonly toolboxApi: ToolboxApi,
|
|
36
|
+
private readonly getRootDir: () => Promise<string>,
|
|
37
|
+
) {}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Executes a shell command in the Sandbox.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} command - Shell command to execute
|
|
43
|
+
* @param {string} [cwd] - Working directory for command execution. If not specified, uses the Sandbox root directory.
|
|
44
|
+
* Default is the user's root directory.
|
|
45
|
+
* @param {Record<string, string>} [env] - Environment variables to set for the command
|
|
46
|
+
* @param {number} [timeout] - Maximum time in seconds to wait for the command to complete. 0 means wait indefinitely.
|
|
47
|
+
* @returns {Promise<ExecuteResponse>} Command execution results containing:
|
|
48
|
+
* - exitCode: The command's exit status
|
|
49
|
+
* - result: Standard output from the command
|
|
50
|
+
* - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata)
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* // Simple command
|
|
54
|
+
* const response = await process.executeCommand('echo "Hello"');
|
|
55
|
+
* console.log(response.artifacts.stdout); // Prints: Hello
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* // Command with working directory
|
|
59
|
+
* const result = await process.executeCommand('ls', 'workspace/src');
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // Command with timeout
|
|
63
|
+
* const result = await process.executeCommand('sleep 10', undefined, 5);
|
|
64
|
+
*/
|
|
65
|
+
public async executeCommand(
|
|
66
|
+
command: string,
|
|
67
|
+
cwd?: string,
|
|
68
|
+
env?: Record<string, string>,
|
|
69
|
+
timeout?: number,
|
|
70
|
+
): Promise<ExecuteResponse> {
|
|
71
|
+
const base64UserCmd = Buffer.from(command).toString('base64')
|
|
72
|
+
command = `echo '${base64UserCmd}' | base64 -d | sh`
|
|
73
|
+
|
|
74
|
+
if (env && Object.keys(env).length > 0) {
|
|
75
|
+
const safeEnvExports =
|
|
76
|
+
Object.entries(env)
|
|
77
|
+
.map(([key, value]) => {
|
|
78
|
+
const encodedValue = Buffer.from(value).toString('base64')
|
|
79
|
+
return `export ${key}=$(echo '${encodedValue}' | base64 -d)`
|
|
80
|
+
})
|
|
81
|
+
.join(';') + ';'
|
|
82
|
+
command = `${safeEnvExports} ${command}`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
command = `sh -c "${command}"`
|
|
86
|
+
|
|
87
|
+
const response = await this.toolboxApi.executeCommand(this.sandboxId, {
|
|
88
|
+
command,
|
|
89
|
+
timeout,
|
|
90
|
+
cwd: cwd ?? (await this.getRootDir()),
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Parse artifacts from the output
|
|
94
|
+
const artifacts = ArtifactParser.parseArtifacts(response.data.result)
|
|
95
|
+
|
|
96
|
+
// Return enhanced response with parsed artifacts
|
|
97
|
+
return {
|
|
98
|
+
...response.data,
|
|
99
|
+
result: artifacts.stdout,
|
|
100
|
+
artifacts,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Executes code in the Sandbox using the appropriate language runtime.
|
|
106
|
+
*
|
|
107
|
+
* @param {string} code - Code to execute
|
|
108
|
+
* @param {CodeRunParams} params - Parameters for code execution
|
|
109
|
+
* @param {number} [timeout] - Maximum time in seconds to wait for execution to complete
|
|
110
|
+
* @returns {Promise<ExecuteResponse>} Code execution results containing:
|
|
111
|
+
* - exitCode: The execution's exit status
|
|
112
|
+
* - result: Standard output from the code
|
|
113
|
+
* - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata)
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* // Run TypeScript code
|
|
117
|
+
* const response = await process.codeRun(`
|
|
118
|
+
* const x = 10;
|
|
119
|
+
* const y = 20;
|
|
120
|
+
* console.log(\`Sum: \${x + y}\`);
|
|
121
|
+
* `);
|
|
122
|
+
* console.log(response.artifacts.stdout); // Prints: Sum: 30
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* // Run Python code with matplotlib
|
|
126
|
+
* const response = await process.codeRun(`
|
|
127
|
+
* import matplotlib.pyplot as plt
|
|
128
|
+
* import numpy as np
|
|
129
|
+
*
|
|
130
|
+
* x = np.linspace(0, 10, 30)
|
|
131
|
+
* y = np.sin(x)
|
|
132
|
+
*
|
|
133
|
+
* plt.figure(figsize=(8, 5))
|
|
134
|
+
* plt.plot(x, y, 'b-', linewidth=2)
|
|
135
|
+
* plt.title('Line Chart')
|
|
136
|
+
* plt.xlabel('X-axis (seconds)')
|
|
137
|
+
* plt.ylabel('Y-axis (amplitude)')
|
|
138
|
+
* plt.grid(True)
|
|
139
|
+
* plt.show()
|
|
140
|
+
* `);
|
|
141
|
+
*
|
|
142
|
+
* if (response.artifacts?.charts) {
|
|
143
|
+
* const chart = response.artifacts.charts[0];
|
|
144
|
+
*
|
|
145
|
+
* console.log(`Type: ${chart.type}`);
|
|
146
|
+
* console.log(`Title: ${chart.title}`);
|
|
147
|
+
* if (chart.type === ChartType.LINE) {
|
|
148
|
+
* const lineChart = chart as LineChart
|
|
149
|
+
* console.log('X Label:', lineChart.x_label)
|
|
150
|
+
* console.log('Y Label:', lineChart.y_label)
|
|
151
|
+
* console.log('X Ticks:', lineChart.x_ticks)
|
|
152
|
+
* console.log('Y Ticks:', lineChart.y_ticks)
|
|
153
|
+
* console.log('X Tick Labels:', lineChart.x_tick_labels)
|
|
154
|
+
* console.log('Y Tick Labels:', lineChart.y_tick_labels)
|
|
155
|
+
* console.log('X Scale:', lineChart.x_scale)
|
|
156
|
+
* console.log('Y Scale:', lineChart.y_scale)
|
|
157
|
+
* console.log('Elements:')
|
|
158
|
+
* console.dir(lineChart.elements, { depth: null })
|
|
159
|
+
* }
|
|
160
|
+
* }
|
|
161
|
+
*/
|
|
162
|
+
public async codeRun(code: string, params?: CodeRunParams, timeout?: number): Promise<ExecuteResponse> {
|
|
163
|
+
const runCommand = this.codeToolbox.getRunCommand(code, params)
|
|
164
|
+
return this.executeCommand(runCommand, undefined, params?.env, timeout)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Creates a new long-running background session in the Sandbox.
|
|
169
|
+
*
|
|
170
|
+
* Sessions are background processes that maintain state between commands, making them ideal for
|
|
171
|
+
* scenarios requiring multiple related commands or persistent environment setup. You can run
|
|
172
|
+
* long-running commands and monitor process status.
|
|
173
|
+
*
|
|
174
|
+
* @param {string} sessionId - Unique identifier for the new session
|
|
175
|
+
* @returns {Promise<void>}
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* // Create a new session
|
|
179
|
+
* const sessionId = 'my-session';
|
|
180
|
+
* await process.createSession(sessionId);
|
|
181
|
+
* const session = await process.getSession(sessionId);
|
|
182
|
+
* // Do work...
|
|
183
|
+
* await process.deleteSession(sessionId);
|
|
184
|
+
*/
|
|
185
|
+
public async createSession(sessionId: string): Promise<void> {
|
|
186
|
+
await this.toolboxApi.createSession(this.sandboxId, {
|
|
187
|
+
sessionId,
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Get a session in the sandbox.
|
|
193
|
+
*
|
|
194
|
+
* @param {string} sessionId - Unique identifier of the session to retrieve
|
|
195
|
+
* @returns {Promise<Session>} Session information including:
|
|
196
|
+
* - sessionId: The session's unique identifier
|
|
197
|
+
* - commands: List of commands executed in the session
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* const session = await process.getSession('my-session');
|
|
201
|
+
* session.commands.forEach(cmd => {
|
|
202
|
+
* console.log(`Command: ${cmd.command}`);
|
|
203
|
+
* });
|
|
204
|
+
*/
|
|
205
|
+
public async getSession(sessionId: string): Promise<Session> {
|
|
206
|
+
const response = await this.toolboxApi.getSession(this.sandboxId, sessionId)
|
|
207
|
+
return response.data
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Gets information about a specific command executed in a session.
|
|
212
|
+
*
|
|
213
|
+
* @param {string} sessionId - Unique identifier of the session
|
|
214
|
+
* @param {string} commandId - Unique identifier of the command
|
|
215
|
+
* @returns {Promise<Command>} Command information including:
|
|
216
|
+
* - id: The command's unique identifier
|
|
217
|
+
* - command: The executed command string
|
|
218
|
+
* - exitCode: Command's exit status (if completed)
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* const cmd = await process.getSessionCommand('my-session', 'cmd-123');
|
|
222
|
+
* if (cmd.exitCode === 0) {
|
|
223
|
+
* console.log(`Command ${cmd.command} completed successfully`);
|
|
224
|
+
* }
|
|
225
|
+
*/
|
|
226
|
+
public async getSessionCommand(sessionId: string, commandId: string): Promise<Command> {
|
|
227
|
+
const response = await this.toolboxApi.getSessionCommand(this.sandboxId, sessionId, commandId)
|
|
228
|
+
return response.data
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Executes a command in an existing session.
|
|
233
|
+
*
|
|
234
|
+
* @param {string} sessionId - Unique identifier of the session to use
|
|
235
|
+
* @param {SessionExecuteRequest} req - Command execution request containing:
|
|
236
|
+
* - command: The command to execute
|
|
237
|
+
* - runAsync: Whether to execute asynchronously
|
|
238
|
+
* @param {number} timeout - Timeout in seconds
|
|
239
|
+
* @returns {Promise<SessionExecuteResponse>} Command execution results containing:
|
|
240
|
+
* - cmdId: Unique identifier for the executed command
|
|
241
|
+
* - output: Command output (if synchronous execution)
|
|
242
|
+
* - exitCode: Command exit status (if synchronous execution)
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* // Execute commands in sequence, maintaining state
|
|
246
|
+
* const sessionId = 'my-session';
|
|
247
|
+
*
|
|
248
|
+
* // Change directory
|
|
249
|
+
* await process.executeSessionCommand(sessionId, {
|
|
250
|
+
* command: 'cd /home/daytona'
|
|
251
|
+
* });
|
|
252
|
+
*
|
|
253
|
+
* // Run command in new directory
|
|
254
|
+
* const result = await process.executeSessionCommand(sessionId, {
|
|
255
|
+
* command: 'pwd'
|
|
256
|
+
* });
|
|
257
|
+
* console.log(result.output); // Prints: /home/daytona
|
|
258
|
+
*/
|
|
259
|
+
public async executeSessionCommand(
|
|
260
|
+
sessionId: string,
|
|
261
|
+
req: SessionExecuteRequest,
|
|
262
|
+
timeout?: number,
|
|
263
|
+
): Promise<SessionExecuteResponse> {
|
|
264
|
+
const response = await this.toolboxApi.executeSessionCommand(
|
|
265
|
+
this.sandboxId,
|
|
266
|
+
sessionId,
|
|
267
|
+
req,
|
|
268
|
+
undefined,
|
|
269
|
+
timeout ? { timeout: timeout * 1000 } : {},
|
|
270
|
+
)
|
|
271
|
+
return response.data
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Get the logs for a command executed in a session.
|
|
276
|
+
*
|
|
277
|
+
* @param {string} sessionId - Unique identifier of the session
|
|
278
|
+
* @param {string} commandId - Unique identifier of the command
|
|
279
|
+
* @returns {Promise<string>} Command logs
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* const logs = await process.getSessionCommandLogs('my-session', 'cmd-123');
|
|
283
|
+
* console.log('Command output:', logs);
|
|
284
|
+
*/
|
|
285
|
+
public async getSessionCommandLogs(sessionId: string, commandId: string): Promise<string>
|
|
286
|
+
/**
|
|
287
|
+
* Asynchronously retrieve and process the logs for a command executed in a session as they become available.
|
|
288
|
+
*
|
|
289
|
+
* @param {string} sessionId - Unique identifier of the session
|
|
290
|
+
* @param {string} commandId - Unique identifier of the command
|
|
291
|
+
* @param {function} onLogs - Callback function to handle each log chunk
|
|
292
|
+
* @returns {Promise<void>}
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* const logs = await process.getSessionCommandLogs('my-session', 'cmd-123', (chunk) => {
|
|
296
|
+
* console.log('Log chunk:', chunk);
|
|
297
|
+
* });
|
|
298
|
+
*/
|
|
299
|
+
public async getSessionCommandLogs(
|
|
300
|
+
sessionId: string,
|
|
301
|
+
commandId: string,
|
|
302
|
+
onLogs: (chunk: string) => void,
|
|
303
|
+
): Promise<void>
|
|
304
|
+
public async getSessionCommandLogs(
|
|
305
|
+
sessionId: string,
|
|
306
|
+
commandId: string,
|
|
307
|
+
onLogs?: (chunk: string) => void,
|
|
308
|
+
): Promise<string | void> {
|
|
309
|
+
if (!onLogs) {
|
|
310
|
+
const response = await this.toolboxApi.getSessionCommandLogs(this.sandboxId, sessionId, commandId)
|
|
311
|
+
return response.data
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
await processStreamingResponse(
|
|
315
|
+
() =>
|
|
316
|
+
this.toolboxApi.getSessionCommandLogs(this.sandboxId, sessionId, commandId, undefined, true, {
|
|
317
|
+
responseType: 'stream',
|
|
318
|
+
}),
|
|
319
|
+
onLogs,
|
|
320
|
+
() =>
|
|
321
|
+
this.getSessionCommand(sessionId, commandId).then((res) => res.exitCode !== null && res.exitCode !== undefined),
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Lists all active sessions in the Sandbox.
|
|
327
|
+
*
|
|
328
|
+
* @returns {Promise<Session[]>} Array of active sessions
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* const sessions = await process.listSessions();
|
|
332
|
+
* sessions.forEach(session => {
|
|
333
|
+
* console.log(`Session ${session.sessionId}:`);
|
|
334
|
+
* session.commands.forEach(cmd => {
|
|
335
|
+
* console.log(`- ${cmd.command} (${cmd.exitCode})`);
|
|
336
|
+
* });
|
|
337
|
+
* });
|
|
338
|
+
*/
|
|
339
|
+
public async listSessions(): Promise<Session[]> {
|
|
340
|
+
const response = await this.toolboxApi.listSessions(this.sandboxId)
|
|
341
|
+
return response.data
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Delete a session from the Sandbox.
|
|
346
|
+
*
|
|
347
|
+
* @param {string} sessionId - Unique identifier of the session to delete
|
|
348
|
+
* @returns {Promise<void>}
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* // Clean up a completed session
|
|
352
|
+
* await process.deleteSession('my-session');
|
|
353
|
+
*/
|
|
354
|
+
public async deleteSession(sessionId: string): Promise<void> {
|
|
355
|
+
await this.toolboxApi.deleteSession(this.sandboxId, sessionId)
|
|
356
|
+
}
|
|
357
|
+
}
|