@daytona/sdk 0.161.0-alpha.1

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.
Files changed (95) hide show
  1. package/README.md +180 -0
  2. package/package.json +56 -0
  3. package/src/CodeInterpreter.d.ts +94 -0
  4. package/src/CodeInterpreter.js +297 -0
  5. package/src/CodeInterpreter.js.map +1 -0
  6. package/src/ComputerUse.d.ts +538 -0
  7. package/src/ComputerUse.js +808 -0
  8. package/src/ComputerUse.js.map +1 -0
  9. package/src/Daytona.d.ts +340 -0
  10. package/src/Daytona.js +538 -0
  11. package/src/Daytona.js.map +1 -0
  12. package/src/FileSystem.d.ts +326 -0
  13. package/src/FileSystem.js +412 -0
  14. package/src/FileSystem.js.map +1 -0
  15. package/src/Git.d.ts +202 -0
  16. package/src/Git.js +326 -0
  17. package/src/Git.js.map +1 -0
  18. package/src/Image.d.ts +264 -0
  19. package/src/Image.js +546 -0
  20. package/src/Image.js.map +1 -0
  21. package/src/LspServer.d.ts +171 -0
  22. package/src/LspServer.js +258 -0
  23. package/src/LspServer.js.map +1 -0
  24. package/src/ObjectStorage.d.ts +78 -0
  25. package/src/ObjectStorage.js +199 -0
  26. package/src/ObjectStorage.js.map +1 -0
  27. package/src/Process.d.ts +490 -0
  28. package/src/Process.js +790 -0
  29. package/src/Process.js.map +1 -0
  30. package/src/PtyHandle.d.ts +154 -0
  31. package/src/PtyHandle.js +416 -0
  32. package/src/PtyHandle.js.map +1 -0
  33. package/src/Sandbox.d.ts +425 -0
  34. package/src/Sandbox.js +776 -0
  35. package/src/Sandbox.js.map +1 -0
  36. package/src/Snapshot.d.ts +139 -0
  37. package/src/Snapshot.js +248 -0
  38. package/src/Snapshot.js.map +1 -0
  39. package/src/Volume.d.ts +83 -0
  40. package/src/Volume.js +119 -0
  41. package/src/Volume.js.map +1 -0
  42. package/src/code-toolbox/SandboxJsCodeToolbox.d.ts +5 -0
  43. package/src/code-toolbox/SandboxJsCodeToolbox.js +20 -0
  44. package/src/code-toolbox/SandboxJsCodeToolbox.js.map +1 -0
  45. package/src/code-toolbox/SandboxPythonCodeToolbox.d.ts +11 -0
  46. package/src/code-toolbox/SandboxPythonCodeToolbox.js +359 -0
  47. package/src/code-toolbox/SandboxPythonCodeToolbox.js.map +1 -0
  48. package/src/code-toolbox/SandboxTsCodeToolbox.d.ts +5 -0
  49. package/src/code-toolbox/SandboxTsCodeToolbox.js +29 -0
  50. package/src/code-toolbox/SandboxTsCodeToolbox.js.map +1 -0
  51. package/src/errors/DaytonaError.d.ts +31 -0
  52. package/src/errors/DaytonaError.js +51 -0
  53. package/src/errors/DaytonaError.js.map +1 -0
  54. package/src/index.d.ts +21 -0
  55. package/src/index.js +45 -0
  56. package/src/index.js.map +1 -0
  57. package/src/types/Charts.d.ts +151 -0
  58. package/src/types/Charts.js +46 -0
  59. package/src/types/Charts.js.map +1 -0
  60. package/src/types/CodeInterpreter.d.ts +76 -0
  61. package/src/types/CodeInterpreter.js +7 -0
  62. package/src/types/CodeInterpreter.js.map +1 -0
  63. package/src/types/ExecuteResponse.d.ts +25 -0
  64. package/src/types/ExecuteResponse.js +7 -0
  65. package/src/types/ExecuteResponse.js.map +1 -0
  66. package/src/types/Pty.d.ts +47 -0
  67. package/src/types/Pty.js +7 -0
  68. package/src/types/Pty.js.map +1 -0
  69. package/src/utils/ArtifactParser.d.ts +13 -0
  70. package/src/utils/ArtifactParser.js +55 -0
  71. package/src/utils/ArtifactParser.js.map +1 -0
  72. package/src/utils/Binary.d.ts +38 -0
  73. package/src/utils/Binary.js +168 -0
  74. package/src/utils/Binary.js.map +1 -0
  75. package/src/utils/FileTransfer.d.ts +14 -0
  76. package/src/utils/FileTransfer.js +216 -0
  77. package/src/utils/FileTransfer.js.map +1 -0
  78. package/src/utils/Import.d.ts +97 -0
  79. package/src/utils/Import.js +79 -0
  80. package/src/utils/Import.js.map +1 -0
  81. package/src/utils/Multipart.d.ts +26 -0
  82. package/src/utils/Multipart.js +113 -0
  83. package/src/utils/Multipart.js.map +1 -0
  84. package/src/utils/Runtime.d.ts +43 -0
  85. package/src/utils/Runtime.js +95 -0
  86. package/src/utils/Runtime.js.map +1 -0
  87. package/src/utils/Stream.d.ts +19 -0
  88. package/src/utils/Stream.js +364 -0
  89. package/src/utils/Stream.js.map +1 -0
  90. package/src/utils/WebSocket.d.ts +9 -0
  91. package/src/utils/WebSocket.js +26 -0
  92. package/src/utils/WebSocket.js.map +1 -0
  93. package/src/utils/otel.decorator.d.ts +82 -0
  94. package/src/utils/otel.decorator.js +141 -0
  95. package/src/utils/otel.decorator.js.map +1 -0
package/src/Process.js ADDED
@@ -0,0 +1,790 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2025 Daytona Platforms Inc.
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.Process = exports.CodeRunParams = exports.MAX_PREFIX_LEN = exports.STDERR_PREFIX_BYTES = exports.STDOUT_PREFIX_BYTES = void 0;
8
+ const tslib_1 = require("tslib");
9
+ const ArtifactParser_1 = require("./utils/ArtifactParser");
10
+ const Stream_1 = require("./utils/Stream");
11
+ const buffer_1 = require("buffer");
12
+ const PtyHandle_1 = require("./PtyHandle");
13
+ const WebSocket_1 = require("./utils/WebSocket");
14
+ const otel_decorator_1 = require("./utils/otel.decorator");
15
+ // 3-byte multiplexing markers inserted by the shell labelers
16
+ exports.STDOUT_PREFIX_BYTES = new Uint8Array([0x01, 0x01, 0x01]);
17
+ exports.STDERR_PREFIX_BYTES = new Uint8Array([0x02, 0x02, 0x02]);
18
+ exports.MAX_PREFIX_LEN = Math.max(exports.STDOUT_PREFIX_BYTES.length, exports.STDERR_PREFIX_BYTES.length);
19
+ /**
20
+ * Parameters for code execution.
21
+ */
22
+ class CodeRunParams {
23
+ /**
24
+ * Command line arguments
25
+ */
26
+ argv;
27
+ /**
28
+ * Environment variables
29
+ */
30
+ env;
31
+ }
32
+ exports.CodeRunParams = CodeRunParams;
33
+ /**
34
+ * Handles process and code execution within a Sandbox.
35
+ *
36
+ * @class
37
+ */
38
+ class Process {
39
+ clientConfig;
40
+ codeToolbox;
41
+ apiClient;
42
+ getPreviewToken;
43
+ constructor(clientConfig, codeToolbox, apiClient, getPreviewToken) {
44
+ this.clientConfig = clientConfig;
45
+ this.codeToolbox = codeToolbox;
46
+ this.apiClient = apiClient;
47
+ this.getPreviewToken = getPreviewToken;
48
+ }
49
+ /**
50
+ * Executes a shell command in the Sandbox.
51
+ *
52
+ * @param {string} command - Shell command to execute
53
+ * @param {string} [cwd] - Working directory for command execution. If not specified, uses the sandbox working directory.
54
+ * @param {Record<string, string>} [env] - Environment variables to set for the command
55
+ * @param {number} [timeout] - Maximum time in seconds to wait for the command to complete.
56
+ * @returns {Promise<ExecuteResponse>} Command execution results containing:
57
+ * - exitCode: The command's exit status
58
+ * - result: Standard output from the command
59
+ * - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata)
60
+ *
61
+ * @example
62
+ * // Simple command
63
+ * const response = await process.executeCommand('echo "Hello"');
64
+ * console.log(response.artifacts.stdout); // Prints: Hello
65
+ *
66
+ * @example
67
+ * // Command with working directory
68
+ * const result = await process.executeCommand('ls', 'workspace/src');
69
+ *
70
+ * @example
71
+ * // Command with timeout
72
+ * const result = await process.executeCommand('sleep 10', undefined, 5);
73
+ */
74
+ async executeCommand(command, cwd, env, timeout) {
75
+ if (env && Object.keys(env).length) {
76
+ const validKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
77
+ for (const key of Object.keys(env)) {
78
+ if (!validKeyPattern.test(key)) {
79
+ throw new Error(`Invalid environment variable name: '${key}'`);
80
+ }
81
+ }
82
+ const safeEnvExports = Object.entries(env)
83
+ .map(([key, value]) => {
84
+ const encodedValue = buffer_1.Buffer.from(value).toString('base64');
85
+ return `export ${key}="$(printf '%s' '${encodedValue}' | base64 -d)"`;
86
+ })
87
+ .join('; ') + '; ';
88
+ command = `${safeEnvExports}${command}`;
89
+ }
90
+ const response = await this.apiClient.executeCommand({
91
+ command,
92
+ timeout,
93
+ cwd: cwd,
94
+ });
95
+ // Parse artifacts from the output
96
+ const artifacts = ArtifactParser_1.ArtifactParser.parseArtifacts(response.data.result);
97
+ // Return enhanced response with parsed artifacts
98
+ return {
99
+ exitCode: response.data.exitCode ?? response.data.code,
100
+ result: artifacts.stdout,
101
+ artifacts,
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
+ async codeRun(code, params, timeout) {
163
+ const runCommand = this.codeToolbox.getRunCommand(code, params);
164
+ return this.executeCommand(runCommand, undefined, params?.env, timeout);
165
+ }
166
+ /**
167
+ * Creates a new long-running background session in the Sandbox.
168
+ *
169
+ * Sessions are background processes that maintain state between commands, making them ideal for
170
+ * scenarios requiring multiple related commands or persistent environment setup. You can run
171
+ * long-running commands and monitor process status.
172
+ *
173
+ * @param {string} sessionId - Unique identifier for the new session
174
+ * @returns {Promise<void>}
175
+ *
176
+ * @example
177
+ * // Create a new session
178
+ * const sessionId = 'my-session';
179
+ * await process.createSession(sessionId);
180
+ * const session = await process.getSession(sessionId);
181
+ * // Do work...
182
+ * await process.deleteSession(sessionId);
183
+ */
184
+ async createSession(sessionId) {
185
+ await this.apiClient.createSession({
186
+ sessionId,
187
+ });
188
+ }
189
+ /**
190
+ * Get a session in the sandbox.
191
+ *
192
+ * @param {string} sessionId - Unique identifier of the session to retrieve
193
+ * @returns {Promise<Session>} Session information including:
194
+ * - sessionId: The session's unique identifier
195
+ * - commands: List of commands executed in the session
196
+ *
197
+ * @example
198
+ * const session = await process.getSession('my-session');
199
+ * session.commands.forEach(cmd => {
200
+ * console.log(`Command: ${cmd.command}`);
201
+ * });
202
+ */
203
+ async getSession(sessionId) {
204
+ const response = await this.apiClient.getSession(sessionId);
205
+ return response.data;
206
+ }
207
+ /**
208
+ * Get the sandbox entrypoint session
209
+ *
210
+ * @returns {Promise<Session>} Entrypoint session information including:
211
+ * - sessionId: The entrypoint session's unique identifier
212
+ * - commands: List of commands executed in the entrypoint session
213
+ *
214
+ * @example
215
+ * const session = await process.getEntrypointSession();
216
+ * session.commands.forEach(cmd => {
217
+ * console.log(`Command: ${cmd.command}`);
218
+ * });
219
+ */
220
+ async getEntrypointSession() {
221
+ const response = await this.apiClient.getEntrypointSession();
222
+ return response.data;
223
+ }
224
+ /**
225
+ * Gets information about a specific command executed in a session.
226
+ *
227
+ * @param {string} sessionId - Unique identifier of the session
228
+ * @param {string} commandId - Unique identifier of the command
229
+ * @returns {Promise<Command>} Command information including:
230
+ * - id: The command's unique identifier
231
+ * - command: The executed command string
232
+ * - exitCode: Command's exit status (if completed)
233
+ *
234
+ * @example
235
+ * const cmd = await process.getSessionCommand('my-session', 'cmd-123');
236
+ * if (cmd.exitCode === 0) {
237
+ * console.log(`Command ${cmd.command} completed successfully`);
238
+ * }
239
+ */
240
+ async getSessionCommand(sessionId, commandId) {
241
+ const response = await this.apiClient.getSessionCommand(sessionId, commandId);
242
+ return response.data;
243
+ }
244
+ /**
245
+ * Executes a command in an existing session.
246
+ *
247
+ * @param {string} sessionId - Unique identifier of the session to use
248
+ * @param {SessionExecuteRequest} req - Command execution request containing:
249
+ * - command: The command to execute
250
+ * - runAsync: Whether to execute asynchronously
251
+ * - suppressInputEcho: Whether to suppress input echo. Default is `false`.
252
+ * @param {number} timeout - Timeout in seconds
253
+ * @returns {Promise<SessionExecuteResponse>} Command execution results containing:
254
+ * - cmdId: Unique identifier for the executed command
255
+ * - output: Combined command output (stdout and stderr) (if synchronous execution)
256
+ * - stdout: Standard output from the command
257
+ * - stderr: Standard error from the command
258
+ * - exitCode: Command exit status (if synchronous execution)
259
+ *
260
+ * @example
261
+ * // Execute commands in sequence, maintaining state
262
+ * const sessionId = 'my-session';
263
+ *
264
+ * // Change directory
265
+ * await process.executeSessionCommand(sessionId, {
266
+ * command: 'cd /home/daytona'
267
+ * });
268
+ *
269
+ * // Run command in new directory
270
+ * const result = await process.executeSessionCommand(sessionId, {
271
+ * command: 'pwd'
272
+ * });
273
+ * console.log('[STDOUT]:', result.stdout);
274
+ * console.log('[STDERR]:', result.stderr);
275
+ */
276
+ async executeSessionCommand(sessionId, req, timeout) {
277
+ const response = await this.apiClient.sessionExecuteCommand(sessionId, req, timeout ? { timeout: timeout * 1000 } : {});
278
+ // Demux the output if it exists
279
+ if (response.data.output) {
280
+ // Convert string to bytes for demuxing
281
+ const outputBytes = new TextEncoder().encode(response.data.output);
282
+ const demuxedCommandLogs = parseSessionCommandLogs(outputBytes);
283
+ return {
284
+ ...response.data,
285
+ stdout: demuxedCommandLogs.stdout,
286
+ stderr: demuxedCommandLogs.stderr,
287
+ };
288
+ }
289
+ return response.data;
290
+ }
291
+ async getSessionCommandLogs(sessionId, commandId, onStdout, onStderr) {
292
+ if (!onStdout && !onStderr) {
293
+ const response = await this.apiClient.getSessionCommandLogs(sessionId, commandId);
294
+ // Parse the response data if it's available
295
+ if (response.data) {
296
+ // Convert string to bytes for demuxing
297
+ const outputBytes = new TextEncoder().encode(response.data || '');
298
+ const demuxedCommandLogs = parseSessionCommandLogs(outputBytes);
299
+ return {
300
+ output: response.data,
301
+ stdout: demuxedCommandLogs.stdout,
302
+ stderr: demuxedCommandLogs.stderr,
303
+ };
304
+ }
305
+ return {
306
+ output: response.data,
307
+ };
308
+ }
309
+ const url = `${this.clientConfig.basePath.replace(/^http/, 'ws')}/process/session/${sessionId}/command/${commandId}/logs?follow=true`;
310
+ const ws = await (0, WebSocket_1.createSandboxWebSocket)(url, this.clientConfig.baseOptions?.headers || {}, this.getPreviewToken);
311
+ await (0, Stream_1.stdDemuxStream)(ws, onStdout, onStderr);
312
+ }
313
+ async getEntrypointLogs(onStdout, onStderr) {
314
+ if (!onStdout && !onStderr) {
315
+ const response = await this.apiClient.getEntrypointLogs();
316
+ // Parse the response data if it's available
317
+ if (response.data) {
318
+ // Convert string to bytes for demuxing
319
+ const outputBytes = new TextEncoder().encode(response.data || '');
320
+ const demuxedCommandLogs = parseSessionCommandLogs(outputBytes);
321
+ return {
322
+ output: response.data,
323
+ stdout: demuxedCommandLogs.stdout,
324
+ stderr: demuxedCommandLogs.stderr,
325
+ };
326
+ }
327
+ return {
328
+ output: response.data,
329
+ };
330
+ }
331
+ const url = `${this.clientConfig.basePath.replace(/^http/, 'ws')}/process/session/entrypoint/logs?follow=true`;
332
+ const ws = await (0, WebSocket_1.createSandboxWebSocket)(url, this.clientConfig.baseOptions?.headers || {}, this.getPreviewToken);
333
+ await (0, Stream_1.stdDemuxStream)(ws, onStdout, onStderr);
334
+ }
335
+ /**
336
+ * Sends input data to a command executed in a session.
337
+ *
338
+ * @param {string} sessionId - Unique identifier of the session
339
+ * @param {string} commandId - Unique identifier of the command
340
+ * @param {string} data - Input data to send
341
+ * @returns {Promise<void>}
342
+ */
343
+ async sendSessionCommandInput(sessionId, commandId, data) {
344
+ await this.apiClient.sendInput(sessionId, commandId, { data });
345
+ }
346
+ /**
347
+ * Lists all active sessions in the Sandbox.
348
+ *
349
+ * @returns {Promise<Session[]>} Array of active sessions
350
+ *
351
+ * @example
352
+ * const sessions = await process.listSessions();
353
+ * sessions.forEach(session => {
354
+ * console.log(`Session ${session.sessionId}:`);
355
+ * session.commands.forEach(cmd => {
356
+ * console.log(`- ${cmd.command} (${cmd.exitCode})`);
357
+ * });
358
+ * });
359
+ */
360
+ async listSessions() {
361
+ const response = await this.apiClient.listSessions();
362
+ return response.data;
363
+ }
364
+ /**
365
+ * Delete a session from the Sandbox.
366
+ *
367
+ * @param {string} sessionId - Unique identifier of the session to delete
368
+ * @returns {Promise<void>}
369
+ *
370
+ * @example
371
+ * // Clean up a completed session
372
+ * await process.deleteSession('my-session');
373
+ */
374
+ async deleteSession(sessionId) {
375
+ await this.apiClient.deleteSession(sessionId);
376
+ }
377
+ /**
378
+ * Create a new PTY (pseudo-terminal) session in the sandbox.
379
+ *
380
+ * Creates an interactive terminal session that can execute commands and handle user input.
381
+ * The PTY session behaves like a real terminal, supporting features like command history.
382
+ *
383
+ * @param {PtyCreateOptions & PtyConnectOptions} options - PTY session configuration including creation and connection options
384
+ * @returns {Promise<PtyHandle>} PTY handle for managing the session
385
+ *
386
+ * @example
387
+ * // Create a PTY session with custom configuration
388
+ * const ptyHandle = await process.createPty({
389
+ * id: 'my-interactive-session',
390
+ * cwd: '/workspace',
391
+ * envs: { TERM: 'xterm-256color', LANG: 'en_US.UTF-8' },
392
+ * cols: 120,
393
+ * rows: 30,
394
+ * onData: (data) => {
395
+ * // Handle terminal output
396
+ * const text = new TextDecoder().decode(data);
397
+ * process.stdout.write(text);
398
+ * },
399
+ * });
400
+ *
401
+ * // Wait for connection to be established
402
+ * await ptyHandle.waitForConnection();
403
+ *
404
+ * // Send commands to the terminal
405
+ * await ptyHandle.sendInput('ls -la\n');
406
+ * await ptyHandle.sendInput('echo "Hello, PTY!"\n');
407
+ * await ptyHandle.sendInput('exit\n');
408
+ *
409
+ * // Wait for completion and get result
410
+ * const result = await ptyHandle.wait();
411
+ * console.log(`PTY session completed with exit code: ${result.exitCode}`);
412
+ *
413
+ * // Clean up
414
+ * await ptyHandle.disconnect();
415
+ */
416
+ async createPty(options) {
417
+ const request = {
418
+ id: options.id,
419
+ cwd: options.cwd,
420
+ envs: options.envs,
421
+ cols: options.cols,
422
+ rows: options.rows,
423
+ lazyStart: true,
424
+ };
425
+ const response = await this.apiClient.createPtySession(request);
426
+ return await this.connectPty(response.data.sessionId, options);
427
+ }
428
+ /**
429
+ * Connect to an existing PTY session in the sandbox.
430
+ *
431
+ * Establishes a WebSocket connection to an existing PTY session, allowing you to
432
+ * interact with a previously created terminal session.
433
+ *
434
+ * @param {string} sessionId - ID of the PTY session to connect to
435
+ * @param {PtyConnectOptions} options - Options for the connection including data handler
436
+ * @returns {Promise<PtyHandle>} PTY handle for managing the session
437
+ *
438
+ * @example
439
+ * // Connect to an existing PTY session
440
+ * const handle = await process.connectPty('my-session', {
441
+ * onData: (data) => {
442
+ * // Handle terminal output
443
+ * const text = new TextDecoder().decode(data);
444
+ * process.stdout.write(text);
445
+ * },
446
+ * });
447
+ *
448
+ * // Wait for connection to be established
449
+ * await handle.waitForConnection();
450
+ *
451
+ * // Send commands to the existing session
452
+ * await handle.sendInput('pwd\n');
453
+ * await handle.sendInput('ls -la\n');
454
+ * await handle.sendInput('exit\n');
455
+ *
456
+ * // Wait for completion
457
+ * const result = await handle.wait();
458
+ * console.log(`Session exited with code: ${result.exitCode}`);
459
+ *
460
+ * // Clean up
461
+ * await handle.disconnect();
462
+ */
463
+ async connectPty(sessionId, options) {
464
+ const url = `${this.clientConfig.basePath.replace(/^http/, 'ws')}/process/pty/${sessionId}/connect`;
465
+ const ws = await (0, WebSocket_1.createSandboxWebSocket)(url, this.clientConfig.baseOptions?.headers || {}, this.getPreviewToken);
466
+ const handle = new PtyHandle_1.PtyHandle(ws, (cols, rows) => this.resizePtySession(sessionId, cols, rows), () => this.killPtySession(sessionId), options.onData, sessionId);
467
+ await handle.waitForConnection();
468
+ return handle;
469
+ }
470
+ /**
471
+ * List all PTY sessions in the sandbox.
472
+ *
473
+ * Retrieves information about all PTY sessions, both active and inactive,
474
+ * that have been created in this sandbox.
475
+ *
476
+ * @returns {Promise<PtySessionInfo[]>} Array of PTY session information
477
+ *
478
+ * @example
479
+ * // List all PTY sessions
480
+ * const sessions = await process.listPtySessions();
481
+ *
482
+ * for (const session of sessions) {
483
+ * console.log(`Session ID: ${session.id}`);
484
+ * console.log(`Active: ${session.active}`);
485
+ * console.log(`Created: ${session.createdAt}`);
486
+ * }
487
+ * console.log('---');
488
+ * }
489
+ */
490
+ async listPtySessions() {
491
+ return (await this.apiClient.listPtySessions()).data.sessions;
492
+ }
493
+ /**
494
+ * Get detailed information about a specific PTY session.
495
+ *
496
+ * Retrieves comprehensive information about a PTY session including its current state,
497
+ * configuration, and metadata.
498
+ *
499
+ * @param {string} sessionId - ID of the PTY session to retrieve information for
500
+ * @returns {Promise<PtySessionInfo>} PTY session information
501
+ *
502
+ * @throws {Error} If the PTY session doesn't exist
503
+ *
504
+ * @example
505
+ * // Get details about a specific PTY session
506
+ * const session = await process.getPtySessionInfo('my-session');
507
+ *
508
+ * console.log(`Session ID: ${session.id}`);
509
+ * console.log(`Active: ${session.active}`);
510
+ * console.log(`Working Directory: ${session.cwd}`);
511
+ * console.log(`Terminal Size: ${session.cols}x${session.rows}`);
512
+ *
513
+ * if (session.processId) {
514
+ * console.log(`Process ID: ${session.processId}`);
515
+ * }
516
+ */
517
+ async getPtySessionInfo(sessionId) {
518
+ return (await this.apiClient.getPtySession(sessionId)).data;
519
+ }
520
+ /**
521
+ * Kill a PTY session and terminate its associated process.
522
+ *
523
+ * Forcefully terminates the PTY session and cleans up all associated resources.
524
+ * This will close any active connections and kill the underlying shell process.
525
+ *
526
+ * @param {string} sessionId - ID of the PTY session to kill
527
+ * @returns {Promise<void>}
528
+ *
529
+ * @throws {Error} If the PTY session doesn't exist or cannot be killed
530
+ *
531
+ * @note This operation is irreversible. Any unsaved work in the terminal session will be lost.
532
+ *
533
+ * @example
534
+ * // Kill a specific PTY session
535
+ * await process.killPtySession('my-session');
536
+ *
537
+ * // Verify the session is no longer active
538
+ * try {
539
+ * const info = await process.getPtySessionInfo('my-session');
540
+ * console.log(`Session still exists but active: ${info.active}`);
541
+ * } catch (error) {
542
+ * console.log('Session has been completely removed');
543
+ * }
544
+ */
545
+ async killPtySession(sessionId) {
546
+ await this.apiClient.deletePtySession(sessionId);
547
+ }
548
+ /**
549
+ * Resize a PTY session's terminal dimensions.
550
+ *
551
+ * Changes the terminal size of an active PTY session. This is useful when the
552
+ * client terminal is resized or when you need to adjust the display for different
553
+ * output requirements.
554
+ *
555
+ * @param {string} sessionId - ID of the PTY session to resize
556
+ * @param {number} cols - New number of terminal columns
557
+ * @param {number} rows - New number of terminal rows
558
+ * @returns {Promise<PtySessionInfo>} Updated session information reflecting the new terminal size
559
+ *
560
+ * @throws {Error} If the PTY session doesn't exist or resize operation fails
561
+ *
562
+ * @note The resize operation will send a SIGWINCH signal to the shell process,
563
+ * allowing terminal applications to adapt to the new size.
564
+ *
565
+ * @example
566
+ * // Resize a PTY session to a larger terminal
567
+ * const updatedInfo = await process.resizePtySession('my-session', 150, 40);
568
+ * console.log(`Terminal resized to ${updatedInfo.cols}x${updatedInfo.rows}`);
569
+ *
570
+ * // You can also use the PtyHandle's resize method
571
+ * await ptyHandle.resize(150, 40); // cols, rows
572
+ */
573
+ async resizePtySession(sessionId, cols, rows) {
574
+ return (await this.apiClient.resizePtySession(sessionId, { cols, rows })).data;
575
+ }
576
+ }
577
+ exports.Process = Process;
578
+ tslib_1.__decorate([
579
+ (0, otel_decorator_1.WithInstrumentation)(),
580
+ tslib_1.__metadata("design:type", Function),
581
+ tslib_1.__metadata("design:paramtypes", [String, String, Object, Number]),
582
+ tslib_1.__metadata("design:returntype", Promise)
583
+ ], Process.prototype, "executeCommand", null);
584
+ tslib_1.__decorate([
585
+ (0, otel_decorator_1.WithInstrumentation)(),
586
+ tslib_1.__metadata("design:type", Function),
587
+ tslib_1.__metadata("design:paramtypes", [String, CodeRunParams, Number]),
588
+ tslib_1.__metadata("design:returntype", Promise)
589
+ ], Process.prototype, "codeRun", null);
590
+ tslib_1.__decorate([
591
+ (0, otel_decorator_1.WithInstrumentation)(),
592
+ tslib_1.__metadata("design:type", Function),
593
+ tslib_1.__metadata("design:paramtypes", [String]),
594
+ tslib_1.__metadata("design:returntype", Promise)
595
+ ], Process.prototype, "createSession", null);
596
+ tslib_1.__decorate([
597
+ (0, otel_decorator_1.WithInstrumentation)(),
598
+ tslib_1.__metadata("design:type", Function),
599
+ tslib_1.__metadata("design:paramtypes", [String, String]),
600
+ tslib_1.__metadata("design:returntype", Promise)
601
+ ], Process.prototype, "getSessionCommand", null);
602
+ tslib_1.__decorate([
603
+ (0, otel_decorator_1.WithInstrumentation)(),
604
+ tslib_1.__metadata("design:type", Function),
605
+ tslib_1.__metadata("design:paramtypes", [String, Object, Number]),
606
+ tslib_1.__metadata("design:returntype", Promise)
607
+ ], Process.prototype, "executeSessionCommand", null);
608
+ tslib_1.__decorate([
609
+ (0, otel_decorator_1.WithInstrumentation)(),
610
+ tslib_1.__metadata("design:type", Function),
611
+ tslib_1.__metadata("design:paramtypes", [String, String, Function, Function]),
612
+ tslib_1.__metadata("design:returntype", Promise)
613
+ ], Process.prototype, "getSessionCommandLogs", null);
614
+ tslib_1.__decorate([
615
+ (0, otel_decorator_1.WithInstrumentation)(),
616
+ tslib_1.__metadata("design:type", Function),
617
+ tslib_1.__metadata("design:paramtypes", [Function, Function]),
618
+ tslib_1.__metadata("design:returntype", Promise)
619
+ ], Process.prototype, "getEntrypointLogs", null);
620
+ tslib_1.__decorate([
621
+ (0, otel_decorator_1.WithInstrumentation)(),
622
+ tslib_1.__metadata("design:type", Function),
623
+ tslib_1.__metadata("design:paramtypes", []),
624
+ tslib_1.__metadata("design:returntype", Promise)
625
+ ], Process.prototype, "listSessions", null);
626
+ tslib_1.__decorate([
627
+ (0, otel_decorator_1.WithInstrumentation)(),
628
+ tslib_1.__metadata("design:type", Function),
629
+ tslib_1.__metadata("design:paramtypes", [String]),
630
+ tslib_1.__metadata("design:returntype", Promise)
631
+ ], Process.prototype, "deleteSession", null);
632
+ tslib_1.__decorate([
633
+ (0, otel_decorator_1.WithInstrumentation)(),
634
+ tslib_1.__metadata("design:type", Function),
635
+ tslib_1.__metadata("design:paramtypes", [Object]),
636
+ tslib_1.__metadata("design:returntype", Promise)
637
+ ], Process.prototype, "createPty", null);
638
+ tslib_1.__decorate([
639
+ (0, otel_decorator_1.WithInstrumentation)(),
640
+ tslib_1.__metadata("design:type", Function),
641
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
642
+ tslib_1.__metadata("design:returntype", Promise)
643
+ ], Process.prototype, "connectPty", null);
644
+ tslib_1.__decorate([
645
+ (0, otel_decorator_1.WithInstrumentation)(),
646
+ tslib_1.__metadata("design:type", Function),
647
+ tslib_1.__metadata("design:paramtypes", []),
648
+ tslib_1.__metadata("design:returntype", Promise)
649
+ ], Process.prototype, "listPtySessions", null);
650
+ tslib_1.__decorate([
651
+ (0, otel_decorator_1.WithInstrumentation)(),
652
+ tslib_1.__metadata("design:type", Function),
653
+ tslib_1.__metadata("design:paramtypes", [String]),
654
+ tslib_1.__metadata("design:returntype", Promise)
655
+ ], Process.prototype, "getPtySessionInfo", null);
656
+ tslib_1.__decorate([
657
+ (0, otel_decorator_1.WithInstrumentation)(),
658
+ tslib_1.__metadata("design:type", Function),
659
+ tslib_1.__metadata("design:paramtypes", [String]),
660
+ tslib_1.__metadata("design:returntype", Promise)
661
+ ], Process.prototype, "killPtySession", null);
662
+ tslib_1.__decorate([
663
+ (0, otel_decorator_1.WithInstrumentation)(),
664
+ tslib_1.__metadata("design:type", Function),
665
+ tslib_1.__metadata("design:paramtypes", [String, Number, Number]),
666
+ tslib_1.__metadata("design:returntype", Promise)
667
+ ], Process.prototype, "resizePtySession", null);
668
+ /**
669
+ * Parse combined stdout/stderr output into separate streams.
670
+ *
671
+ * @param data - Combined log bytes with STDOUT_PREFIX_BYTES and STDERR_PREFIX_BYTES markers
672
+ * @returns Object with separated stdout and stderr strings
673
+ */
674
+ function parseSessionCommandLogs(data) {
675
+ const [stdoutBytes, stderrBytes] = demuxLog(data);
676
+ // Convert bytes to strings, ignoring potential encoding issues
677
+ const stdoutStr = new TextDecoder('utf-8', { fatal: false }).decode(stdoutBytes);
678
+ const stderrStr = new TextDecoder('utf-8', { fatal: false }).decode(stderrBytes);
679
+ // For backwards compatibility, output field contains the original combined data
680
+ const outputStr = new TextDecoder('utf-8', { fatal: false }).decode(data);
681
+ return {
682
+ output: outputStr,
683
+ stdout: stdoutStr,
684
+ stderr: stderrStr,
685
+ };
686
+ }
687
+ /**
688
+ * Demultiplex combined stdout/stderr log data.
689
+ *
690
+ * @param data - Combined log bytes with STDOUT_PREFIX_BYTES and STDERR_PREFIX_BYTES markers
691
+ * @returns Tuple of [stdout_bytes, stderr_bytes]
692
+ */
693
+ function demuxLog(data) {
694
+ const outChunks = [];
695
+ const errChunks = [];
696
+ let state = 'none';
697
+ // Forward index (no per-loop re-slicing)
698
+ let i = 0;
699
+ while (i < data.length) {
700
+ // Find the nearest forward marker (stdout or stderr) from current index
701
+ const stdoutIndex = findSubarray(data, exports.STDOUT_PREFIX_BYTES, i);
702
+ const stderrIndex = findSubarray(data, exports.STDERR_PREFIX_BYTES, i);
703
+ // Pick the closest marker index and type
704
+ let nextIdx = -1;
705
+ let nextMarker = null;
706
+ let nextLen = 0;
707
+ if (stdoutIndex !== -1 && (stderrIndex === -1 || stdoutIndex < stderrIndex)) {
708
+ nextIdx = stdoutIndex;
709
+ nextMarker = 'stdout';
710
+ nextLen = exports.STDOUT_PREFIX_BYTES.length;
711
+ }
712
+ else if (stderrIndex !== -1) {
713
+ nextIdx = stderrIndex;
714
+ nextMarker = 'stderr';
715
+ nextLen = exports.STDERR_PREFIX_BYTES.length;
716
+ }
717
+ if (nextIdx === -1) {
718
+ // No more markers → dump remainder into current state
719
+ if (state === 'stdout') {
720
+ outChunks.push(data.subarray(i));
721
+ }
722
+ else if (state === 'stderr') {
723
+ errChunks.push(data.subarray(i));
724
+ }
725
+ break;
726
+ }
727
+ // Write everything before the marker into current state
728
+ if (state === 'stdout' && nextIdx > i) {
729
+ outChunks.push(data.subarray(i, nextIdx));
730
+ }
731
+ else if (state === 'stderr' && nextIdx > i) {
732
+ errChunks.push(data.subarray(i, nextIdx));
733
+ }
734
+ // Advance past marker and switch state
735
+ i = nextIdx + nextLen;
736
+ if (nextMarker) {
737
+ state = nextMarker;
738
+ }
739
+ }
740
+ // Concatenate all chunks
741
+ return [concatenateUint8Arrays(outChunks), concatenateUint8Arrays(errChunks)];
742
+ }
743
+ /**
744
+ * Efficiently concatenate multiple Uint8Array chunks into a single Uint8Array.
745
+ *
746
+ * @param chunks - Array of Uint8Array chunks to concatenate
747
+ * @returns A single Uint8Array containing all chunks
748
+ */
749
+ function concatenateUint8Arrays(chunks) {
750
+ if (chunks.length === 0) {
751
+ return new Uint8Array(0);
752
+ }
753
+ if (chunks.length === 1) {
754
+ return chunks[0];
755
+ }
756
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
757
+ const result = new Uint8Array(totalLength);
758
+ let offset = 0;
759
+ for (const chunk of chunks) {
760
+ result.set(chunk, offset);
761
+ offset += chunk.length;
762
+ }
763
+ return result;
764
+ }
765
+ /**
766
+ * Helper function to find a subarray within a larger array.
767
+ *
768
+ * @param haystack - The array to search in
769
+ * @param needle - The subarray to find
770
+ * @param fromIndex - starting index
771
+ * @returns The index of the first occurrence, or -1 if not found
772
+ */
773
+ function findSubarray(haystack, needle, fromIndex = 0) {
774
+ if (needle.length === 0)
775
+ return 0;
776
+ if (haystack.length < needle.length || fromIndex < 0 || fromIndex > haystack.length - needle.length)
777
+ return -1;
778
+ const limit = haystack.length - needle.length;
779
+ for (let i = fromIndex; i <= limit; i++) {
780
+ let j = 0;
781
+ for (; j < needle.length; j++) {
782
+ if (haystack[i + j] !== needle[j])
783
+ break;
784
+ }
785
+ if (j === needle.length)
786
+ return i;
787
+ }
788
+ return -1;
789
+ }
790
+ //# sourceMappingURL=Process.js.map