withruntime 0.9.0 → 0.11.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.
- package/BLAXEL.md +4 -4
- package/DAYTONA.md +52 -40
- package/E2B.md +65 -62
- package/README.md +15 -7
- package/README.src.md +15 -7
- package/VERCEL.md +34 -22
- package/compatibility-lock.json +16 -16
- package/dist/blaxel/errors.js +1 -1
- package/dist/blaxel/lookup.d.ts +3 -2
- package/dist/blaxel/lookup.js +3 -2
- package/dist/blaxel/pagination.d.ts +2 -2
- package/dist/blaxel/pagination.js +45 -17
- package/dist/blaxel/preview.d.ts +2 -1
- package/dist/blaxel/preview.js +15 -13
- package/dist/blaxel/process.js +56 -10
- package/dist/blaxel/sandbox.d.ts +2 -0
- package/dist/blaxel/sandbox.js +2 -0
- package/dist/blaxel/snapshot.js +3 -5
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +262 -56
- package/dist/client.d.ts +41 -3
- package/dist/client.js +67 -11
- package/dist/cloudflare/identity.d.ts +7 -0
- package/dist/cloudflare/identity.js +13 -0
- package/dist/cloudflare/index.d.ts +9 -0
- package/dist/cloudflare/index.js +47 -9
- package/dist/cloudflare/worker.d.ts +4 -0
- package/dist/cloudflare/worker.js +166 -16
- package/dist/codesandbox/guest-service.js +57 -20
- package/dist/codesandbox/index.js +42 -8
- package/dist/compat/core.d.ts +9 -8
- package/dist/compat/core.js +60 -21
- package/dist/compat/files.js +22 -4
- package/dist/compat/lease.d.ts +36 -0
- package/dist/compat/lease.js +87 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +107 -38
- package/dist/daytona/computer-use.d.ts +162 -0
- package/dist/daytona/computer-use.js +324 -0
- package/dist/daytona/context.d.ts +10 -0
- package/dist/daytona/context.js +24 -0
- package/dist/daytona/daytona.d.ts +20 -0
- package/dist/daytona/daytona.js +134 -20
- package/dist/daytona/filesystem.d.ts +17 -4
- package/dist/daytona/filesystem.js +129 -38
- package/dist/daytona/index.d.ts +3 -27
- package/dist/daytona/index.js +2 -7
- package/dist/daytona/process.d.ts +63 -6
- package/dist/daytona/process.js +224 -23
- package/dist/daytona/sandbox.d.ts +20 -6
- package/dist/daytona/sandbox.js +55 -32
- package/dist/e2b/client.d.ts +5 -0
- package/dist/e2b/client.js +6 -2
- package/dist/e2b/commands.d.ts +43 -12
- package/dist/e2b/commands.js +217 -64
- package/dist/e2b/errors.d.ts +7 -0
- package/dist/e2b/errors.js +20 -0
- package/dist/e2b/filesystem.d.ts +2 -1
- package/dist/e2b/filesystem.js +43 -6
- package/dist/e2b/index.d.ts +3 -2
- package/dist/e2b/index.js +2 -1
- package/dist/e2b/pty.d.ts +24 -0
- package/dist/e2b/pty.js +83 -0
- package/dist/e2b/sandbox.d.ts +17 -6
- package/dist/e2b/sandbox.js +239 -43
- package/dist/e2b/users.d.ts +30 -0
- package/dist/e2b/users.js +185 -0
- package/dist/file-source.d.ts +16 -0
- package/dist/file-source.js +162 -0
- package/dist/freestyle/index.d.ts +9 -1
- package/dist/freestyle/index.js +38 -5
- package/dist/index.d.ts +3 -1
- package/dist/login.js +16 -10
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.js +6 -1
- package/dist/modal/index.js +2 -1
- package/dist/network-cli.js +139 -43
- package/dist/openai-agents/index.js +9 -45
- package/dist/page.d.ts +1 -1
- package/dist/page.js +2 -2
- package/dist/products/browser.d.ts +60 -0
- package/dist/products/browser.js +37 -0
- package/dist/products/desktop.d.ts +2 -2
- package/dist/products/desktop.js +2 -2
- package/dist/products/images.d.ts +3 -1
- package/dist/products/images.js +14 -2
- package/dist/products/index.d.ts +14 -0
- package/dist/products/index.js +12 -0
- package/dist/products/network-products.d.ts +7 -0
- package/dist/products/network-products.js +3 -0
- package/dist/products/observability.d.ts +44 -0
- package/dist/products/observability.js +6 -0
- package/dist/products/previews.d.ts +8 -2
- package/dist/products/previews.js +11 -3
- package/dist/products/private-network.d.ts +22 -0
- package/dist/products/private-network.js +10 -0
- package/dist/products/volumes.d.ts +42 -0
- package/dist/products/volumes.js +36 -0
- package/dist/products/watch.js +61 -8
- package/dist/proxy.js +3 -1
- package/dist/runloop/index.d.ts +13 -27
- package/dist/runloop/index.js +149 -52
- package/dist/sandbox.d.ts +59 -8
- package/dist/sandbox.js +479 -68
- package/dist/snapshots.d.ts +9 -4
- package/dist/sprites/index.js +69 -33
- package/dist/tar.d.ts +3 -1
- package/dist/tar.js +140 -14
- package/dist/transport.d.ts +4 -7
- package/dist/transport.js +205 -122
- package/dist/types.d.ts +5 -2
- package/dist/vercel/command.d.ts +1 -1
- package/dist/vercel/command.js +3 -2
- package/dist/vercel/errors.d.ts +1 -1
- package/dist/vercel/errors.js +7 -1
- package/dist/vercel/index.d.ts +1 -7
- package/dist/vercel/index.js +1 -3
- package/dist/vercel/sandbox-user.d.ts +70 -0
- package/dist/vercel/sandbox-user.js +206 -0
- package/dist/vercel/sandbox.d.ts +55 -20
- package/dist/vercel/sandbox.js +353 -99
- package/dist/vercel/snapshot.d.ts +3 -2
- package/dist/vercel/snapshot.js +9 -5
- package/package.json +2 -1
package/dist/daytona/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { Daytona, CodeLanguage, SnapshotService, VolumeService, DEFAULT_RESOURCES, DEFAULT_AUTO_STOP_MINUTES, lifecycleOf, type CreateSandboxBaseParams, type CreateSandboxFromImageParams, type CreateSandboxFromSnapshotParams, type CreateSnapshotParams, type ForkSandboxParams, type ListSandboxesQuery, type PaginatedSnapshots, type Resources, type Snapshot, type Volume, type VolumeMount, } from "./daytona.js";
|
|
2
2
|
export { Sandbox, CodeInterpreter, networkRules, windowSeconds, type ExecutionError, type ExecutionResult, type InterpreterContext, type OutputMessage, type PortPreviewUrl, } from "./sandbox.js";
|
|
3
|
-
export { Process, CodeRunParams, type Command, type ExecuteResponse, type Session, type SessionCommandLogsResponse, type SessionExecuteRequest, type SessionExecuteResponse, } from "./process.js";
|
|
4
|
-
export { FileSystem, type FileDownloadRequest, type FileDownloadResponse, type FileInfo, type FilePermissionsParams, type FileUpload, type Match, type ReplaceResult, type SearchFilesResponse, type UploadSource, } from "./filesystem.js";
|
|
3
|
+
export { Process, CodeRunParams, PtyHandle, type PtyConnectOptions, type PtyCreateOptions, type PtyResult, type PtySessionInfo, type Command, type ExecuteResponse, type Session, type SessionCommandLogsResponse, type SessionExecuteRequest, type SessionExecuteResponse, } from "./process.js";
|
|
4
|
+
export { FileSystem, type FileDownloadRequest, type FileDownloadResponse, type FileInfo, type FilePermissionsParams, type FileUpload, type Match, type ReplaceResult, type SearchFilesResponse, type UploadSource, type UploadProgress, type UploadStreamOptions, } from "./filesystem.js";
|
|
5
5
|
export { Git, type GitStatus, type ListBranchResponse } from "./git.js";
|
|
6
|
+
export { Accessibility, ComputerUse, Display, Keyboard, Mouse, RecordingService, Screenshot, type ComputerUseStartResponse, type ComputerUseStatusResponse, type ComputerUseStopResponse, type DisplayInfo, type ListRecordingsResponse, type Recording, type ScreenshotOptions, type ScreenshotRegion, type ScreenshotResponse, type WindowInfo, } from "./computer-use.js";
|
|
6
7
|
export { Image } from "./image.js";
|
|
7
8
|
export { resolvePath } from "./context.js";
|
|
8
9
|
export type { DaytonaConfig, WithRuntime } from "./client.js";
|
|
@@ -18,31 +19,6 @@ export declare const SandboxState: {
|
|
|
18
19
|
readonly DESTROYED: "destroyed";
|
|
19
20
|
};
|
|
20
21
|
export type SandboxState = (typeof SandboxState)[keyof typeof SandboxState];
|
|
21
|
-
export declare const ComputerUse: {
|
|
22
|
-
(...args: unknown[]): never;
|
|
23
|
-
new (...args: unknown[]): never;
|
|
24
|
-
readonly [key: string]: (...args: unknown[]) => never;
|
|
25
|
-
};
|
|
26
|
-
export declare const Mouse: {
|
|
27
|
-
(...args: unknown[]): never;
|
|
28
|
-
new (...args: unknown[]): never;
|
|
29
|
-
readonly [key: string]: (...args: unknown[]) => never;
|
|
30
|
-
};
|
|
31
|
-
export declare const Keyboard: {
|
|
32
|
-
(...args: unknown[]): never;
|
|
33
|
-
new (...args: unknown[]): never;
|
|
34
|
-
readonly [key: string]: (...args: unknown[]) => never;
|
|
35
|
-
};
|
|
36
|
-
export declare const Screenshot: {
|
|
37
|
-
(...args: unknown[]): never;
|
|
38
|
-
new (...args: unknown[]): never;
|
|
39
|
-
readonly [key: string]: (...args: unknown[]) => never;
|
|
40
|
-
};
|
|
41
|
-
export declare const Display: {
|
|
42
|
-
(...args: unknown[]): never;
|
|
43
|
-
new (...args: unknown[]): never;
|
|
44
|
-
readonly [key: string]: (...args: unknown[]) => never;
|
|
45
|
-
};
|
|
46
22
|
export declare const LspLanguageId: {
|
|
47
23
|
(...args: unknown[]): never;
|
|
48
24
|
new (...args: unknown[]): never;
|
package/dist/daytona/index.js
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
import { NotSupportedError } from "./errors.js";
|
|
10
10
|
export { Daytona, CodeLanguage, SnapshotService, VolumeService, DEFAULT_RESOURCES, DEFAULT_AUTO_STOP_MINUTES, lifecycleOf, } from "./daytona.js";
|
|
11
11
|
export { Sandbox, CodeInterpreter, networkRules, windowSeconds, } from "./sandbox.js";
|
|
12
|
-
export { Process, CodeRunParams, } from "./process.js";
|
|
12
|
+
export { Process, CodeRunParams, PtyHandle, } from "./process.js";
|
|
13
13
|
export { FileSystem, } from "./filesystem.js";
|
|
14
14
|
export { Git } from "./git.js";
|
|
15
|
+
export { Accessibility, ComputerUse, Display, Keyboard, Mouse, RecordingService, Screenshot, } from "./computer-use.js";
|
|
15
16
|
export { Image } from "./image.js";
|
|
16
17
|
export { resolvePath } from "./context.js";
|
|
17
18
|
export * from "./errors.js";
|
|
@@ -41,10 +42,4 @@ function unsupportedExport(name, alternative) {
|
|
|
41
42
|
},
|
|
42
43
|
});
|
|
43
44
|
}
|
|
44
|
-
const DESKTOP = "Use Runtime's desktop: `await sandbox.withruntime.desktop.start()`.";
|
|
45
|
-
export const ComputerUse = unsupportedExport("computer use", DESKTOP);
|
|
46
|
-
export const Mouse = unsupportedExport("computer use (Mouse)", DESKTOP);
|
|
47
|
-
export const Keyboard = unsupportedExport("computer use (Keyboard)", DESKTOP);
|
|
48
|
-
export const Screenshot = unsupportedExport("computer use (Screenshot)", DESKTOP);
|
|
49
|
-
export const Display = unsupportedExport("computer use (Display)", DESKTOP);
|
|
50
45
|
export const LspLanguageId = unsupportedExport("language servers", "Start one in a session with process.executeSessionCommand(..., { runAsync: true }).");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Terminal } from "../sandbox.js";
|
|
1
2
|
import { quote, type SandboxContext } from "./context.js";
|
|
2
3
|
/** Daytona's ExecuteResponse. `result` is the command's stdout and stderr
|
|
3
4
|
* together, in the order they were written. */
|
|
@@ -76,11 +77,67 @@ export declare class Process {
|
|
|
76
77
|
deleteSession(sessionId: string): Promise<void>;
|
|
77
78
|
getEntrypointSession(): Promise<never>;
|
|
78
79
|
getEntrypointLogs(): Promise<never>;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
/** Starts an interactive shell on a terminal (a PTY) that outlives this
|
|
81
|
+
* connection: disconnect() leaves it running, connectPty(id) attaches
|
|
82
|
+
* again, killPtySession(id) ends it. On Runtime it is a process started
|
|
83
|
+
* with a terminal, found again by its id among the sandbox's processes. */
|
|
84
|
+
createPty(options: PtyCreateOptions & Partial<PtyConnectOptions>): Promise<PtyHandle>;
|
|
85
|
+
/** Attaches to a running PTY session. Output it printed before arrives
|
|
86
|
+
* first, then what it prints from now on. */
|
|
87
|
+
connectPty(sessionId: string, options?: Partial<PtyConnectOptions>): Promise<PtyHandle>;
|
|
88
|
+
listPtySessions(): Promise<PtySessionInfo[]>;
|
|
89
|
+
getPtySessionInfo(sessionId: string): Promise<PtySessionInfo>;
|
|
90
|
+
/** Ends the session's shell and everything it runs. */
|
|
91
|
+
killPtySession(sessionId: string): Promise<void>;
|
|
92
|
+
resizePtySession(sessionId: string, cols: number, rows: number): Promise<PtySessionInfo>;
|
|
93
|
+
}
|
|
94
|
+
/** Daytona's PtyCreateOptions. */
|
|
95
|
+
export interface PtyCreateOptions {
|
|
96
|
+
id: string;
|
|
97
|
+
cwd?: string;
|
|
98
|
+
envs?: Record<string, string>;
|
|
99
|
+
cols?: number;
|
|
100
|
+
rows?: number;
|
|
101
|
+
}
|
|
102
|
+
/** Daytona's PtyConnectOptions. */
|
|
103
|
+
export interface PtyConnectOptions {
|
|
104
|
+
onData: (data: Uint8Array) => void | Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
/** Daytona's PtyResult. */
|
|
107
|
+
export interface PtyResult {
|
|
108
|
+
exitCode?: number;
|
|
109
|
+
error?: string;
|
|
110
|
+
}
|
|
111
|
+
/** Daytona's PtySessionInfo. */
|
|
112
|
+
export interface PtySessionInfo {
|
|
113
|
+
active: boolean;
|
|
114
|
+
cols: number;
|
|
115
|
+
createdAt: string;
|
|
116
|
+
cwd: string;
|
|
117
|
+
envs: Record<string, string>;
|
|
118
|
+
id: string;
|
|
119
|
+
lazyStart: boolean;
|
|
120
|
+
rows: number;
|
|
121
|
+
}
|
|
122
|
+
/** One connection to a PTY session, Daytona's PtyHandle over Runtime's
|
|
123
|
+
* terminal WebSocket. */
|
|
124
|
+
export declare class PtyHandle {
|
|
125
|
+
#private;
|
|
126
|
+
readonly sessionId: string;
|
|
127
|
+
/** Use process.createPty or process.connectPty. */
|
|
128
|
+
constructor(terminal: Terminal, sessionId: string, resize: (cols: number, rows: number) => Promise<PtySessionInfo>, kill: () => Promise<void>);
|
|
129
|
+
get exitCode(): number | undefined;
|
|
130
|
+
get error(): string | undefined;
|
|
131
|
+
isConnected(): boolean;
|
|
132
|
+
/** Resolves at once: the handle is returned connected. */
|
|
133
|
+
waitForConnection(): Promise<void>;
|
|
134
|
+
sendInput(data: string | Uint8Array): Promise<void>;
|
|
135
|
+
resize(cols: number, rows: number): Promise<PtySessionInfo>;
|
|
136
|
+
/** Closes this connection; the session keeps running. */
|
|
137
|
+
disconnect(): Promise<void>;
|
|
138
|
+
/** Resolves when the session ends (or this connection closes) with its
|
|
139
|
+
* exit code, or `error` saying why there is none. */
|
|
140
|
+
wait(): Promise<PtyResult>;
|
|
141
|
+
kill(): Promise<void>;
|
|
85
142
|
}
|
|
86
143
|
export { quote };
|
package/dist/daytona/process.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { HOME, LONGEST_MS, quote, resolvePath, WHOLE_OUTPUT, } from "./context.js";
|
|
3
|
-
import { DaytonaCommandAlreadyCompletedError, DaytonaConflictError, DaytonaConnectionError, DaytonaNotFoundError, DaytonaProcessExecutionTimeoutError, DaytonaSessionEndedError, guard, NotSupportedError, } from "./errors.js";
|
|
2
|
+
import { HOME, LONGEST_MS, quote, resolvePath, runAs, WHOLE_OUTPUT, } from "./context.js";
|
|
3
|
+
import { DaytonaCommandAlreadyCompletedError, DaytonaConflictError, DaytonaConnectionError, DaytonaError, DaytonaNotFoundError, DaytonaProcessExecutionTimeoutError, DaytonaSessionEndedError, guard, NotSupportedError, } from "./errors.js";
|
|
4
4
|
export class CodeRunParams {
|
|
5
5
|
argv;
|
|
6
6
|
env;
|
|
@@ -57,6 +57,8 @@ class ShellSession {
|
|
|
57
57
|
export class Process {
|
|
58
58
|
#ctx;
|
|
59
59
|
#sessions = new Map();
|
|
60
|
+
/** What only this client knows of its PTY sessions: envs and size. */
|
|
61
|
+
#ptys = new Map();
|
|
60
62
|
constructor(ctx) {
|
|
61
63
|
this.#ctx = ctx;
|
|
62
64
|
}
|
|
@@ -64,6 +66,15 @@ export class Process {
|
|
|
64
66
|
const merged = { ...this.#ctx.env, ...extra };
|
|
65
67
|
return Object.keys(merged).length ? { env: merged } : {};
|
|
66
68
|
}
|
|
69
|
+
/** A command and its environment option as Runtime runs them: as given
|
|
70
|
+
* for the sandbox owner, through sudo for create's `user`. */
|
|
71
|
+
#as(command, extra) {
|
|
72
|
+
const user = this.#ctx.user;
|
|
73
|
+
if (!user)
|
|
74
|
+
return [command, this.#env(extra)];
|
|
75
|
+
const argv = typeof command === "string" ? ["bash", "-c", command] : command;
|
|
76
|
+
return [runAs(user, argv, { ...this.#ctx.env, ...extra }).argv, {}];
|
|
77
|
+
}
|
|
67
78
|
/** Runs a shell command and resolves with its exit code and output. A
|
|
68
79
|
* non-zero exit is a result, not an error. `timeout` is in seconds; past
|
|
69
80
|
* it the command is killed and DaytonaProcessExecutionTimeoutError is
|
|
@@ -72,9 +83,10 @@ export class Process {
|
|
|
72
83
|
await this.#ctx.ensureHome(`${command}\n${cwd ?? ""}`);
|
|
73
84
|
const runtime = await this.#ctx.live();
|
|
74
85
|
const timeoutMs = timeout ? timeout * 1000 : LONGEST_MS;
|
|
75
|
-
const
|
|
86
|
+
const [run, environment] = this.#as(`{ ${command}\n} 2>&1`, env);
|
|
87
|
+
const result = await guard("sandbox", () => runtime.exec(run, {
|
|
76
88
|
cwd: cwd === undefined ? HOME : resolvePath(cwd),
|
|
77
|
-
...
|
|
89
|
+
...environment,
|
|
78
90
|
timeoutMs,
|
|
79
91
|
...WHOLE_OUTPUT,
|
|
80
92
|
}));
|
|
@@ -96,9 +108,10 @@ export class Process {
|
|
|
96
108
|
? ["bun", "-e", code]
|
|
97
109
|
: ["node", "-e", code];
|
|
98
110
|
const timeoutMs = timeout ? timeout * 1000 : LONGEST_MS;
|
|
99
|
-
const
|
|
111
|
+
const [run, environment] = this.#as(["sh", "-c", 'exec "$@" 2>&1', "sh", ...interpreter, ...(params.argv ?? [])], params.env);
|
|
112
|
+
const result = await guard("sandbox", () => runtime.exec(run, {
|
|
100
113
|
cwd: HOME,
|
|
101
|
-
...
|
|
114
|
+
...environment,
|
|
102
115
|
timeoutMs,
|
|
103
116
|
...WHOLE_OUTPUT,
|
|
104
117
|
}));
|
|
@@ -120,9 +133,16 @@ export class Process {
|
|
|
120
133
|
if (this.#sessions.has(sessionId) || (await this.#discover(sessionId)))
|
|
121
134
|
throw new DaytonaConflictError(`Session ${sessionId} already exists.`, 409);
|
|
122
135
|
const runtime = await this.#ctx.live();
|
|
123
|
-
const
|
|
136
|
+
const [run, environment] = this.#as([
|
|
137
|
+
"bash",
|
|
138
|
+
"--noprofile",
|
|
139
|
+
"--norc",
|
|
140
|
+
"-s",
|
|
141
|
+
`${TAG}${sessionId}`,
|
|
142
|
+
]);
|
|
143
|
+
const process = await guard("sandbox", () => runtime.spawn(run, {
|
|
124
144
|
cwd: HOME,
|
|
125
|
-
...
|
|
145
|
+
...environment,
|
|
126
146
|
stdin: "pipe",
|
|
127
147
|
timeoutMs: LONGEST_MS,
|
|
128
148
|
}));
|
|
@@ -329,25 +349,209 @@ export class Process {
|
|
|
329
349
|
return entrypoint();
|
|
330
350
|
}
|
|
331
351
|
// ---- terminals ---------------------------------------------------------
|
|
332
|
-
|
|
333
|
-
|
|
352
|
+
/** Starts an interactive shell on a terminal (a PTY) that outlives this
|
|
353
|
+
* connection: disconnect() leaves it running, connectPty(id) attaches
|
|
354
|
+
* again, killPtySession(id) ends it. On Runtime it is a process started
|
|
355
|
+
* with a terminal, found again by its id among the sandbox's processes. */
|
|
356
|
+
async createPty(options) {
|
|
357
|
+
const id = options?.id;
|
|
358
|
+
if (!id)
|
|
359
|
+
throw new DaytonaError("A PTY session needs an id.", 400);
|
|
360
|
+
if (await this.#findPty(id))
|
|
361
|
+
throw new DaytonaConflictError(`PTY session ${id} already exists.`, 409);
|
|
362
|
+
const cols = options.cols ?? 80;
|
|
363
|
+
const rows = options.rows ?? 24;
|
|
364
|
+
await this.#ctx.ensureHome(options.cwd);
|
|
365
|
+
const cwd = options.cwd === undefined ? HOME : resolvePath(options.cwd);
|
|
366
|
+
const envs = { ...options.envs };
|
|
367
|
+
const runtime = await this.#ctx.live();
|
|
368
|
+
const [run, environment] = this.#as(["bash", "-l", "-i", "-s", ptyTag(id), `${cols}x${rows}`], {
|
|
369
|
+
TERM: "xterm-256color",
|
|
370
|
+
...envs,
|
|
371
|
+
});
|
|
372
|
+
const process = await guard("sandbox", () => runtime.spawn(run, { cwd, ...environment, pty: { cols, rows }, timeoutMs: LONGEST_MS }));
|
|
373
|
+
this.#ptys.set(id, { envs, cols, rows });
|
|
374
|
+
try {
|
|
375
|
+
return await this.#attach(id, process.id, options.onData);
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
await process.kill("SIGKILL").catch(() => undefined);
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/** Attaches to a running PTY session. Output it printed before arrives
|
|
383
|
+
* first, then what it prints from now on. */
|
|
384
|
+
async connectPty(sessionId, options) {
|
|
385
|
+
const found = await this.#findPty(sessionId);
|
|
386
|
+
if (!found)
|
|
387
|
+
throw new DaytonaNotFoundError(`PTY session ${sessionId} was not found.`, 404);
|
|
388
|
+
return this.#attach(sessionId, found.id, options?.onData);
|
|
389
|
+
}
|
|
390
|
+
async listPtySessions() {
|
|
391
|
+
const latest = new Map();
|
|
392
|
+
for (const info of await this.#ptyProcesses())
|
|
393
|
+
latest.set(ptyOf(info.command).id, info);
|
|
394
|
+
return [...latest.values()].map((info) => this.#ptyInfo(info));
|
|
395
|
+
}
|
|
396
|
+
async getPtySessionInfo(sessionId) {
|
|
397
|
+
const found = (await this.#ptyProcesses())
|
|
398
|
+
.filter((info) => ptyOf(info.command).id === sessionId)
|
|
399
|
+
.at(-1);
|
|
400
|
+
if (!found)
|
|
401
|
+
throw new DaytonaNotFoundError(`PTY session ${sessionId} was not found.`, 404);
|
|
402
|
+
return this.#ptyInfo(found);
|
|
403
|
+
}
|
|
404
|
+
/** Ends the session's shell and everything it runs. */
|
|
405
|
+
async killPtySession(sessionId) {
|
|
406
|
+
const process = await this.#ptyProcess(sessionId);
|
|
407
|
+
await guard("process", () => process.kill("SIGKILL"));
|
|
408
|
+
}
|
|
409
|
+
async resizePtySession(sessionId, cols, rows) {
|
|
410
|
+
const process = await this.#ptyProcess(sessionId);
|
|
411
|
+
await guard("process", () => process.resize(cols, rows));
|
|
412
|
+
const known = this.#ptys.get(sessionId);
|
|
413
|
+
this.#ptys.set(sessionId, { envs: known?.envs ?? {}, cols, rows });
|
|
414
|
+
return this.#ptyInfo({ ...process.info, state: "running" });
|
|
415
|
+
}
|
|
416
|
+
/** Terminal processes this adapter started, a killed one gone as on
|
|
417
|
+
* Daytona; an exited one stays, inactive. */
|
|
418
|
+
async #ptyProcesses() {
|
|
419
|
+
const runtime = await this.#ctx.live();
|
|
420
|
+
const list = await guard("sandbox", () => runtime.processes.list());
|
|
421
|
+
return list.filter((info) => info.state !== "killed" && ptyOf(info.command));
|
|
422
|
+
}
|
|
423
|
+
async #findPty(sessionId) {
|
|
424
|
+
return (await this.#ptyProcesses()).find((info) => info.state === "running" && ptyOf(info.command).id === sessionId);
|
|
425
|
+
}
|
|
426
|
+
async #ptyProcess(sessionId) {
|
|
427
|
+
const found = await this.#findPty(sessionId);
|
|
428
|
+
if (!found)
|
|
429
|
+
throw new DaytonaNotFoundError(`PTY session ${sessionId} was not found.`, 404);
|
|
430
|
+
const runtime = await this.#ctx.live();
|
|
431
|
+
return guard("process", () => runtime.processes.get(found.id));
|
|
432
|
+
}
|
|
433
|
+
#ptyInfo(info) {
|
|
434
|
+
const tag = ptyOf(info.command);
|
|
435
|
+
const known = this.#ptys.get(tag.id);
|
|
436
|
+
return {
|
|
437
|
+
active: info.state === "running",
|
|
438
|
+
cols: known?.cols ?? tag.cols,
|
|
439
|
+
createdAt: info.startedAt,
|
|
440
|
+
cwd: info.cwd,
|
|
441
|
+
envs: { ...known?.envs },
|
|
442
|
+
id: tag.id,
|
|
443
|
+
lazyStart: false,
|
|
444
|
+
rows: known?.rows ?? tag.rows,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
async #attach(sessionId, processId, onData) {
|
|
448
|
+
const runtime = await this.#ctx.live();
|
|
449
|
+
const terminal = await guard("sandbox", () => runtime.terminal({
|
|
450
|
+
processId,
|
|
451
|
+
...(onData
|
|
452
|
+
? {
|
|
453
|
+
onData: (data) => void Promise.resolve()
|
|
454
|
+
.then(() => onData(data))
|
|
455
|
+
.catch(() => undefined),
|
|
456
|
+
}
|
|
457
|
+
: {}),
|
|
458
|
+
}));
|
|
459
|
+
return new PtyHandle(terminal, sessionId, (cols, rows) => this.resizePtySession(sessionId, cols, rows), () => this.killPtySession(sessionId));
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/** One connection to a PTY session, Daytona's PtyHandle over Runtime's
|
|
463
|
+
* terminal WebSocket. */
|
|
464
|
+
export class PtyHandle {
|
|
465
|
+
sessionId;
|
|
466
|
+
#terminal;
|
|
467
|
+
#resize;
|
|
468
|
+
#kill;
|
|
469
|
+
#result;
|
|
470
|
+
#connected = true;
|
|
471
|
+
#disconnected = false;
|
|
472
|
+
#exitCode;
|
|
473
|
+
#error;
|
|
474
|
+
/** Use process.createPty or process.connectPty. */
|
|
475
|
+
constructor(terminal, sessionId, resize, kill) {
|
|
476
|
+
this.sessionId = sessionId;
|
|
477
|
+
this.#terminal = terminal;
|
|
478
|
+
this.#resize = resize;
|
|
479
|
+
this.#kill = kill;
|
|
480
|
+
this.#result = terminal.exited.then((code) => {
|
|
481
|
+
this.#connected = false;
|
|
482
|
+
if (code !== null)
|
|
483
|
+
this.#exitCode = code;
|
|
484
|
+
else
|
|
485
|
+
this.#error = this.#disconnected
|
|
486
|
+
? "Disconnected; the PTY session keeps running. connectPty() attaches again."
|
|
487
|
+
: "The PTY session was ended by a signal.";
|
|
488
|
+
return {
|
|
489
|
+
...(this.#exitCode === undefined ? {} : { exitCode: this.#exitCode }),
|
|
490
|
+
...(this.#error === undefined ? {} : { error: this.#error }),
|
|
491
|
+
};
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
get exitCode() {
|
|
495
|
+
return this.#exitCode;
|
|
496
|
+
}
|
|
497
|
+
get error() {
|
|
498
|
+
return this.#error;
|
|
334
499
|
}
|
|
335
|
-
|
|
336
|
-
return
|
|
500
|
+
isConnected() {
|
|
501
|
+
return this.#connected;
|
|
337
502
|
}
|
|
338
|
-
|
|
339
|
-
|
|
503
|
+
/** Resolves at once: the handle is returned connected. */
|
|
504
|
+
async waitForConnection() {
|
|
505
|
+
if (!this.#connected && this.#exitCode === undefined)
|
|
506
|
+
throw new DaytonaConnectionError(this.#error ?? "Connection closed");
|
|
340
507
|
}
|
|
341
|
-
|
|
342
|
-
|
|
508
|
+
async sendInput(data) {
|
|
509
|
+
if (!this.#connected)
|
|
510
|
+
throw new DaytonaConnectionError("PTY is not connected");
|
|
511
|
+
try {
|
|
512
|
+
this.#terminal.write(data);
|
|
513
|
+
}
|
|
514
|
+
catch (error) {
|
|
515
|
+
throw new DaytonaConnectionError(`Failed to send input to PTY: ${error instanceof Error ? error.message : String(error)}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
resize(cols, rows) {
|
|
519
|
+
return this.#resize(cols, rows);
|
|
520
|
+
}
|
|
521
|
+
/** Closes this connection; the session keeps running. */
|
|
522
|
+
async disconnect() {
|
|
523
|
+
if (!this.#connected)
|
|
524
|
+
return;
|
|
525
|
+
this.#disconnected = true;
|
|
526
|
+
this.#terminal.close();
|
|
343
527
|
}
|
|
344
|
-
|
|
345
|
-
|
|
528
|
+
/** Resolves when the session ends (or this connection closes) with its
|
|
529
|
+
* exit code, or `error` saying why there is none. */
|
|
530
|
+
wait() {
|
|
531
|
+
return this.#result;
|
|
346
532
|
}
|
|
347
|
-
|
|
348
|
-
return
|
|
533
|
+
kill() {
|
|
534
|
+
return this.#kill();
|
|
349
535
|
}
|
|
350
536
|
}
|
|
537
|
+
const PTY_TAG = "daytona-pty:";
|
|
538
|
+
/** A session id as one word of the shell's command line, found again by
|
|
539
|
+
* listPtySessions in any client. */
|
|
540
|
+
function ptyTag(id) {
|
|
541
|
+
return PTY_TAG + Buffer.from(id).toString("base64url");
|
|
542
|
+
}
|
|
543
|
+
function ptyOf(command) {
|
|
544
|
+
const words = String(command).split(" ");
|
|
545
|
+
const at = words.findIndex((word) => word.startsWith(PTY_TAG));
|
|
546
|
+
if (at < 0)
|
|
547
|
+
return undefined;
|
|
548
|
+
const size = /^(\d+)x(\d+)$/.exec(words[at + 1] ?? "");
|
|
549
|
+
return {
|
|
550
|
+
id: Buffer.from(words[at].slice(PTY_TAG.length), "base64url").toString(),
|
|
551
|
+
cols: Number(size?.[1] ?? 80),
|
|
552
|
+
rows: Number(size?.[2] ?? 24),
|
|
553
|
+
};
|
|
554
|
+
}
|
|
351
555
|
function describe(command) {
|
|
352
556
|
return {
|
|
353
557
|
id: command.id,
|
|
@@ -355,9 +559,6 @@ function describe(command) {
|
|
|
355
559
|
...(command.exitCode === undefined ? {} : { exitCode: command.exitCode }),
|
|
356
560
|
};
|
|
357
561
|
}
|
|
358
|
-
function pty() {
|
|
359
|
-
return Promise.reject(new NotSupportedError("Daytona's PTY sessions", "Use `await sandbox.withruntime.terminal({ cols, rows, onData })` for an interactive terminal, or a session for commands."));
|
|
360
|
-
}
|
|
361
562
|
function entrypoint() {
|
|
362
563
|
return Promise.reject(new NotSupportedError("The image entrypoint session", "A Runtime image does not run an entrypoint; start it with process.createSession and executeSessionCommand."));
|
|
363
564
|
}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import type { Runtime } from "../client.js";
|
|
2
2
|
import type { RuntimeSandbox } from "./client.js";
|
|
3
|
+
import { ComputerUse } from "./computer-use.js";
|
|
3
4
|
import { DaytonaNotFoundError } from "./errors.js";
|
|
4
5
|
import { FileSystem } from "./filesystem.js";
|
|
5
6
|
import { Git } from "./git.js";
|
|
6
7
|
import { Process } from "./process.js";
|
|
7
8
|
/** How the sandbox's lease follows Daytona's lifecycle settings. */
|
|
8
9
|
export interface Lifecycle {
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
10
|
+
/** The lease each call renews, 60 to 3600 seconds: Runtime's longest
|
|
11
|
+
* lease is an hour. */
|
|
11
12
|
windowSeconds: number;
|
|
13
|
+
/** Seconds without a call from this client before the sandbox pauses
|
|
14
|
+
* (Daytona's autoStopInterval); Infinity for 0, never. Past an hour the
|
|
15
|
+
* lease is renewed an hour at a time while this object lives. When
|
|
16
|
+
* absent, windowSeconds. */
|
|
17
|
+
idleSeconds?: number;
|
|
12
18
|
/** Epoch ms past which the lease is never extended (ttlMinutes). */
|
|
13
19
|
deadline?: number;
|
|
14
20
|
/** stop() ends the sandbox instead of pausing it (ephemeral, or
|
|
@@ -24,6 +30,8 @@ export interface SandboxOptions {
|
|
|
24
30
|
public: boolean;
|
|
25
31
|
lifecycle: Lifecycle;
|
|
26
32
|
snapshot?: string;
|
|
33
|
+
/** create's `user`, when not the sandbox owner. */
|
|
34
|
+
user?: string;
|
|
27
35
|
}
|
|
28
36
|
export type SandboxState = "started" | "starting" | "stopping" | "stopped" | "paused" | "destroying" | "destroyed";
|
|
29
37
|
export interface PortPreviewUrl {
|
|
@@ -90,7 +98,8 @@ export declare class Sandbox {
|
|
|
90
98
|
get name(): string;
|
|
91
99
|
get organizationId(): string;
|
|
92
100
|
/** Daytona's user name, so `/home/${sandbox.user}` leads to the working
|
|
93
|
-
* directory
|
|
101
|
+
* directory, and commands run as Runtime's sandbox owner, with passwordless
|
|
102
|
+
* sudo; or the user given at create, whose commands run through sudo. */
|
|
94
103
|
get user(): string;
|
|
95
104
|
get labels(): Record<string, string>;
|
|
96
105
|
get target(): string;
|
|
@@ -126,7 +135,7 @@ export declare class Sandbox {
|
|
|
126
135
|
/** Counts as activity: moves the lease a full autoStop window on. */
|
|
127
136
|
refreshActivity(): Promise<void>;
|
|
128
137
|
/** The sandbox pauses after `interval` minutes without a call from this
|
|
129
|
-
* client
|
|
138
|
+
* client; 0 never. Past an hour, while this object lives. */
|
|
130
139
|
setAutostopInterval(interval: number): Promise<void>;
|
|
131
140
|
setAutoPauseInterval(interval: number): Promise<void>;
|
|
132
141
|
/** Runtime has no archive tier; recorded only. */
|
|
@@ -161,8 +170,10 @@ export declare class Sandbox {
|
|
|
161
170
|
* named `name`; `daytona.create({ snapshot: name })` starts from it. */
|
|
162
171
|
createSnapshot(name: string, _timeout?: number): Promise<void>;
|
|
163
172
|
_experimental_createSnapshot(name: string, timeout?: number): Promise<void>;
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
/** Daytona's computer use over Runtime's desktop: `await
|
|
174
|
+
* sandbox.computerUse.start()`, then the mouse, keyboard and screenshots. */
|
|
175
|
+
get computerUse(): ComputerUse;
|
|
176
|
+
setLabels(labels: Record<string, string>): Promise<Record<string, string>>;
|
|
166
177
|
recover(): Promise<never>;
|
|
167
178
|
resize(): Promise<never>;
|
|
168
179
|
waitForResizeComplete(): Promise<never>;
|
|
@@ -181,6 +192,9 @@ export declare class Sandbox {
|
|
|
181
192
|
}
|
|
182
193
|
/** Daytona's autoStopInterval (minutes; 0 is off) as the lease window. */
|
|
183
194
|
export declare function windowSeconds(autoStopMinutes: number): number;
|
|
195
|
+
/** Daytona's autoStopInterval (minutes; 0 is never) as seconds without a
|
|
196
|
+
* call before the sandbox pauses. */
|
|
197
|
+
export declare function idleSeconds(autoStopMinutes: number): number;
|
|
184
198
|
/** Minutes as Runtime's retention: whole days, 1 to 365. */
|
|
185
199
|
export declare function retentionDays(minutes: number): number;
|
|
186
200
|
/** Daytona's network settings as Runtime's rules, or undefined for the
|